Merge "cleanup old controllers and models for virtual deployments"
[joid.git] / ci / genK8Bundle.py
1 #!/usr/bin/python
2 # -*- coding: utf-8 -*-
3
4 """
5 This script generates a juju deployer bundle based on
6 scenario name, and lab config file.
7
8 Parameters:
9  -s, --scenario : scenario name
10  -l, --lab      : lab config file
11 """
12
13 from optparse import OptionParser
14 from jinja2 import Environment, FileSystemLoader
15 from distutils.version import LooseVersion, StrictVersion
16 import os
17 import subprocess
18 import random
19 import yaml
20 import sys
21
22 #
23 # Parse parameters
24 #
25
26 parser = OptionParser()
27 parser.add_option("-s", "--scenario", dest="scenario", help="scenario name")
28 parser.add_option("-l", "--lab", dest="lab", help="lab config file")
29 (options, args) = parser.parse_args()
30 scenario = options.scenario
31 labconfig_file = options.lab
32
33 #
34 # Set Path and configs path
35 #
36
37 scenarioconfig_file = 'default_deployment_config.yaml'
38 # Capture our current directory
39 jujuver = subprocess.check_output(["juju", "--version"])
40
41 TPL_DIR = os.path.dirname(os.path.abspath(__file__))+'/config_tpl/juju2/bundlek8_tpl'
42
43 #
44 # Prepare variables
45 #
46
47 # Prepare a storage for passwords
48 passwords_store = dict()
49
50 #
51 # Local Functions
52 #
53
54
55 def load_yaml(filepath):
56     """Load YAML file"""
57     with open(filepath, 'r') as stream:
58         try:
59             return yaml.load(stream)
60         except yaml.YAMLError as exc:
61             print(exc)
62
63 #
64 # Templates functions
65 #
66
67
68 def unit_qty():
69     """Return quantity of units to deploy"""
70     global config
71     if config['os']['ha']['mode'] == 'ha':
72         return config['os']['ha']['cluster_size']
73     else:
74         return 1
75
76
77 def unit_ceph_qty():
78     """Return size of the ceph cluster"""
79     global config
80     if config['os']['ha']['mode'] == 'ha':
81         return config['os']['ha']['cluster_size']
82     else:
83         if config['opnfv']['units'] >= 3:
84             return config['os']['ha']['cluster_size']
85         else:
86             return 2
87
88 def unit_scaleio_qty():
89     """Return size of the scaleio cluster"""
90     return 3
91
92 def to_select(qty=False):
93     """Return a random list of machines numbers to deploy"""
94     global config
95     if not qty:
96         qty = config['os']['ha']['cluster_size'] if \
97                 config['os']['ha']['mode'] == 'ha' else 1
98     if config['os']['hyperconverged']:
99         return random.sample(range(0, config['opnfv']['units']), qty)
100     else:
101         return random.sample(range(0, qty), qty)
102
103
104 def get_password(key, length=16, special=False):
105     """Return a new random password or a already created one"""
106     global passwords_store
107     if key not in passwords_store.keys():
108         alphabet = "abcdefghijklmnopqrstuvwxyz"
109         upperalphabet = alphabet.upper()
110         char_list = alphabet + upperalphabet + '0123456789'
111         pwlist = []
112         if special:
113             char_list += "+-,;./:?!*"
114         for i in range(length):
115             pwlist.append(char_list[random.randrange(len(char_list))])
116         random.shuffle(pwlist)
117         passwords_store[key] = "".join(pwlist)
118     return passwords_store[key]
119
120 #
121 # Config import
122 #
123
124 # Load scenario Config
125 config = load_yaml(scenarioconfig_file)
126 # Load lab Config
127 config.update(load_yaml(labconfig_file))
128
129 # We transform array to hash for an easier work
130 config['opnfv']['spaces_dict'] = dict()
131 for space in config['opnfv']['spaces']:
132     config['opnfv']['spaces_dict'][space['type']] = space
133 config['opnfv']['storage_dict'] = dict()
134 for storage in config['opnfv']['storage']:
135     config['opnfv']['storage_dict'][storage['type']] = storage
136
137 #
138 # Parse scenario name
139 #
140
141 # Set default scenario name
142 if not scenario:
143     scenario = "k8-nosdn-baremetal-core"
144
145 # Parse scenario name
146 try:
147     sc = scenario.split('-')
148     (sdn, features, hamode) = sc[1:4]
149     features = features.split('_')
150     if len(sc) > 4:
151         extra = sc[4].split('_')
152     else:
153         extra = []
154 except ValueError as err:
155     print('Error: Bad scenario name syntax, use '
156           '"k8-nosdn-baremetal-core" format')
157     sys.exit(1)
158
159 #
160 # Update config with scenario name
161 #
162
163 if 'dpdk' in features:
164     config['os']['network']['dpdk'] = True
165 if 'lb' in features:
166     config['k8']['feature']['loadbalancer'] = True
167
168 # change ha mode
169 config['k8']['network']['controller'] = sdn
170
171 # Set beta option from extra
172 if 'hugepages' in extra:
173     config['os']['beta']['huge_pages'] = True
174 if 'lb' in extra:
175     config['k8']['feature']['loadbalancer'] = True
176 if 'mitaka' in extra:
177     config['os']['release'] = 'mitaka'
178 if 'xenial' in extra:
179     config['ubuntu']['release'] = 'xenial'
180
181 #
182 # Transform template to bundle.yaml according to config
183 #
184
185 # Create the jinja2 environment.
186 env = Environment(loader=FileSystemLoader(TPL_DIR),
187                   trim_blocks=True)
188 template = env.get_template('bundle.yaml')
189
190 # Add functions
191 env.globals.update(get_password=get_password)
192 env.globals.update(unit_qty=unit_qty)
193 env.globals.update(unit_ceph_qty=unit_ceph_qty)
194 env.globals.update(unit_scaleio_qty=unit_scaleio_qty)
195 env.globals.update(to_select=to_select)
196
197 # Render the template
198 output = template.render(**config)
199
200 # Check output syntax
201 try:
202     yaml.load(output)
203 except yaml.YAMLError as exc:
204     print(exc)
205
206 # print output
207 print(output)