blob: 54f15ae0f11dda46ec4dfae528ac9a20490d3cda [file] [log] [blame]
Ondrej Smolab57a23b2018-01-24 11:18:24 +01001# -*- coding: utf-8 -*-
azvyagintsevbca1f462018-05-25 19:06:46 +03002"""
Ondrej Smolab57a23b2018-01-24 11:18:24 +01003Module 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
azvyagintsevbca1f462018-05-25 19:06:46 +030012"""
Ondrej Smolab57a23b2018-01-24 11:18:24 +010013
14from __future__ import absolute_import
15
16import collections
17import copy
18import hashlib
19import io
20import json
21import logging
22import os.path
23import time
24import urllib2
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +020025# Salt utils
Ondrej Smolab57a23b2018-01-24 11:18:24 +010026from salt.exceptions import CommandExecutionError, SaltInvocationError
27
28LOG = logging.getLogger(__name__)
29
30SIZE = {
31 "M": 1000000,
32 "G": 1000000000,
33 "T": 1000000000000,
34}
35
36RAID = {
37 0: "raid-0",
38 1: "raid-1",
39 5: "raid-5",
40 10: "raid-10",
41}
42
43# Import third party libs
44HAS_MASS = False
45try:
46 from maas_client import MAASClient, MAASDispatcher, MAASOAuth
47 HAS_MASS = True
48except ImportError:
49 LOG.debug('Missing MaaS client module is Missing. Skipping')
50
51
52def __virtual__():
azvyagintsevbca1f462018-05-25 19:06:46 +030053 """
Ondrej Smolab57a23b2018-01-24 11:18:24 +010054 Only load this module if maas-client
55 is installed on this minion.
azvyagintsevbca1f462018-05-25 19:06:46 +030056 """
Ondrej Smolab57a23b2018-01-24 11:18:24 +010057 if HAS_MASS:
58 return 'maasng'
59 return False
60
61
62APIKEY_FILE = '/var/lib/maas/.maas_credentials'
63
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +020064
Ondrej Smolab57a23b2018-01-24 11:18:24 +010065def _format_data(data):
66 class Lazy:
67 def __str__(self):
68 return ' '.join(['{0}={1}'.format(k, v)
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +020069 for k, v in data.iteritems()])
Ondrej Smolab57a23b2018-01-24 11:18:24 +010070 return Lazy()
71
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +020072
Ondrej Smolab57a23b2018-01-24 11:18:24 +010073def _create_maas_client():
74 global APIKEY_FILE
75 try:
76 api_token = file(APIKEY_FILE).read().splitlines()[-1].strip()\
77 .split(':')
78 except:
79 LOG.exception('token')
80 auth = MAASOAuth(*api_token)
81 api_url = 'http://localhost:5240/MAAS'
82 dispatcher = MAASDispatcher()
83 return MAASClient(auth, dispatcher, api_url)
84
Ondrej Smolab57a23b2018-01-24 11:18:24 +010085
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +020086def _get_blockdevice_id_by_name(hostname, device):
87
88 # TODO validation
Ondrej Smolab57a23b2018-01-24 11:18:24 +010089 return list_blockdevices(hostname)[device]["id"]
90
Ondrej Smolab57a23b2018-01-24 11:18:24 +010091
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +020092def _get_volume_group_id_by_name(hostname, device):
93
94 # TODO validation
Ondrej Smolab57a23b2018-01-24 11:18:24 +010095 return list_volume_groups(hostname)[device]["id"]
96
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +020097
azvyagintsevbca1f462018-05-25 19:06:46 +030098def _get_volume_id_by_name(hostname, volume_name, volume_group, maas_volname=True):
99
100 if not maas_volname:
101 # MAAS-like name
Pavel Cizinsky8dd85b52018-06-18 21:40:13 +0200102 volume_name = str("%s-%s" % (volume_group, volume_name))
103 # TODO validation
azvyagintsevbca1f462018-05-25 19:06:46 +0300104 return get_volumes(hostname, volume_group)[volume_name]["id"]
105
106
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100107def _get_partition_id_by_name(hostname, device, partition):
108
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200109 # TODO validation
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100110 return list_partitions(hostname, device)[partition]["id"]
111
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200112# MACHINE SECTION
113
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100114
115def get_machine(hostname):
azvyagintsevbca1f462018-05-25 19:06:46 +0300116 """
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100117 Get information aboout specified machine
118
119 CLI Example:
120
121 .. code-block:: bash
122
123 salt-call maasng.get_machine server_hostname
azvyagintsevbca1f462018-05-25 19:06:46 +0300124 """
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100125 try:
126 return list_machines()[hostname]
127 except KeyError:
128 return {"error": "Machine not found on MaaS server"}
129
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200130
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100131def list_machines():
azvyagintsevbca1f462018-05-25 19:06:46 +0300132 """
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100133 Get list of all machines from maas server
134
135 CLI Example:
136
137 .. code-block:: bash
138
139 salt 'maas-node' maasng.list_machines
azvyagintsevbca1f462018-05-25 19:06:46 +0300140 """
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200141 machines = {}
142 maas = _create_maas_client()
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100143 json_res = json.loads(maas.get(u'api/2.0/machines/').read())
144 for item in json_res:
145 machines[item["hostname"]] = item
146 return machines
147
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200148
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100149def create_machine():
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200150 # TODO
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100151
152 return False
153
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200154
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100155def update_machine():
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200156 # TODO
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100157
158 return False
159
azvyagintsevbca1f462018-05-25 19:06:46 +0300160# END MACHINE SECTION
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200161# RAID SECTION
162
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100163
164def create_raid(hostname, name, level, disks=[], partitions=[], **kwargs):
azvyagintsevbca1f462018-05-25 19:06:46 +0300165 """
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100166 Create new raid on machine.
167
168 CLI Example:
169
170 .. code-block:: bash
171
172 salt-call maasng.create_raid hostname=kvm03 name=md0 level=1 disks=[vdb,vdc] partitions=[vdd-part1,vde-part1]
azvyagintsevbca1f462018-05-25 19:06:46 +0300173 """
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100174
175 result = {}
176
177 if len(disks) == 0 and len(partitions) == 0:
178 result["error"] = "Disks or partitions need to be provided"
179
180 disk_ids = []
181 partition_ids = []
182
183 for disk in disks:
184 try:
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200185 disk_ids.append(str(_get_blockdevice_id_by_name(hostname, disk)))
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100186 except KeyError:
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200187 result["error"] = "Device {0} does not exists on machine {1}".format(
188 disk, hostname)
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100189 return result
190
191 for partition in partitions:
192 try:
193 device = partition.split("-")[0]
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200194 device_part = list_partitions(hostname, device)
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100195 partition_ids.append(str(device_part[partition]["id"]))
196 except KeyError:
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200197 result["error"] = "Partition {0} does not exists on machine {1}".format(
198 partition, hostname)
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100199 return result
200
201 data = {
202 "name": name,
203 "level": RAID[int(level)],
204 "block_devices": disk_ids,
205 "partitions": partition_ids,
206 }
207
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200208 maas = _create_maas_client()
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100209 system_id = get_machine(hostname)["system_id"]
210 LOG.info(system_id)
211
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200212 # TODO validation
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100213 LOG.info(data)
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200214 json_res = json.loads(
215 maas.post(u"api/2.0/nodes/{0}/raids/".format(system_id), None, **data).read())
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100216 LOG.info(json_res)
217 result["new"] = "Raid {0} created".format(name)
218
219 return result
220
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200221
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100222def list_raids(hostname):
azvyagintsevbca1f462018-05-25 19:06:46 +0300223 """
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100224 Get list all raids on machine
225
226 CLI Example:
227
228 .. code-block:: bash
229
230 salt-call maasng.list_raids server_hostname
azvyagintsevbca1f462018-05-25 19:06:46 +0300231 """
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100232
azvyagintsevbca1f462018-05-25 19:06:46 +0300233 raids = {}
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200234 maas = _create_maas_client()
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100235 system_id = get_machine(hostname)["system_id"]
Pavel Cizinsky8dd85b52018-06-18 21:40:13 +0200236 # TODO validation
237 json_res = json.loads(
238 maas.get(u"api/2.0/nodes/{0}/raids/".format(system_id)).read())
azvyagintsevbca1f462018-05-25 19:06:46 +0300239 LOG.debug('list_raids:{} {}'.format(system_id, json_res))
240 for item in json_res:
241 raids[item["name"]] = item
242 return raids
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100243
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200244
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100245def get_raid(hostname, name):
azvyagintsevbca1f462018-05-25 19:06:46 +0300246 """
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100247 Get information about specific raid on machine
248
249 CLI Example:
250
251 .. code-block:: bash
252
253 salt-call maasng.get_raids server_hostname md0
azvyagintsevbca1f462018-05-25 19:06:46 +0300254 """
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100255
256 return list_raids(hostname)[name]
257
258
azvyagintsevbca1f462018-05-25 19:06:46 +0300259def _get_raid_id_by_name(hostname, raid_name):
260 return get_raid(hostname, raid_name)['id']
261
262
263def delete_raid(hostname, raid_name):
264 """
265 Delete RAID on a machine.
266
267 CLI Example:
268
269 .. code-block:: bash
270
271 salt 'maas-node' maasng.delete_raid server_hostname raid_name
272 salt-call maasng.delete_raid server_hostname raid_name
273 """
274 result = {}
Pavel Cizinsky8dd85b52018-06-18 21:40:13 +0200275 maas = _create_maas_client()
azvyagintsevbca1f462018-05-25 19:06:46 +0300276 system_id = get_machine(hostname)["system_id"]
277 raid_id = _get_raid_id_by_name(hostname, raid_name)
Pavel Cizinsky8dd85b52018-06-18 21:40:13 +0200278 LOG.debug('delete_raid: {} {}'.format(system_id, raid_id))
279 maas.delete(
280 u"api/2.0/nodes/{0}/raid/{1}/".format(system_id, raid_id)).read()
azvyagintsevbca1f462018-05-25 19:06:46 +0300281
282 result["new"] = "Raid {0} deleted".format(raid_name)
283 return result
284
285# END RAID SECTION
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200286# BLOCKDEVICES SECTION
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100287
azvyagintsevbca1f462018-05-25 19:06:46 +0300288
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100289def list_blockdevices(hostname):
azvyagintsevbca1f462018-05-25 19:06:46 +0300290 """
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100291 Get list of all blockdevices (disks) on machine
292
293 CLI Example:
294
295 .. code-block:: bash
296
297 salt 'maas-node' maasng.list_blockdevices server_hostname
298 salt-call maasng.list_blockdevices server_hostname
azvyagintsevbca1f462018-05-25 19:06:46 +0300299 """
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100300 ret = {}
301
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200302 maas = _create_maas_client()
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100303 system_id = get_machine(hostname)["system_id"]
304 LOG.info(system_id)
305
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200306 # TODO validation if exists
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100307
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200308 json_res = json.loads(
309 maas.get(u"api/2.0/nodes/{0}/blockdevices/".format(system_id)).read())
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100310 LOG.info(json_res)
311 for item in json_res:
312 ret[item["name"]] = item
313
314 return ret
315
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200316
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100317def get_blockdevice(hostname, name):
azvyagintsevbca1f462018-05-25 19:06:46 +0300318 """
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100319 Get information about blockdevice (disk) on machine
320
321 CLI Example:
322
323 .. code-block:: bash
324
325 salt 'maas-node' maasng.get_blockdevice server_hostname sda
326 salt-call maasng.get_blockdevice server_hostname sda
azvyagintsevbca1f462018-05-25 19:06:46 +0300327 """
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100328
329 return list_blockdevices(hostname)[name]
330
azvyagintsevbca1f462018-05-25 19:06:46 +0300331# END BLOCKDEVICES SECTION
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200332# PARTITIONS
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100333
azvyagintsevbca1f462018-05-25 19:06:46 +0300334
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100335def list_partitions(hostname, device):
azvyagintsevbca1f462018-05-25 19:06:46 +0300336 """
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100337 Get list of all partitions on specific device located on specific machine
338
339 CLI Example:
340
341 .. code-block:: bash
342
343 salt 'maas-node' maasng.list_partitions server_hostname sda
344 salt-call maasng.list_partitions server_hostname sda
azvyagintsevbca1f462018-05-25 19:06:46 +0300345 """
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100346 ret = {}
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200347 maas = _create_maas_client()
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100348 system_id = get_machine(hostname)["system_id"]
349 LOG.info(system_id)
350
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200351 partitions = get_blockdevice(hostname, device)["partitions"]
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100352 LOG.info(partitions)
353
354 #json_res = json.loads(maas.get(u"api/2.0/nodes/{0}/blockdevices/{1}/partitions/".format(system_id, device_id)).read())
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200355 # LOG.info(json_res)
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100356
357 if len(device) > 0:
358 for item in partitions:
359 name = item["path"].split('/')[-1]
360 ret[name] = item
361
362 return ret
363
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200364
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100365def get_partition(hostname, device, partition):
azvyagintsevbca1f462018-05-25 19:06:46 +0300366 """
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100367 Get information about specific parition on device located on machine
368
369 CLI Example:
370
371 .. code-block:: bash
372
373 salt 'maas-node' maasng.get_partition server_hostname disk_name partition
374 salt-call maasng.get_partition server_hostname disk_name partition
375
376 root_size = size in GB
azvyagintsevbca1f462018-05-25 19:06:46 +0300377 """
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100378
379 return list_partitions(partition)[name]
380
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200381
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100382def create_partition(hostname, disk, size, fs_type=None, mount=None):
azvyagintsevbca1f462018-05-25 19:06:46 +0300383 """
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100384 Create new partition on device.
385
386 CLI Example:
387
388 .. code-block:: bash
389
390 salt 'maas-node' maasng.create_partition server_hostname disk_name 10 ext4 "/"
391 salt-call maasng.create_partition server_hostname disk_name 10 ext4 "/"
azvyagintsevbca1f462018-05-25 19:06:46 +0300392 """
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200393 # TODO validation
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100394 result = {}
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200395 maas = _create_maas_client()
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100396 system_id = get_machine(hostname)["system_id"]
397 LOG.info(system_id)
398
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200399 device_id = _get_blockdevice_id_by_name(hostname, disk)
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100400 LOG.info(device_id)
401
402 value, unit = size[:-1], size[-1]
403 calc_size = str(int(value) * SIZE[unit])
404 LOG.info(calc_size)
405
406 data = {
407 "size": calc_size
408 }
409
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200410 # TODO validation
411 partition = json.loads(maas.post(
412 u"api/2.0/nodes/{0}/blockdevices/{1}/partitions/".format(system_id, device_id), None, **data).read())
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100413 LOG.info(partition)
414 result["partition"] = "Partition created on {0}".format(disk)
415
416 if fs_type != None:
417 data_fs_type = {
418 "fstype": fs_type
419 }
420 partition_id = str(partition["id"])
421 LOG.info("Partition id: " + partition_id)
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200422 # TODO validation
423 json_res = json.loads(maas.post(u"api/2.0/nodes/{0}/blockdevices/{1}/partition/{2}".format(
424 system_id, device_id, partition_id), "format", **data_fs_type).read())
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100425 LOG.info(json_res)
426 result["filesystem"] = "Filesystem {0} created".format(fs_type)
427
428 if mount != None:
429 data = {
430 "mount_point": mount
431 }
432
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200433 # TODO validation
434 json_res = json.loads(maas.post(u"api/2.0/nodes/{0}/blockdevices/{1}/partition/{2}".format(
435 system_id, device_id, str(partition['id'])), "mount", **data).read())
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100436 LOG.info(json_res)
437 result["mount"] = "Mount point {0} created".format(mount)
438
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100439 return result
440
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200441
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100442def delete_partition(hostname, disk, partition_name):
azvyagintsevbca1f462018-05-25 19:06:46 +0300443 """
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100444 Delete partition on device.
445
446 CLI Example:
447
448 .. code-block:: bash
449
450 salt 'maas-node' maasng.delete_partition server_hostname disk_name partition_name
451 salt-call maasng.delete_partition server_hostname disk_name partition_name
452
453 root_size = size in GB
azvyagintsevbca1f462018-05-25 19:06:46 +0300454 """
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100455 result = {}
456 data = {}
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200457 maas = _create_maas_client()
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100458 system_id = get_machine(hostname)["system_id"]
459 LOG.info(system_id)
460
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200461 device_id = _get_blockdevice_id_by_name(hostname, disk)
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100462 LOG.info(device_id)
463
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200464 partition_id = _get_partition_id_by_name(hostname, disk, partition_name)
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100465
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200466 maas.delete(u"api/2.0/nodes/{0}/blockdevices/{1}/partition/{2}".format(
467 system_id, device_id, partition_id)).read()
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100468 result["new"] = "Partition {0} deleted".format(partition_name)
469 return result
470
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200471
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100472def delete_partition_by_id(hostname, disk, partition_id):
azvyagintsevbca1f462018-05-25 19:06:46 +0300473 """
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100474 Delete partition on device. Partition spefified by id of parition
475
476 CLI Example:
477
478 .. code-block:: bash
479
480 salt 'maas-node' maasng.delete_partition_by_id server_hostname disk_name partition_id
481 salt-call maasng.delete_partition_by_id server_hostname disk_name partition_id
482
483 root_size = size in GB
azvyagintsevbca1f462018-05-25 19:06:46 +0300484 """
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100485 result = {}
486 data = {}
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200487 maas = _create_maas_client()
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100488 system_id = get_machine(hostname)["system_id"]
489 LOG.info(system_id)
490
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200491 device_id = _get_blockdevice_id_by_name(hostname, disk)
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100492 LOG.info(device_id)
493
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200494 maas.delete(u"api/2.0/nodes/{0}/blockdevices/{1}/partition/{2}".format(
495 system_id, device_id, partition_id)).read()
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100496 result["new"] = "Partition {0} deleted".format(partition_id)
497 return result
azvyagintsevbca1f462018-05-25 19:06:46 +0300498# END PARTITIONS
499# DISK LAYOUT
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100500
azvyagintsevbca1f462018-05-25 19:06:46 +0300501
Pavel Cizinsky8dd85b52018-06-18 21:40:13 +0200502def drop_storage_schema(hostname, disk=None):
azvyagintsevbca1f462018-05-25 19:06:46 +0300503 """
504 #1. Drop lv
505 #2. Drop vg
506 #3. Drop md # need to zero-block?
507 #3. Drop part
508 """
509
510 if __opts__['test']:
511 ret['result'] = None
Pavel Cizinsky8dd85b52018-06-18 21:40:13 +0200512 ret['comment'] = 'Storage schema on {0} will be removed'.format(
513 hostname)
azvyagintsevbca1f462018-05-25 19:06:46 +0300514 return ret
Pavel Cizinsky8dd85b52018-06-18 21:40:13 +0200515 # TODO validation if exists
azvyagintsevbca1f462018-05-25 19:06:46 +0300516 vgs = list_volume_groups(hostname)
517 for vg in vgs:
518 delete_volume_group(hostname, vg)
519
520 raids = list_raids(hostname)
521 for raid in raids:
522 delete_raid(hostname, raid)
523
524 blocks = list_blockdevices(hostname)
525 for block_d in blocks:
526 partitions = __salt__['maasng.list_partitions'](hostname, block_d)
527 for partition_name, partition in partitions.iteritems():
528 LOG.info('delete partition:\n{}'.format(partition))
Pavel Cizinsky8dd85b52018-06-18 21:40:13 +0200529 __salt__['maasng.delete_partition_by_id'](
530 hostname, block_d, partition["id"])
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200531
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100532
533def update_disk_layout(hostname, layout, root_size=None, root_device=None, volume_group=None, volume_name=None, volume_size=None):
azvyagintsevbca1f462018-05-25 19:06:46 +0300534 """
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100535 Update disk layout. Flat or LVM layout supported.
536
537 CLI Example:
538
539 .. code-block:: bash
540
541 salt 'maas-node' maasng.update_disk_layout server_hostname lvm root_size=None, root_device=None, volume_group=None, volume_name=None, volume_size=None
542 salt-call maasng.update_disk_layout server_hostname lvm root_size=None, root_device=None, volume_group=None, volume_name=None, volume_size=None
543
544 root_size = size in GB
azvyagintsevbca1f462018-05-25 19:06:46 +0300545 """
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100546 result = {}
547 data = {
548 "storage_layout": layout,
549 }
550
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200551 maas = _create_maas_client()
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100552 system_id = get_machine(hostname)["system_id"]
553 LOG.info(system_id)
554
azvyagintsevbca1f462018-05-25 19:06:46 +0300555 if layout == 'custom':
556 drop_storage_schema(hostname)
557 result["new"] = {
558 "storage_layout": layout,
559 }
560
561 return result
562
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100563 if root_size != None:
564 bit_size = str(root_size * 1073741824)
565 LOG.info(bit_size)
566 data["root_size"] = bit_size
567
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100568 if root_device != None:
569 LOG.info(root_device)
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200570 data["root_device"] = str(
571 _get_blockdevice_id_by_name(hostname, root_device))
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100572
573 if layout == 'lvm':
574 if volume_group != None:
575 LOG.info(volume_group)
576 data["vg_name"] = volume_group
577 if volume_name != None:
578 LOG.info(volume_name)
579 data["lv_name"] = volume_name
580 if volume_size != None:
581 vol_size = str(volume_size * 1073741824)
582 LOG.info(vol_size)
583 data["lv_size"] = vol_size
584
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200585 # TODO validation
586 json_res = json.loads(maas.post(
587 u"api/2.0/machines/{0}/".format(system_id), "set_storage_layout", **data).read())
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100588 LOG.info(json_res)
589 result["new"] = {
590 "storage_layout": layout,
591 }
592
593 return result
594
azvyagintsevbca1f462018-05-25 19:06:46 +0300595# END DISK LAYOUT
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200596# LVM
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100597
Pavel Cizinsky8dd85b52018-06-18 21:40:13 +0200598
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100599def list_volume_groups(hostname):
azvyagintsevbca1f462018-05-25 19:06:46 +0300600 """
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100601 Get list of all volume group on machine.
602
603 CLI Example:
604
605 .. code-block:: bash
606
607 salt 'maas-node' maasng.list_volume_groups server_hostname
608 salt-call maasng.list_volume_groups server_hostname
azvyagintsevbca1f462018-05-25 19:06:46 +0300609 """
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100610 volume_groups = {}
611
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200612 maas = _create_maas_client()
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100613 system_id = get_machine(hostname)["system_id"]
614 LOG.info(system_id)
615
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200616 # TODO validation if exists
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100617
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200618 json_res = json.loads(
619 maas.get(u"api/2.0/nodes/{0}/volume-groups/".format(system_id)).read())
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100620 LOG.info(json_res)
621 for item in json_res:
622 volume_groups[item["name"]] = item
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200623 # return
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100624 return volume_groups
625
626
627def get_volume_group(hostname, name):
azvyagintsevbca1f462018-05-25 19:06:46 +0300628 """
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100629 Get information about specific volume group on machine.
630
631 CLI Example:
632
633 .. code-block:: bash
634
635 salt 'maas-node' maasng.list_blockdevices server_hostname
636 salt-call maasng.list_blockdevices server_hostname
azvyagintsevbca1f462018-05-25 19:06:46 +0300637 """
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200638 # TODO validation that exists
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100639 return list_volume_groups(hostname)[name]
640
641
642def create_volume_group(hostname, volume_group_name, disks=[], partitions=[]):
azvyagintsevbca1f462018-05-25 19:06:46 +0300643 """
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100644 Create new volume group on machine. Disks or partitions needs to be provided.
645
646 CLI Example:
647
648 .. code-block:: bash
649
650 salt 'maas-node' maasng.create_volume_group volume_group_name, disks=[sda,sdb], partitions=[]
651 salt-call maasng.create_volume_group server_hostname
azvyagintsevbca1f462018-05-25 19:06:46 +0300652 """
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100653 result = {}
654
655 data = {
656 "name": volume_group_name,
657 }
658
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200659 maas = _create_maas_client()
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100660 system_id = get_machine(hostname)["system_id"]
661 LOG.info(system_id)
662
663 disk_ids = []
664 partition_ids = []
665
666 for disk in disks:
667 p_disk = get_blockdevice(hostname, disk)
668 if p_disk["partition_table_type"] == None:
669 disk_ids.append(str(p_disk["id"]))
670 else:
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200671 result["error"] = "Device {0} on machine {1} cointains partition table".format(
672 disk, hostname)
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100673 return result
674
675 for partition in partitions:
676 try:
677 device = partition.split("-")[0]
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200678 device_part = list_partitions(hostname, device)
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100679 partition_ids.append(str(device_part[partition]["id"]))
680 except KeyError:
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200681 result["error"] = "Partition {0} does not exists on machine {1}".format(
682 partition, hostname)
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100683 return result
684
685 data["block_devices"] = disk_ids
686 data["partitions"] = partition_ids
687 LOG.info(partition_ids)
688 LOG.info(partitions)
689
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200690 # TODO validation
691 json_res = json.loads(maas.post(
692 u"api/2.0/nodes/{0}/volume-groups/".format(system_id), None, **data).read())
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100693 LOG.info(json_res)
694 result["new"] = "Volume group {0} created".format(json_res["name"])
695
696 return result
697
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200698
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100699def delete_volume_group(hostname, name):
azvyagintsevbca1f462018-05-25 19:06:46 +0300700 """
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100701 Delete volume group on machine.
702
703 CLI Example:
704
705 .. code-block:: bash
706
707 salt 'maas-node' maasng.delete_volume_group server_hostname vg0
708 salt-call maasng.delete_volume_group server_hostname vg0
azvyagintsevbca1f462018-05-25 19:06:46 +0300709 """
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100710
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200711 maas = _create_maas_client()
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100712 system_id = get_machine(hostname)["system_id"]
azvyagintsevbca1f462018-05-25 19:06:46 +0300713 LOG.debug('delete_volume_group:{}'.format(system_id))
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100714
azvyagintsevbca1f462018-05-25 19:06:46 +0300715 vg_id = str(_get_volume_group_id_by_name(hostname, name))
716 for vol in get_volumes(hostname, name):
Pavel Cizinsky8dd85b52018-06-18 21:40:13 +0200717 delete_volume(hostname, vol, name)
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100718
Pavel Cizinsky8dd85b52018-06-18 21:40:13 +0200719 # TODO validation
720 json_res = json.loads(maas.delete(
721 u"api/2.0/nodes/{0}/volume-group/{1}/".format(system_id, vg_id)).read() or 'null')
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100722 LOG.info(json_res)
723
724 return True
725
726
727def create_volume(hostname, volume_name, volume_group, size, fs_type=None, mount=None):
azvyagintsevbca1f462018-05-25 19:06:46 +0300728 """
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100729 Create volume on volume group.
730
731 CLI Example:
732
733 .. code-block:: bash
734
735 salt 'maas-node' maasng.create_volume server_hostname volume_name, volume_group, size, fs_type=None, mount=None
736 salt-call maasng.create_volume server_hostname volume_name, volume_group, size, fs_type=None, mount=None
azvyagintsevbca1f462018-05-25 19:06:46 +0300737 """
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100738
739 data = {
740 "name": volume_name,
741 }
742
743 value, unit = size[:-1], size[-1]
744 bit_size = str(int(value) * SIZE[unit])
745 LOG.info(bit_size)
746
747 data["size"] = bit_size
748
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200749 maas = _create_maas_client()
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100750 system_id = get_machine(hostname)["system_id"]
751 LOG.info(system_id)
752
753 volume_group_id = str(_get_volume_group_id_by_name(hostname, volume_group))
754
755 LOG.info(volume_group_id)
756
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200757 # TODO validation
758 json_res = json.loads(maas.post(u"api/2.0/nodes/{0}/volume-group/{1}/".format(
759 system_id, volume_group_id), "create_logical_volume", **data).read())
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100760 LOG.info(json_res)
761
762 if fs_type != None or mount != None:
Pavel Cizinsky8dd85b52018-06-18 21:40:13 +0200763 ret = create_volume_filesystem(
764 hostname, volume_group + "-" + volume_name, fs_type, mount)
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100765
766 return True
767
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100768
azvyagintsevbca1f462018-05-25 19:06:46 +0300769def delete_volume(hostname, volume_name, volume_group):
770 """
771 Delete volume from volume group.
772 Tips: maas always use 'volume_group-volume_name' name schema.Example: 'vg0-glusterfs'
773 This function expexts same format.
774
775 CLI Example:
776
777 .. code-block:: bash
778
779 salt 'maas-node' maasng.delete_volume server_hostname volume_name volume_group
780 salt 'maas-node' maasng.delete_volume server_hostname vg0-vol0 vg0
781 salt-call maasng.delete_volume server_hostname volume_name volume_group
782 """
783
Pavel Cizinsky8dd85b52018-06-18 21:40:13 +0200784 maas = _create_maas_client()
azvyagintsevbca1f462018-05-25 19:06:46 +0300785 system_id = get_machine(hostname)["system_id"]
786 LOG.debug('delete_volume:{}'.format(system_id))
787
788 volume_group_id = str(_get_volume_group_id_by_name(hostname, volume_group))
Pavel Cizinsky8dd85b52018-06-18 21:40:13 +0200789 volume_id = str(_get_volume_id_by_name(
790 hostname, volume_name, volume_group))
azvyagintsevbca1f462018-05-25 19:06:46 +0300791
792 if None in [volume_group_id, volume_id]:
793 return False
794
795 data = {
796 "id": volume_id,
797 }
798
Pavel Cizinsky8dd85b52018-06-18 21:40:13 +0200799 # TODO validation
800 json_res = json.loads(maas.post(u"api/2.0/nodes/{0}/volume-group/{1}/".format(
801 system_id, volume_group_id), "delete_logical_volume", **data).read() or 'null')
azvyagintsevbca1f462018-05-25 19:06:46 +0300802 return True
803
804
805def get_volumes(hostname, vg_name):
806 """
807 Get list of volumes in volume group.
808 """
809 volumes = {}
Pavel Cizinsky8dd85b52018-06-18 21:40:13 +0200810 _volumes = list_volume_groups(
811 hostname)[vg_name].get('logical_volumes', False)
azvyagintsevbca1f462018-05-25 19:06:46 +0300812 if _volumes:
813 for item in _volumes:
814 volumes[item["name"]] = item
815 return volumes
816
817# END LVM
818
819
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200820def create_volume_filesystem(hostname, device, fs_type=None, mount=None):
821
822 maas = _create_maas_client()
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100823 system_id = get_machine(hostname)["system_id"]
824
825 blockdevices_id = _get_blockdevice_id_by_name(hostname, device)
826 data = {}
827 if fs_type != None:
828 data["fstype"] = fs_type
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200829 # TODO validation
830 json_res = json.loads(maas.post(u"/api/2.0/nodes/{0}/blockdevices/{1}/".format(
831 system_id, blockdevices_id), "format", **data).read())
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100832 LOG.info(json_res)
833
834 if mount != None:
835 data["mount_point"] = mount
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200836 # TODO validation
837 json_res = json.loads(maas.post(u"/api/2.0/nodes/{0}/blockdevices/{1}/".format(
838 system_id, blockdevices_id), "mount", **data).read())
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100839 LOG.info(json_res)
840
841 return True
842
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100843
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100844def set_boot_disk(hostname, name):
azvyagintsevbca1f462018-05-25 19:06:46 +0300845 """
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100846 Create volume on volume group.
847
848 CLI Example:
849
850 .. code-block:: bash
851
852 salt 'maas-node' maasng.set_boot_disk server_hostname disk_name
853 salt-call maasng.set_boot_disk server_hostname disk_name
azvyagintsevbca1f462018-05-25 19:06:46 +0300854 """
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100855 data = {}
856 result = {}
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200857 maas = _create_maas_client()
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100858 system_id = get_machine(hostname)["system_id"]
859 blockdevices_id = _get_blockdevice_id_by_name(hostname, name)
860
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200861 maas.post(u"/api/2.0/nodes/{0}/blockdevices/{1}/".format(
862 system_id, blockdevices_id), "set_boot_disk", **data).read()
863 # TODO validation for error response (disk does not exists and node does not exists)
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100864 result["new"] = "Disk {0} was set as bootable".format(name)
865
866 return result
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200867
azvyagintsevbca1f462018-05-25 19:06:46 +0300868# NETWORKING
869
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200870
871def list_fabric():
azvyagintsevbca1f462018-05-25 19:06:46 +0300872 """
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200873 Get list of all fabric
874
875 CLI Example:
876
877 .. code-block:: bash
878
879 salt 'maas-node' maasng.list_fabric
azvyagintsevbca1f462018-05-25 19:06:46 +0300880 """
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200881 fabrics = {}
882 maas = _create_maas_client()
883 json_res = json.loads(maas.get(u'api/2.0/fabrics/').read())
884 LOG.info(json_res)
885 for item in json_res:
886 fabrics[item["name"]] = item
887 return fabrics
888
889
890def create_fabric(name):
azvyagintsevbca1f462018-05-25 19:06:46 +0300891 """
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200892 Create new fabric.
893
894 CLI Example:
895
896 .. code-block:: bash
897
898 salt 'maas-node' maasng.create_fabric
azvyagintsevbca1f462018-05-25 19:06:46 +0300899 """
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200900 result = {}
901 data = {
902 "name": name,
903 "description": '',
904 "class_type": '',
905
906 }
907
908 maas = _create_maas_client()
909 json_res = json.loads(maas.post(u"api/2.0/fabrics/", None, **data).read())
Pavel Cizinsky8dd85b52018-06-18 21:40:13 +0200910 LOG.debug("crete_fabric:{}".format(json_res))
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200911 result["new"] = "Fabrics {0} created".format(json_res["name"])
912 return result
913
914
915def list_subnet():
azvyagintsevbca1f462018-05-25 19:06:46 +0300916 """
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200917 Get list of all subnets
918
919 CLI Example:
920
921 .. code-block:: bash
922
923 salt 'maas-node' maasng.list_subnet
azvyagintsevbca1f462018-05-25 19:06:46 +0300924 """
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200925 subnets = {}
926 maas = _create_maas_client()
927 json_res = json.loads(maas.get(u'api/2.0/subnets/').read())
928 LOG.info(json_res)
929 for item in json_res:
930 subnets[item["name"]] = item
931 return subnets
932
933
934def list_vlans(fabric):
azvyagintsevbca1f462018-05-25 19:06:46 +0300935 """
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200936 Get list of all vlans for specific fabric
937
938 CLI Example:
939
940 .. code-block:: bash
941
942 salt 'maas-node' maasng.list_vlans
azvyagintsevbca1f462018-05-25 19:06:46 +0300943 """
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200944 vlans = {}
945 maas = _create_maas_client()
Pavel Cizinsky8dd85b52018-06-18 21:40:13 +0200946 fabric_id = get_fabricid(fabric)
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200947
948 json_res = json.loads(
949 maas.get(u'api/2.0/fabrics/{0}/vlans/'.format(fabric_id)).read())
950 LOG.info(json_res)
951 for item in json_res:
952 vlans[item["name"]] = item
953 return vlans
954
955
Pavel Cizinsky8dd85b52018-06-18 21:40:13 +0200956def get_fabricid(fabric):
azvyagintsevbca1f462018-05-25 19:06:46 +0300957 """
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200958 Get id for specific fabric
959
960 CLI Example:
961
962 .. code-block:: bash
963
Pavel Cizinsky8dd85b52018-06-18 21:40:13 +0200964 salt 'maas-node' maasng.get_fabricid fabric_name
azvyagintsevbca1f462018-05-25 19:06:46 +0300965 """
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200966 try:
967 return list_fabric()[fabric]['id']
968 except KeyError:
969 return {"error": "Frabic not found on MaaS server"}
970
971
Pavel Cizinsky864a3292018-05-25 16:24:48 +0200972def update_vlan(name, fabric, vid, description, primary_rack, dhcp_on=False):
azvyagintsevbca1f462018-05-25 19:06:46 +0300973 """
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200974 Update vlan
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200975 CLI Example:
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200976 .. code-block:: bash
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200977 salt 'maas-node' maasng.update_vlan name, fabric, vid, description, dhcp_on
azvyagintsevbca1f462018-05-25 19:06:46 +0300978 """
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200979 result = {}
980
981 data = {
982 "name": name,
983 "dhcp_on": str(dhcp_on),
984 "description": description,
Pavel Cizinsky864a3292018-05-25 16:24:48 +0200985 "primary_rack": primary_rack,
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200986 }
987 maas = _create_maas_client()
Pavel Cizinsky8dd85b52018-06-18 21:40:13 +0200988 fabric_id = get_fabricid(fabric)
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200989
990 json_res = json.loads(maas.put(
991 u'api/2.0/fabrics/{0}/vlans/{1}/'.format(fabric_id, vid), **data).read())
azvyagintsev3ff2ef12018-06-01 21:30:45 +0300992 LOG.debug("update_vlan:{}".format(json_res))
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200993 result["new"] = "Vlan {0} was updated".format(json_res["name"])
994
995 return result
azvyagintsevbca1f462018-05-25 19:06:46 +0300996
Pavel Cizinsky8dd85b52018-06-18 21:40:13 +0200997
998def list_subnets():
999 """
1000 Get list of subnet from maas server
1001
1002 CLI Example:
1003
1004 .. code-block:: bash
1005
1006 salt 'maas-node' maasng.list_subnet
1007 """
1008 subnets = {}
1009 maas = _create_maas_client()
1010 json_res = json.loads(maas.get(u'api/2.0/subnets/').read())
1011 for item in json_res:
1012 subnets[item["name"]] = item
1013 return subnets
1014
1015
1016def create_subnet(cidr, name, fabric, gateway_ip):
1017 """
1018 Create subnet
1019
1020 CLI Example:
1021
1022 .. code-block:: bash
1023
1024 salt 'maas-node' maasng.create_subnet cidr, name, fabric, gateway_ip
1025 """
1026
1027 fabric_id = get_fabricid(fabric)
1028 result = {}
1029
1030 data = {
1031 "cidr": cidr,
1032 "name": name,
1033 "fabric": str(fabric_id),
1034 "gateway_ip": gateway_ip,
1035 }
1036 maas = _create_maas_client()
1037
1038 json_res = json.loads(maas.post(u"api/2.0/subnets/", None, **data).read())
1039 LOG.debug("create_subnet:{}".format(json_res))
1040 result["new"] = "Subnet {0} with CIDR {1} and gateway {2} was created".format(
1041 name, cidr, gateway_ip)
1042
1043 return result
1044
1045
1046def get_subnet(subnet):
1047 """
1048 Get details for specific subnet
1049
1050 CLI Example:
1051
1052 .. code-block:: bash
1053
1054 salt 'maas-node' maasng.get_subnet subnet_name
1055 """
1056 try:
1057 return list_subnet()[subnet]
1058 except KeyError:
1059 return {"error": "Subnet not found on MaaS server"}
1060
1061
1062def get_subnetid(subnet):
1063 """
1064 Get id for specific subnet
1065
1066 CLI Example:
1067
1068 .. code-block:: bash
1069
1070 salt 'maas-node' maasng.get_subnetid subnet_name
1071 """
1072 try:
1073 return list_subnet()[subnet]['id']
1074 except KeyError:
1075 return {"error": "Subnet not found on MaaS server"}
1076
1077
1078def list_ipranges():
1079 """
1080 Get list of all ipranges from maas server
1081
1082 CLI Example:
1083
1084 .. code-block:: bash
1085
1086 salt 'maas-node' maasng.list_ipranges
1087 """
1088 ipranges = {}
1089 maas = _create_maas_client()
1090 json_res = json.loads(maas.get(u'api/2.0/ipranges/').read())
1091 for item in json_res:
1092 ipranges[item["start_ip"]] = item
1093 return ipranges
1094
1095
1096def create_iprange(type_range, start_ip, end_ip, comment):
1097 """
1098 Create ip range
1099
1100 CLI Example:
1101
1102 .. code-block:: bash
1103
1104 salt 'maas-node' maasng.create_iprange type, start ip, end ip, comment
1105 """
1106 result = {}
1107
1108 data = {
1109 "type": type_range,
1110 "start_ip": start_ip,
1111 "end_ip": end_ip,
1112 "comment": comment,
1113 }
1114 maas = _create_maas_client()
1115
1116 json_res = json.loads(maas.post(u"api/2.0/ipranges/", None, **data).read())
1117
1118 LOG.debug("create_iprange:{}".format(json_res))
1119 result["new"] = "Iprange with type {0}, start ip {1}, end ip {2}, was created".format(
1120 type_range, start_ip, end_ip)
1121
1122 return result
1123
1124
1125def get_iprangeid(start_ip):
1126 """
1127 Get id for ip range from maas server
1128
1129 CLI Example:
1130
1131 .. code-block:: bash
1132
1133 salt 'maas-node' maasng.get_iprangeid start_ip
1134 """
1135 try:
1136 return list_ipranges()[start_ip]['id']
1137 except KeyError:
1138 return {"error": "Ip range not found on MaaS server"}
1139
1140
1141def get_startip(start_ip):
1142 """
1143 Get start ip for ip range
1144
1145 CLI Example:
1146
1147 .. code-block:: bash
1148
1149 salt 'maas-node' maasng.get_startip start ip
1150 """
1151 try:
1152 return list_ipranges()[start_ip]
1153 except KeyError:
1154 return {"error": "Ip range not found on MaaS server"}
azvyagintsevbca1f462018-05-25 19:06:46 +03001155# END NETWORKING
azvyagintsev3ff2ef12018-06-01 21:30:45 +03001156
1157# MAAS CONFIG SECTION
1158
1159
1160def _get_boot_source_id_by_url(url):
1161 # FIXME: fix ret\validation
1162 try:
1163 bs_id = get_boot_source(url=url)["id"]
1164 except KeyError:
1165 return {"error": "boot-source:{0} not exist!".format(url)}
1166 return bs_id
1167
1168
1169def get_boot_source(url=None):
1170 """
1171 Read a boot source by url. If url not specified - return all.
1172
1173 CLI Example:
1174
1175 .. code-block:: bash
1176
1177 salt 'maas-node' maasng.get_boot_source url
1178
1179 """
1180 boot_sources = {}
1181 maas = _create_maas_client()
1182 json_res = json.loads(maas.get(u'api/2.0/boot-sources/').read() or 'null')
1183 for item in json_res:
1184 boot_sources[str(item["url"])] = item
1185 if url:
1186 return boot_sources.get(url, {})
1187 return boot_sources
1188
1189
1190def delete_boot_source(url, bs_id=None):
1191 """
1192 Delete a boot source by url.
1193
1194 CLI Example:
1195
1196 .. code-block:: bash
1197
1198 sal 'maas-node' maasng.delete url
1199
1200 """
1201 result = {}
1202 if not bs_id:
1203 bs_id = _get_boot_source_id_by_url(url)
1204 maas = _create_maas_client()
1205 json_res = json.loads(maas.delete(
1206 u'/api/2.0/boot-sources/{0}/'.format(bs_id)).read() or 'null')
1207 LOG.debug("delete_boot_source:{}".format(json_res))
1208 result["new"] = "Boot-resource {0} deleted".format(url)
1209 return result
1210
1211
1212def boot_sources_delete_all_others(except_urls=[]):
1213 """
1214 Delete all boot-sources, except defined in 'except_urls' list.
1215 """
1216 result = {}
1217 maas_boot_sources = get_boot_source()
1218 if 0 in [len(except_urls), len(maas_boot_sources)]:
1219 result['result'] = None
1220 result[
1221 "comment"] = "Exclude or maas sources for delete empty. No changes goinng to be."
1222 return result
1223 for url in maas_boot_sources.keys():
1224 if url not in except_urls:
1225 LOG.info("Removing boot-source:{}".format(url))
1226 boot_resources_import(action='stop_import', wait=True)
1227 result["changes"] = delete_boot_source(url)
1228 return result
1229
1230
1231def create_boot_source(url, keyring_filename='', keyring_data='', wait=False):
1232 """
1233 Create and import maas boot-source: link to maas-ephemeral repo
1234 Be aware, those step will import resource to rack ctrl, but you also need to import
1235 them into the region!
1236
1237
1238 :param url: The URL of the BootSource.
1239 :param keyring_filename: The path to the keyring file for this BootSource.
1240 :param keyring_data: The GPG keyring for this BootSource, base64-encoded data.
1241
1242 """
1243
1244 # TODO: not work with 'update' currently => keyring update may fail.
1245 result = {}
1246
1247 data = {
1248 "url": url,
1249 "keyring_filename": keyring_filename,
1250 "keyring_data": str(keyring_data),
1251 }
1252
1253 maas = _create_maas_client()
azvyagintsev3ff2ef12018-06-01 21:30:45 +03001254 if url in get_boot_source():
1255 result['result'] = None
1256 result["comment"] = "boot resource already exist"
1257 return result
1258
1259 # NOTE: maas.post will return 400, if url already defined.
1260 json_res = json.loads(
1261 maas.post(u'api/2.0/boot-sources/', None, **data).read())
1262 if wait:
1263 LOG.debug(
1264 "Sleep for 5s,to get MaaS some time to process previous request")
1265 time.sleep(5)
1266 ret = boot_resources_is_importing(wait=True)
1267 if ret is dict:
1268 return ret
1269 LOG.debug("create_boot_source:{}".format(json_res))
1270 result["new"] = "boot resource {0} was created".format(json_res["url"])
1271
1272 return result
1273
1274
1275def boot_resources_import(action='import', wait=False):
1276 """
1277 import/stop_import the boot resources.
1278
1279 :param action: import\stop_import
1280 :param wait: True\False. Wait till process finished.
1281
1282 CLI Example:
1283
1284 .. code-block:: bash
1285
1286 salt 'maas-node' maasng.boot_resources_import action='import'
1287
1288 """
1289 maas = _create_maas_client()
1290 # Have no idea why, but usual jsonloads not work here..
1291 imp = maas.post(u'api/2.0/boot-resources/', action)
1292 if imp.code == 200:
1293 LOG.debug('boot_resources_import:{}'.format(imp.readline()))
1294 if wait:
1295 boot_resources_is_importing(wait=True)
1296 return True
1297 else:
1298 return False
1299
1300
1301def boot_resources_is_importing(wait=False):
1302 maas = _create_maas_client()
1303 result = {}
1304 if wait:
1305 started_at = time.time()
1306 poll_time = 5
1307 timeout = 60 * 15
1308 while boot_resources_is_importing(wait=False):
1309 c_timeout = timeout - (time.time() - started_at)
1310 if c_timeout <= 0:
1311 result['result'] = False
1312 result["comment"] = "Boot-resources import not finished in time"
1313 return result
1314 LOG.info(
1315 "Waiting boot-resources import done\n"
1316 "sleep for:{}s "
1317 "Left:{}/{}s".format(poll_time, round(c_timeout), timeout))
1318 time.sleep(poll_time)
1319 return json.loads(
1320 maas.get(u'api/2.0/boot-resources/', 'is_importing').read())
1321 else:
1322 return json.loads(
1323 maas.get(u'api/2.0/boot-resources/', 'is_importing').read())
1324
1325#####
Pavel Cizinsky8dd85b52018-06-18 21:40:13 +02001326# def boot_sources_selections_delete_all_others(except_urls=[]):
azvyagintsev3ff2ef12018-06-01 21:30:45 +03001327# """
1328# """
1329# result = {}
1330# return result
1331
1332
1333def is_boot_source_selections_in(dict1, list1):
1334 """
1335 Check that requested boot-selection already in maas bs selections, if True- return bss id.
1336 # FIXME: those hack check doesn't look good.
1337 """
1338 for bs in list1:
1339 same = set(dict1.keys()) & set(bs.keys())
1340 if all(elem in same for elem in
1341 ['os', 'release', 'arches', 'subarches', 'labels']):
1342 LOG.debug(
1343 "boot-selection in maas:{0}\nlooks same to requested:{1}".format(
1344 bs, dict1))
1345 return bs['id']
1346 return False
1347
1348
1349def get_boot_source_selections(bs_url):
1350 """
1351 Get boot-source selections.
1352 """
1353 # check for key_error!
1354 bs_id = _get_boot_source_id_by_url(bs_url)
1355 maas = _create_maas_client()
1356 json_res = json.loads(
1357 maas.get(u'/api/2.0/boot-sources/{0}/selections/'.format(bs_id)).read())
1358 LOG.debug(
1359 "get_boot_source_selections for url:{} \n{}".format(bs_url, json_res))
1360 return json_res
1361
1362
1363def create_boot_source_selections(bs_url, os, release, arches="*",
1364 subarches="*", labels="*", wait=True):
1365 """
1366 Create a new boot source selection for bs_url.
1367 :param os: The OS (e.g. ubuntu, centos) for which to import resources.Required.
1368 :param release: The release for which to import resources. Required.
1369 :param arches: The architecture list for which to import resources.
1370 :param subarches: The subarchitecture list for which to import resources.
1371 :param labels: The label lists for which to import resources.
1372 """
1373
1374 result = {}
1375
1376 data = {
1377 "os": os,
1378 "release": release,
1379 "arches": arches,
1380 "subarches": subarches,
1381 "labels": labels,
1382 }
1383
1384 maas = _create_maas_client()
1385 bs_id = _get_boot_source_id_by_url(bs_url)
1386 # TODO add pre-create verify
1387 maas_bs_s = get_boot_source_selections(bs_url)
1388 if is_boot_source_selections_in(data, maas_bs_s):
1389 result["result"] = True
1390 result[
1391 "comment"] = 'Requested boot-source selection for {0} already exist.'.format(
1392 bs_url)
1393 return result
1394
1395 # NOTE: maas.post will return 400, if url already defined.
1396 json_res = json.loads(
1397 maas.post(u'api/2.0/boot-sources/{0}/selections/'.format(bs_id), None,
1398 **data).read())
1399 LOG.debug("create_boot_source_selections:{}".format(json_res))
1400 if wait:
1401 LOG.debug(
1402 "Sleep for 5s,to get MaaS some time to process previous request")
1403 time.sleep(5)
1404 ret = boot_resources_import(action='import', wait=True)
1405 if ret is dict:
1406 return ret
1407 result["new"] = "boot-source selection for {0} was created".format(bs_url)
1408
1409 return result
1410
1411# END MAAS CONFIG SECTION