blob: 8e4d1f2b7da37ad79b215cb59a37ab923ce5220a [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
102 volume_name = str("%s-%s" % (volume_group,volume_name))
103 ##TODO validation
104 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"]
azvyagintsevbca1f462018-05-25 19:06:46 +0300236 #TODO validation
237 json_res = json.loads(maas.get(u"api/2.0/nodes/{0}/raids/".format(system_id)).read())
238 LOG.debug('list_raids:{} {}'.format(system_id, json_res))
239 for item in json_res:
240 raids[item["name"]] = item
241 return raids
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100242
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200243
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100244def get_raid(hostname, name):
azvyagintsevbca1f462018-05-25 19:06:46 +0300245 """
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100246 Get information about specific raid on machine
247
248 CLI Example:
249
250 .. code-block:: bash
251
252 salt-call maasng.get_raids server_hostname md0
azvyagintsevbca1f462018-05-25 19:06:46 +0300253 """
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100254
255 return list_raids(hostname)[name]
256
257
azvyagintsevbca1f462018-05-25 19:06:46 +0300258def _get_raid_id_by_name(hostname, raid_name):
259 return get_raid(hostname, raid_name)['id']
260
261
262def delete_raid(hostname, raid_name):
263 """
264 Delete RAID on a machine.
265
266 CLI Example:
267
268 .. code-block:: bash
269
270 salt 'maas-node' maasng.delete_raid server_hostname raid_name
271 salt-call maasng.delete_raid server_hostname raid_name
272 """
273 result = {}
274 maas=_create_maas_client()
275 system_id = get_machine(hostname)["system_id"]
276 raid_id = _get_raid_id_by_name(hostname, raid_name)
277 LOG.debug('delete_raid: {} {}'.format(system_id,raid_id))
278 maas.delete(u"api/2.0/nodes/{0}/raid/{1}/".format(system_id, raid_id)).read()
279
280 result["new"] = "Raid {0} deleted".format(raid_name)
281 return result
282
283# END RAID SECTION
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200284# BLOCKDEVICES SECTION
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100285
azvyagintsevbca1f462018-05-25 19:06:46 +0300286
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100287def list_blockdevices(hostname):
azvyagintsevbca1f462018-05-25 19:06:46 +0300288 """
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100289 Get list of all blockdevices (disks) on machine
290
291 CLI Example:
292
293 .. code-block:: bash
294
295 salt 'maas-node' maasng.list_blockdevices server_hostname
296 salt-call maasng.list_blockdevices server_hostname
azvyagintsevbca1f462018-05-25 19:06:46 +0300297 """
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100298 ret = {}
299
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200300 maas = _create_maas_client()
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100301 system_id = get_machine(hostname)["system_id"]
302 LOG.info(system_id)
303
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200304 # TODO validation if exists
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100305
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200306 json_res = json.loads(
307 maas.get(u"api/2.0/nodes/{0}/blockdevices/".format(system_id)).read())
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100308 LOG.info(json_res)
309 for item in json_res:
310 ret[item["name"]] = item
311
312 return ret
313
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200314
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100315def get_blockdevice(hostname, name):
azvyagintsevbca1f462018-05-25 19:06:46 +0300316 """
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100317 Get information about blockdevice (disk) on machine
318
319 CLI Example:
320
321 .. code-block:: bash
322
323 salt 'maas-node' maasng.get_blockdevice server_hostname sda
324 salt-call maasng.get_blockdevice server_hostname sda
azvyagintsevbca1f462018-05-25 19:06:46 +0300325 """
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100326
327 return list_blockdevices(hostname)[name]
328
azvyagintsevbca1f462018-05-25 19:06:46 +0300329# END BLOCKDEVICES SECTION
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200330# PARTITIONS
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100331
azvyagintsevbca1f462018-05-25 19:06:46 +0300332
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100333def list_partitions(hostname, device):
azvyagintsevbca1f462018-05-25 19:06:46 +0300334 """
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100335 Get list of all partitions on specific device located on specific machine
336
337 CLI Example:
338
339 .. code-block:: bash
340
341 salt 'maas-node' maasng.list_partitions server_hostname sda
342 salt-call maasng.list_partitions server_hostname sda
azvyagintsevbca1f462018-05-25 19:06:46 +0300343 """
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100344 ret = {}
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200345 maas = _create_maas_client()
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100346 system_id = get_machine(hostname)["system_id"]
347 LOG.info(system_id)
348
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200349 partitions = get_blockdevice(hostname, device)["partitions"]
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100350 LOG.info(partitions)
351
352 #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 +0200353 # LOG.info(json_res)
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100354
355 if len(device) > 0:
356 for item in partitions:
357 name = item["path"].split('/')[-1]
358 ret[name] = item
359
360 return ret
361
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200362
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100363def get_partition(hostname, device, partition):
azvyagintsevbca1f462018-05-25 19:06:46 +0300364 """
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100365 Get information about specific parition on device located on machine
366
367 CLI Example:
368
369 .. code-block:: bash
370
371 salt 'maas-node' maasng.get_partition server_hostname disk_name partition
372 salt-call maasng.get_partition server_hostname disk_name partition
373
374 root_size = size in GB
azvyagintsevbca1f462018-05-25 19:06:46 +0300375 """
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100376
377 return list_partitions(partition)[name]
378
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200379
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100380def create_partition(hostname, disk, size, fs_type=None, mount=None):
azvyagintsevbca1f462018-05-25 19:06:46 +0300381 """
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100382 Create new partition on device.
383
384 CLI Example:
385
386 .. code-block:: bash
387
388 salt 'maas-node' maasng.create_partition server_hostname disk_name 10 ext4 "/"
389 salt-call maasng.create_partition server_hostname disk_name 10 ext4 "/"
azvyagintsevbca1f462018-05-25 19:06:46 +0300390 """
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200391 # TODO validation
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100392 result = {}
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200393 maas = _create_maas_client()
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100394 system_id = get_machine(hostname)["system_id"]
395 LOG.info(system_id)
396
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200397 device_id = _get_blockdevice_id_by_name(hostname, disk)
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100398 LOG.info(device_id)
399
400 value, unit = size[:-1], size[-1]
401 calc_size = str(int(value) * SIZE[unit])
402 LOG.info(calc_size)
403
404 data = {
405 "size": calc_size
406 }
407
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200408 # TODO validation
409 partition = json.loads(maas.post(
410 u"api/2.0/nodes/{0}/blockdevices/{1}/partitions/".format(system_id, device_id), None, **data).read())
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100411 LOG.info(partition)
412 result["partition"] = "Partition created on {0}".format(disk)
413
414 if fs_type != None:
415 data_fs_type = {
416 "fstype": fs_type
417 }
418 partition_id = str(partition["id"])
419 LOG.info("Partition id: " + partition_id)
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200420 # TODO validation
421 json_res = json.loads(maas.post(u"api/2.0/nodes/{0}/blockdevices/{1}/partition/{2}".format(
422 system_id, device_id, partition_id), "format", **data_fs_type).read())
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100423 LOG.info(json_res)
424 result["filesystem"] = "Filesystem {0} created".format(fs_type)
425
426 if mount != None:
427 data = {
428 "mount_point": mount
429 }
430
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200431 # TODO validation
432 json_res = json.loads(maas.post(u"api/2.0/nodes/{0}/blockdevices/{1}/partition/{2}".format(
433 system_id, device_id, str(partition['id'])), "mount", **data).read())
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100434 LOG.info(json_res)
435 result["mount"] = "Mount point {0} created".format(mount)
436
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100437 return result
438
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200439
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100440def delete_partition(hostname, disk, partition_name):
azvyagintsevbca1f462018-05-25 19:06:46 +0300441 """
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100442 Delete partition on device.
443
444 CLI Example:
445
446 .. code-block:: bash
447
448 salt 'maas-node' maasng.delete_partition server_hostname disk_name partition_name
449 salt-call maasng.delete_partition server_hostname disk_name partition_name
450
451 root_size = size in GB
azvyagintsevbca1f462018-05-25 19:06:46 +0300452 """
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100453 result = {}
454 data = {}
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200455 maas = _create_maas_client()
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100456 system_id = get_machine(hostname)["system_id"]
457 LOG.info(system_id)
458
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200459 device_id = _get_blockdevice_id_by_name(hostname, disk)
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100460 LOG.info(device_id)
461
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200462 partition_id = _get_partition_id_by_name(hostname, disk, partition_name)
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100463
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200464 maas.delete(u"api/2.0/nodes/{0}/blockdevices/{1}/partition/{2}".format(
465 system_id, device_id, partition_id)).read()
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100466 result["new"] = "Partition {0} deleted".format(partition_name)
467 return result
468
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200469
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100470def delete_partition_by_id(hostname, disk, partition_id):
azvyagintsevbca1f462018-05-25 19:06:46 +0300471 """
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100472 Delete partition on device. Partition spefified by id of parition
473
474 CLI Example:
475
476 .. code-block:: bash
477
478 salt 'maas-node' maasng.delete_partition_by_id server_hostname disk_name partition_id
479 salt-call maasng.delete_partition_by_id server_hostname disk_name partition_id
480
481 root_size = size in GB
azvyagintsevbca1f462018-05-25 19:06:46 +0300482 """
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100483 result = {}
484 data = {}
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200485 maas = _create_maas_client()
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100486 system_id = get_machine(hostname)["system_id"]
487 LOG.info(system_id)
488
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200489 device_id = _get_blockdevice_id_by_name(hostname, disk)
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100490 LOG.info(device_id)
491
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200492 maas.delete(u"api/2.0/nodes/{0}/blockdevices/{1}/partition/{2}".format(
493 system_id, device_id, partition_id)).read()
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100494 result["new"] = "Partition {0} deleted".format(partition_id)
495 return result
azvyagintsevbca1f462018-05-25 19:06:46 +0300496# END PARTITIONS
497# DISK LAYOUT
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100498
azvyagintsevbca1f462018-05-25 19:06:46 +0300499
500def drop_storage_schema(hostname,disk=None):
501 """
502 #1. Drop lv
503 #2. Drop vg
504 #3. Drop md # need to zero-block?
505 #3. Drop part
506 """
507
508 if __opts__['test']:
509 ret['result'] = None
510 ret['comment'] = 'Storage schema on {0} will be removed'.format(hostname)
511 return ret
512 #TODO validation if exists
513 vgs = list_volume_groups(hostname)
514 for vg in vgs:
515 delete_volume_group(hostname, vg)
516
517 raids = list_raids(hostname)
518 for raid in raids:
519 delete_raid(hostname, raid)
520
521 blocks = list_blockdevices(hostname)
522 for block_d in blocks:
523 partitions = __salt__['maasng.list_partitions'](hostname, block_d)
524 for partition_name, partition in partitions.iteritems():
525 LOG.info('delete partition:\n{}'.format(partition))
526 __salt__['maasng.delete_partition_by_id'](hostname, block_d, partition["id"])
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200527
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100528
529def 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 +0300530 """
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100531 Update disk layout. Flat or LVM layout supported.
532
533 CLI Example:
534
535 .. code-block:: bash
536
537 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
538 salt-call maasng.update_disk_layout server_hostname lvm root_size=None, root_device=None, volume_group=None, volume_name=None, volume_size=None
539
540 root_size = size in GB
azvyagintsevbca1f462018-05-25 19:06:46 +0300541 """
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100542 result = {}
543 data = {
544 "storage_layout": layout,
545 }
546
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200547 maas = _create_maas_client()
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100548 system_id = get_machine(hostname)["system_id"]
549 LOG.info(system_id)
550
azvyagintsevbca1f462018-05-25 19:06:46 +0300551 if layout == 'custom':
552 drop_storage_schema(hostname)
553 result["new"] = {
554 "storage_layout": layout,
555 }
556
557 return result
558
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100559 if root_size != None:
560 bit_size = str(root_size * 1073741824)
561 LOG.info(bit_size)
562 data["root_size"] = bit_size
563
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100564 if root_device != None:
565 LOG.info(root_device)
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200566 data["root_device"] = str(
567 _get_blockdevice_id_by_name(hostname, root_device))
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100568
569 if layout == 'lvm':
570 if volume_group != None:
571 LOG.info(volume_group)
572 data["vg_name"] = volume_group
573 if volume_name != None:
574 LOG.info(volume_name)
575 data["lv_name"] = volume_name
576 if volume_size != None:
577 vol_size = str(volume_size * 1073741824)
578 LOG.info(vol_size)
579 data["lv_size"] = vol_size
580
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200581 # TODO validation
582 json_res = json.loads(maas.post(
583 u"api/2.0/machines/{0}/".format(system_id), "set_storage_layout", **data).read())
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100584 LOG.info(json_res)
585 result["new"] = {
586 "storage_layout": layout,
587 }
588
589 return result
590
azvyagintsevbca1f462018-05-25 19:06:46 +0300591# END DISK LAYOUT
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200592# LVM
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100593
594def list_volume_groups(hostname):
azvyagintsevbca1f462018-05-25 19:06:46 +0300595 """
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100596 Get list of all volume group on machine.
597
598 CLI Example:
599
600 .. code-block:: bash
601
602 salt 'maas-node' maasng.list_volume_groups server_hostname
603 salt-call maasng.list_volume_groups server_hostname
azvyagintsevbca1f462018-05-25 19:06:46 +0300604 """
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100605 volume_groups = {}
606
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200607 maas = _create_maas_client()
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100608 system_id = get_machine(hostname)["system_id"]
609 LOG.info(system_id)
610
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200611 # TODO validation if exists
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100612
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200613 json_res = json.loads(
614 maas.get(u"api/2.0/nodes/{0}/volume-groups/".format(system_id)).read())
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100615 LOG.info(json_res)
616 for item in json_res:
617 volume_groups[item["name"]] = item
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200618 # return
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100619 return volume_groups
620
621
622def get_volume_group(hostname, name):
azvyagintsevbca1f462018-05-25 19:06:46 +0300623 """
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100624 Get information about specific volume group on machine.
625
626 CLI Example:
627
628 .. code-block:: bash
629
630 salt 'maas-node' maasng.list_blockdevices server_hostname
631 salt-call maasng.list_blockdevices server_hostname
azvyagintsevbca1f462018-05-25 19:06:46 +0300632 """
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200633 # TODO validation that exists
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100634 return list_volume_groups(hostname)[name]
635
636
637def create_volume_group(hostname, volume_group_name, disks=[], partitions=[]):
azvyagintsevbca1f462018-05-25 19:06:46 +0300638 """
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100639 Create new volume group on machine. Disks or partitions needs to be provided.
640
641 CLI Example:
642
643 .. code-block:: bash
644
645 salt 'maas-node' maasng.create_volume_group volume_group_name, disks=[sda,sdb], partitions=[]
646 salt-call maasng.create_volume_group server_hostname
azvyagintsevbca1f462018-05-25 19:06:46 +0300647 """
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100648 result = {}
649
650 data = {
651 "name": volume_group_name,
652 }
653
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200654 maas = _create_maas_client()
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100655 system_id = get_machine(hostname)["system_id"]
656 LOG.info(system_id)
657
658 disk_ids = []
659 partition_ids = []
660
661 for disk in disks:
662 p_disk = get_blockdevice(hostname, disk)
663 if p_disk["partition_table_type"] == None:
664 disk_ids.append(str(p_disk["id"]))
665 else:
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200666 result["error"] = "Device {0} on machine {1} cointains partition table".format(
667 disk, hostname)
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100668 return result
669
670 for partition in partitions:
671 try:
672 device = partition.split("-")[0]
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200673 device_part = list_partitions(hostname, device)
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100674 partition_ids.append(str(device_part[partition]["id"]))
675 except KeyError:
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200676 result["error"] = "Partition {0} does not exists on machine {1}".format(
677 partition, hostname)
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100678 return result
679
680 data["block_devices"] = disk_ids
681 data["partitions"] = partition_ids
682 LOG.info(partition_ids)
683 LOG.info(partitions)
684
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200685 # TODO validation
686 json_res = json.loads(maas.post(
687 u"api/2.0/nodes/{0}/volume-groups/".format(system_id), None, **data).read())
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100688 LOG.info(json_res)
689 result["new"] = "Volume group {0} created".format(json_res["name"])
690
691 return result
692
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200693
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100694def delete_volume_group(hostname, name):
azvyagintsevbca1f462018-05-25 19:06:46 +0300695 """
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100696 Delete volume group on machine.
697
698 CLI Example:
699
700 .. code-block:: bash
701
702 salt 'maas-node' maasng.delete_volume_group server_hostname vg0
703 salt-call maasng.delete_volume_group server_hostname vg0
azvyagintsevbca1f462018-05-25 19:06:46 +0300704 """
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100705
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200706 maas = _create_maas_client()
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100707 system_id = get_machine(hostname)["system_id"]
azvyagintsevbca1f462018-05-25 19:06:46 +0300708 LOG.debug('delete_volume_group:{}'.format(system_id))
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100709
azvyagintsevbca1f462018-05-25 19:06:46 +0300710 vg_id = str(_get_volume_group_id_by_name(hostname, name))
711 for vol in get_volumes(hostname, name):
712 delete_volume(hostname,vol,name)
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100713
azvyagintsevbca1f462018-05-25 19:06:46 +0300714 #TODO validation
715 json_res = json.loads(maas.delete(u"api/2.0/nodes/{0}/volume-group/{1}/".format(system_id, vg_id)).read() or 'null')
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100716 LOG.info(json_res)
717
718 return True
719
720
721def create_volume(hostname, volume_name, volume_group, size, fs_type=None, mount=None):
azvyagintsevbca1f462018-05-25 19:06:46 +0300722 """
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100723 Create volume on volume group.
724
725 CLI Example:
726
727 .. code-block:: bash
728
729 salt 'maas-node' maasng.create_volume server_hostname volume_name, volume_group, size, fs_type=None, mount=None
730 salt-call maasng.create_volume server_hostname volume_name, volume_group, size, fs_type=None, mount=None
azvyagintsevbca1f462018-05-25 19:06:46 +0300731 """
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100732
733 data = {
734 "name": volume_name,
735 }
736
737 value, unit = size[:-1], size[-1]
738 bit_size = str(int(value) * SIZE[unit])
739 LOG.info(bit_size)
740
741 data["size"] = bit_size
742
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200743 maas = _create_maas_client()
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100744 system_id = get_machine(hostname)["system_id"]
745 LOG.info(system_id)
746
747 volume_group_id = str(_get_volume_group_id_by_name(hostname, volume_group))
748
749 LOG.info(volume_group_id)
750
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200751 # TODO validation
752 json_res = json.loads(maas.post(u"api/2.0/nodes/{0}/volume-group/{1}/".format(
753 system_id, volume_group_id), "create_logical_volume", **data).read())
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100754 LOG.info(json_res)
755
756 if fs_type != None or mount != None:
azvyagintsevbca1f462018-05-25 19:06:46 +0300757 ret = create_volume_filesystem(hostname, volume_group + "-" + volume_name, fs_type, mount)
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100758
759 return True
760
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100761
azvyagintsevbca1f462018-05-25 19:06:46 +0300762def delete_volume(hostname, volume_name, volume_group):
763 """
764 Delete volume from volume group.
765 Tips: maas always use 'volume_group-volume_name' name schema.Example: 'vg0-glusterfs'
766 This function expexts same format.
767
768 CLI Example:
769
770 .. code-block:: bash
771
772 salt 'maas-node' maasng.delete_volume server_hostname volume_name volume_group
773 salt 'maas-node' maasng.delete_volume server_hostname vg0-vol0 vg0
774 salt-call maasng.delete_volume server_hostname volume_name volume_group
775 """
776
777 maas=_create_maas_client()
778 system_id = get_machine(hostname)["system_id"]
779 LOG.debug('delete_volume:{}'.format(system_id))
780
781 volume_group_id = str(_get_volume_group_id_by_name(hostname, volume_group))
782 volume_id = str(_get_volume_id_by_name(hostname, volume_name, volume_group))
783
784 if None in [volume_group_id, volume_id]:
785 return False
786
787 data = {
788 "id": volume_id,
789 }
790
791 #TODO validation
792 json_res = json.loads(maas.post(u"api/2.0/nodes/{0}/volume-group/{1}/".format(system_id, volume_group_id), "delete_logical_volume", **data).read() or 'null')
793 return True
794
795
796def get_volumes(hostname, vg_name):
797 """
798 Get list of volumes in volume group.
799 """
800 volumes = {}
801 _volumes = list_volume_groups(hostname)[vg_name].get('logical_volumes', False)
802 if _volumes:
803 for item in _volumes:
804 volumes[item["name"]] = item
805 return volumes
806
807# END LVM
808
809
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200810def create_volume_filesystem(hostname, device, fs_type=None, mount=None):
811
812 maas = _create_maas_client()
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100813 system_id = get_machine(hostname)["system_id"]
814
815 blockdevices_id = _get_blockdevice_id_by_name(hostname, device)
816 data = {}
817 if fs_type != None:
818 data["fstype"] = fs_type
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200819 # TODO validation
820 json_res = json.loads(maas.post(u"/api/2.0/nodes/{0}/blockdevices/{1}/".format(
821 system_id, blockdevices_id), "format", **data).read())
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100822 LOG.info(json_res)
823
824 if mount != None:
825 data["mount_point"] = mount
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200826 # TODO validation
827 json_res = json.loads(maas.post(u"/api/2.0/nodes/{0}/blockdevices/{1}/".format(
828 system_id, blockdevices_id), "mount", **data).read())
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100829 LOG.info(json_res)
830
831 return True
832
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100833
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100834def set_boot_disk(hostname, name):
azvyagintsevbca1f462018-05-25 19:06:46 +0300835 """
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100836 Create volume on volume group.
837
838 CLI Example:
839
840 .. code-block:: bash
841
842 salt 'maas-node' maasng.set_boot_disk server_hostname disk_name
843 salt-call maasng.set_boot_disk server_hostname disk_name
azvyagintsevbca1f462018-05-25 19:06:46 +0300844 """
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100845 data = {}
846 result = {}
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200847 maas = _create_maas_client()
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100848 system_id = get_machine(hostname)["system_id"]
849 blockdevices_id = _get_blockdevice_id_by_name(hostname, name)
850
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200851 maas.post(u"/api/2.0/nodes/{0}/blockdevices/{1}/".format(
852 system_id, blockdevices_id), "set_boot_disk", **data).read()
853 # TODO validation for error response (disk does not exists and node does not exists)
Ondrej Smolab57a23b2018-01-24 11:18:24 +0100854 result["new"] = "Disk {0} was set as bootable".format(name)
855
856 return result
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200857
azvyagintsevbca1f462018-05-25 19:06:46 +0300858# NETWORKING
859
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200860
861def list_fabric():
azvyagintsevbca1f462018-05-25 19:06:46 +0300862 """
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200863 Get list of all fabric
864
865 CLI Example:
866
867 .. code-block:: bash
868
869 salt 'maas-node' maasng.list_fabric
azvyagintsevbca1f462018-05-25 19:06:46 +0300870 """
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200871 fabrics = {}
872 maas = _create_maas_client()
873 json_res = json.loads(maas.get(u'api/2.0/fabrics/').read())
874 LOG.info(json_res)
875 for item in json_res:
876 fabrics[item["name"]] = item
877 return fabrics
878
879
880def create_fabric(name):
azvyagintsevbca1f462018-05-25 19:06:46 +0300881 """
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200882 Create new fabric.
883
884 CLI Example:
885
886 .. code-block:: bash
887
888 salt 'maas-node' maasng.create_fabric
azvyagintsevbca1f462018-05-25 19:06:46 +0300889 """
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200890 result = {}
891 data = {
892 "name": name,
893 "description": '',
894 "class_type": '',
895
896 }
897
898 maas = _create_maas_client()
899 json_res = json.loads(maas.post(u"api/2.0/fabrics/", None, **data).read())
900 LOG.info(json_res)
901 result["new"] = "Fabrics {0} created".format(json_res["name"])
902 return result
903
904
905def list_subnet():
azvyagintsevbca1f462018-05-25 19:06:46 +0300906 """
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200907 Get list of all subnets
908
909 CLI Example:
910
911 .. code-block:: bash
912
913 salt 'maas-node' maasng.list_subnet
azvyagintsevbca1f462018-05-25 19:06:46 +0300914 """
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200915 subnets = {}
916 maas = _create_maas_client()
917 json_res = json.loads(maas.get(u'api/2.0/subnets/').read())
918 LOG.info(json_res)
919 for item in json_res:
920 subnets[item["name"]] = item
921 return subnets
922
923
924def list_vlans(fabric):
azvyagintsevbca1f462018-05-25 19:06:46 +0300925 """
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200926 Get list of all vlans for specific fabric
927
928 CLI Example:
929
930 .. code-block:: bash
931
932 salt 'maas-node' maasng.list_vlans
azvyagintsevbca1f462018-05-25 19:06:46 +0300933 """
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200934 vlans = {}
935 maas = _create_maas_client()
936 fabric_id = get_fabric(fabric)
937
938 json_res = json.loads(
939 maas.get(u'api/2.0/fabrics/{0}/vlans/'.format(fabric_id)).read())
940 LOG.info(json_res)
941 for item in json_res:
942 vlans[item["name"]] = item
943 return vlans
944
945
946def get_fabric(fabric):
azvyagintsevbca1f462018-05-25 19:06:46 +0300947 """
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200948 Get id for specific fabric
949
950 CLI Example:
951
952 .. code-block:: bash
953
954 salt-call maasng.get_fabric fabric_name
azvyagintsevbca1f462018-05-25 19:06:46 +0300955 """
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200956 try:
957 return list_fabric()[fabric]['id']
958 except KeyError:
959 return {"error": "Frabic not found on MaaS server"}
960
961
Pavel Cizinsky864a3292018-05-25 16:24:48 +0200962def update_vlan(name, fabric, vid, description, primary_rack, dhcp_on=False):
azvyagintsevbca1f462018-05-25 19:06:46 +0300963 """
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200964 Update vlan
965
966 CLI Example:
967
968 .. code-block:: bash
969
970 salt 'maas-node' maasng.update_vlan name, fabric, vid, description, dhcp_on
azvyagintsevbca1f462018-05-25 19:06:46 +0300971 """
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200972 result = {}
973
974 data = {
975 "name": name,
976 "dhcp_on": str(dhcp_on),
977 "description": description,
Pavel Cizinsky864a3292018-05-25 16:24:48 +0200978 "primary_rack": primary_rack,
Pavel Cizinsky0995e8f2018-05-04 17:10:37 +0200979 }
980 maas = _create_maas_client()
981 fabric_id = get_fabric(fabric)
982
983 json_res = json.loads(maas.put(
984 u'api/2.0/fabrics/{0}/vlans/{1}/'.format(fabric_id, vid), **data).read())
985 print(json_res)
986 result["new"] = "Vlan {0} was updated".format(json_res["name"])
987
988 return result
azvyagintsevbca1f462018-05-25 19:06:46 +0300989
990# END NETWORKING