
This PS implements the following changes: - switches freeze approach to requirements-direct.txt and requirements-frozen.txt files - adjusts code tabulation style according to yapf recommendations - replaces deprecated usage of responce.body attribute with responce.text - fixes integration tests in controlled by Makefile + tox - uplifts Helm to v3.9.4 Change-Id: I751db72eb8f670825382f11a36657112faeb169a
217 lines
7.7 KiB
Python
217 lines
7.7 KiB
Python
# Copyright 2017 AT&T Intellectual Property. All other rights reserved.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
"""API model for MaaS node storage partition resource."""
|
|
|
|
import uuid
|
|
|
|
from . import base as model_base
|
|
|
|
import drydock_provisioner.error as errors
|
|
|
|
|
|
class Partition(model_base.ResourceBase):
|
|
|
|
resource_url = 'nodes/{system_id}/blockdevices/{device_id}/partition/{resource_id}'
|
|
fields = [
|
|
'resource_id',
|
|
'system_id',
|
|
'device_id',
|
|
'name',
|
|
'path',
|
|
'size',
|
|
'type',
|
|
'uuid',
|
|
'filesystem',
|
|
'bootable',
|
|
]
|
|
json_fields = [
|
|
'size',
|
|
'uuid',
|
|
'bootable',
|
|
]
|
|
"""Filesystem dictionary fields:
|
|
mount_point: the mount point on the system directory hierarchy
|
|
fstype: The filesystem format, defaults to ext4
|
|
mount_options: The mount options specified in /etc/fstab, defaults to 'defaults'
|
|
label: The filesystem lab
|
|
uuid: The filesystem uuid
|
|
"""
|
|
|
|
def __init__(self, api_client, **kwargs):
|
|
super().__init__(api_client, **kwargs)
|
|
|
|
def format(self, fstype='ext4', uuid_str=None, fs_label=None):
|
|
"""Format this partition with a filesystem.
|
|
|
|
:param fstype: String of the filesystem format to use, defaults to ext4
|
|
:param uuid: String of the UUID to assign to the filesystem. One will be
|
|
generated if this is left as None
|
|
"""
|
|
try:
|
|
data = {'fstype': fstype}
|
|
|
|
if uuid_str:
|
|
data['uuid'] = str(uuid_str)
|
|
else:
|
|
data['uuid'] = str(uuid.uuid4())
|
|
|
|
if fs_label is not None:
|
|
data['label'] = fs_label
|
|
|
|
url = self.interpolate_url()
|
|
|
|
self.logger.debug(
|
|
"Formatting device %s on node %s as filesystem: %s" %
|
|
(self.name, self.system_id, data))
|
|
resp = self.api_client.post(url, op='format', files=data)
|
|
|
|
if not resp.ok:
|
|
raise Exception("MAAS error: %s - %s" %
|
|
(resp.status_code, resp.text))
|
|
|
|
self.refresh()
|
|
except Exception as ex:
|
|
msg = "Error: format of device %s on node %s failed: %s" \
|
|
% (self.name, self.system_id, str(ex))
|
|
self.logger.error(msg)
|
|
raise errors.DriverError(msg)
|
|
|
|
def unformat(self):
|
|
"""Unformat this block device.
|
|
|
|
Will attempt to unmount the device first.
|
|
"""
|
|
try:
|
|
self.refresh()
|
|
if self.filesystem is None:
|
|
self.logger.debug(
|
|
"Device %s not currently formatted, skipping unformat." %
|
|
(self.name))
|
|
return
|
|
|
|
if self.filesystem.get('mount_pount', None) is not None:
|
|
self.unmount()
|
|
|
|
url = self.interpolate_url()
|
|
|
|
self.logger.debug("Unformatting device %s on node %s" %
|
|
(self.name, self.system_id))
|
|
resp = self.api_client.post(url, op='unformat')
|
|
if not resp.ok:
|
|
raise Exception("MAAS error: %s - %s" %
|
|
(resp.status_code, resp.text))
|
|
self.refresh()
|
|
except Exception as ex:
|
|
msg = "Error: unformat of device %s on node %s failed: %s" \
|
|
% (self.name, self.system_id, str(ex))
|
|
self.logger.error(msg)
|
|
raise errors.DriverError(msg)
|
|
|
|
def mount(self, mount_point=None, mount_options='defaults'):
|
|
"""Mount this block device with a filesystem.
|
|
|
|
:param mount_point: The mountpoint on the system
|
|
:param mount_options: fstab style mount options, defaults to 'defaults'
|
|
"""
|
|
try:
|
|
if mount_point is None:
|
|
raise errors.DriverError(
|
|
"Cannot mount a block device on an empty mount point.")
|
|
|
|
data = {'mount_point': mount_point, 'mount_options': mount_options}
|
|
|
|
url = self.interpolate_url()
|
|
|
|
self.logger.debug(
|
|
"Mounting device %s on node %s at mount point %s" %
|
|
(self.resource_id, self.system_id, mount_point))
|
|
resp = self.api_client.post(url, op='mount', files=data)
|
|
if not resp.ok:
|
|
raise Exception("MAAS error: %s - %s" %
|
|
(resp.status_code, resp.text))
|
|
self.refresh()
|
|
except Exception as ex:
|
|
msg = "Error: mount of device %s on node %s failed: %s" \
|
|
% (self.name, self.system_id, str(ex))
|
|
self.logger.error(msg)
|
|
raise errors.DriverError(msg)
|
|
|
|
def unmount(self):
|
|
"""Unmount this block device."""
|
|
try:
|
|
self.refresh()
|
|
if self.filesystem is None or self.filesystem.get(
|
|
'mount_point', None) is None:
|
|
self.logger.debug(
|
|
"Device %s not currently mounted, skipping unmount." %
|
|
(self.name))
|
|
|
|
url = self.interpolate_url()
|
|
|
|
self.logger.debug("Unmounting device %s on node %s" %
|
|
(self.name, self.system_id))
|
|
resp = self.api_client.post(url, op='unmount')
|
|
if not resp.ok:
|
|
raise Exception("MAAS error: %s - %s" %
|
|
(resp.status_code, resp.text))
|
|
self.refresh()
|
|
except Exception as ex:
|
|
msg = "Error: unmount of device %s on node %s failed: %s" \
|
|
% (self.name, self.system_id, str(ex))
|
|
self.logger.error(msg)
|
|
raise errors.DriverError(msg)
|
|
|
|
def set_bootable(self):
|
|
"""Set this disk as the system bootdisk."""
|
|
try:
|
|
url = self.interpolate_url()
|
|
self.logger.debug("Setting device %s on node %s as bootable." %
|
|
(self.resource_id, self.system_id))
|
|
resp = self.api_client.post(url, op='set_boot_disk')
|
|
if not resp.ok:
|
|
raise Exception("MAAS error: %s - %s" %
|
|
(resp.status_code, resp.text))
|
|
self.refresh()
|
|
except Exception as ex:
|
|
msg = "Error: setting device %s on node %s to boot failed: %s" \
|
|
% (self.name, self.system_id, str(ex))
|
|
self.logger.error(msg)
|
|
raise errors.DriverError(msg)
|
|
|
|
@classmethod
|
|
def from_dict(cls, api_client, obj_dict):
|
|
"""Instantiate this model from a dictionary.
|
|
|
|
Because MaaS decides to replace the resource ids with the
|
|
representation of the resource, we must reverse it for a true
|
|
representation of the block device
|
|
"""
|
|
refined_dict = {k: obj_dict.get(k, None) for k in cls.fields}
|
|
if 'id' in obj_dict.keys():
|
|
refined_dict['resource_id'] = obj_dict.get('id')
|
|
|
|
i = cls(api_client, **refined_dict)
|
|
return i
|
|
|
|
|
|
class Partitions(model_base.ResourceCollectionBase):
|
|
|
|
collection_url = 'nodes/{system_id}/blockdevices/{device_id}/partitions/'
|
|
collection_resource = Partition
|
|
|
|
def __init__(self, api_client, **kwargs):
|
|
super().__init__(api_client)
|
|
self.system_id = kwargs.get('system_id', None)
|
|
self.device_id = kwargs.get('device_id', None)
|