blob: 2417dfab45410a2f44841b16cdd197fd12310865 [file] [log] [blame]
Ales Komarek663b85c2016-03-11 14:26:42 +01001# -*- coding: utf-8 -*-
2'''
3Module for handling maas calls.
4
5:optdepends: pyapi-maas Python adapter
6:configuration: This module is not usable until the following are specified
7 either in a pillar or in the minion's config file::
8
9 maas.url: 'https://maas.domain.com/'
10 maas.token: fdsfdsdsdsfa:fsdfae3fassd:fdsfdsfsafasdfsa
11
12'''
13
14from __future__ import absolute_import
15
Krzysztof Szukiełojćc4b33092017-02-15 13:25:38 +010016import io
Ales Komarek663b85c2016-03-11 14:26:42 +010017import logging
Krzysztof Szukiełojćc4b33092017-02-15 13:25:38 +010018import os.path
19import subprocess
20import urllib2
21import hashlib
Ales Komarek663b85c2016-03-11 14:26:42 +010022
smolaon27359ae2016-03-11 17:15:34 +010023import json
24
Ales Komarek663b85c2016-03-11 14:26:42 +010025LOG = logging.getLogger(__name__)
26
27# Import third party libs
28HAS_MASS = False
29try:
Damian Szelugad0ac0ac2017-03-29 15:15:33 +020030 from maas_client import MAASClient, MAASDispatcher, MAASOAuth
Ales Komarek663b85c2016-03-11 14:26:42 +010031 HAS_MASS = True
32except ImportError:
Krzysztof Szukiełojćc4b33092017-02-15 13:25:38 +010033 LOG.exception('why??')
Ales Komarek663b85c2016-03-11 14:26:42 +010034
35def __virtual__():
36 '''
37 Only load this module if maas-client
38 is installed on this minion.
39 '''
40 if HAS_MASS:
41 return 'maas'
42 return False
43
Krzysztof Szukiełojćc4b33092017-02-15 13:25:38 +010044APIKEY_FILE = '/var/lib/maas/.maas_credentials'
45
46def _format_data(data):
47 class Lazy:
48 def __str__(self):
49 return ' '.join(['{0}={1}'.format(k, v)
50 for k, v in data.iteritems()])
51
52 return Lazy()
Ales Komarek663b85c2016-03-11 14:26:42 +010053
54
Krzysztof Szukiełojćc4b33092017-02-15 13:25:38 +010055def _create_maas_client():
56 global APIKEY_FILE
57 try:
Krzysztof Szukiełojć43bc7e02017-03-17 10:32:07 +010058 api_token = file(APIKEY_FILE).read().splitlines()[-1].strip().split(':')
Krzysztof Szukiełojćc4b33092017-02-15 13:25:38 +010059 except:
60 LOG.exception('token')
61 auth = MAASOAuth(*api_token)
62 api_url = 'http://localhost:5240/MAAS'
Ales Komarek663b85c2016-03-11 14:26:42 +010063 dispatcher = MAASDispatcher()
Krzysztof Szukiełojćc4b33092017-02-15 13:25:38 +010064 return MAASClient(auth, dispatcher, api_url)
Ales Komarek663b85c2016-03-11 14:26:42 +010065
Krzysztof Szukiełojćc4b33092017-02-15 13:25:38 +010066class MaasObject(object):
67 def __init__(self):
68 self._maas = _create_maas_client()
69 self._extra_data_urls = {}
70 self._extra_data = {}
71 self._update = False
72 self._element_key = 'name'
73 self._update_key = 'id'
74
75 def send(self, data):
76 LOG.info('%s %s', self.__class__.__name__.lower(), _format_data(data))
77 if self._update:
78 return self._maas.put(self._update_url.format(data[self._update_key]), **data).read()
Krzysztof Szukiełojć43bc7e02017-03-17 10:32:07 +010079 if isinstance(self._create_url, tuple):
Krzysztof Szukiełojćd57a32d2017-04-04 11:25:02 +020080 return self._maas.post(self._create_url[0].format(**data),
81 *self._create_url[1:], **data).read()
82 return self._maas.post(self._create_url.format(**data), None, **data).read()
Krzysztof Szukiełojćc4b33092017-02-15 13:25:38 +010083
84 def process(self):
Krzysztof Szukiełojćd57a32d2017-04-04 11:25:02 +020085 try:
86 config = __salt__['config.get']('maas')
87 for part in self._config_path.split('.'):
88 config = config.get(part, {})
89 extra = {}
90 for name, url_call in self._extra_data_urls.iteritems():
91 key = 'id'
92 key_name = 'name'
93 if isinstance(url_call, tuple):
94 if len(url_call) == 2:
95 url_call, key = url_call[:]
96 else:
97 url_call, key, key_name = url_call[:]
98 if key:
99 extra[name] = {v[key_name]: v[key] for v in
100 json.loads(self._maas.get(url_call).read())}
101 else:
102 extra[name] = {v[key_name]: v for v in
103 json.loads(self._maas.get(url_call).read())}
104 if self._all_elements_url:
105 all_elements = {}
106 elements = self._maas.get(self._all_elements_url).read()
107 res_json = json.loads(elements)
108 for element in res_json:
109 if isinstance(element, (str, unicode)):
110 all_elements[element] = {}
111 else:
112 all_elements[element[self._element_key]] = element
113 else:
114 all_elements = {}
115 ret = {
116 'success': [],
117 'errors': {},
118 'updated': [],
119 }
120 for name, config_data in config.iteritems():
121 self._update = False
122 try:
123 data = self.fill_data(name, config_data, **extra)
124 if data is None:
125 ret['updated'].append(name)
126 continue
127 if name in all_elements:
128 self._update = True
129 data = self.update(data, all_elements[name])
130 self.send(data)
131 ret['updated'].append(name)
132 else:
133 self.send(data)
134 ret['success'].append(name)
135 except urllib2.HTTPError as e:
136 etxt = e.read()
137 LOG.exception('Failed for object %s reason %s', name, etxt)
138 ret['errors'][name] = str(etxt)
139 except Exception as e:
140 LOG.exception('Failed for object %s reason %s', name, e)
141 ret['errors'][name] = str(e)
Krzysztof Szukiełojć04e18332017-04-04 11:51:44 +0200142 except Exception as e:
143 LOG.exception('Error Global')
144 raise
Krzysztof Szukiełojćc4b33092017-02-15 13:25:38 +0100145 if ret['errors']:
146 raise Exception(ret)
147 return ret
Ales Komarek663b85c2016-03-11 14:26:42 +0100148
149
Krzysztof Szukiełojćc4b33092017-02-15 13:25:38 +0100150class Fabric(MaasObject):
151 def __init__(self):
152 super(Fabric, self).__init__()
153 self._all_elements_url = u'api/2.0/fabrics/'
154 self._create_url = u'api/2.0/fabrics/'
155 self._update_url = u'api/2.0/fabrics/{0}/'
156 self._config_path = 'region.fabrics'
Ales Komarek663b85c2016-03-11 14:26:42 +0100157
Krzysztof Szukiełojćc4b33092017-02-15 13:25:38 +0100158 def fill_data(self, name, fabric):
159 data = {
160 'name': name,
161 'description': fabric.get('description', ''),
162 }
163 if 'class_type' in fabric:
164 data['class_type'] = fabric.get('class_type'),
165 return data
Ales Komarek663b85c2016-03-11 14:26:42 +0100166
Krzysztof Szukiełojćc4b33092017-02-15 13:25:38 +0100167 def update(self, new, old):
168 new['id'] = str(old['id'])
169 return new
Ales Komarek663b85c2016-03-11 14:26:42 +0100170
Krzysztof Szukiełojćc4b33092017-02-15 13:25:38 +0100171class Subnet(MaasObject):
172 def __init__(self):
173 super(Subnet, self).__init__()
174 self._all_elements_url = u'api/2.0/subnets/'
175 self._create_url = u'api/2.0/subnets/'
176 self._update_url = u'api/2.0/subnets/{0}/'
177 self._config_path = 'region.subnets'
178 self._extra_data_urls = {'fabrics':u'api/2.0/fabrics/'}
Ales Komarek0fafa572016-03-11 14:56:44 +0100179
Krzysztof Szukiełojćc4b33092017-02-15 13:25:38 +0100180 def fill_data(self, name, subnet, fabrics):
181 data = {
182 'name': name,
183 'fabric': str(fabrics[subnet.get('fabric', '')]),
184 'cidr': subnet.get('cidr'),
185 'gateway_ip': subnet['gateway_ip'],
186 }
187 self._iprange = subnet['iprange']
188 return data
Krzysztof Szukiełojć15b62b72017-02-15 08:58:18 +0100189
Krzysztof Szukiełojćc4b33092017-02-15 13:25:38 +0100190 def update(self, new, old):
191 new['id'] = str(old['id'])
192 return new
Ales Komarek0fafa572016-03-11 14:56:44 +0100193
Krzysztof Szukiełojćc4b33092017-02-15 13:25:38 +0100194 def send(self, data):
195 response = super(Subnet, self).send(data)
196 res_json = json.loads(response)
197 self._process_iprange(res_json['id'])
198 return response
Krzysztof Szukiełojć15b62b72017-02-15 08:58:18 +0100199
Krzysztof Szukiełojćc4b33092017-02-15 13:25:38 +0100200 def _process_iprange(self, subnet_id):
201 ipranges = json.loads(self._maas.get(u'api/2.0/ipranges/').read())
202 LOG.warn('all %s ipranges %s', subnet_id, ipranges)
203 update = False
204 old_data = None
205 for iprange in ipranges:
206 if iprange['subnet']['id'] == subnet_id:
207 update = True
208 old_data = iprange
209 break
210 data = {
211 'start_ip': self._iprange.get('start'),
212 'end_ip': self._iprange.get('end'),
213 'subnet': str(subnet_id),
214 'type': self._iprange.get('type', 'dynamic')
215 }
216 LOG.warn('INFO: %s\n OLD: %s', data, old_data)
217 LOG.info('iprange %s', _format_data(data))
218 if update:
219 LOG.warn('UPDATING %s %s', data, old_data)
220 self._maas.put(u'api/2.0/ipranges/{0}/'.format(old_data['id']), **data)
smolaonc3385f82016-03-11 19:01:24 +0100221 else:
Krzysztof Szukiełojćc4b33092017-02-15 13:25:38 +0100222 self._maas.post(u'api/2.0/ipranges/', None, **data)
smolaonc3385f82016-03-11 19:01:24 +0100223
Krzysztof Szukiełojćc4b33092017-02-15 13:25:38 +0100224class DHCPSnippet(MaasObject):
225 def __init__(self):
226 super(DHCPSnippet, self).__init__()
227 self._all_elements_url = u'api/2.0/dhcp-snippets/'
228 self._create_url = u'api/2.0/dhcp-snippets/'
229 self._update_url = u'api/2.0/dhcp-snippets/{0}/'
230 self._config_path = 'region.dhcp_snippets'
231 self._extra_data_urls = {'subnets': u'api/2.0/subnets/'}
Krzysztof Szukiełojć15b62b72017-02-15 08:58:18 +0100232
Krzysztof Szukiełojćc4b33092017-02-15 13:25:38 +0100233 def fill_data(self, name, snippet, subnets):
234 data = {
235 'name': name,
236 'value': snippet['value'],
237 'description': snippet['description'],
238 'enabled': str(snippet['enabled'] and 1 or 0),
239 'subnet': str(subnets[snippet['subnet']]),
240 }
241 return data
smolaonc3385f82016-03-11 19:01:24 +0100242
Krzysztof Szukiełojćc4b33092017-02-15 13:25:38 +0100243 def update(self, new, old):
244 new['id'] = str(old['id'])
245 return new
Krzysztof Szukiełojć15b62b72017-02-15 08:58:18 +0100246
Krzysztof Szukiełojćc4b33092017-02-15 13:25:38 +0100247class PacketRepository(MaasObject):
248 def __init__(self):
249 super(PacketRepository, self).__init__()
250 self._all_elements_url = u'api/2.0/package-repositories/'
251 self._create_url = u'api/2.0/package-repositories/'
252 self._update_url = u'api/2.0/package-repositories/{0}/'
253 self._config_path = 'region.package_repositories'
Krzysztof Szukiełojć15b62b72017-02-15 08:58:18 +0100254
Krzysztof Szukiełojćc4b33092017-02-15 13:25:38 +0100255 def fill_data(self, name, package_repository):
256 data = {
257 'name': name,
258 'url': package_repository['url'],
259 'distributions': package_repository['distributions'],
260 'components': package_repository['components'],
261 'arches': package_repository['arches'],
262 'key': package_repository['key'],
263 'enabled': str(package_repository['enabled'] and 1 or 0),
264 }
265 if 'disabled_pockets' in package_repository:
266 data['disabled_pockets'] = package_repository['disable_pockets'],
267 return data
Krzysztof Szukiełojć15b62b72017-02-15 08:58:18 +0100268
Krzysztof Szukiełojćc4b33092017-02-15 13:25:38 +0100269 def update(self, new, old):
270 new['id'] = str(old['id'])
271 return new
Krzysztof Szukiełojć15b62b72017-02-15 08:58:18 +0100272
Krzysztof Szukiełojćc4b33092017-02-15 13:25:38 +0100273class Device(MaasObject):
274 def __init__(self):
275 super(Device, self).__init__()
276 self._all_elements_url = u'api/2.0/devices/'
277 self._create_url = u'api/2.0/devices/'
278 self._update_url = u'api/2.0/devices/{0}/'
279 self._config_path = 'region.devices'
280 self._element_key = 'hostname'
281 self._update_key = 'system_id'
smolaonc3385f82016-03-11 19:01:24 +0100282
Krzysztof Szukiełojćc4b33092017-02-15 13:25:38 +0100283 def fill_data(self, name, device_data):
284 data = {
285 'mac_addresses': device_data['mac'],
286 'hostname': name,
287 }
288 self._interface = device_data['interface']
289 return data
290
291 def update(self, new, old):
Krzysztof Szukiełojća6352a42017-03-17 14:21:57 +0100292 old_macs = set(v['mac_address'].lower() for v in old['interface_set'])
293 if new['mac_addresses'].lower() not in old_macs:
Krzysztof Szukiełojćc4b33092017-02-15 13:25:38 +0100294 self._update = False
Krzysztof Szukiełojća6352a42017-03-17 14:21:57 +0100295 LOG.info('Mac changed deleting old device %s', old['system_id'])
Krzysztof Szukiełojćc4b33092017-02-15 13:25:38 +0100296 self._maas.delete(u'api/2.0/devices/{0}/'.format(old['system_id']))
297 else:
298 new[self._update_key] = str(old[self._update_key])
299 return new
300
301 def send(self, data):
302 response = super(Device, self).send(data)
303 resp_json = json.loads(response)
304 system_id = resp_json['system_id']
305 iface_id = resp_json['interface_set'][0]['id']
Krzysztof Szukiełojća6352a42017-03-17 14:21:57 +0100306 self._link_interface(system_id, iface_id)
Krzysztof Szukiełojćc4b33092017-02-15 13:25:38 +0100307 return response
308
309 def _link_interface(self, system_id, interface_id):
310 data = {
311 'mode': self._interface.get('mode', 'STATIC'),
Krzysztof Szukiełojća6352a42017-03-17 14:21:57 +0100312 'subnet': self._interface['subnet'],
313 'ip_address': self._interface['ip_address'],
Krzysztof Szukiełojćc4b33092017-02-15 13:25:38 +0100314 }
315 if 'default_gateway' in self._interface:
316 data['default_gateway'] = self._interface.get('default_gateway')
317 if self._update:
318 data['force'] = '1'
319 LOG.info('interfaces link_subnet %s %s %s', system_id, interface_id,
320 _format_data(data))
321 self._maas.post(u'/api/2.0/nodes/{0}/interfaces/{1}/'
322 .format(system_id, interface_id), 'link_subnet',
323 **data)
324
325
326class Machine(MaasObject):
327 def __init__(self):
328 super(Machine, self).__init__()
329 self._all_elements_url = u'api/2.0/machines/'
330 self._create_url = u'api/2.0/machines/'
331 self._update_url = u'api/2.0/machines/{0}/'
332 self._config_path = 'region.machines'
333 self._element_key = 'hostname'
334 self._update_key = 'system_id'
335
336 def fill_data(self, name, machine_data):
Krzysztof Szukiełojćc4b33092017-02-15 13:25:38 +0100337 power_data = machine_data['power_parameters']
338 data = {
339 'hostname': name,
340 'architecture': machine_data.get('architecture', 'amd64/generic'),
Krzysztof Szukiełojćd57a32d2017-04-04 11:25:02 +0200341 'mac_addresses': machine_data['interface']['mac'],
Krzysztof Szukiełojćc4b33092017-02-15 13:25:38 +0100342 'power_type': machine_data.get('power_type', 'ipmi'),
343 'power_parameters_power_address': power_data['power_address'],
344 }
345 if 'power_user' in power_data:
346 data['power_parameters_power_user'] = power_data['power_user']
347 if 'power_password' in power_data:
348 data['power_parameters_power_pass'] = \
349 power_data['power_password']
350 return data
351
352 def update(self, new, old):
Krzysztof Szukiełojća6352a42017-03-17 14:21:57 +0100353 old_macs = set(v['mac_address'].lower() for v in old['interface_set'])
354 if new['mac_addresses'].lower() not in old_macs:
Krzysztof Szukiełojćc4b33092017-02-15 13:25:38 +0100355 self._update = False
Krzysztof Szukiełojća6352a42017-03-17 14:21:57 +0100356 LOG.info('Mac changed deleting old machine %s', old['system_id'])
357 self._maas.delete(u'api/2.0/machines/{0}/'.format(old['system_id']))
Krzysztof Szukiełojćc4b33092017-02-15 13:25:38 +0100358 else:
359 new[self._update_key] = str(old[self._update_key])
360 return new
361
Krzysztof Szukiełojćd57a32d2017-04-04 11:25:02 +0200362
363class AssignMachinesIP(MaasObject):
364 def __init__(self):
365 super(AssignMachinesIP, self).__init__()
366 self._all_elements_url = None
367 self._create_url = (u'/api/2.0/nodes/{system_id}/interfaces/{interface_id}/', 'link_subnet')
368 self._config_path = 'region.machines'
369 self._element_key = 'hostname'
370 self._update_key = 'system_id'
371 self._extra_data_urls = {'machines' : (u'api/2.0/machines/', None, 'hostname')}
372
373 def fill_data(self, name, data, machines):
374 interface = data['interface']
375 machine = machines[name]
376 if 'ip' not in interface:
Krzysztof Szukiełojća6352a42017-03-17 14:21:57 +0100377 return
378 data = {
379 'mode': 'STATIC',
Krzysztof Szukiełojćd57a32d2017-04-04 11:25:02 +0200380 'subnet': str(interface.get('subnet')),
381 'ip_address': str(interface.get('ip')),
Krzysztof Szukiełojća6352a42017-03-17 14:21:57 +0100382 }
Krzysztof Szukiełojćd57a32d2017-04-04 11:25:02 +0200383 if 'default_gateway' in interface:
384 data['default_gateway'] = interface.get('gateway')
Krzysztof Szukiełojća6352a42017-03-17 14:21:57 +0100385 if self._update:
386 data['force'] = '1'
Krzysztof Szukiełojćd57a32d2017-04-04 11:25:02 +0200387 data['system_id'] = str(machine['system_id'])
388 data['interface_id'] = str(machine['interface_set'][0]['id'])
389 return data
Krzysztof Szukiełojća6352a42017-03-17 14:21:57 +0100390
391
Krzysztof Szukiełojćc4b33092017-02-15 13:25:38 +0100392class BootResource(MaasObject):
393 def __init__(self):
394 super(BootResource, self).__init__()
395 self._all_elements_url = u'api/2.0/boot-resources/'
396 self._create_url = u'api/2.0/boot-resources/'
397 self._update_url = u'api/2.0/boot-resources/{0}/'
398 self._config_path = 'region.boot_resources'
399
400 def fill_data(self, name, boot_data):
401 sha256 = hashlib.sha256()
402 sha256.update(file(boot_data['content']).read())
403 data = {
404 'name': name,
405 'title': boot_data['title'],
406 'architecture': boot_data['architecture'],
407 'filetype': boot_data['filetype'],
408 'size': str(os.path.getsize(boot_data['content'])),
409 'sha256': sha256.hexdigest(),
410 'content': io.open(boot_data['content']),
411 }
412 return data
413
414 def update(self, new, old):
415 self._update = False
416 return new
417
Krzysztof Szukiełojć43bc7e02017-03-17 10:32:07 +0100418class CommissioningScripts(MaasObject):
419 def __init__(self):
420 super(CommissioningScripts, self).__init__()
421 self._all_elements_url = u'api/2.0/commissioning-scripts/'
422 self._create_url = u'api/2.0/commissioning-scripts/'
Krzysztof Szukiełojć43bc7e02017-03-17 10:32:07 +0100423 self._config_path = 'region.commissioning_scripts'
Krzysztof Szukiełojća6352a42017-03-17 14:21:57 +0100424 self._update_url = u'api/2.0/commissioning-scripts/{0}'
Krzysztof Szukiełojć43bc7e02017-03-17 10:32:07 +0100425 self._update_key = 'name'
426
427 def fill_data(self, name, file_path):
428 data = {
429 'name': name,
430 'content': io.open(file_path),
431 }
432 return data
433
434 def update(self, new, old):
435 return new
436
437class MaasConfig(MaasObject):
438 def __init__(self):
439 super(MaasConfig, self).__init__()
440 self._all_elements_url = None
441 self._create_url = (u'api/2.0/maas/', u'set_config')
442 self._config_path = 'region.maas_config'
443
444 def fill_data(self, name, value):
445 data = {
446 'name': name,
Krzysztof Szukiełojća6352a42017-03-17 14:21:57 +0100447 'value': str(value),
Krzysztof Szukiełojć43bc7e02017-03-17 10:32:07 +0100448 }
449 return data
450
451 def update(self, new, old):
452 self._update = False
453 return new
454
455
Krzysztof Szukiełojća1bd77e2017-03-30 08:34:22 +0200456class SSHPrefs(MaasObject):
457 def __init__(self):
458 super(SSHPrefs, self).__init__()
459 self._all_elements_url = None
460 self._create_url = u'api/2.0/account/prefs/sshkeys/'
461 self._config_path = 'region.sshprefs'
462 self._element_key = 'hostname'
463 self._update_key = 'system_id'
464
465 def fill_data(self, value):
466 data = {
467 'key': value,
468 }
469 return data
470
471 def process(self):
472 config = __salt__['config.get']('maas')
473 for part in self._config_path.split('.'):
474 config = config.get(part, {})
475 extra = {}
476 for name, url_call in self._extra_data_urls.iteritems():
477 key = 'id'
478 if isinstance(url_call, tuple):
479 url_call, key = url_call[:]
480 extra[name] = {v['name']: v[key] for v in
481 json.loads(self._maas.get(url_call).read())}
482 if self._all_elements_url:
483 all_elements = {}
484 elements = self._maas.get(self._all_elements_url).read()
485 res_json = json.loads(elements)
486 for element in res_json:
487 if isinstance(element, (str, unicode)):
488 all_elements[element] = {}
489 else:
490 all_elements[element[self._element_key]] = element
491 else:
492 all_elements = {}
493 ret = {
494 'success': [],
495 'errors': {},
496 'updated': [],
497 }
498 for config_data in config:
499 name = config_data[:10]
500 try:
501 data = self.fill_data(config_data, **extra)
502 self.send(data)
503 ret['success'].append(name)
504 except urllib2.HTTPError as e:
505 etxt = e.read()
506 LOG.exception('Failed for object %s reason %s', name, etxt)
507 ret['errors'][name] = str(etxt)
508 except Exception as e:
509 LOG.exception('Failed for object %s reason %s', name, e)
510 ret['errors'][name] = str(e)
511 if ret['errors']:
512 raise Exception(ret)
513 return ret
Krzysztof Szukiełojć8cc32b42017-03-29 15:22:57 +0200514
515class Domain(MaasObject):
516 def __init__(self):
517 super(Domain, self).__init__()
518 self._all_elements_url = u'/api/2.0/domains/'
519 self._create_url = u'/api/2.0/domains/'
520 self._config_path = 'region.domain'
521 self._update_url = u'/api/2.0/domains/{0}/'
522
523 def fill_data(self, value):
524 data = {
525 'name': value,
526 }
527 self._update = True
528 return data
529
530 def update(self, new, old):
531 new['id'] = str(old['id'])
532 new['authoritative'] = str(old['authoritative'])
533 return new
534
535 def process(self):
536 config = __salt__['config.get']('maas')
537 for part in self._config_path.split('.'):
538 config = config.get(part, {})
539 extra = {}
540 for name, url_call in self._extra_data_urls.iteritems():
541 key = 'id'
542 if isinstance(url_call, tuple):
543 url_call, key = url_call[:]
544 extra[name] = {v['name']: v[key] for v in
545 json.loads(self._maas.get(url_call).read())}
546 if self._all_elements_url:
547 all_elements = {}
548 elements = self._maas.get(self._all_elements_url).read()
549 res_json = json.loads(elements)
550 for element in res_json:
551 if isinstance(element, (str, unicode)):
552 all_elements[element] = {}
553 else:
554 all_elements[element[self._element_key]] = element
555 else:
556 all_elements = {}
557 ret = {
558 'success': [],
559 'errors': {},
560 'updated': [],
561 }
562 try:
563 data = self.fill_data(config, **extra)
564 data = self.update(data, all_elements.values()[0])
565 self.send(data)
566 ret['success'].append('domain')
567 except urllib2.HTTPError as e:
568 etxt = e.read()
569 LOG.exception('Failed for object %s reason %s', 'domain', etxt)
570 ret['errors']['domain'] = str(etxt)
571 except Exception as e:
572 LOG.exception('Failed for object %s reason %s', 'domain', e)
573 ret['errors']['domain'] = str(e)
574 if ret['errors']:
575 raise Exception(ret)
576 return ret
577
578
Krzysztof Szukiełojć04e18332017-04-04 11:51:44 +0200579class MachinesStatus(MaasObject):
580 @classmethod
581 def execute(cls):
582 self._maas = _create_maas_client()
583 result = self._maas.get(u'api/2.0/machines/')
584 json_result = json.loads(result.read())
585 res = []
586 for machine in json_result:
587 res.append({
588 'hostname': machine['hostname']
589 'system_id': machine['system_id']
590 'status': machine['status']
591 })
592 return res
593
594
Krzysztof Szukiełojćc4b33092017-02-15 13:25:38 +0100595def process_fabrics():
596 return Fabric().process()
597
598def process_subnets():
599 return Subnet().process()
600
601def process_dhcp_snippets():
602 return DHCPSnippet().process()
603
604def process_package_repositories():
605 return PacketRepository().process()
606
607def process_devices():
608 return Device().process()
609
610def process_machines():
611 return Machine().process()
612
Krzysztof Szukiełojć04e18332017-04-04 11:51:44 +0200613def process_assign_machines_ip():
614 return AssignMachinesIP().process()
615
616def machines_status():
617 return MachinesStatus.execute()
618
Krzysztof Szukiełojćc4b33092017-02-15 13:25:38 +0100619def process_boot_resources():
620 return BootResource().process()
Krzysztof Szukiełojć43bc7e02017-03-17 10:32:07 +0100621
622def process_maas_config():
623 return MaasConfig().process()
624
625def process_commissioning_scripts():
626 return CommissioningScripts().process()
Krzysztof Szukiełojć8cc32b42017-03-29 15:22:57 +0200627
628def process_domain():
629 return Domain().process()
Krzysztof Szukiełojća1bd77e2017-03-30 08:34:22 +0200630
631def process_sshprefs():
632 return SSHPrefs().process()