Merge "Auto Generated INFO.yaml file"
[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 TPL_DIR = os.path.dirname(os.path.abspath(__file__))+'/config_tpl/juju2/bundlek8_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 = "k8-nosdn-baremetal-core"
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           '"k8-nosdn-baremetal-core" format')
154     sys.exit(1)
155
156 #
157 # Update config with scenario name
158 #
159
160 if 'dpdk' in features:
161     config['os']['network']['dpdk'] = True
162 if 'lb' in features:
163     config['k8']['feature']['loadbalancer'] = True
164 if 'ceph' in features:
165     config['k8']['feature']['storage'] = 'ceph'
166
167 # change ha mode
168 config['k8']['network']['controller'] = sdn
169
170 # Set beta option from extra
171 if 'hugepages' in extra:
172     config['os']['beta']['huge_pages'] = True
173 if 'lb' in extra:
174     config['k8']['feature']['loadbalancer'] = True
175 if 'mitaka' in extra:
176     config['os']['release'] = 'mitaka'
177 if 'xenial' in extra:
178     config['ubuntu']['release'] = 'xenial'
179
180 #
181 # Transform template to bundle.yaml according to config
182 #
183
184 # Create the jinja2 environment.
185 env = Environment(loader=FileSystemLoader(TPL_DIR),
186                   trim_blocks=True)
187 template = env.get_template('bundle.yaml')
188
189 # Add functions
190 env.globals.update(get_password=get_password)
191 env.globals.update(unit_qty=unit_qty)
192 env.globals.update(unit_ceph_qty=unit_ceph_qty)
193 env.globals.update(unit_scaleio_qty=unit_scaleio_qty)
194 env.globals.update(to_select=to_select)
195
196 # Render the template
197 output = template.render(**config)
198
199 # Check output syntax
200 try:
201     yaml.load(output)
202 except yaml.YAMLError as exc:
203     print(exc)
204
205 # print output
206 print(output)