Merge ~gavin.lin/cc-lab-manager:add-main into cc-lab-manager:master
- Git
- lp:~gavin.lin/cc-lab-manager
- add-main
- Merge into master
Proposed by
Gavin Lin
Status: | Merged |
---|---|
Approved by: | Gavin Lin |
Approved revision: | e83324914f0fbda4313bdac902f2ea3494738591 |
Merged at revision: | 335a4ab8693473435f127bac4fe2c539bef2f791 |
Proposed branch: | ~gavin.lin/cc-lab-manager:add-main |
Merge into: | cc-lab-manager:master |
Diff against target: |
1512 lines (+1005/-62) 32 files modified
build/lib/cc_lab_manager/c3_db/c3_db.py (+22/-5) build/lib/cc_lab_manager/commands/__init__.py (+0/-0) build/lib/cc_lab_manager/commands/cc_lab_manager.py (+49/-0) build/lib/cc_lab_manager/dhcp/__init__.py (+0/-0) build/lib/cc_lab_manager/dhcp/dhcp_config_generator.py (+31/-14) build/lib/cc_lab_manager/gen_config/__init__.py (+0/-0) build/lib/cc_lab_manager/gen_config/gen_agent_tf_config.py (+35/-25) build/lib/cc_lab_manager/gsheet_db/__init__.py (+0/-0) build/lib/cc_lab_manager/gsheet_db/db_gsheet.py (+7/-7) build/lib/cc_lab_manager/maas/__init__.py (+0/-0) build/lib/cc_lab_manager/maas/create_maas_node.py (+11/-10) cc_lab_manager.egg-info/PKG-INFO (+11/-0) cc_lab_manager.egg-info/SOURCES.txt (+23/-0) cc_lab_manager.egg-info/dependency_links.txt (+1/-0) cc_lab_manager.egg-info/entry_points.txt (+3/-0) cc_lab_manager.egg-info/requires.txt (+4/-0) cc_lab_manager.egg-info/top_level.txt (+1/-0) cc_lab_manager/__init__.py (+0/-0) cc_lab_manager/c3_db/__init__.py (+0/-0) cc_lab_manager/c3_db/c3_db.py (+128/-0) cc_lab_manager/commands/__init__.py (+0/-0) cc_lab_manager/commands/cc_lab_manager.py (+49/-0) cc_lab_manager/dhcp/__init__.py (+0/-0) cc_lab_manager/dhcp/dhcp_config_generator.py (+96/-0) cc_lab_manager/gen_config/__init__.py (+0/-0) cc_lab_manager/gen_config/gen_agent_tf_config.py (+203/-0) cc_lab_manager/gsheet_db/__init__.py (+0/-0) cc_lab_manager/gsheet_db/db_gsheet.py (+107/-0) cc_lab_manager/gsheet_db/gsheet_db.py (+91/-0) cc_lab_manager/maas/__init__.py (+0/-0) cc_lab_manager/maas/create_maas_node.py (+124/-0) setup.py (+9/-1) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Kevin Yeh | Approve | ||
Review via email: mp+421633@code.launchpad.net |
Commit message
Combine functions into a workflow and work in a single command.
Description of the change
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | diff --git a/cc-lab-manager/c3-db/__init__.py b/build/lib/cc_lab_manager/__init__.py |
2 | similarity index 100% |
3 | rename from cc-lab-manager/c3-db/__init__.py |
4 | rename to build/lib/cc_lab_manager/__init__.py |
5 | diff --git a/cc-lab-manager/dhcp/__init__.py b/build/lib/cc_lab_manager/c3_db/__init__.py |
6 | similarity index 100% |
7 | rename from cc-lab-manager/dhcp/__init__.py |
8 | rename to build/lib/cc_lab_manager/c3_db/__init__.py |
9 | diff --git a/cc-lab-manager/c3-db/c3-db.py b/build/lib/cc_lab_manager/c3_db/c3_db.py |
10 | similarity index 86% |
11 | rename from cc-lab-manager/c3-db/c3-db.py |
12 | rename to build/lib/cc_lab_manager/c3_db/c3_db.py |
13 | index a9f6779..b9b0d7e 100644 |
14 | --- a/cc-lab-manager/c3-db/c3-db.py |
15 | +++ b/build/lib/cc_lab_manager/c3_db/c3_db.py |
16 | @@ -1,7 +1,9 @@ |
17 | import sqlite3 |
18 | import logging |
19 | +import argparse |
20 | import c3.api.query as c3query |
21 | from c3.api.api_utils import APIQuery |
22 | +import os |
23 | |
24 | logger = logging.getLogger('cc-lab-manager') |
25 | |
26 | @@ -22,6 +24,8 @@ def c3_to_db(db_path): |
27 | for cid_db in cid_list: |
28 | cid = ''.join(cid_db) |
29 | logger.info('Processing {}...'.format(cid)) |
30 | + if '-' not in cid or 'TEL' in cid: |
31 | + continue |
32 | |
33 | # Query hardware info from c3 |
34 | result = '' |
35 | @@ -94,17 +98,30 @@ def c3_to_db(db_path): |
36 | hwdb.close() |
37 | |
38 | |
39 | +def environ_or_required(key): |
40 | + if os.environ.get(key): |
41 | + return {'default': os.environ.get(key)} |
42 | + else: |
43 | + return {'required': True} |
44 | + |
45 | + |
46 | def main(): |
47 | + parser = argparse.ArgumentParser() |
48 | + parser.add_argument('--conf', help="Config file for C3 API", default = os.environ.get('CCLM_CC_TOOL_BOX') + '/config/c3-cli/my_conf.ini') |
49 | + parser.add_argument('--c3user', help="C3 User Account", **environ_or_required('CCLM_C3_USERNAME')) |
50 | + parser.add_argument('--c3apikey', help="C3 API Key", **environ_or_required('CCLM_C3_APIKEY')) |
51 | + parser.add_argument('--hwdb', help="C3 API Key", **environ_or_required('CCLM_HARDWARE_DB')) |
52 | + args = parser.parse_args() |
53 | + |
54 | ci = c3query.configuration.get_instance() |
55 | - ci.read_configuration('my_conf.ini') |
56 | + ci.read_configuration(args.conf) |
57 | |
58 | api = APIQuery(ci.config['C3']['URI']) |
59 | - rparam = {"username": ci.config['C3']['UserName'], |
60 | - "api_key": ci.config['C3']['APIKey']} |
61 | + rparam = {"username": args.c3user, |
62 | + "api_key": args.c3apikey} |
63 | |
64 | c3query.api_instance.set_api_params(api, rparam) |
65 | - hwdb = './hardware.db' |
66 | - c3_to_db(hwdb) |
67 | + c3_to_db(args.hwdb) |
68 | |
69 | |
70 | if __name__ == '__main__': |
71 | diff --git a/build/lib/cc_lab_manager/commands/__init__.py b/build/lib/cc_lab_manager/commands/__init__.py |
72 | new file mode 100644 |
73 | index 0000000..e69de29 |
74 | --- /dev/null |
75 | +++ b/build/lib/cc_lab_manager/commands/__init__.py |
76 | diff --git a/build/lib/cc_lab_manager/commands/cc_lab_manager.py b/build/lib/cc_lab_manager/commands/cc_lab_manager.py |
77 | new file mode 100644 |
78 | index 0000000..7da03df |
79 | --- /dev/null |
80 | +++ b/build/lib/cc_lab_manager/commands/cc_lab_manager.py |
81 | @@ -0,0 +1,49 @@ |
82 | +import logging |
83 | +import os |
84 | +import sys |
85 | + |
86 | +from cc_lab_manager.gsheet_db import gsheet_db |
87 | +from cc_lab_manager.gsheet_db import db_gsheet |
88 | +from cc_lab_manager.c3_db import c3_db |
89 | +from cc_lab_manager.dhcp import dhcp_config_generator |
90 | +from cc_lab_manager.maas import create_maas_node |
91 | +from cc_lab_manager.gen_config import gen_agent_tf_config |
92 | + |
93 | +logger = logging.getLogger('cc-lab-manager') |
94 | + |
95 | +def main(): |
96 | + # Read data from the google sheet to db |
97 | + gsheet_db.main() |
98 | + |
99 | + # Get needed information from c3 |
100 | + c3_db.main() |
101 | + |
102 | + # Generate DHCP config for each subnets |
103 | + # TODO: Currently these config files need to be copied |
104 | + # manually, then MAAS will apply it automatically |
105 | + dhcp_config_generator.main() |
106 | + |
107 | + # Create MAAS nodes for DUTs |
108 | + create_maas_node.main() |
109 | + |
110 | + # Create agent configs for DUTs |
111 | + # TODO: Currently these configs need to be push/pull |
112 | + # and applied manually |
113 | + gen_agent_tf_config.main() |
114 | + |
115 | + # Write data in db back to the google sheet |
116 | + db_gsheet.main() |
117 | + |
118 | + #ci = c3query.configuration.get_instance() |
119 | + |
120 | + #api = APIQuery(ci.config['C3']['URI']) |
121 | + #rparam = {"username": ci.config['C3']['UserName'], |
122 | + # "api_key": ci.config['C3']['APIKey']} |
123 | + |
124 | + #c3query.api_instance.set_api_params(api, rparam) |
125 | + #hwdb = './hardware.db' |
126 | + #c3_to_db(hwdb) |
127 | + |
128 | + |
129 | +if __name__ == '__main__': |
130 | + main() |
131 | diff --git a/build/lib/cc_lab_manager/dhcp/__init__.py b/build/lib/cc_lab_manager/dhcp/__init__.py |
132 | new file mode 100644 |
133 | index 0000000..e69de29 |
134 | --- /dev/null |
135 | +++ b/build/lib/cc_lab_manager/dhcp/__init__.py |
136 | diff --git a/cc-lab-manager/dhcp/dhcp-config-generator.py b/build/lib/cc_lab_manager/dhcp/dhcp_config_generator.py |
137 | similarity index 69% |
138 | rename from cc-lab-manager/dhcp/dhcp-config-generator.py |
139 | rename to build/lib/cc_lab_manager/dhcp/dhcp_config_generator.py |
140 | index 4ea854f..e586dd4 100644 |
141 | --- a/cc-lab-manager/dhcp/dhcp-config-generator.py |
142 | +++ b/build/lib/cc_lab_manager/dhcp/dhcp_config_generator.py |
143 | @@ -1,7 +1,8 @@ |
144 | import sqlite3 |
145 | import logging |
146 | +import argparse |
147 | +import os |
148 | from jinja2 import Template |
149 | -import c3.api.query as c3query |
150 | |
151 | logger = logging.getLogger('cc-lab-manager') |
152 | |
153 | @@ -38,15 +39,19 @@ host {{Lab}}-{{Frame}}-S{{Shelf}}-P{{Partition}}-ctl { |
154 | |
155 | ''' |
156 | |
157 | - def generate_dhcp_conf(self, ip_mac_list, dhcp_conf): |
158 | - dhcp_conf_data = '' |
159 | + def generate_dhcp_conf(self, ip_mac_list, dhcp_conf_path): |
160 | + dhcp_conf_data = {} |
161 | for ip_mac in ip_mac_list: |
162 | if ip_mac['IP'] == '' or ip_mac['Controller_IP'] == ''\ |
163 | or ip_mac['Lab'] == '' or ip_mac['Frame'] == ''\ |
164 | or ip_mac['Shelf'] == '' or ip_mac['Partition'] == '': |
165 | - logger.error("Missing required information for", ip_mac['CID']) |
166 | + if ip_mac['CID'] == '': |
167 | + ip_mac_list.remove(ip_mac) |
168 | + else: |
169 | + logger.info("Missing required information for", ip_mac['CID']) |
170 | continue |
171 | |
172 | + # Generate MAC for dummy devices or devices without fixed MAC |
173 | if ip_mac['MAC'] == '': |
174 | ip = ip_mac['IP'].split('.') |
175 | ip_mac['MAC'] = (f'ff:ff:ff:{int(ip[1]):02x}:' |
176 | @@ -56,23 +61,35 @@ host {{Lab}}-{{Frame}}-S{{Shelf}}-P{{Partition}}-ctl { |
177 | ip_mac['Controller_MAC'] = (f'ff:ff:ff:{int(ip[1]):02x}:' |
178 | f'{int(ip[2]):02x}:' |
179 | f'{int(ip[3]):02x}') |
180 | + |
181 | tm = Template(self.dhcp_template) |
182 | machine_ip = tm.render(ip_mac) |
183 | - dhcp_conf_data += machine_ip |
184 | - with open(dhcp_conf, 'w') as out: |
185 | - out.write(dhcp_conf_data) |
186 | + if ip_mac['Lab'] not in dhcp_conf_data: |
187 | + dhcp_conf_data[ip_mac['Lab']] = machine_ip |
188 | + else: |
189 | + dhcp_conf_data[ip_mac['Lab']] += machine_ip |
190 | |
191 | + for lab_id in dhcp_conf_data: |
192 | + with open(os.path.join(dhcp_conf_path, 'cert-' + lab_id.lower() + '-dhcpd-pool.conf'), 'w') as out: |
193 | + out.write(dhcp_conf_data[lab_id]) |
194 | |
195 | -def main(): |
196 | |
197 | - ci = c3query.configuration.get_instance() |
198 | - ci.read_configuration('my_conf.ini') |
199 | +def environ_or_required(key): |
200 | + if os.environ.get(key): |
201 | + return {'default': os.environ.get(key)} |
202 | + else: |
203 | + return {'required': True} |
204 | + |
205 | + |
206 | +def main(): |
207 | + parser = argparse.ArgumentParser() |
208 | + parser.add_argument('--cctoolbox', help="Path to cc-tool-box for storing dhcp config", **environ_or_required('CCLM_CC_TOOL_BOX')) |
209 | + parser.add_argument('--hwdb', help="Hardware db to read ip mapping", **environ_or_required('CCLM_HARDWARE_DB')) |
210 | + args = parser.parse_args() |
211 | |
212 | - hwdb = ci.config['CC-LAB-MANAGER']['HWDB'] |
213 | - dhcp_conf = ci.config['CC-LAB-MANAGER']['DHCP_CONFIG'] |
214 | - ip_mac_list = read_data_from_db(hwdb) |
215 | + ip_mac_list = read_data_from_db(args.hwdb) |
216 | dm = DhcpManager() |
217 | - dm.generate_dhcp_conf(ip_mac_list, dhcp_conf) |
218 | + dm.generate_dhcp_conf(ip_mac_list, os.path.join(args.cctoolbox, 'config', 'dhcp')) |
219 | |
220 | |
221 | if __name__ == '__main__': |
222 | diff --git a/build/lib/cc_lab_manager/gen_config/__init__.py b/build/lib/cc_lab_manager/gen_config/__init__.py |
223 | new file mode 100644 |
224 | index 0000000..e69de29 |
225 | --- /dev/null |
226 | +++ b/build/lib/cc_lab_manager/gen_config/__init__.py |
227 | diff --git a/cc-lab-manager/gen-config/gen-agent-tf-config.py b/build/lib/cc_lab_manager/gen_config/gen_agent_tf_config.py |
228 | similarity index 73% |
229 | rename from cc-lab-manager/gen-config/gen-agent-tf-config.py |
230 | rename to build/lib/cc_lab_manager/gen_config/gen_agent_tf_config.py |
231 | index 337fe3e..8056656 100644 |
232 | --- a/cc-lab-manager/gen-config/gen-agent-tf-config.py |
233 | +++ b/build/lib/cc_lab_manager/gen_config/gen_agent_tf_config.py |
234 | @@ -6,7 +6,7 @@ import argparse |
235 | agent_config = {"device_ip": None, |
236 | "secure_id": None, |
237 | "node_id": None, |
238 | - "maas_user": "sru-pool", |
239 | + "maas_user": "cert_maas_admin", |
240 | "agent_name": None, |
241 | "node_name": None, |
242 | "reset_efi": "true", |
243 | @@ -65,27 +65,32 @@ def read_data_from_db(cursor): |
244 | results = cursor.fetchall() |
245 | return list(results) |
246 | |
247 | -def create_agent_config_dir(db_machine_list): |
248 | +def create_agent_config_dir(db_machine_list, cfg_path): |
249 | |
250 | for machine in db_machine_list: |
251 | |
252 | - agent_name = "sru"+machine["cid"].replace("-","") |
253 | + if machine['lab'] == '': |
254 | + continue |
255 | + agent_name = "dut"+machine["cid"].replace("-","") |
256 | try: |
257 | - os.makedirs("{}".format(agent_name)) |
258 | + os.makedirs(os.path.join(cfg_path, 'data-' + machine['lab'].lower(), agent_name)) |
259 | except: |
260 | print("dir exist") |
261 | |
262 | -def generate_agent_config(db_machine_list): |
263 | +def generate_agent_config(db_machine_list, cfg_path): |
264 | |
265 | for machine in db_machine_list: |
266 | |
267 | + if machine['lab'] == '': |
268 | + continue |
269 | agent_conf = agent_config.copy() |
270 | - agent_name = "sru" + machine["cid"].replace("-","") |
271 | + agent_name = "dut" + machine["cid"].replace("-","") |
272 | secure_id = machine["SecureID"] |
273 | ip = machine["IP"] |
274 | node_id = machine["MAAS_Node_ID"] |
275 | - node_name = machine["Model"].replace(")","",).replace("(","",).replace(" ","-")+ "-" + \ |
276 | - machine["sku"].replace(" ","").split("-")[-1] + "-" + machine["cid"] |
277 | + # node_name = machine["Model"].replace(")","",).replace("(","",).replace(" ","-")+ "-" + \ |
278 | + # machine["sku"].replace(" ","").split("-")[-1] + "-" + machine["cid"] |
279 | + node_name = machine["cid"] |
280 | |
281 | agent_conf["node_name"] = node_name.lower() |
282 | agent_conf["agent_name"] = agent_name |
283 | @@ -95,7 +100,7 @@ def generate_agent_config(db_machine_list): |
284 | agent_conf["env"]["HEXR_DEVICE_SECURE_ID"] = secure_id |
285 | agent_conf["env"]["DEVICE_IP"] = ip |
286 | |
287 | - with open("{}/default.yaml".format(agent_name), "w+") as f: |
288 | + with open(os.path.join(cfg_path, 'data-' + machine['lab'].lower(), agent_name, 'default.yaml'), "w+") as f: |
289 | |
290 | for key in agent_config: |
291 | if key == "env": |
292 | @@ -108,36 +113,39 @@ def generate_agent_config(db_machine_list): |
293 | f.write("{key}: {value}\n".format(key=key,value=agent_conf[key])) |
294 | |
295 | |
296 | -def generate_tf_config(db_machine_list): |
297 | +def generate_tf_config(db_machine_list, cfg_path): |
298 | |
299 | for machine in db_machine_list: |
300 | + if machine['lab'] == '': |
301 | + continue |
302 | tf_conf = tf_config.copy() |
303 | |
304 | - agent_name = "sru" + machine["cid"].replace("-","") |
305 | + agent_name = "dut" + machine["cid"].replace("-","") |
306 | tf_conf["agent_id"] = agent_name |
307 | tf_conf["execution_basedir"] = tf_conf["execution_basedir"].format(agent_name) |
308 | tf_conf["logging_basedir"] = tf_conf["logging_basedir"].format(agent_name) |
309 | tf_conf["results_basedir"] = tf_conf["results_basedir"].format(agent_name) |
310 | |
311 | - with open("{}/testflinger-agent.conf".format(agent_name), "w+") as f: |
312 | + with open(os.path.join(cfg_path, 'data-' + machine['lab'].lower(), agent_name, 'testflinger-agent.conf'), "w+") as f: |
313 | for key in tf_conf: |
314 | if key == "job_queues": |
315 | f.write(key+":\n"+"- "+machine["cid"] + "\n") |
316 | else: |
317 | f.write(key + ": " + tf_conf[key] + "\n") |
318 | |
319 | -def create_agent_yaml(db_machine_list): |
320 | +def create_agent_yaml(db_machine_list, cfg_path): |
321 | |
322 | - if not os.path.isfile("ce-tf-agents.yaml"): |
323 | + # TODO: We need to separate configs for labs |
324 | + if not os.path.isfile(os.path.join(cfg_path, "ce-tf-agents-tel-l5.yaml")): |
325 | |
326 | - with open("ce-tf-agents.yaml","w") as f: |
327 | + with open(os.path.join(cfg_path, "ce-tf-agents-tel-l5.yaml"),"w") as f: |
328 | data = { |
329 | "series": "focal", |
330 | "description": "cert-testflinger-agents", |
331 | "applications":{ |
332 | - "agent-host-server":{ |
333 | + "agent-host-server" + "-tel-l5":{ |
334 | "series": "focal", |
335 | - "constraints": "tags=agent-host", |
336 | + "constraints": "tags=agent-host" + "-tel-l5", |
337 | "charm": "../charms/testflinger-agent-host-charm", |
338 | "num_units": 1, |
339 | "resources":{ |
340 | @@ -149,19 +157,21 @@ def create_agent_yaml(db_machine_list): |
341 | } |
342 | yaml.dump(data, f, default_flow_style=False, encoding='utf-8', allow_unicode=True, sort_keys=False) |
343 | |
344 | - with open("ce-tf-agents.yaml","r+") as f: |
345 | + with open(os.path.join(cfg_path, "ce-tf-agents-tel-l5.yaml"),"r+") as f: |
346 | |
347 | data = yaml.safe_load(f) |
348 | for machine in db_machine_list: |
349 | - agent_name = "sru" + machine["cid"].replace("-","") |
350 | + if machine['lab'] == '': |
351 | + continue |
352 | + agent_name = "dut" + machine["cid"].replace("-","") |
353 | if agent_name in data["applications"]: |
354 | print("exist") |
355 | else: |
356 | data["applications"][agent_name] = { |
357 | "charm":"../charms/testflinger-agent-charm", |
358 | "resources":{ |
359 | - "device_configfile":"data/{}/default.yaml".format(agent_name), |
360 | - "testflinger_agent_configfile":"data/{}/testflinger-agent.conf".format(agent_name) |
361 | + "device_configfile":os.path.join(cfg_path, 'data-' + machine['lab'].lower(), agent_name, 'default.yaml'), |
362 | + "testflinger_agent_configfile":os.path.join(cfg_path, 'data-' + machine['lab'].lower(), agent_name, 'testflinger-agent.conf') |
363 | }, |
364 | "to": ["agent-host-server"] |
365 | } |
366 | @@ -183,10 +193,10 @@ def main(): |
367 | db = get_db_obj(args.database) |
368 | cursor = get_cursor_obj(db) |
369 | machine_list = read_data_from_db(cursor) |
370 | - create_agent_config_dir(machine_list) |
371 | - generate_agent_config(machine_list) |
372 | - generate_tf_config(machine_list) |
373 | - create_agent_yaml(machine_list) |
374 | + create_agent_config_dir(machine_list, os.path.join(os.environ.get('CCLM_CERT_JUJU'), 'ce-cert')) |
375 | + generate_agent_config(machine_list, os.path.join(os.environ.get('CCLM_CERT_JUJU'), 'ce-cert')) |
376 | + generate_tf_config(machine_list, os.path.join(os.environ.get('CCLM_CERT_JUJU'), 'ce-cert')) |
377 | + create_agent_yaml(machine_list, os.path.join(os.environ.get('CCLM_CERT_JUJU'), 'ce-cert')) |
378 | close_db(db) |
379 | |
380 | if __name__ == '__main__': |
381 | diff --git a/build/lib/cc_lab_manager/gsheet_db/__init__.py b/build/lib/cc_lab_manager/gsheet_db/__init__.py |
382 | new file mode 100644 |
383 | index 0000000..e69de29 |
384 | --- /dev/null |
385 | +++ b/build/lib/cc_lab_manager/gsheet_db/__init__.py |
386 | diff --git a/cc-lab-manager/gsheet-db/db-gsheet.py b/build/lib/cc_lab_manager/gsheet_db/db_gsheet.py |
387 | similarity index 92% |
388 | rename from cc-lab-manager/gsheet-db/db-gsheet.py |
389 | rename to build/lib/cc_lab_manager/gsheet_db/db_gsheet.py |
390 | index a0c7100..c535445 100644 |
391 | --- a/cc-lab-manager/gsheet-db/db-gsheet.py |
392 | +++ b/build/lib/cc_lab_manager/gsheet_db/db_gsheet.py |
393 | @@ -35,9 +35,9 @@ def iter_all_strings(): |
394 | if tmp_string == "az": |
395 | return col_position_list |
396 | |
397 | -def get_column_to_be_updated(): |
398 | +def get_column_to_be_updated(token_file): |
399 | |
400 | - gc = pygsheets.authorize(service_file='token.json') |
401 | + gc = pygsheets.authorize(service_file=token_file) |
402 | sht = gc.open_by_url(gsheet_url) |
403 | wks = sht[0] |
404 | machine_list = wks.get_all_records(empty_value='', head=1, majdim='ROWS', numericise_data=False) |
405 | @@ -61,7 +61,7 @@ def sync_c3_data_to_sheet(db_machine_list,token_file): |
406 | wks = sht[0] |
407 | |
408 | # mapping table for position of column |
409 | - col_to_be_updated = get_column_to_be_updated() |
410 | + col_to_be_updated = get_column_to_be_updated(token_file) |
411 | |
412 | row_num = 2 |
413 | cell_list = [] # list for storing cell that are waiting for update. |
414 | @@ -73,9 +73,9 @@ def sync_c3_data_to_sheet(db_machine_list,token_file): |
415 | wks.update_cells(cell_list) |
416 | |
417 | |
418 | -def read_data_from_db(cursor): |
419 | +def read_data_from_db(cursor, token_file): |
420 | |
421 | - col_in_c3 = list(get_column_to_be_updated().keys()) |
422 | + col_in_c3 = list(get_column_to_be_updated(token_file).keys()) |
423 | sqlcmd = 'select {} from lab_hw'.format(",".join(col_in_c3[0:])) |
424 | cursor.execute(sqlcmd) |
425 | results = cursor.fetchall() |
426 | @@ -99,9 +99,9 @@ def main(): |
427 | gsheet_url = args.url |
428 | db = get_db_obj(args.database) |
429 | cursor = get_cursor_obj(db) |
430 | - sync_c3_data_to_sheet(read_data_from_db(cursor),args.token) |
431 | + sync_c3_data_to_sheet(read_data_from_db(cursor, args.token),args.token) |
432 | close_db(db) |
433 | |
434 | |
435 | if __name__ == '__main__': |
436 | - main() |
437 | \ No newline at end of file |
438 | + main() |
439 | diff --git a/cc-lab-manager/gsheet-db/gsheet-db.py b/build/lib/cc_lab_manager/gsheet_db/gsheet_db.py |
440 | similarity index 100% |
441 | rename from cc-lab-manager/gsheet-db/gsheet-db.py |
442 | rename to build/lib/cc_lab_manager/gsheet_db/gsheet_db.py |
443 | diff --git a/build/lib/cc_lab_manager/maas/__init__.py b/build/lib/cc_lab_manager/maas/__init__.py |
444 | new file mode 100644 |
445 | index 0000000..e69de29 |
446 | --- /dev/null |
447 | +++ b/build/lib/cc_lab_manager/maas/__init__.py |
448 | diff --git a/cc-lab-manager/maas/create-maas-node.py b/build/lib/cc_lab_manager/maas/create_maas_node.py |
449 | similarity index 88% |
450 | rename from cc-lab-manager/maas/create-maas-node.py |
451 | rename to build/lib/cc_lab_manager/maas/create_maas_node.py |
452 | index e57d8a5..05be6dc 100644 |
453 | --- a/cc-lab-manager/maas/create-maas-node.py |
454 | +++ b/build/lib/cc_lab_manager/maas/create_maas_node.py |
455 | @@ -33,12 +33,11 @@ def read_data_from_db(cursor): |
456 | |
457 | return list(results) |
458 | |
459 | -def get_maas_session(maas_ip): |
460 | +def get_maas_session(maas_ip, maas_admin, maas_admin_password): |
461 | client = login( |
462 | "http://{}:5240/MAAS/".format(maas_ip), |
463 | - username="ubuntu", password="ubuntu", |
464 | + username=maas_admin, password=maas_admin_password, |
465 | ) |
466 | - print(type(client)) |
467 | return client |
468 | |
469 | def get_mac_list(machine_list): |
470 | @@ -63,7 +62,7 @@ def get_maas_mac_list(client): |
471 | |
472 | return mac_list |
473 | |
474 | -def create_maas_node(machine_list): |
475 | +def create_maas_node(machine_list, maas_admin, maas_admin_password): |
476 | |
477 | mass_is_connecting = "" |
478 | client = "" |
479 | @@ -72,28 +71,28 @@ def create_maas_node(machine_list): |
480 | |
481 | if not mass_is_connecting: |
482 | mass_is_connecting = machine["MAAS_Server"] |
483 | - client = get_maas_session(mass_is_connecting) |
484 | + client = get_maas_session(mass_is_connecting, maas_admin, maas_admin_password) |
485 | maas_mac_list = get_maas_mac_list(client) |
486 | elif machine["MAAS_Server"] != mass_is_connecting: |
487 | mass_is_connecting = machine["MAAS_Server"] |
488 | - client = get_maas_session(mass_is_connecting) |
489 | + client = get_maas_session(mass_is_connecting, maas_admin, maas_admin_password) |
490 | maas_mac_list = get_maas_mac_list(client) |
491 | |
492 | power_type = machine["Power"].lower() if machine["Power"] != "" else "manual" |
493 | power_parameter = {} |
494 | node_name = (machine["Model"].replace(")","",).replace("(","",).replace(" ","-")+ "-" + \ |
495 | machine["sku"].replace(" ","").split("-")[-1] + "-" + machine["cid"]).lower() |
496 | + node_name = machine["cid"].lower() |
497 | |
498 | - if machine["MAC"] in maas_mac_list: |
499 | + if machine["MAC"] in maas_mac_list or machine["MAC"] == '': |
500 | continue |
501 | if power_type == "apc" or power_type == "raritan": |
502 | power_parameter["power_address"] = machine["PDU_IP"] |
503 | power_parameter["node_outlet"] = machine["PDU_Outlet"] |
504 | power_parameter["power_on_delay"] = 30 |
505 | - |
506 | elif power_type == "amt": |
507 | power_parameter["power_address"] = machine["IP"] |
508 | - power_parameter["power_pass"] = "Insecure_101" |
509 | + power_parameter["power_pass"] = "Insecure-101" |
510 | |
511 | maas_node = client.machines.create("amd64",machine["MAC"], "manual",hostname=node_name) |
512 | |
513 | @@ -111,11 +110,13 @@ def main(): |
514 | |
515 | parser = argparse.ArgumentParser() |
516 | parser.add_argument('--database', help="Database location",**environ_or_required('CCLM_HARDWARE_DB')) |
517 | + parser.add_argument('--maas_admin', help="MAAS Admin account",**environ_or_required('CCLM_MAAS_ADMIN')) |
518 | + parser.add_argument('--maas_admin_password', help="Password for MAAS Admin account",**environ_or_required('CCLM_MAAS_ADMIN_PASSWD')) |
519 | args = parser.parse_args() |
520 | db = get_db_obj(args.database) |
521 | cursor = get_cursor_obj(db) |
522 | machine_list = read_data_from_db(cursor) |
523 | - create_maas_node(machine_list) |
524 | + create_maas_node(machine_list, args.maas_admin, args.maas_admin_password) |
525 | update_node_id(cursor) |
526 | close_db(db) |
527 | |
528 | diff --git a/cc_lab_manager.egg-info/PKG-INFO b/cc_lab_manager.egg-info/PKG-INFO |
529 | new file mode 100644 |
530 | index 0000000..03809d0 |
531 | --- /dev/null |
532 | +++ b/cc_lab_manager.egg-info/PKG-INFO |
533 | @@ -0,0 +1,11 @@ |
534 | +Metadata-Version: 1.1 |
535 | +Name: cc-lab-manager |
536 | +Version: 0.1 |
537 | +Summary: Automated managing hardwares in Canonical Certification Labs |
538 | +Home-page: https://code.launchpad.net/cc-lab-manager/ |
539 | +Author: Gavin Lin (gavin.lin) |
540 | +Author-email: gavin.lin@canonical.com |
541 | +License: UNKNOWN |
542 | +Description: UNKNOWN |
543 | +Platform: UNKNOWN |
544 | +Classifier: Programming Language :: Python |
545 | diff --git a/cc_lab_manager.egg-info/SOURCES.txt b/cc_lab_manager.egg-info/SOURCES.txt |
546 | new file mode 100644 |
547 | index 0000000..7cfee1b |
548 | --- /dev/null |
549 | +++ b/cc_lab_manager.egg-info/SOURCES.txt |
550 | @@ -0,0 +1,23 @@ |
551 | +README.md |
552 | +setup.cfg |
553 | +setup.py |
554 | +cc_lab_manager/__init__.py |
555 | +cc_lab_manager.egg-info/PKG-INFO |
556 | +cc_lab_manager.egg-info/SOURCES.txt |
557 | +cc_lab_manager.egg-info/dependency_links.txt |
558 | +cc_lab_manager.egg-info/entry_points.txt |
559 | +cc_lab_manager.egg-info/requires.txt |
560 | +cc_lab_manager.egg-info/top_level.txt |
561 | +cc_lab_manager/c3_db/__init__.py |
562 | +cc_lab_manager/c3_db/c3_db.py |
563 | +cc_lab_manager/commands/__init__.py |
564 | +cc_lab_manager/commands/cc_lab_manager.py |
565 | +cc_lab_manager/dhcp/__init__.py |
566 | +cc_lab_manager/dhcp/dhcp_config_generator.py |
567 | +cc_lab_manager/gen_config/__init__.py |
568 | +cc_lab_manager/gen_config/gen_agent_tf_config.py |
569 | +cc_lab_manager/gsheet_db/__init__.py |
570 | +cc_lab_manager/gsheet_db/db_gsheet.py |
571 | +cc_lab_manager/gsheet_db/gsheet_db.py |
572 | +cc_lab_manager/maas/__init__.py |
573 | +cc_lab_manager/maas/create_maas_node.py |
574 | \ No newline at end of file |
575 | diff --git a/cc_lab_manager.egg-info/dependency_links.txt b/cc_lab_manager.egg-info/dependency_links.txt |
576 | new file mode 100644 |
577 | index 0000000..8b13789 |
578 | --- /dev/null |
579 | +++ b/cc_lab_manager.egg-info/dependency_links.txt |
580 | @@ -0,0 +1 @@ |
581 | + |
582 | diff --git a/cc_lab_manager.egg-info/entry_points.txt b/cc_lab_manager.egg-info/entry_points.txt |
583 | new file mode 100644 |
584 | index 0000000..21bd2e3 |
585 | --- /dev/null |
586 | +++ b/cc_lab_manager.egg-info/entry_points.txt |
587 | @@ -0,0 +1,3 @@ |
588 | +[console_scripts] |
589 | +cc-lab-manager = cc_lab_manager.commands.cc_lab_manager:main |
590 | + |
591 | diff --git a/cc_lab_manager.egg-info/requires.txt b/cc_lab_manager.egg-info/requires.txt |
592 | new file mode 100644 |
593 | index 0000000..26dccbc |
594 | --- /dev/null |
595 | +++ b/cc_lab_manager.egg-info/requires.txt |
596 | @@ -0,0 +1,4 @@ |
597 | +aiohttp==3.7.2 |
598 | +jinja2 |
599 | +pysheets |
600 | +python-libmaas |
601 | diff --git a/cc_lab_manager.egg-info/top_level.txt b/cc_lab_manager.egg-info/top_level.txt |
602 | new file mode 100644 |
603 | index 0000000..b831c50 |
604 | --- /dev/null |
605 | +++ b/cc_lab_manager.egg-info/top_level.txt |
606 | @@ -0,0 +1 @@ |
607 | +cc_lab_manager |
608 | diff --git a/cc_lab_manager/__init__.py b/cc_lab_manager/__init__.py |
609 | new file mode 100644 |
610 | index 0000000..e69de29 |
611 | --- /dev/null |
612 | +++ b/cc_lab_manager/__init__.py |
613 | diff --git a/cc_lab_manager/c3_db/__init__.py b/cc_lab_manager/c3_db/__init__.py |
614 | new file mode 100644 |
615 | index 0000000..e69de29 |
616 | --- /dev/null |
617 | +++ b/cc_lab_manager/c3_db/__init__.py |
618 | diff --git a/cc_lab_manager/c3_db/c3_db.py b/cc_lab_manager/c3_db/c3_db.py |
619 | new file mode 100644 |
620 | index 0000000..b9b0d7e |
621 | --- /dev/null |
622 | +++ b/cc_lab_manager/c3_db/c3_db.py |
623 | @@ -0,0 +1,128 @@ |
624 | +import sqlite3 |
625 | +import logging |
626 | +import argparse |
627 | +import c3.api.query as c3query |
628 | +from c3.api.api_utils import APIQuery |
629 | +import os |
630 | + |
631 | +logger = logging.getLogger('cc-lab-manager') |
632 | + |
633 | + |
634 | +def c3_to_db(db_path): |
635 | + """ |
636 | + Query machine info from c3 and write to db. |
637 | + """ |
638 | + |
639 | + # Read CID from db |
640 | + try: |
641 | + hwdb = sqlite3.connect(db_path) |
642 | + cur = hwdb.execute('SELECT cid FROM lab_hw') |
643 | + cid_list = cur.fetchall() |
644 | + except Exception as e: |
645 | + logger.error('Error when reading db: ', e) |
646 | + |
647 | + for cid_db in cid_list: |
648 | + cid = ''.join(cid_db) |
649 | + logger.info('Processing {}...'.format(cid)) |
650 | + if '-' not in cid or 'TEL' in cid: |
651 | + continue |
652 | + |
653 | + # Query hardware info from c3 |
654 | + result = '' |
655 | + try: |
656 | + result = c3query.query_over_api_hardware(cid) |
657 | + except Exception as e: |
658 | + logger.error("Error when query c3: ", e) |
659 | + |
660 | + if result: |
661 | + # Map hardware info from c3 to db column |
662 | + try: |
663 | + location = result['location']['name'] |
664 | + except Exception as e: |
665 | + logger.warning('Failed Reading location: {}'.format(e)) |
666 | + location = 'None' |
667 | + try: |
668 | + account = result['account']['name'] |
669 | + except Exception as e: |
670 | + logger.warning('Failed reading account: {}'.format(e)) |
671 | + account = 'None' |
672 | + try: |
673 | + platform_name = result['platform']['name'] |
674 | + codename = result['platform']['codename'] |
675 | + form_factor = result['platform']['form_factor'] |
676 | + model = result['platform']['aliases'] |
677 | + except Exception as e: |
678 | + logger.warning('Failed reading platform: {}'.format(e)) |
679 | + platform_name = 'None' |
680 | + codename = 'None' |
681 | + form_factor = 'None' |
682 | + model = 'None' |
683 | + try: |
684 | + canonical_contact = result['canonical_contact']['display_name'] |
685 | + except Exception as e: |
686 | + logger.warning('Failed reading canonical_contact: {}' |
687 | + .format(e)) |
688 | + canonical_contact = 'None' |
689 | + try: |
690 | + holder = result['holder']['name'] |
691 | + except Exception as e: |
692 | + logger.warning('Failed reading holder: {}'.format(e)) |
693 | + holder = 'None' |
694 | + hw_info = {'Location': location, |
695 | + 'Status': result['status'], |
696 | + 'Account': account, |
697 | + 'Project': result['project_name'], |
698 | + 'Model': model, |
699 | + 'CanonicalLabel': result['canonical_label'], |
700 | + 'PlatformName': platform_name, |
701 | + 'CodeName': codename, |
702 | + 'SKU': result['sku'], |
703 | + 'HardwareBuild': result['hardware_build'], |
704 | + 'Form': form_factor, |
705 | + 'CanonicalContact': canonical_contact, |
706 | + 'Holder': holder, |
707 | + 'SecureID': result['secure_id']} |
708 | + |
709 | + # Write hardware info to db |
710 | + try: |
711 | + for key in hw_info: |
712 | + sql_cmd = 'UPDATE lab_hw SET {} = "{}" WHERE CID = "{}"' \ |
713 | + .format(key, hw_info[key], |
714 | + result['canonical_id']) |
715 | + hwdb.execute(sql_cmd) |
716 | + hwdb.commit() |
717 | + except Exception as e: |
718 | + logger.error('Error writing to db: ', e) |
719 | + hwdb.close() |
720 | + |
721 | + hwdb.close() |
722 | + |
723 | + |
724 | +def environ_or_required(key): |
725 | + if os.environ.get(key): |
726 | + return {'default': os.environ.get(key)} |
727 | + else: |
728 | + return {'required': True} |
729 | + |
730 | + |
731 | +def main(): |
732 | + parser = argparse.ArgumentParser() |
733 | + parser.add_argument('--conf', help="Config file for C3 API", default = os.environ.get('CCLM_CC_TOOL_BOX') + '/config/c3-cli/my_conf.ini') |
734 | + parser.add_argument('--c3user', help="C3 User Account", **environ_or_required('CCLM_C3_USERNAME')) |
735 | + parser.add_argument('--c3apikey', help="C3 API Key", **environ_or_required('CCLM_C3_APIKEY')) |
736 | + parser.add_argument('--hwdb', help="C3 API Key", **environ_or_required('CCLM_HARDWARE_DB')) |
737 | + args = parser.parse_args() |
738 | + |
739 | + ci = c3query.configuration.get_instance() |
740 | + ci.read_configuration(args.conf) |
741 | + |
742 | + api = APIQuery(ci.config['C3']['URI']) |
743 | + rparam = {"username": args.c3user, |
744 | + "api_key": args.c3apikey} |
745 | + |
746 | + c3query.api_instance.set_api_params(api, rparam) |
747 | + c3_to_db(args.hwdb) |
748 | + |
749 | + |
750 | +if __name__ == '__main__': |
751 | + main() |
752 | diff --git a/cc_lab_manager/commands/__init__.py b/cc_lab_manager/commands/__init__.py |
753 | new file mode 100644 |
754 | index 0000000..e69de29 |
755 | --- /dev/null |
756 | +++ b/cc_lab_manager/commands/__init__.py |
757 | diff --git a/cc_lab_manager/commands/cc_lab_manager.py b/cc_lab_manager/commands/cc_lab_manager.py |
758 | new file mode 100644 |
759 | index 0000000..7da03df |
760 | --- /dev/null |
761 | +++ b/cc_lab_manager/commands/cc_lab_manager.py |
762 | @@ -0,0 +1,49 @@ |
763 | +import logging |
764 | +import os |
765 | +import sys |
766 | + |
767 | +from cc_lab_manager.gsheet_db import gsheet_db |
768 | +from cc_lab_manager.gsheet_db import db_gsheet |
769 | +from cc_lab_manager.c3_db import c3_db |
770 | +from cc_lab_manager.dhcp import dhcp_config_generator |
771 | +from cc_lab_manager.maas import create_maas_node |
772 | +from cc_lab_manager.gen_config import gen_agent_tf_config |
773 | + |
774 | +logger = logging.getLogger('cc-lab-manager') |
775 | + |
776 | +def main(): |
777 | + # Read data from the google sheet to db |
778 | + gsheet_db.main() |
779 | + |
780 | + # Get needed information from c3 |
781 | + c3_db.main() |
782 | + |
783 | + # Generate DHCP config for each subnets |
784 | + # TODO: Currently these config files need to be copied |
785 | + # manually, then MAAS will apply it automatically |
786 | + dhcp_config_generator.main() |
787 | + |
788 | + # Create MAAS nodes for DUTs |
789 | + create_maas_node.main() |
790 | + |
791 | + # Create agent configs for DUTs |
792 | + # TODO: Currently these configs need to be push/pull |
793 | + # and applied manually |
794 | + gen_agent_tf_config.main() |
795 | + |
796 | + # Write data in db back to the google sheet |
797 | + db_gsheet.main() |
798 | + |
799 | + #ci = c3query.configuration.get_instance() |
800 | + |
801 | + #api = APIQuery(ci.config['C3']['URI']) |
802 | + #rparam = {"username": ci.config['C3']['UserName'], |
803 | + # "api_key": ci.config['C3']['APIKey']} |
804 | + |
805 | + #c3query.api_instance.set_api_params(api, rparam) |
806 | + #hwdb = './hardware.db' |
807 | + #c3_to_db(hwdb) |
808 | + |
809 | + |
810 | +if __name__ == '__main__': |
811 | + main() |
812 | diff --git a/cc_lab_manager/dhcp/__init__.py b/cc_lab_manager/dhcp/__init__.py |
813 | new file mode 100644 |
814 | index 0000000..e69de29 |
815 | --- /dev/null |
816 | +++ b/cc_lab_manager/dhcp/__init__.py |
817 | diff --git a/cc_lab_manager/dhcp/dhcp_config_generator.py b/cc_lab_manager/dhcp/dhcp_config_generator.py |
818 | new file mode 100644 |
819 | index 0000000..e586dd4 |
820 | --- /dev/null |
821 | +++ b/cc_lab_manager/dhcp/dhcp_config_generator.py |
822 | @@ -0,0 +1,96 @@ |
823 | +import sqlite3 |
824 | +import logging |
825 | +import argparse |
826 | +import os |
827 | +from jinja2 import Template |
828 | + |
829 | +logger = logging.getLogger('cc-lab-manager') |
830 | + |
831 | + |
832 | +def read_data_from_db(path_to_db): |
833 | + db = sqlite3.connect(path_to_db) |
834 | + db.row_factory = sqlite3.Row |
835 | + col_in_db = ["CID", "MAC", "Controller_MAC", "Provision", "IP", |
836 | + "Controller_IP", "Lab", "Frame", "Shelf", "Partition"] |
837 | + sqlcmd = ('select {},{},{},{},{},{},{},{},{},{} from lab_hw' |
838 | + .format(*col_in_db)) |
839 | + db_row_objs = db.execute(sqlcmd).fetchall() |
840 | + db.close() |
841 | + db_dict_list = [] |
842 | + for row_obj in db_row_objs: |
843 | + db_dict_list.append({k: row_obj[k] for k in row_obj.keys()}) |
844 | + return db_dict_list |
845 | + |
846 | + |
847 | +class DhcpManager: |
848 | + def __init__(self): |
849 | + self.dhcp_template = ''' |
850 | +# {{CID}} |
851 | +host {{Lab}}-{{Frame}}-S{{Shelf}}-P{{Partition}} { |
852 | + hardware ethernet {{MAC}}; |
853 | + fixed-address {{IP}}; |
854 | +} |
855 | + |
856 | +# {{CID}}-controller |
857 | +host {{Lab}}-{{Frame}}-S{{Shelf}}-P{{Partition}}-ctl { |
858 | + hardware ethernet {{Controller_MAC}}; |
859 | + fixed-address {{Controller_IP}}; |
860 | +} |
861 | + |
862 | +''' |
863 | + |
864 | + def generate_dhcp_conf(self, ip_mac_list, dhcp_conf_path): |
865 | + dhcp_conf_data = {} |
866 | + for ip_mac in ip_mac_list: |
867 | + if ip_mac['IP'] == '' or ip_mac['Controller_IP'] == ''\ |
868 | + or ip_mac['Lab'] == '' or ip_mac['Frame'] == ''\ |
869 | + or ip_mac['Shelf'] == '' or ip_mac['Partition'] == '': |
870 | + if ip_mac['CID'] == '': |
871 | + ip_mac_list.remove(ip_mac) |
872 | + else: |
873 | + logger.info("Missing required information for", ip_mac['CID']) |
874 | + continue |
875 | + |
876 | + # Generate MAC for dummy devices or devices without fixed MAC |
877 | + if ip_mac['MAC'] == '': |
878 | + ip = ip_mac['IP'].split('.') |
879 | + ip_mac['MAC'] = (f'ff:ff:ff:{int(ip[1]):02x}:' |
880 | + f'{int(ip[2]):02x}:{int(ip[3]):02x}') |
881 | + if ip_mac['Controller_MAC'] == '': |
882 | + ip = ip_mac['Controller_IP'].split('.') |
883 | + ip_mac['Controller_MAC'] = (f'ff:ff:ff:{int(ip[1]):02x}:' |
884 | + f'{int(ip[2]):02x}:' |
885 | + f'{int(ip[3]):02x}') |
886 | + |
887 | + tm = Template(self.dhcp_template) |
888 | + machine_ip = tm.render(ip_mac) |
889 | + if ip_mac['Lab'] not in dhcp_conf_data: |
890 | + dhcp_conf_data[ip_mac['Lab']] = machine_ip |
891 | + else: |
892 | + dhcp_conf_data[ip_mac['Lab']] += machine_ip |
893 | + |
894 | + for lab_id in dhcp_conf_data: |
895 | + with open(os.path.join(dhcp_conf_path, 'cert-' + lab_id.lower() + '-dhcpd-pool.conf'), 'w') as out: |
896 | + out.write(dhcp_conf_data[lab_id]) |
897 | + |
898 | + |
899 | +def environ_or_required(key): |
900 | + if os.environ.get(key): |
901 | + return {'default': os.environ.get(key)} |
902 | + else: |
903 | + return {'required': True} |
904 | + |
905 | + |
906 | +def main(): |
907 | + parser = argparse.ArgumentParser() |
908 | + parser.add_argument('--cctoolbox', help="Path to cc-tool-box for storing dhcp config", **environ_or_required('CCLM_CC_TOOL_BOX')) |
909 | + parser.add_argument('--hwdb', help="Hardware db to read ip mapping", **environ_or_required('CCLM_HARDWARE_DB')) |
910 | + args = parser.parse_args() |
911 | + |
912 | + ip_mac_list = read_data_from_db(args.hwdb) |
913 | + dm = DhcpManager() |
914 | + dm.generate_dhcp_conf(ip_mac_list, os.path.join(args.cctoolbox, 'config', 'dhcp')) |
915 | + |
916 | + |
917 | +if __name__ == '__main__': |
918 | + main() |
919 | diff --git a/cc_lab_manager/gen_config/__init__.py b/cc_lab_manager/gen_config/__init__.py |
920 | new file mode 100644 |
921 | index 0000000..e69de29 |
922 | --- /dev/null |
923 | +++ b/cc_lab_manager/gen_config/__init__.py |
924 | diff --git a/cc_lab_manager/gen_config/gen_agent_tf_config.py b/cc_lab_manager/gen_config/gen_agent_tf_config.py |
925 | new file mode 100644 |
926 | index 0000000..8056656 |
927 | --- /dev/null |
928 | +++ b/cc_lab_manager/gen_config/gen_agent_tf_config.py |
929 | @@ -0,0 +1,203 @@ |
930 | +import sqlite3 |
931 | +import os |
932 | +import yaml |
933 | +import argparse |
934 | + |
935 | +agent_config = {"device_ip": None, |
936 | + "secure_id": None, |
937 | + "node_id": None, |
938 | + "maas_user": "cert_maas_admin", |
939 | + "agent_name": None, |
940 | + "node_name": None, |
941 | + "reset_efi": "true", |
942 | + "env":{"HEXR_DEVICE_SECURE_ID": None, |
943 | + "WPA_BG_SSID": "ubuntu-cert-bg-wpa-tpelab", |
944 | + "WPA_BG_PSK": "insecure", |
945 | + "WPA_N_SSID": "ubuntu-cert-n-wpa-tpelab", |
946 | + "WPA_N_PSK": "insecure", |
947 | + "WPA_AC_SSID": "ubuntu-cert-ac-wpa-tpelab", |
948 | + "WPA_AC_PSK": "insecure", |
949 | + "OPEN_BG_SSID": "ubuntu-cert-bg-open-tpelab", |
950 | + "OPEN_N_SSID": "ubuntu-cert-n-open-tpelab", |
951 | + "OPEN_AC_SSID": "ubuntu-cert-ac-open-tpelab", |
952 | + "DEVICE_IP": None |
953 | + } |
954 | + } |
955 | + |
956 | +tf_config = {"agent_id": None, |
957 | + "server_address": "https://testflinger.canonical.com", |
958 | + "global_timeout": "43200", |
959 | + "output_timeout": "8000", |
960 | + "execution_basedir": "/home/ubuntu/testflinger/{}/run", |
961 | + "logging_basedir": "/home/ubuntu/testflinger/{}/logs", |
962 | + "results_basedir": "/home/ubuntu/testflinger/{}/results", |
963 | + "logging_level": "INFO", |
964 | + "job_queues": None, |
965 | + "setup_command": "tf-setup", |
966 | + "provision_command": "tf-provision", |
967 | + "test_command": "tf-test", |
968 | + "reserve_command": "tf-reserve", |
969 | + "cleanup_command": "tf-cleanup", |
970 | + "provision_type": "maas2" |
971 | + } |
972 | + |
973 | +def get_db_obj(path_to_db): |
974 | + |
975 | + db = sqlite3.connect(path_to_db) |
976 | + db.row_factory = sqlite3.Row |
977 | + return db |
978 | + |
979 | +def get_cursor_obj(db_obj): |
980 | + |
981 | + cursor = db_obj.cursor() |
982 | + return cursor |
983 | + |
984 | +def close_db(db): |
985 | + db.commit() |
986 | + db.close() |
987 | + |
988 | +def read_data_from_db(cursor): |
989 | + |
990 | + col_in_c3 = ["CID","Lab","IP","SKU","MAAS_Node_ID","Model","SecureID"] |
991 | + |
992 | + sqlcmd = 'select {},{},{},{},{},{},{} from lab_hw where CID not like \'TEL-%\''.format(*col_in_c3) |
993 | + cursor.execute(sqlcmd) |
994 | + results = cursor.fetchall() |
995 | + return list(results) |
996 | + |
997 | +def create_agent_config_dir(db_machine_list, cfg_path): |
998 | + |
999 | + for machine in db_machine_list: |
1000 | + |
1001 | + if machine['lab'] == '': |
1002 | + continue |
1003 | + agent_name = "dut"+machine["cid"].replace("-","") |
1004 | + try: |
1005 | + os.makedirs(os.path.join(cfg_path, 'data-' + machine['lab'].lower(), agent_name)) |
1006 | + except: |
1007 | + print("dir exist") |
1008 | + |
1009 | +def generate_agent_config(db_machine_list, cfg_path): |
1010 | + |
1011 | + for machine in db_machine_list: |
1012 | + |
1013 | + if machine['lab'] == '': |
1014 | + continue |
1015 | + agent_conf = agent_config.copy() |
1016 | + agent_name = "dut" + machine["cid"].replace("-","") |
1017 | + secure_id = machine["SecureID"] |
1018 | + ip = machine["IP"] |
1019 | + node_id = machine["MAAS_Node_ID"] |
1020 | + # node_name = machine["Model"].replace(")","",).replace("(","",).replace(" ","-")+ "-" + \ |
1021 | + # machine["sku"].replace(" ","").split("-")[-1] + "-" + machine["cid"] |
1022 | + node_name = machine["cid"] |
1023 | + |
1024 | + agent_conf["node_name"] = node_name.lower() |
1025 | + agent_conf["agent_name"] = agent_name |
1026 | + agent_conf["secure_id"] = secure_id |
1027 | + agent_conf["node_id"] = node_id |
1028 | + agent_conf["device_ip"] = ip |
1029 | + agent_conf["env"]["HEXR_DEVICE_SECURE_ID"] = secure_id |
1030 | + agent_conf["env"]["DEVICE_IP"] = ip |
1031 | + |
1032 | + with open(os.path.join(cfg_path, 'data-' + machine['lab'].lower(), agent_name, 'default.yaml'), "w+") as f: |
1033 | + |
1034 | + for key in agent_config: |
1035 | + if key == "env": |
1036 | + f.write(key+" :\n") |
1037 | + for env_key in agent_config["env"]: |
1038 | + if "SSID" in env_key: |
1039 | + agent_conf["env"][env_key] += machine["lab"][-1] |
1040 | + f.write(" {key}: {value}\n".format(key=env_key,value=agent_conf["env"][env_key])) |
1041 | + else: |
1042 | + f.write("{key}: {value}\n".format(key=key,value=agent_conf[key])) |
1043 | + |
1044 | + |
1045 | +def generate_tf_config(db_machine_list, cfg_path): |
1046 | + |
1047 | + for machine in db_machine_list: |
1048 | + if machine['lab'] == '': |
1049 | + continue |
1050 | + tf_conf = tf_config.copy() |
1051 | + |
1052 | + agent_name = "dut" + machine["cid"].replace("-","") |
1053 | + tf_conf["agent_id"] = agent_name |
1054 | + tf_conf["execution_basedir"] = tf_conf["execution_basedir"].format(agent_name) |
1055 | + tf_conf["logging_basedir"] = tf_conf["logging_basedir"].format(agent_name) |
1056 | + tf_conf["results_basedir"] = tf_conf["results_basedir"].format(agent_name) |
1057 | + |
1058 | + with open(os.path.join(cfg_path, 'data-' + machine['lab'].lower(), agent_name, 'testflinger-agent.conf'), "w+") as f: |
1059 | + for key in tf_conf: |
1060 | + if key == "job_queues": |
1061 | + f.write(key+":\n"+"- "+machine["cid"] + "\n") |
1062 | + else: |
1063 | + f.write(key + ": " + tf_conf[key] + "\n") |
1064 | + |
1065 | +def create_agent_yaml(db_machine_list, cfg_path): |
1066 | + |
1067 | + # TODO: We need to separate configs for labs |
1068 | + if not os.path.isfile(os.path.join(cfg_path, "ce-tf-agents-tel-l5.yaml")): |
1069 | + |
1070 | + with open(os.path.join(cfg_path, "ce-tf-agents-tel-l5.yaml"),"w") as f: |
1071 | + data = { |
1072 | + "series": "focal", |
1073 | + "description": "cert-testflinger-agents", |
1074 | + "applications":{ |
1075 | + "agent-host-server" + "-tel-l5":{ |
1076 | + "series": "focal", |
1077 | + "constraints": "tags=agent-host" + "-tel-l5", |
1078 | + "charm": "../charms/testflinger-agent-host-charm", |
1079 | + "num_units": 1, |
1080 | + "resources":{ |
1081 | + "ssh_priv_key": "agent-host/id_rsa", |
1082 | + "ssh_pub_key": "agent-host/id_rsa.pub", |
1083 | + }, |
1084 | + } |
1085 | + } |
1086 | + } |
1087 | + yaml.dump(data, f, default_flow_style=False, encoding='utf-8', allow_unicode=True, sort_keys=False) |
1088 | + |
1089 | + with open(os.path.join(cfg_path, "ce-tf-agents-tel-l5.yaml"),"r+") as f: |
1090 | + |
1091 | + data = yaml.safe_load(f) |
1092 | + for machine in db_machine_list: |
1093 | + if machine['lab'] == '': |
1094 | + continue |
1095 | + agent_name = "dut" + machine["cid"].replace("-","") |
1096 | + if agent_name in data["applications"]: |
1097 | + print("exist") |
1098 | + else: |
1099 | + data["applications"][agent_name] = { |
1100 | + "charm":"../charms/testflinger-agent-charm", |
1101 | + "resources":{ |
1102 | + "device_configfile":os.path.join(cfg_path, 'data-' + machine['lab'].lower(), agent_name, 'default.yaml'), |
1103 | + "testflinger_agent_configfile":os.path.join(cfg_path, 'data-' + machine['lab'].lower(), agent_name, 'testflinger-agent.conf') |
1104 | + }, |
1105 | + "to": ["agent-host-server"] |
1106 | + } |
1107 | + f.seek(0) |
1108 | + yaml.dump(data, f, default_flow_style=False, encoding='utf-8', allow_unicode=True, sort_keys=False) |
1109 | + |
1110 | + |
1111 | +def environ_or_required(key): |
1112 | + if os.environ.get(key): |
1113 | + return {'default': os.environ.get(key)} |
1114 | + else: |
1115 | + return {'required': True} |
1116 | + |
1117 | +def main(): |
1118 | + |
1119 | + parser = argparse.ArgumentParser() |
1120 | + parser.add_argument('--database', help="Database location",**environ_or_required('CCLM_HARDWARE_DB')) |
1121 | + args = parser.parse_args() |
1122 | + db = get_db_obj(args.database) |
1123 | + cursor = get_cursor_obj(db) |
1124 | + machine_list = read_data_from_db(cursor) |
1125 | + create_agent_config_dir(machine_list, os.path.join(os.environ.get('CCLM_CERT_JUJU'), 'ce-cert')) |
1126 | + generate_agent_config(machine_list, os.path.join(os.environ.get('CCLM_CERT_JUJU'), 'ce-cert')) |
1127 | + generate_tf_config(machine_list, os.path.join(os.environ.get('CCLM_CERT_JUJU'), 'ce-cert')) |
1128 | + create_agent_yaml(machine_list, os.path.join(os.environ.get('CCLM_CERT_JUJU'), 'ce-cert')) |
1129 | + close_db(db) |
1130 | + |
1131 | +if __name__ == '__main__': |
1132 | + main() |
1133 | diff --git a/cc_lab_manager/gsheet_db/__init__.py b/cc_lab_manager/gsheet_db/__init__.py |
1134 | new file mode 100644 |
1135 | index 0000000..e69de29 |
1136 | --- /dev/null |
1137 | +++ b/cc_lab_manager/gsheet_db/__init__.py |
1138 | diff --git a/cc_lab_manager/gsheet_db/db_gsheet.py b/cc_lab_manager/gsheet_db/db_gsheet.py |
1139 | new file mode 100644 |
1140 | index 0000000..c535445 |
1141 | --- /dev/null |
1142 | +++ b/cc_lab_manager/gsheet_db/db_gsheet.py |
1143 | @@ -0,0 +1,107 @@ |
1144 | +import pygsheets |
1145 | +import sqlite3 |
1146 | +import sys |
1147 | +from string import ascii_lowercase |
1148 | +import itertools |
1149 | +import argparse |
1150 | +import os |
1151 | + |
1152 | +gsheet_url = '' |
1153 | +start_column_name = 'Location' |
1154 | + |
1155 | +def get_db_obj(path_to_db): |
1156 | + |
1157 | + db = sqlite3.connect(path_to_db) |
1158 | + db.row_factory = sqlite3.Row |
1159 | + return db |
1160 | + |
1161 | +def get_cursor_obj(db_obj): |
1162 | + |
1163 | + cursor = db_obj.cursor() |
1164 | + return cursor |
1165 | + |
1166 | +def close_db(db): |
1167 | + db.commit() |
1168 | + db.close() |
1169 | + |
1170 | +def iter_all_strings(): |
1171 | + # generate alphabet list a,b,c.........az for accessing cell's position. |
1172 | + |
1173 | + col_position_list = [] |
1174 | + for size in itertools.count(1): |
1175 | + for s in itertools.product(ascii_lowercase,repeat = size): |
1176 | + tmp_string = "".join(s) |
1177 | + col_position_list.append("".join(tmp_string)) |
1178 | + if tmp_string == "az": |
1179 | + return col_position_list |
1180 | + |
1181 | +def get_column_to_be_updated(token_file): |
1182 | + |
1183 | + gc = pygsheets.authorize(service_file=token_file) |
1184 | + sht = gc.open_by_url(gsheet_url) |
1185 | + wks = sht[0] |
1186 | + machine_list = wks.get_all_records(empty_value='', head=1, majdim='ROWS', numericise_data=False) |
1187 | + keylist = list(machine_list[0].keys()) |
1188 | + |
1189 | + started_index = keylist.index(start_column_name) |
1190 | + col_to_be_updated = dict.fromkeys(keylist[started_index:]) |
1191 | + col_position_list = iter_all_strings() |
1192 | + |
1193 | + for key in col_to_be_updated: |
1194 | + col_to_be_updated[key] = col_position_list[started_index] |
1195 | + started_index += 1 |
1196 | + |
1197 | + return col_to_be_updated |
1198 | + |
1199 | + |
1200 | +def sync_c3_data_to_sheet(db_machine_list,token_file): |
1201 | + |
1202 | + gc = pygsheets.authorize(service_file=token_file) |
1203 | + sht = gc.open_by_url(gsheet_url) |
1204 | + wks = sht[0] |
1205 | + |
1206 | + # mapping table for position of column |
1207 | + col_to_be_updated = get_column_to_be_updated(token_file) |
1208 | + |
1209 | + row_num = 2 |
1210 | + cell_list = [] # list for storing cell that are waiting for update. |
1211 | + for machine in db_machine_list: |
1212 | + for key in col_to_be_updated: |
1213 | + cell_list.append(pygsheets.Cell(col_to_be_updated[key]+str(row_num),machine[key])) |
1214 | + |
1215 | + row_num += 1 |
1216 | + wks.update_cells(cell_list) |
1217 | + |
1218 | + |
1219 | +def read_data_from_db(cursor, token_file): |
1220 | + |
1221 | + col_in_c3 = list(get_column_to_be_updated(token_file).keys()) |
1222 | + sqlcmd = 'select {} from lab_hw'.format(",".join(col_in_c3[0:])) |
1223 | + cursor.execute(sqlcmd) |
1224 | + results = cursor.fetchall() |
1225 | + |
1226 | + return list(results) |
1227 | + |
1228 | +def environ_or_required(key): |
1229 | + if os.environ.get(key): |
1230 | + return {'default': os.environ.get(key)} |
1231 | + else: |
1232 | + return {'required': True} |
1233 | + |
1234 | +def main(): |
1235 | + |
1236 | + parser = argparse.ArgumentParser() |
1237 | + parser.add_argument('--url', help="Google sheets URL",**environ_or_required('CCLM_GOOGLE_SHEET')) |
1238 | + parser.add_argument('--token', help="Google API token",**environ_or_required('CCLM_GOOGLE_TOKEN')) |
1239 | + parser.add_argument('--database', help="Database location",**environ_or_required('CCLM_HARDWARE_DB')) |
1240 | + args = parser.parse_args() |
1241 | + global gsheet_url |
1242 | + gsheet_url = args.url |
1243 | + db = get_db_obj(args.database) |
1244 | + cursor = get_cursor_obj(db) |
1245 | + sync_c3_data_to_sheet(read_data_from_db(cursor, args.token),args.token) |
1246 | + close_db(db) |
1247 | + |
1248 | + |
1249 | +if __name__ == '__main__': |
1250 | + main() |
1251 | diff --git a/cc_lab_manager/gsheet_db/gsheet_db.py b/cc_lab_manager/gsheet_db/gsheet_db.py |
1252 | new file mode 100644 |
1253 | index 0000000..1b11014 |
1254 | --- /dev/null |
1255 | +++ b/cc_lab_manager/gsheet_db/gsheet_db.py |
1256 | @@ -0,0 +1,91 @@ |
1257 | +import pygsheets |
1258 | +import sqlite3 |
1259 | +import sys |
1260 | +import argparse |
1261 | +import os |
1262 | + |
1263 | +gsheet_url = '' |
1264 | + |
1265 | +def get_machine_list(token_file): |
1266 | + |
1267 | + gc = pygsheets.authorize(service_file=token_file) |
1268 | + sht = gc.open_by_url(gsheet_url) |
1269 | + wks = sht[0] |
1270 | + machine_list = wks.get_all_records(empty_value='', head=1, majdim='ROWS', numericise_data=False) |
1271 | + |
1272 | + return machine_list |
1273 | + |
1274 | +def get_db_obj(path_to_db): |
1275 | + |
1276 | + db = sqlite3.connect(path_to_db) |
1277 | + return db |
1278 | + |
1279 | +def get_cursor_obj(db_obj): |
1280 | + |
1281 | + cursor = db_obj.cursor() |
1282 | + return cursor |
1283 | + |
1284 | +def close_db(db): |
1285 | + db.commit() |
1286 | + db.close() |
1287 | + |
1288 | +def check_db_table_exist(cursor,table_name): |
1289 | + |
1290 | + sqlcmd = 'select name from sqlite_master where type=\'table\' and name="{table_name}"'.format(table_name=table_name) |
1291 | + cursor.execute(sqlcmd) |
1292 | + result = cursor.fetchone() |
1293 | + return result |
1294 | + |
1295 | +def write_machine_list_to_db(cursor,token_file): |
1296 | + |
1297 | + machine_list = get_machine_list(token_file) |
1298 | + keylist = [*machine_list[0]] |
1299 | + create_cmd = "CREATE TABLE lab_hw ({})".format(keylist[0]+ " PRIMARY KEY," +",".join(keylist[1:])) |
1300 | + |
1301 | + #check table is exist or not |
1302 | + if check_db_table_exist(cursor,"lab_hw"): |
1303 | + print('table exist') |
1304 | + cursor.execute("DELETE FROM lab_hw") |
1305 | + |
1306 | + else: |
1307 | + try: |
1308 | + cursor.execute(create_cmd) |
1309 | + |
1310 | + except sqlite3.Error as er: |
1311 | + print('SQLite error: %s' % (' '.join(er.args))) |
1312 | + |
1313 | + insert_cmd_fmt = 'insert into lab_hw values("{}")' |
1314 | + |
1315 | + for machine in machine_list: |
1316 | + if machine["CID"] == "": |
1317 | + print("1") |
1318 | + machine["CID"] = machine["Lab"] + machine["Frame"] + machine["Shelf"] + machine["Partition"] |
1319 | + insert_cmd = insert_cmd_fmt.format('","'.join(machine.values())) |
1320 | + try: |
1321 | + cursor.execute(insert_cmd) |
1322 | + |
1323 | + except sqlite3.Error as er: |
1324 | + print('SQLite error: %s' % (' '.join(er.args))) |
1325 | + |
1326 | +def environ_or_required(key): |
1327 | + if os.environ.get(key): |
1328 | + return {'default': os.environ.get(key)} |
1329 | + else: |
1330 | + return {'required': True} |
1331 | + |
1332 | +def main(): |
1333 | + |
1334 | + parser = argparse.ArgumentParser() |
1335 | + parser.add_argument('--url', help="Google sheets URL",**environ_or_required('CCLM_GOOGLE_SHEET')) |
1336 | + parser.add_argument('--token', help="Google API token",**environ_or_required('CCLM_GOOGLE_TOKEN')) |
1337 | + parser.add_argument('--database', help="Database location",**environ_or_required('CCLM_HARDWARE_DB')) |
1338 | + args = parser.parse_args() |
1339 | + global gsheet_url |
1340 | + gsheet_url = args.url |
1341 | + db = get_db_obj(args.database) |
1342 | + cursor = get_cursor_obj(db) |
1343 | + write_machine_list_to_db(cursor,args.token) |
1344 | + close_db(db) |
1345 | + |
1346 | +if __name__ == '__main__': |
1347 | + main() |
1348 | diff --git a/cc_lab_manager/maas/__init__.py b/cc_lab_manager/maas/__init__.py |
1349 | new file mode 100644 |
1350 | index 0000000..e69de29 |
1351 | --- /dev/null |
1352 | +++ b/cc_lab_manager/maas/__init__.py |
1353 | diff --git a/cc_lab_manager/maas/create_maas_node.py b/cc_lab_manager/maas/create_maas_node.py |
1354 | new file mode 100644 |
1355 | index 0000000..05be6dc |
1356 | --- /dev/null |
1357 | +++ b/cc_lab_manager/maas/create_maas_node.py |
1358 | @@ -0,0 +1,124 @@ |
1359 | +from doctest import master |
1360 | +from maas.client import connect |
1361 | +from maas.client import login |
1362 | +from maas.client.enum import LinkMode |
1363 | +import argparse |
1364 | +import os |
1365 | +import sqlite3 |
1366 | + |
1367 | +update_node_id_list = [] |
1368 | + |
1369 | +def get_db_obj(path_to_db): |
1370 | + |
1371 | + db = sqlite3.connect(path_to_db) |
1372 | + db.row_factory = sqlite3.Row |
1373 | + return db |
1374 | + |
1375 | +def get_cursor_obj(db_obj): |
1376 | + |
1377 | + cursor = db_obj.cursor() |
1378 | + return cursor |
1379 | + |
1380 | +def close_db(db): |
1381 | + db.commit() |
1382 | + db.close() |
1383 | + |
1384 | +def read_data_from_db(cursor): |
1385 | + |
1386 | + col_in_c3 = ["CID","MAC","Model","SKU","Power","IP","PDU_IP","PDU_Outlet","MAAS_Server","MAAS_Node_ID"] |
1387 | + |
1388 | + sqlcmd = 'select {} from lab_hw where CID not like \'TEL-%\' order by MAAS_Server'.format(",".join(col_in_c3[0:])) |
1389 | + cursor.execute(sqlcmd) |
1390 | + results = cursor.fetchall() |
1391 | + |
1392 | + return list(results) |
1393 | + |
1394 | +def get_maas_session(maas_ip, maas_admin, maas_admin_password): |
1395 | + client = login( |
1396 | + "http://{}:5240/MAAS/".format(maas_ip), |
1397 | + username=maas_admin, password=maas_admin_password, |
1398 | + ) |
1399 | + return client |
1400 | + |
1401 | +def get_mac_list(machine_list): |
1402 | + |
1403 | + mac_list = [] |
1404 | + for machine in machine_list: |
1405 | + mac_list.append(machine["mac"]) |
1406 | + |
1407 | + return mac_list |
1408 | + |
1409 | +def update_node_id(cursor): |
1410 | + |
1411 | + sqlcmd = 'update lab_hw set MAAS_Node_ID=? where CID=?' |
1412 | + cursor.executemany(sqlcmd, update_node_id_list) |
1413 | + |
1414 | +def get_maas_mac_list(client): |
1415 | + |
1416 | + mac_list = [] |
1417 | + for machine in client.machines.list(): |
1418 | + for key in machine.interfaces.by_name: |
1419 | + mac_list.append(machine.interfaces.by_name[key].mac_address) |
1420 | + |
1421 | + return mac_list |
1422 | + |
1423 | +def create_maas_node(machine_list, maas_admin, maas_admin_password): |
1424 | + |
1425 | + mass_is_connecting = "" |
1426 | + client = "" |
1427 | + |
1428 | + for machine in machine_list: |
1429 | + |
1430 | + if not mass_is_connecting: |
1431 | + mass_is_connecting = machine["MAAS_Server"] |
1432 | + client = get_maas_session(mass_is_connecting, maas_admin, maas_admin_password) |
1433 | + maas_mac_list = get_maas_mac_list(client) |
1434 | + elif machine["MAAS_Server"] != mass_is_connecting: |
1435 | + mass_is_connecting = machine["MAAS_Server"] |
1436 | + client = get_maas_session(mass_is_connecting, maas_admin, maas_admin_password) |
1437 | + maas_mac_list = get_maas_mac_list(client) |
1438 | + |
1439 | + power_type = machine["Power"].lower() if machine["Power"] != "" else "manual" |
1440 | + power_parameter = {} |
1441 | + node_name = (machine["Model"].replace(")","",).replace("(","",).replace(" ","-")+ "-" + \ |
1442 | + machine["sku"].replace(" ","").split("-")[-1] + "-" + machine["cid"]).lower() |
1443 | + node_name = machine["cid"].lower() |
1444 | + |
1445 | + if machine["MAC"] in maas_mac_list or machine["MAC"] == '': |
1446 | + continue |
1447 | + if power_type == "apc" or power_type == "raritan": |
1448 | + power_parameter["power_address"] = machine["PDU_IP"] |
1449 | + power_parameter["node_outlet"] = machine["PDU_Outlet"] |
1450 | + power_parameter["power_on_delay"] = 30 |
1451 | + elif power_type == "amt": |
1452 | + power_parameter["power_address"] = machine["IP"] |
1453 | + power_parameter["power_pass"] = "Insecure-101" |
1454 | + |
1455 | + maas_node = client.machines.create("amd64",machine["MAC"], "manual",hostname=node_name) |
1456 | + |
1457 | + update_node_id_list.append([maas_node.system_id, machine["CID"]]) |
1458 | + maas_node.set_power(power_type=power_type.lower(),power_parameters=power_parameter) |
1459 | + |
1460 | + |
1461 | +def environ_or_required(key): |
1462 | + if os.environ.get(key): |
1463 | + return {'default': os.environ.get(key)} |
1464 | + else: |
1465 | + return {'required': True} |
1466 | + |
1467 | +def main(): |
1468 | + |
1469 | + parser = argparse.ArgumentParser() |
1470 | + parser.add_argument('--database', help="Database location",**environ_or_required('CCLM_HARDWARE_DB')) |
1471 | + parser.add_argument('--maas_admin', help="MAAS Admin account",**environ_or_required('CCLM_MAAS_ADMIN')) |
1472 | + parser.add_argument('--maas_admin_password', help="Password for MAAS Admin account",**environ_or_required('CCLM_MAAS_ADMIN_PASSWD')) |
1473 | + args = parser.parse_args() |
1474 | + db = get_db_obj(args.database) |
1475 | + cursor = get_cursor_obj(db) |
1476 | + machine_list = read_data_from_db(cursor) |
1477 | + create_maas_node(machine_list, args.maas_admin, args.maas_admin_password) |
1478 | + update_node_id(cursor) |
1479 | + close_db(db) |
1480 | + |
1481 | +if __name__ == '__main__': |
1482 | + main() |
1483 | diff --git a/dist/cc_lab_manager-0.1-py3.8.egg b/dist/cc_lab_manager-0.1-py3.8.egg |
1484 | new file mode 100644 |
1485 | index 0000000..cd9a0a4 |
1486 | Binary files /dev/null and b/dist/cc_lab_manager-0.1-py3.8.egg differ |
1487 | diff --git a/setup.py b/setup.py |
1488 | index a609291..d39888c 100644 |
1489 | --- a/setup.py |
1490 | +++ b/setup.py |
1491 | @@ -1,7 +1,7 @@ |
1492 | #!/usr/bin/env python3 |
1493 | from setuptools import setup, find_packages |
1494 | |
1495 | -INSTALL_REQUIRES = ['pysheets'] |
1496 | +INSTALL_REQUIRES = ['pysheets', 'jinja2', 'python-libmaas', 'aiohttp==3.7.2'] |
1497 | |
1498 | setup( |
1499 | name='cc-lab-manager', |
1500 | @@ -12,4 +12,12 @@ setup( |
1501 | author_email='gavin.lin@canonical.com', |
1502 | url='https://code.launchpad.net/cc-lab-manager/', |
1503 | install_requires=INSTALL_REQUIRES, |
1504 | + entry_points={ |
1505 | + 'console_scripts': [ |
1506 | + 'cc-lab-manager=cc_lab_manager.commands.cc_lab_manager:main', |
1507 | + ] |
1508 | + }, |
1509 | + classifiers=[ |
1510 | + "Programming Language :: Python", |
1511 | + ] |
1512 | ) |
LGTM +1