python-fuelclient/fuelclient/commands/role.py

264 lines
9.5 KiB
Python

# -*- coding: utf-8 -*-
#
# Copyright 2016 Vitalii Kulanov
#
# 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.
import abc
import os
from oslo_utils import fileutils
import six
from fuelclient.cli import error
from fuelclient.commands import base
from fuelclient.common import data_utils
class RoleMixIn(object):
entity_name = 'role'
supported_file_formats = ('json', 'yaml')
fields_mapper = (
('env', 'clusters'),
('release', 'releases')
)
def parse_model(self, args):
for param, role_class in self.fields_mapper:
model_id = getattr(args, param)
if model_id:
return role_class, model_id
@staticmethod
def get_file_path(directory, owner_type, owner_id, role_name, file_format):
return os.path.join(os.path.abspath(directory),
'{owner}_{id}'.format(owner=owner_type,
id=owner_id),
'{}.{}'.format(role_name, file_format))
@six.add_metaclass(abc.ABCMeta)
class BaseUploadCommand(RoleMixIn, base.BaseCommand):
"""Base class for uploading metadata of a role."""
@abc.abstractproperty
def action(self):
"""String with the name of the action."""
pass
@abc.abstractproperty
def uploader(self):
"""Callable for uploading data."""
pass
def get_parser(self, prog_name):
parser = super(BaseUploadCommand, self).get_parser(prog_name)
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument('-r',
'--release',
type=int,
help='Id of the release')
group.add_argument('-e',
'--env',
type=int,
help='Id of the environment')
parser.add_argument('-n',
'--name',
required=True,
help='Name of role.')
parser.add_argument('-f',
'--format',
required=True,
choices=self.supported_file_formats,
help='Format of serialized role description.')
parser.add_argument('-d',
'--directory',
required=False,
default=os.path.curdir,
help='Source directory. Defaults to '
'the current directory.')
return parser
def take_action(self, parsed_args):
model, model_id = self.parse_model(parsed_args)
params = {"owner_type": model,
"owner_id": model_id,
"role_name": parsed_args.name}
file_path = self.get_file_path(parsed_args.directory,
model,
model_id,
parsed_args.name,
parsed_args.format)
try:
with open(file_path, 'r') as stream:
data = data_utils.safe_load(parsed_args.format, stream)
self.uploader(data, **params)
except (OSError, IOError):
msg = "Could not read description for role '{}' at {}".format(
parsed_args.name, file_path)
raise error.InvalidFileException(msg)
msg = ("Description of role '{role}' for {owner} with id {id} was "
"{action}d from {file_path}\n".format(role=parsed_args.name,
owner=model,
id=model_id,
action=self.action,
file_path=file_path))
self.app.stdout.write(msg)
class RoleList(RoleMixIn, base.BaseListCommand):
"""Show list of all available roles for release or cluster."""
columns = ("name",
"group",
"conflicts",
"description")
def get_parser(self, prog_name):
parser = super(RoleList, self).get_parser(prog_name)
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument('-r',
'--release',
type=int,
help='Id of the release')
group.add_argument('-e',
'--env',
type=int,
help='Id of the environment'
)
return parser
def take_action(self, parsed_args):
model, model_id = self.parse_model(parsed_args)
data = self.client.get_all(model, model_id)
data = data_utils.get_display_data_multi(self.columns, data)
return self.columns, data
class RoleDownload(RoleMixIn, base.BaseCommand):
"""Download full role description to file."""
def get_parser(self, prog_name):
parser = super(RoleDownload, self).get_parser(prog_name)
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument('-r',
'--release',
type=int,
help='Id of the release')
group.add_argument('-e',
'--env',
type=int,
help='Id of the environment'
)
parser.add_argument('-n',
'--name',
required=True,
help='Name of role.')
parser.add_argument('-f',
'--format',
required=True,
choices=self.supported_file_formats,
help='Format of serialized role description.')
parser.add_argument('-d',
'--directory',
required=False,
default=os.path.curdir,
help='Destination directory. Defaults to '
'the current directory.')
return parser
def take_action(self, parsed_args):
model, model_id = self.parse_model(parsed_args)
file_path = self.get_file_path(parsed_args.directory,
model,
model_id,
parsed_args.name,
parsed_args.format)
data = self.client.get_one(model,
model_id,
parsed_args.name)
try:
fileutils.ensure_tree(os.path.dirname(file_path))
fileutils.delete_if_exists(file_path)
with open(file_path, 'w') as stream:
data_utils.safe_dump(parsed_args.format, stream, data)
except (OSError, IOError):
msg = ("Could not store description data "
"for role {} at {}".format(parsed_args.name, file_path))
raise error.InvalidFileException(msg)
msg = ("Description data of role '{}' within {} id {} "
"was stored in {}\n".format(parsed_args.name,
model,
model_id,
file_path))
self.app.stdout.write(msg)
class RoleUpdate(BaseUploadCommand):
"""Update a role from file description."""
action = "update"
@property
def uploader(self):
return self.client.update
class RoleCreate(BaseUploadCommand):
"""Create a role from file description"""
action = "create"
@property
def uploader(self):
return self.client.create
class RoleDelete(RoleMixIn, base.BaseCommand):
"""Delete a role from release or cluster"""
def get_parser(self, prog_name):
parser = super(RoleDelete, self).get_parser(prog_name)
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument('-r',
'--release',
type=int,
help='Id of the release')
group.add_argument('-e',
'--env',
type=int,
help='Id of the environment'
)
parser.add_argument('-n',
'--name',
required=True,
help='Name of role.')
return parser
def take_action(self, parsed_args):
model, model_id = self.parse_model(parsed_args)
self.client.delete(model,
model_id,
parsed_args.name)
msg = "Role '{}' was deleted from {} with id {}\n".format(
parsed_args.name, model, model_id)
self.app.stdout.write(msg)