python-saharaclient/saharaclient/osc/v1/node_group_templates.py

692 lines
26 KiB
Python

# Copyright (c) 2015 Mirantis Inc.
#
# 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 sys
from osc_lib.command import command
from osc_lib import exceptions
from osc_lib import utils as osc_utils
from oslo_log import log as logging
from oslo_serialization import jsonutils as json
from saharaclient.osc.v1 import utils
NGT_FIELDS = ['id', 'name', 'plugin_name', 'plugin_version', 'node_processes',
'description', 'auto_security_group', 'security_groups',
'availability_zone', 'flavor_id', 'floating_ip_pool',
'volumes_per_node', 'volumes_size',
'volume_type', 'volume_local_to_instance', 'volume_mount_prefix',
'volumes_availability_zone', 'use_autoconfig',
'is_proxy_gateway', 'is_default', 'is_protected', 'is_public']
def _format_ngt_output(data):
data['node_processes'] = osc_utils.format_list(data['node_processes'])
data['plugin_version'] = data.pop('hadoop_version')
if data['volumes_per_node'] == 0:
del data['volume_local_to_instance']
del data['volume_mount_prefix']
del data['volume_type'],
del data['volumes_availability_zone']
del data['volumes_size']
class CreateNodeGroupTemplate(command.ShowOne):
"""Creates node group template"""
log = logging.getLogger(__name__ + ".CreateNodeGroupTemplate")
def get_parser(self, prog_name):
parser = super(CreateNodeGroupTemplate, self).get_parser(prog_name)
parser.add_argument(
'--name',
metavar="<name>",
help="Name of the node group template [REQUIRED if JSON is not "
"provided]",
)
parser.add_argument(
'--plugin',
metavar="<plugin>",
help="Name of the plugin [REQUIRED if JSON is not provided]"
)
parser.add_argument(
'--plugin-version',
metavar="<plugin_version>",
help="Version of the plugin [REQUIRED if JSON is not provided]"
)
parser.add_argument(
'--processes',
metavar="<processes>",
nargs="+",
help="List of the processes that will be launched on each "
"instance [REQUIRED if JSON is not provided]"
)
parser.add_argument(
'--flavor',
metavar="<flavor>",
help="Name or ID of the flavor [REQUIRED if JSON is not provided]"
)
parser.add_argument(
'--security-groups',
metavar="<security-groups>",
nargs="+",
help="List of the security groups for the instances in this node "
"group"
)
parser.add_argument(
'--auto-security-group',
action='store_true',
default=False,
help='Indicates if an additional security group should be created '
'for the node group',
)
parser.add_argument(
'--availability-zone',
metavar="<availability-zone>",
help="Name of the availability zone where instances "
"will be created"
)
parser.add_argument(
'--floating-ip-pool',
metavar="<floating-ip-pool>",
help="ID of the floating IP pool"
)
parser.add_argument(
'--volumes-per-node',
type=int,
metavar="<volumes-per-node>",
help="Number of volumes attached to every node"
)
parser.add_argument(
'--volumes-size',
type=int,
metavar="<volumes-size>",
help='Size of volumes attached to node (GB). '
'This parameter will be taken into account only '
'if volumes-per-node is set and non-zero'
)
parser.add_argument(
'--volumes-type',
metavar="<volumes-type>",
help='Type of the volumes. '
'This parameter will be taken into account only '
'if volumes-per-node is set and non-zero'
)
parser.add_argument(
'--volumes-availability-zone',
metavar="<volumes-availability-zone>",
help='Name of the availability zone where volumes will be created.'
' This parameter will be taken into account only '
'if volumes-per-node is set and non-zero'
)
parser.add_argument(
'--volumes-mount-prefix',
metavar="<volumes-mount-prefix>",
help='Prefix for mount point directory. '
'This parameter will be taken into account only '
'if volumes-per-node is set and non-zero'
)
parser.add_argument(
'--volumes-locality',
action='store_true',
default=False,
help='If enabled, instance and attached volumes will be created on'
' the same physical host. This parameter will be taken into '
'account only if volumes-per-node is set and non-zero',
)
parser.add_argument(
'--description',
metavar="<description>",
help='Description of the node group template'
)
parser.add_argument(
'--autoconfig',
action='store_true',
default=False,
help='If enabled, instances of the node group will be '
'automatically configured',
)
parser.add_argument(
'--proxy-gateway',
action='store_true',
default=False,
help='If enabled, instances of the node group will be used to '
'access other instances in the cluster',
)
parser.add_argument(
'--public',
action='store_true',
default=False,
help='Make the node group template public (Visible from other '
'projects)',
)
parser.add_argument(
'--protected',
action='store_true',
default=False,
help='Make the node group template protected',
)
parser.add_argument(
'--json',
metavar='<filename>',
help='JSON representation of the node group template. Other '
'arguments will not be taken into account if this one is '
'provided'
)
parser.add_argument(
'--shares',
metavar='<filename>',
help='JSON representation of the manila shares'
)
parser.add_argument(
'--configs',
metavar='<filename>',
help='JSON representation of the node group template configs'
)
return parser
def take_action(self, parsed_args):
self.log.debug("take_action(%s)", parsed_args)
client = self.app.client_manager.data_processing
if parsed_args.json:
blob = osc_utils.read_blob_file_contents(parsed_args.json)
try:
template = json.loads(blob)
except ValueError as e:
raise exceptions.CommandError(
'An error occurred when reading '
'template from file %s: %s' % (parsed_args.json, e))
data = client.node_group_templates.create(**template).to_dict()
else:
if (not parsed_args.name or not parsed_args.plugin or
not parsed_args.plugin_version or not parsed_args.flavor or
not parsed_args.processes):
raise exceptions.CommandError(
'At least --name, --plugin, --plugin-version, --processes,'
' --flavor arguments should be specified or json template '
'should be provided with --json argument')
configs = None
if parsed_args.configs:
blob = osc_utils.read_blob_file_contents(parsed_args.configs)
try:
configs = json.loads(blob)
except ValueError as e:
raise exceptions.CommandError(
'An error occurred when reading '
'configs from file %s: %s' % (parsed_args.configs, e))
shares = None
if parsed_args.shares:
blob = osc_utils.read_blob_file_contents(parsed_args.shares)
try:
shares = json.loads(blob)
except ValueError as e:
raise exceptions.CommandError(
'An error occurred when reading '
'shares from file %s: %s' % (parsed_args.shares, e))
compute_client = self.app.client_manager.compute
flavor_id = osc_utils.find_resource(
compute_client.flavors, parsed_args.flavor).id
data = client.node_group_templates.create(
name=parsed_args.name,
plugin_name=parsed_args.plugin,
hadoop_version=parsed_args.plugin_version,
flavor_id=flavor_id,
description=parsed_args.description,
volumes_per_node=parsed_args.volumes_per_node,
volumes_size=parsed_args.volumes_size,
node_processes=parsed_args.processes,
floating_ip_pool=parsed_args.floating_ip_pool,
security_groups=parsed_args.security_groups,
auto_security_group=parsed_args.auto_security_group,
availability_zone=parsed_args.availability_zone,
volume_type=parsed_args.volumes_type,
is_proxy_gateway=parsed_args.proxy_gateway,
volume_local_to_instance=parsed_args.volumes_locality,
use_autoconfig=parsed_args.autoconfig,
is_public=parsed_args.public,
is_protected=parsed_args.protected,
node_configs=configs,
shares=shares,
volumes_availability_zone=parsed_args.volumes_availability_zone
).to_dict()
_format_ngt_output(data)
data = utils.prepare_data(data, NGT_FIELDS)
return self.dict2columns(data)
class ListNodeGroupTemplates(command.Lister):
"""Lists node group templates"""
log = logging.getLogger(__name__ + ".ListNodeGroupTemplates")
def get_parser(self, prog_name):
parser = super(ListNodeGroupTemplates, self).get_parser(prog_name)
parser.add_argument(
'--long',
action='store_true',
default=False,
help='List additional fields in output',
)
parser.add_argument(
'--plugin',
metavar="<plugin>",
help="List node group templates for specific plugin"
)
parser.add_argument(
'--plugin-version',
metavar="<plugin_version>",
help="List node group templates with specific version of the "
"plugin"
)
parser.add_argument(
'--name',
metavar="<name-substring>",
help="List node group templates with specific substring in the "
"name"
)
return parser
def take_action(self, parsed_args):
self.log.debug("take_action(%s)", parsed_args)
client = self.app.client_manager.data_processing
search_opts = {}
if parsed_args.plugin:
search_opts['plugin_name'] = parsed_args.plugin
if parsed_args.plugin_version:
search_opts['hadoop_version'] = parsed_args.plugin_version
data = client.node_group_templates.list(search_opts=search_opts)
if parsed_args.name:
data = utils.get_by_name_substring(data, parsed_args.name)
if parsed_args.long:
columns = ('name', 'id', 'plugin_name', 'hadoop_version',
'node_processes', 'description')
column_headers = utils.prepare_column_headers(
columns, {'hadoop_version': 'plugin_version'})
else:
columns = ('name', 'id', 'plugin_name', 'hadoop_version')
column_headers = utils.prepare_column_headers(
columns, {'hadoop_version': 'plugin_version'})
return (
column_headers,
(osc_utils.get_item_properties(
s,
columns,
formatters={
'node_processes': osc_utils.format_list
}
) for s in data)
)
class ShowNodeGroupTemplate(command.ShowOne):
"""Display node group template details"""
log = logging.getLogger(__name__ + ".ShowNodeGroupTemplate")
def get_parser(self, prog_name):
parser = super(ShowNodeGroupTemplate, self).get_parser(prog_name)
parser.add_argument(
"node_group_template",
metavar="<node-group-template>",
help="Name or id of the node group template to display",
)
return parser
def take_action(self, parsed_args):
self.log.debug("take_action(%s)", parsed_args)
client = self.app.client_manager.data_processing
data = utils.get_resource(
client.node_group_templates,
parsed_args.node_group_template).to_dict()
_format_ngt_output(data)
data = utils.prepare_data(data, NGT_FIELDS)
return self.dict2columns(data)
class DeleteNodeGroupTemplate(command.Command):
"""Deletes node group template"""
log = logging.getLogger(__name__ + ".DeleteNodeGroupTemplate")
def get_parser(self, prog_name):
parser = super(DeleteNodeGroupTemplate, self).get_parser(prog_name)
parser.add_argument(
"node_group_template",
metavar="<node-group-template>",
nargs="+",
help="Name(s) or id(s) of the node group template(s) to delete",
)
return parser
def take_action(self, parsed_args):
self.log.debug("take_action(%s)", parsed_args)
client = self.app.client_manager.data_processing
for ngt in parsed_args.node_group_template:
ngt_id = utils.get_resource_id(
client.node_group_templates, ngt)
client.node_group_templates.delete(ngt_id)
sys.stdout.write(
'Node group template "{ngt}" has been removed '
'successfully.\n'.format(ngt=ngt))
class UpdateNodeGroupTemplate(command.ShowOne):
"""Updates node group template"""
log = logging.getLogger(__name__ + ".UpdateNodeGroupTemplate")
def get_parser(self, prog_name):
parser = super(UpdateNodeGroupTemplate, self).get_parser(prog_name)
parser.add_argument(
'node_group_template',
metavar="<node-group-template>",
help="Name or ID of the node group template",
)
parser.add_argument(
'--name',
metavar="<name>",
help="New name of the node group template",
)
parser.add_argument(
'--plugin',
metavar="<plugin>",
help="Name of the plugin"
)
parser.add_argument(
'--plugin-version',
metavar="<plugin_version>",
help="Version of the plugin"
)
parser.add_argument(
'--processes',
metavar="<processes>",
nargs="+",
help="List of the processes that will be launched on each "
"instance"
)
parser.add_argument(
'--security-groups',
metavar="<security-groups>",
nargs="+",
help="List of the security groups for the instances in this node "
"group"
)
autosecurity = parser.add_mutually_exclusive_group()
autosecurity.add_argument(
'--auto-security-group-enable',
action='store_true',
help='Additional security group should be created '
'for the node group',
dest='use_auto_security_group'
)
autosecurity.add_argument(
'--auto-security-group-disable',
action='store_false',
help='Additional security group should not be created '
'for the node group',
dest='use_auto_security_group'
)
parser.add_argument(
'--availability-zone',
metavar="<availability-zone>",
help="Name of the availability zone where instances "
"will be created"
)
parser.add_argument(
'--flavor',
metavar="<flavor>",
help="Name or ID of the flavor"
)
parser.add_argument(
'--floating-ip-pool',
metavar="<floating-ip-pool>",
help="ID of the floating IP pool"
)
parser.add_argument(
'--volumes-per-node',
type=int,
metavar="<volumes-per-node>",
help="Number of volumes attached to every node"
)
parser.add_argument(
'--volumes-size',
type=int,
metavar="<volumes-size>",
help='Size of volumes attached to node (GB). '
'This parameter will be taken into account only '
'if volumes-per-node is set and non-zero'
)
parser.add_argument(
'--volumes-type',
metavar="<volumes-type>",
help='Type of the volumes. '
'This parameter will be taken into account only '
'if volumes-per-node is set and non-zero'
)
parser.add_argument(
'--volumes-availability-zone',
metavar="<volumes-availability-zone>",
help='Name of the availability zone where volumes will be created.'
' This parameter will be taken into account only '
'if volumes-per-node is set and non-zero'
)
parser.add_argument(
'--volumes-mount-prefix',
metavar="<volumes-mount-prefix>",
help='Prefix for mount point directory. '
'This parameter will be taken into account only '
'if volumes-per-node is set and non-zero'
)
volumelocality = parser.add_mutually_exclusive_group()
volumelocality.add_argument(
'--volumes-locality-enable',
action='store_true',
help='Instance and attached volumes will be created on '
'the same physical host. This parameter will be taken into '
'account only if volumes-per-node is set and non-zero',
dest='volume_locality'
)
volumelocality.add_argument(
'--volumes-locality-disable',
action='store_false',
help='Instance and attached volumes creation on the same physical '
'host will not be regulated. This parameter will be taken'
'into account only if volumes-per-node is set and non-zero',
dest='volume_locality'
)
parser.add_argument(
'--description',
metavar="<description>",
help='Description of the node group template'
)
autoconfig = parser.add_mutually_exclusive_group()
autoconfig.add_argument(
'--autoconfig-enable',
action='store_true',
help='Instances of the node group will be '
'automatically configured',
dest='use_autoconfig'
)
autoconfig.add_argument(
'--autoconfig-disable',
action='store_false',
help='Instances of the node group will not be '
'automatically configured',
dest='use_autoconfig'
)
proxy = parser.add_mutually_exclusive_group()
proxy.add_argument(
'--proxy-gateway-enable',
action='store_true',
help='Instances of the node group will be used to '
'access other instances in the cluster',
dest='is_proxy_gateway'
)
proxy.add_argument(
'--proxy-gateway-disable',
action='store_false',
help='Instances of the node group will not be used to '
'access other instances in the cluster',
dest='is_proxy_gateway'
)
public = parser.add_mutually_exclusive_group()
public.add_argument(
'--public',
action='store_true',
help='Make the node group template public '
'(Visible from other projects)',
dest='is_public'
)
public.add_argument(
'--private',
action='store_false',
help='Make the node group template private '
'(Visible only from this project)',
dest='is_public'
)
protected = parser.add_mutually_exclusive_group()
protected.add_argument(
'--protected',
action='store_true',
help='Make the node group template protected',
dest='is_protected'
)
protected.add_argument(
'--unprotected',
action='store_false',
help='Make the node group template unprotected',
dest='is_protected'
)
parser.add_argument(
'--json',
metavar='<filename>',
help='JSON representation of the node group template update '
'fields. Other arguments will not be taken into account if '
'this one is provided'
)
parser.add_argument(
'--shares',
metavar='<filename>',
help='JSON representation of the manila shares'
)
parser.add_argument(
'--configs',
metavar='<filename>',
help='JSON representation of the node group template configs'
)
parser.set_defaults(is_public=None, is_protected=None,
is_proxy_gateway=None, volume_locality=None,
use_auto_security_group=None, use_autoconfig=None)
return parser
def take_action(self, parsed_args):
self.log.debug("take_action(%s)", parsed_args)
client = self.app.client_manager.data_processing
ngt_id = utils.get_resource_id(
client.node_group_templates, parsed_args.node_group_template)
if parsed_args.json:
blob = osc_utils.read_blob_file_contents(parsed_args.json)
try:
template = json.loads(blob)
except ValueError as e:
raise exceptions.CommandError(
'An error occurred when reading '
'template from file %s: %s' % (parsed_args.json, e))
data = client.node_group_templates.update(
ngt_id, **template).to_dict()
else:
configs = None
if parsed_args.configs:
blob = osc_utils.read_blob_file_contents(parsed_args.configs)
try:
configs = json.loads(blob)
except ValueError as e:
raise exceptions.CommandError(
'An error occurred when reading '
'configs from file %s: %s' % (parsed_args.configs, e))
shares = None
if parsed_args.shares:
blob = osc_utils.read_blob_file_contents(parsed_args.shares)
try:
shares = json.loads(blob)
except ValueError as e:
raise exceptions.CommandError(
'An error occurred when reading '
'shares from file %s: %s' % (parsed_args.shares, e))
flavor_id = None
if parsed_args.flavor:
compute_client = self.app.client_manager.compute
flavor_id = osc_utils.find_resource(
compute_client.flavors, parsed_args.flavor).id
update_dict = utils.create_dict_from_kwargs(
name=parsed_args.name,
plugin_name=parsed_args.plugin,
hadoop_version=parsed_args.plugin_version,
flavor_id=flavor_id,
description=parsed_args.description,
volumes_per_node=parsed_args.volumes_per_node,
volumes_size=parsed_args.volumes_size,
node_processes=parsed_args.processes,
floating_ip_pool=parsed_args.floating_ip_pool,
security_groups=parsed_args.security_groups,
auto_security_group=parsed_args.use_auto_security_group,
availability_zone=parsed_args.availability_zone,
volume_type=parsed_args.volumes_type,
is_proxy_gateway=parsed_args.is_proxy_gateway,
volume_local_to_instance=parsed_args.volume_locality,
use_autoconfig=parsed_args.use_autoconfig,
is_public=parsed_args.is_public,
is_protected=parsed_args.is_protected,
node_configs=configs,
shares=shares,
volumes_availability_zone=parsed_args.volumes_availability_zone
)
data = client.node_group_templates.update(
ngt_id, **update_dict).to_dict()
_format_ngt_output(data)
data = utils.prepare_data(data, NGT_FIELDS)
return self.dict2columns(data)