f0198d77d4cf8addde61dd383e9f6aea5ad4b512
[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
165 # change ha mode
166 config['k8']['network']['controller'] = sdn
167
168 # Set beta option from extra
169 if 'hugepages' in extra:
170     config['os']['beta']['huge_pages'] = True
171 if 'lb' in extra:
172     config['k8']['feature']['loadbalancer'] = True
173 if 'mitaka' in extra:
174     config['os']['release'] = 'mitaka'
175 if 'xenial' in extra:
176     config['ubuntu']['release'] = 'xenial'
177
178 #
179 # Transform template to bundle.yaml according to config
180 #
181
182 # Create the jinja2 environment.
183 env = Environment(loader=FileSystemLoader(TPL_DIR),
184                   trim_blocks=True)
185 template = env.get_template('bundle.yaml')
186
187 # Add functions
188 env.globals.update(get_password=get_password)
189 env.globals.update(unit_qty=unit_qty)
190 env.globals.update(unit_ceph_qty=unit_ceph_qty)
191 env.globals.update(unit_scaleio_qty=unit_scaleio_qty)
192 env.globals.update(to_select=to_select)
193
194 # Render the template
195 output = template.render(**config)
196
197 # Check output syntax
198 try:
199     yaml.load(output)
200 except yaml.YAMLError as exc:
201     print(exc)
202
203 # print output
204 print(output)