modified to enable cpu pinning anf ceph.
[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     config['os']['beta']['huge_pages'] = True
186     config['os']['beta']['cpu_pin'] = True
187 if 'bgpvpn' in features:
188     config['os']['network']['bgpvpn'] = True
189 if 'odll3' in features:
190     config['os']['network']['odll3'] = True
191 if 'dishypcon' in features:
192     config['os']['hyperconverged'] = False
193 if 'hugepages' in features:
194     config['os']['beta']['huge_pages'] = True
195     config['os']['beta']['cpu_pin'] = True
196
197
198 # Set beta option from extra
199 if 'publicapi' in extra:
200     config['os']['beta']['public_api'] = True
201 if 'radosgwcluster' in extra:
202     config['os']['beta']['hacluster_ceph_radosgw'] = True
203 if 'hugepages' in extra:
204     config['os']['beta']['huge_pages'] = True
205     config['os']['beta']['cpu_pin'] = True
206 if 'mitaka' in extra:
207     config['os']['release'] = 'mitaka'
208 if 'trusty' in extra:
209     config['ubuntu']['release'] = 'trusty'
210     if 'liberty' in extra:
211         config['os']['release'] = 'liberty'
212 if 'xenial' in extra:
213     config['ubuntu']['release'] = 'xenial'
214 if 'dishypcon' in extra:
215     config['os']['hyperconverged'] = False
216
217 #
218 # Transform template to bundle.yaml according to config
219 #
220
221 # Create the jinja2 environment.
222 env = Environment(loader=FileSystemLoader(TPL_DIR),
223                   trim_blocks=True)
224 template = env.get_template('bundle.yaml')
225
226 # Add functions
227 env.globals.update(get_password=get_password)
228 env.globals.update(unit_qty=unit_qty)
229 env.globals.update(unit_ceph_qty=unit_ceph_qty)
230 env.globals.update(unit_scaleio_qty=unit_scaleio_qty)
231 env.globals.update(to_select=to_select)
232
233 # Render the template
234 output = template.render(**config)
235
236 # Check output syntax
237 try:
238     yaml.load(output)
239 except yaml.YAMLError as exc:
240     print(exc)
241
242 # print output
243 print(output)