Merge "Automatic Deployment - Deployment Hardware Adapter - Deployment Environment...
[genesis.git] / fuel / deploy / deploy.py
1 import subprocess
2 import sys
3 import time
4 import os
5 from dha import DeploymentHardwareAdapter
6 from dea import DeploymentEnvironmentAdapter
7
8 SUPPORTED_RELEASE = 'Juno on CentOS 6.5'
9 N = {'id': 0, 'status': 1, 'name': 2, 'cluster': 3, 'ip': 4, 'mac': 5,
10      'roles': 6, 'pending_roles': 7, 'online': 8}
11 E = {'id': 0, 'status': 1, 'name': 2, 'mode': 3, 'release_id': 4,
12      'changes': 5, 'pending_release_id': 6}
13 R = {'id': 0, 'name': 1, 'state': 2, 'operating_system': 3, 'version': 4}
14 RO = {'name': 0, 'conflicts': 1}
15
16 def exec_cmd(cmd):
17     process = subprocess.Popen(cmd,
18                                stdout=subprocess.PIPE,
19                                stderr=subprocess.STDOUT,
20                                shell=True)
21     return process.communicate()[0]
22
23 def parse(printout):
24    parsed_list = []
25    lines = printout.splitlines()
26    for l in lines[2:]:
27         parsed = [e.strip() for e in l.split('|')]
28         parsed_list.append(parsed)
29    return parsed_list
30
31 def err(error_message):
32     sys.stderr.write(error_message)
33     sys.exit(1)
34
35
36
37 class Deploy(object):
38
39     def __init__(self):
40         self.supported_release = None
41
42     def get_id_list(self, list):
43         return [l[0] for l in list]
44
45     def cleanup_fuel_environments(self, env_list):
46         WAIT_LOOP = 10
47         SLEEP_TIME = 2
48         id_list = self.get_id_list(env_list)
49         for id in id_list:
50             exec_cmd('fuel env --env %s --delete' % id)
51             for i in range(WAIT_LOOP):
52                 if id in self.get_id_list(parse(exec_cmd('fuel env list'))):
53                     time.sleep(SLEEP_TIME)
54                 else:
55                     continue
56
57     def cleanup_fuel_nodes(self, node_list):
58         for node in node_list:
59             if node[N['status']] == 'discover':
60                 exec_cmd('fuel node --node-id %s --delete-from-db'
61                          % node[N['id']])
62                 exec_cmd('dockerctl shell cobbler cobbler system remove '
63                          '--name node-%s' % node[N['id']])
64
65     def check_previous_installation(self):
66         env_list = parse(exec_cmd('fuel env list'))
67         if env_list:
68             self.cleanup_fuel_environments(env_list)
69         node_list = parse(exec_cmd('fuel node list'))
70         if node_list:
71             self.cleanup_fuel_nodes(node_list)
72
73     def check_supported_release(self):
74         release_list= parse(exec_cmd('fuel release -l'))
75         for release in release_list:
76             if release[R['name']] == SUPPORTED_RELEASE:
77                 self.supported_release = release
78                 break
79         if not self.supported_release:
80             err("This Fuel doesn't contain the following "
81                 "release: %s\n" % SUPPORTED_RELEASE)
82
83     def check_role_definitions(self):
84         role_list= parse(exec_cmd('fuel role --release %s'
85                                   % self.supported_release[R['id']]))
86         roles = [role[RO['name']] for role in role_list]
87         if 'compute' not in roles:
88             err("Role compute does not exist in release %"
89                 % self.supported_release[R['name']])
90         if 'controller' not in roles:
91             err("Role controller does not exist in release %"
92                 % self.supported_release[R['name']])
93
94     def check_prerequisites(self):
95         self.check_supported_release()
96         self.check_role_definitions()
97         self.check_previous_installation()
98
99     def count_discovered_nodes(self, node_list):
100         discovered_nodes = 0
101         for node in node_list:
102             if node[N['status']] == 'discover':
103                 discovered_nodes += 1
104         return discovered_nodes
105
106     def wait_for_discovered_blades(self, no_of_blades):
107         WAIT_LOOP = 10
108         SLEEP_TIME = 2
109         all_discovered = False
110         node_list = parse(exec_cmd('fuel node list'))
111         for i in range(WAIT_LOOP):
112             if (self.count_discovered_nodes(node_list) < no_of_blades):
113                 time.sleep(SLEEP_TIME)
114                 node_list = parse(exec_cmd('fuel node list'))
115             else:
116                 all_discovered = True
117                 break
118         if not all_discovered:
119             err("There are %s blades defined, but not all of "
120                 "them have been discovered\n" % no_of_blades)
121
122     def assign_cluster_node_ids(self, dha, dea, controllers, compute_hosts):
123         node_list= parse(exec_cmd('fuel node list'))
124         for shelf_id in dea.get_shelf_ids():
125             for blade_id in dea.get_blade_ids(shelf_id):
126                 blade_mac_list = dha.get_blade_mac_addresses(
127                     shelf_id, blade_id)
128
129                 found = False
130                 for node in node_list:
131                     if (node[N['mac']] in blade_mac_list and
132                         node[N['status']] == 'discover'):
133                         found = True
134                         break
135                 if found:
136                     if dea.is_controller(shelf_id, blade_id):
137                         controllers.append(node[N['id']])
138                     if dea.is_compute_host(shelf_id, blade_id):
139                         compute_hosts.append(node[N['id']])
140                 else:
141                     err("Could not find the Node ID for blade "
142                         "with MACs %s or blade is not in "
143                         "discover status\n" % blade_mac_list)
144
145     def env_exists(self, env_name):
146         env_list = parse(exec_cmd('fuel env --list'))
147         for env in env_list:
148             if env[E['name']] == env_name and env[E['status']] == 'new':
149                 return True
150         return False
151
152     def configure_environment(self, dea):
153         env_name = dea.get_environment_name()
154         exec_cmd('fuel env -c --name %s --release %s --mode ha --net neutron '
155                  '--nst vlan' % (env_name, self.supported_release[R['id']]))
156
157         if not self.env_exists(env_name):
158             err("Failed to create environment %s" % env_name)
159
160
161
162 def main():
163
164     yaml_path = exec_cmd('pwd').strip() + '/dea.yaml'
165     deploy = Deploy()
166
167     dea = DeploymentEnvironmentAdapter()
168
169     if not os.path.isfile(yaml_path):
170         sys.stderr.write("ERROR: File %s not found\n" % yaml_path)
171         sys.exit(1)
172
173     dea.parse_yaml(yaml_path)
174
175     dha = DeploymentHardwareAdapter(dea.get_server_type())
176
177     deploy.check_prerequisites()
178
179     dha.power_off_blades()
180
181     dha.configure_networking()
182
183     dha.reset_to_factory_defaults()
184
185     dha.set_boot_order()
186
187     dha.power_on_blades()
188
189     dha.get_blade_mac_addresses()
190
191     deploy.wait_for_discovered_blades(dea.get_no_of_blades())
192
193     controllers = []
194     compute_hosts = []
195     deploy.assign_cluster_node_ids(dha, dea, controllers, compute_hosts)
196
197     deploy.configure_environment(dea)
198
199
200
201 if __name__ == '__main__':
202     main()