summaryrefslogtreecommitdiffstats
path: root/validator/src/validation_tool/src/config.py
blob: 443467ee2f8c9a0951c7dbf6b12bb86d6fe62849 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
##############################################################################
# Copyright (c) 2015 Todd Gaunt and others.
#
# All rights reserved. This program and the accompanying materials
# are made available under the terms of the Apache License, Version 2.0
# which accompanies this distribution, and is available at
# http://www.apache.org/licenses/LICENSE-2.0
##############################################################################

import logging
import sys
import os
import yaml
import struct
import socket

from pharosvalidator import util
from collections import namedtuple

class Topology():
    """
    Topology: Class to store any number of Network classes
    and metadata about them
    """
    def __init__(self, yaml_config):
        # Dictionary of available networks
        self.logger = logging.getLogger(__name__)
        self.networks = {}
        self.external_networks = []

        # Fill the above dictionaries
        self.parse_yaml(yaml_config)

    def parse_yaml(self, yaml_config):
        """
        parse_yaml: parses the yaml configuration file this program uses
        for all the network and node information
        """
        config = safe_yaml_read(yaml_config)
        for network in config["networks"]:
            self.logger.info("Reading network section {}".format(network))
            if network == "admin":
                self.networks[network] = Network(config["networks"][network])
            #TODO
            elif network == "external":
                for external_network in config["networks"][network]:
                    self.external_networks.append(Network(external_network))

class Network():
    """
    Network: Class to store all information on a given network
    """
    def __init__(self, network):
        try:
            self.logger = logging.getLogger(__name__)

            # Some generic settings
            self.enabled = network["enabled"]
            self.vlan = network["vlan"]

            # VM settings
            self.installer_nic_type = network["installer_vm"]["nic_type"]
            self.installer_members = network["installer_vm"]["members"]
            self.installer_ip = network["installer_vm"]["ip"]

            # Tuple containing the minimum and maximum
            self.usable_ip_range = self.parse_ip_range(network["usable_ip_range"])
            self.gateway = network["gateway"]
            self.cidr = network["cidr"]
            self.dhcp_range = network["dhcp_range"]
            self.dns_domain = network["dns-domain"]
            self.dns_search = network["dns-search"]

            subnet, netmask = self.split_cidr(network["cidr"])
            self.subnet = subnet
            self.netmask = netmask

            # List of all dns servers
            self.dns_upstream = network["dns-upstream"]

            self.nic_mapping = {}
        except KeyError as e:
            self.logger.error("Field {} not available in network configuration file".format(e))

    def split_cidr(self, cidr):
        """
        split_cidr: Split up cidr notation subnets into a subnet string and a
        netmask string

        input: cidr notation of a subnet

        output: Subnet string; Netmask string
        """
        split = cidr.split('/')
        host_bits = int(split[1])
        netmask = self.cidr_to_netmask(host_bits)
        subnet = split[0]

        return subnet, netmask

    def parse_ip_range(self, ip_range_string):
        """
        parse_ip_range: Create a named tuple object that contains the lowest
        ip address and the highest ip address from a configuration file

        input: String formatted like so "min, max" where min/max are ip addresses

        output: Named tuple object containing a minimum and maximum field
        """
        rp = ip_range_string.split(",")
        ip_range = namedtuple("ip_range", ['minimum', 'maximum'])(minimum=min(rp), maximum=max(rp))
        return ip_range

    def cidr_to_netmask(self, cidr):
        bits = 0xffffffff ^ (1 << 32 - cidr) - 1
        netmask = socket.inet_ntoa(struct.pack('>I', bits))
        self.logger.debug("Netmask generated from cidr '{}': '{}'".format(cidr, netmask))
        return netmask

class Inventory():
    """
    Inventory: Class to hold configuration file data
    """
    def __init__(self, yaml_config):
        # Create the class logger
        self.logger = logging.getLogger(__name__)

        self.nodes = []

        # Fill the above list
        self.parse_yaml(yaml_config)

    def parse_yaml(self, yaml_config):
        config = safe_yaml_read(yaml_config)
        nodes = []
        for node in config["nodes"]:
            self.nodes.append(Node(node))

    def nodecount(self):
        return len(self.nodes)

class Node():
    """
    Node: Class to hold
    """
    def __init__(self, node):
        self.logger = logging.getLogger(__name__)
        try:
            self.name = node["name"]
            self.tags = node["tags"]
            self.arch = node["arch"]
            self.mac_address = node["mac_address"] # ipmi mac address
            self.cpus = node["cpus"]
            self.memory = node["memory"]
            self.disk = node["disk"]
        except KeyError as e:
            self.logger.error("Field {} not available in inventory file".format(e))

        # Power sub section
        if node["power"]["type"] == "ipmi":
            try:
                self.ipmi_addr = node["power"]["address"]
                self.ipmi_user = node["power"]["user"]
                self.ipmi_pass = node["power"]["pass"]
            except KeyError as e:
                self.logger.error("Field {} not available in inventory file".format(e))
        else:
            pass

def safe_yaml_read(yamlfile):
    logger = logging.getLogger(__name__)
    if os.path.isfile(yamlfile) == False:
        logger.critical("Could not open find {}".format(yamlfile))
        quit(1)
    with open(yamlfile, 'r') as fd:
        return yaml.load(fd.read())