b70b29a36a351871d22e300bc9e413d028fe928b
[joid.git] / ci / genBundle.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 if LooseVersion(jujuver) >= LooseVersion('2'):
42     TPL_DIR = os.path.dirname(os.path.abspath(__file__))+'/config_tpl/juju2/bundle_tpl'
43 else:
44     TPL_DIR = os.path.dirname(os.path.abspath(__file__))+'/config_tpl/bundle_tpl'
45
46 #
47 # Prepare variables
48 #
49
50 # Prepare a storage for passwords
51 passwords_store = dict()
52
53 #
54 # Local Functions
55 #
56
57
58 def load_yaml(filepath):
59     """Load YAML file"""
60     with open(filepath, 'r') as stream:
61         try:
62             return yaml.load(stream)
63         except yaml.YAMLError as exc:
64             print(exc)
65
66 #
67 # Templates functions
68 #
69
70
71 def unit_qty():
72     """Return quantity of units to deploy"""
73     global config
74     if config['os']['ha']['mode'] == 'ha':
75         return config['os']['ha']['cluster_size']
76     else:
77         return 1
78
79
80 def unit_ceph_qty():
81     """Return size of the ceph cluster"""
82     global config
83     if config['os']['ha']['mode'] == 'ha':
84         return config['os']['ha']['cluster_size']
85     else:
86         if config['opnfv']['units'] >= 3:
87             return config['os']['ha']['cluster_size']
88         else:
89             return 2
90
91 def unit_scaleio_qty():
92     """Return size of the scaleio cluster"""
93     return 3
94
95 def to_select(qty=False):
96     """Return a random list of machines numbers to deploy"""
97     global config
98     if not qty:
99         qty = config['os']['ha']['cluster_size'] if \
100                 config['os']['ha']['mode'] == 'ha' else 1
101     if config['os']['hyperconverged']:
102         return random.sample(range(0, config['opnfv']['units']), qty)
103     else:
104         return random.sample(range(0, qty), qty)
105
106
107 def get_password(key, length=16, special=False):
108     """Return a new random password or a already created one"""
109     global passwords_store
110     if key not in passwords_store.keys():
111         alphabet = "abcdefghijklmnopqrstuvwxyz"
112         upperalphabet = alphabet.upper()
113         char_list = alphabet + upperalphabet + '0123456789'
114         pwlist = []
115         if special:
116             char_list += "+-,;./:?!*"
117         for i in range(length):
118             pwlist.append(char_list[random.randrange(len(char_list))])
119         random.shuffle(pwlist)
120         passwords_store[key] = "".join(pwlist)
121     return passwords_store[key]
122
123 #
124 # Config import
125 #
126
127 # Load scenario Config
128 config = load_yaml(scenarioconfig_file)
129 # Load lab Config
130 config.update(load_yaml(labconfig_file))
131
132 # We transform array to hash for an easier work
133 config['opnfv']['spaces_dict'] = dict()
134 for space in config['opnfv']['spaces']:
135     config['opnfv']['spaces_dict'][space['type']] = space
136 config['opnfv']['storage_dict'] = dict()
137 for storage in config['opnfv']['storage']:
138     config['opnfv']['storage_dict'][storage['type']] = storage
139
140 #
141 # Parse scenario name
142 #
143
144 # Set default scenario name
145 if not scenario:
146     scenario = "os-nosdn-nofeature-nonha"
147
148 # Parse scenario name
149 try:
150     sc = scenario.split('-')
151     (sdn, features, hamode) = sc[1:4]
152     features = features.split('_')
153     if len(sc) > 4:
154         extra = sc[4].split('_')
155     else:
156         extra = []
157 except ValueError as err:
158     print('Error: Bad scenario name syntax, use '
159           '"os-<controller>-<nfvfeature>-<mode>[-<extrastuff>]" format')
160     sys.exit(1)
161
162 #
163 # Update config with scenario name
164 #
165
166 # change ha mode
167 config['os']['ha']['mode'] = hamode
168
169 # change ha mode
170 config['os']['network']['controller'] = sdn
171
172 if 'ocl' in sdn:
173     config['os']['hyperconverged'] = False
174
175 # Change features
176 if 'lxd' in features:
177     config['os']['lxd'] = True
178 if 'dvr' in features:
179     config['os']['network']['dvr'] = True
180 if 'ipv6' in features:
181     config['os']['network']['ipv6'] = True
182 if 'ovs' in features:
183     config['os']['network']['enhanced_ovs'] = True
184 if 'sfc' in features:
185     config['os']['network']['sfc'] = True
186 if 'dpdk' in features:
187     config['os']['network']['dpdk'] = True
188     config['os']['beta']['huge_pages'] = True
189     config['os']['beta']['cpu_pin'] = True
190 if 'bgpvpn' in features:
191     config['os']['network']['bgpvpn'] = True
192 if 'odll3' in features:
193     config['os']['network']['odll3'] = True
194 if 'dishypcon' in features:
195     config['os']['hyperconverged'] = False
196 if 'hugepages' in features:
197     config['os']['beta']['huge_pages'] = True
198     config['os']['beta']['cpu_pin'] = True
199 if 'openbaton' in features:
200     config['os']['service']['openbaton'] = True
201
202
203 # Set beta option from extra
204 if 'publicapi' in extra:
205     config['os']['beta']['public_api'] = True
206 if 'radosgwcluster' in extra:
207     config['os']['beta']['hacluster_ceph_radosgw'] = True
208 if 'hugepages' in extra:
209     config['os']['beta']['huge_pages'] = True
210     config['os']['beta']['cpu_pin'] = True
211 if 'mitaka' in extra:
212     config['os']['release'] = 'mitaka'
213 if 'trusty' in extra:
214     config['ubuntu']['release'] = 'trusty'
215     if 'liberty' in extra:
216         config['os']['release'] = 'liberty'
217 if 'xenial' in extra:
218     config['ubuntu']['release'] = 'xenial'
219 if 'dishypcon' in extra:
220     config['os']['hyperconverged'] = False
221 if 'openbaton' in features:
222     config['os']['service']['openbaton'] = True
223
224 #
225 # Transform template to bundle.yaml according to config
226 #
227
228 # Create the jinja2 environment.
229 env = Environment(loader=FileSystemLoader(TPL_DIR),
230                   trim_blocks=True)
231 template = env.get_template('bundle.yaml')
232
233 # Add functions
234 env.globals.update(get_password=get_password)
235 env.globals.update(unit_qty=unit_qty)
236 env.globals.update(unit_ceph_qty=unit_ceph_qty)
237 env.globals.update(unit_scaleio_qty=unit_scaleio_qty)
238 env.globals.update(to_select=to_select)
239
240 # Render the template
241 output = template.render(**config)
242
243 # Check output syntax
244 try:
245     yaml.load(output)
246 except yaml.YAMLError as exc:
247     print(exc)
248
249 # print output
250 print(output)