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