2e08d3b9d411fd26a8d99e23b58ddeb6252e41ad
[apex.git] / lib / python / apex / inventory.py
1 ##############################################################################
2 # Copyright (c) 2016 Dan Radez (dradez@redhat.com) and others.
3 #
4 # All rights reserved. This program and the accompanying materials
5 # are made available under the terms of the Apache License, Version 2.0
6 # which accompanies this distribution, and is available at
7 # http://www.apache.org/licenses/LICENSE-2.0
8 ##############################################################################
9
10 import yaml
11 import json
12
13 from .common import constants
14 from .common import utils
15
16
17 class Inventory(dict):
18     """
19     This class parses an APEX inventory yaml file into an object. It
20     generates or detects all missing fields for deployment.
21
22     It then collapses one level of identification from the object to
23     convert it to a structure that can be dumped into a json file formatted
24     such that Triple-O can read the resulting json as an instackenv.json file.
25     """
26     def __init__(self, source, ha=True, virtual=False):
27         init_dict = {}
28         self.root_device = constants.DEFAULT_ROOT_DEV
29         if isinstance(source, str):
30             with open(source, 'r') as inventory_file:
31                 yaml_dict = yaml.safe_load(inventory_file)
32             # collapse node identifiers from the structure
33             init_dict['nodes'] = list(map(lambda n: n[1],
34                                           yaml_dict['nodes'].items()))
35         else:
36             # assume input is a dict to build from
37             init_dict = source
38
39         # move ipmi_* to pm_*
40         # make mac a list
41         def munge_nodes(node):
42             node['pm_addr'] = node['ipmi_ip']
43             node['pm_password'] = node['ipmi_pass']
44             node['pm_user'] = node['ipmi_user']
45             node['mac'] = [node['mac_address']]
46             if 'cpus' in node:
47                 node['cpu'] = node['cpus']
48
49             for i in ('ipmi_ip', 'ipmi_pass', 'ipmi_user', 'mac_address',
50                       'disk_device'):
51                 if i == 'disk_device' and 'disk_device' in node.keys():
52                     self.root_device = node[i]
53                 else:
54                     continue
55                 del node[i]
56
57             return node
58
59         super().__init__({'nodes': list(map(munge_nodes, init_dict['nodes']))})
60
61         # verify number of nodes
62         if ha and len(self['nodes']) < 5:
63             raise InventoryException('You must provide at least 5 '
64                                      'nodes for HA baremetal deployment')
65         elif len(self['nodes']) < 2:
66             raise InventoryException('You must provide at least 2 nodes '
67                                      'for non-HA baremetal deployment')
68
69         if virtual:
70             self['arch'] = 'x86_64'
71             self['host-ip'] = '192.168.122.1'
72             self['power_manager'] = \
73                 'nova.virt.baremetal.virtual_power_driver.VirtualPowerManager'
74             self['seed-ip'] = ''
75             self['ssh-key'] = 'INSERT_STACK_USER_PRIV_KEY'
76             self['ssh-user'] = 'root'
77
78     def dump_instackenv_json(self):
79         print(json.dumps(dict(self), sort_keys=True, indent=4))
80
81     def dump_bash(self, path=None):
82         """
83         Prints settings for bash consumption.
84
85         If optional path is provided, bash string will be written to the file
86         instead of stdout.
87         """
88         bash_str = "{}={}\n".format('root_disk_list', str(self.root_device))
89         utils.write_str(bash_str, path)
90
91
92 class InventoryException(Exception):
93     def __init__(self, value):
94         self.value = value
95
96     def __str__(self):
97             return self.value