adding support for Newton and correct provide type.
[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 # Change features
173 if 'lxd' in features:
174     config['os']['lxd'] = True
175 if 'dvr' in features:
176     config['os']['network']['dvr'] = True
177 if 'ipv6' in features:
178     config['os']['network']['ipv6'] = True
179 if 'ovs' in features:
180     config['os']['network']['enhanced_ovs'] = True
181 if 'sfc' in features:
182     config['os']['network']['sfc'] = True
183 if 'dpdk' in features:
184     config['os']['network']['dpdk'] = True
185 if 'bgpvpn' in features:
186     config['os']['network']['bgpvpn'] = True
187 if 'odll3' in features:
188     config['os']['network']['odll3'] = True
189 if 'dishypcon' in features:
190     config['os']['hyperconverged'] = False
191
192 # Set beta option from extra
193 if 'publicapi' in extra:
194     config['os']['beta']['public_api'] = True
195 if 'radosgwcluster' in extra:
196     config['os']['beta']['hacluster_ceph_radosgw'] = True
197 if 'hugepages' in extra:
198     config['os']['beta']['huge_pages'] = True
199 if 'trusty' in extra:
200     config['ubuntu']['release'] = 'trusty'
201     if 'liberty' in extra:
202         config['os']['release'] = 'liberty'
203 if 'xenial' in extra:
204     config['ubuntu']['release'] = 'xenial'
205     if 'newton' in extra:
206         config['os']['release'] = 'newton'
207 if 'dishypcon' in extra:
208     config['os']['hyperconverged'] = False
209
210 #
211 # Transform template to bundle.yaml according to config
212 #
213
214 # Create the jinja2 environment.
215 env = Environment(loader=FileSystemLoader(TPL_DIR),
216                   trim_blocks=True)
217 template = env.get_template('bundle.yaml')
218
219 # Add functions
220 env.globals.update(get_password=get_password)
221 env.globals.update(unit_qty=unit_qty)
222 env.globals.update(unit_ceph_qty=unit_ceph_qty)
223 env.globals.update(unit_scaleio_qty=unit_scaleio_qty)
224 env.globals.update(to_select=to_select)
225
226 # Render the template
227 output = template.render(**config)
228
229 # Check output syntax
230 try:
231     yaml.load(output)
232 except yaml.YAMLError as exc:
233     print(exc)
234
235 # print output
236 print(output)