0799acf939
This changes the default value for nodegroups min_node_count to 0. Scaling nodegroups to 0 is also allowed. Change-Id: I74dd0d34990b71b290b6ccbe707afb8cc7ae7340 Depends-On: Id63459d0fe9836e678bb7569f23d29eabc225e9e story: 2007851 task: 40147
302 lines
11 KiB
Python
302 lines
11 KiB
Python
# Copyright (c) 2018 European Organization for Nuclear Research.
|
|
# All 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.
|
|
|
|
from magnumclient.common import utils as magnum_utils
|
|
from magnumclient.i18n import _
|
|
|
|
from osc_lib.command import command
|
|
from osc_lib import utils
|
|
|
|
|
|
NODEGROUP_ATTRIBUTES = [
|
|
'uuid',
|
|
'name',
|
|
'cluster_id',
|
|
'project_id',
|
|
'docker_volume_size',
|
|
'labels',
|
|
'labels_overridden',
|
|
'labels_skipped',
|
|
'labels_added',
|
|
'flavor_id',
|
|
'image_id',
|
|
'node_addresses',
|
|
'node_count',
|
|
'role',
|
|
'max_node_count',
|
|
'min_node_count',
|
|
'is_default',
|
|
'stack_id',
|
|
'status',
|
|
'status_reason',
|
|
]
|
|
|
|
|
|
class CreateNodeGroup(command.Command):
|
|
_description = _("Create a nodegroup")
|
|
|
|
def get_parser(self, prog_name):
|
|
parser = super(CreateNodeGroup, self).get_parser(prog_name)
|
|
# NOTE: All arguments are positional and, if not provided
|
|
# with a default, required.
|
|
parser.add_argument('--docker-volume-size',
|
|
dest='docker_volume_size',
|
|
type=int,
|
|
metavar='<docker-volume-size>',
|
|
help=('The size in GB for the docker volume to '
|
|
'use.'))
|
|
parser.add_argument('--labels',
|
|
metavar='<KEY1=VALUE1,KEY2=VALUE2;KEY3=VALUE3...>',
|
|
action='append',
|
|
help=_('Arbitrary labels in the form of key=value'
|
|
'pairs to associate with a nodegroup. '
|
|
'May be used multiple times.'))
|
|
parser.add_argument('cluster',
|
|
metavar='<cluster>',
|
|
help='Name of the nodegroup to create.')
|
|
parser.add_argument('name',
|
|
metavar='<name>',
|
|
help='Name of the nodegroup to create.')
|
|
parser.add_argument('--node-count',
|
|
dest='node_count',
|
|
type=int,
|
|
default=1,
|
|
metavar='<node-count>',
|
|
help='The nodegroup node count.')
|
|
parser.add_argument('--min-nodes',
|
|
dest='min_node_count',
|
|
type=int,
|
|
default=0,
|
|
metavar='<min-nodes>',
|
|
help='The nodegroup minimum node count.')
|
|
parser.add_argument('--max-nodes',
|
|
dest='max_node_count',
|
|
type=int,
|
|
default=None,
|
|
metavar='<max-nodes>',
|
|
help='The nodegroup maximum node count.')
|
|
parser.add_argument('--role',
|
|
dest='role',
|
|
type=str,
|
|
default='worker',
|
|
metavar='<role>',
|
|
help=('The role of the nodegroup'))
|
|
parser.add_argument(
|
|
'--image',
|
|
metavar='<image>',
|
|
help=_('The name or UUID of the base image to customize for the '
|
|
'NodeGroup.'))
|
|
parser.add_argument(
|
|
'--flavor',
|
|
metavar='<flavor>',
|
|
help=_('The nova flavor name or UUID to use when launching the '
|
|
'nodes in this NodeGroup.'))
|
|
parser.add_argument(
|
|
'--merge-labels',
|
|
dest='merge_labels',
|
|
action='store_true',
|
|
default=False,
|
|
help=_('The labels provided will be merged with the labels '
|
|
'configured in the specified cluster.'))
|
|
|
|
return parser
|
|
|
|
def take_action(self, parsed_args):
|
|
self.log.debug("take_action(%s)", parsed_args)
|
|
|
|
mag_client = self.app.client_manager.container_infra
|
|
args = {
|
|
'name': parsed_args.name,
|
|
'node_count': parsed_args.node_count,
|
|
'max_node_count': parsed_args.max_node_count,
|
|
'min_node_count': parsed_args.min_node_count,
|
|
'role': parsed_args.role,
|
|
}
|
|
|
|
if parsed_args.labels is not None:
|
|
args['labels'] = magnum_utils.handle_labels(parsed_args.labels)
|
|
|
|
if parsed_args.docker_volume_size is not None:
|
|
args['docker_volume_size'] = parsed_args.docker_volume_size
|
|
|
|
if parsed_args.flavor is not None:
|
|
args['flavor_id'] = parsed_args.flavor
|
|
|
|
if parsed_args.image is not None:
|
|
args['image_id'] = parsed_args.image
|
|
|
|
if parsed_args.merge_labels:
|
|
# We are only sending this if it's True. This
|
|
# way we avoid breaking older APIs.
|
|
args["merge_labels"] = parsed_args.merge_labels
|
|
|
|
cluster_id = parsed_args.cluster
|
|
nodegroup = mag_client.nodegroups.create(cluster_id, **args)
|
|
print("Request to create nodegroup %s accepted"
|
|
% nodegroup.uuid)
|
|
|
|
|
|
class DeleteNodeGroup(command.Command):
|
|
_description = _("Delete a nodegroup")
|
|
|
|
def get_parser(self, prog_name):
|
|
parser = super(DeleteNodeGroup, self).get_parser(prog_name)
|
|
parser.add_argument(
|
|
'cluster',
|
|
metavar='<cluster>',
|
|
help=_('ID or name of the cluster where the nodegroup(s) '
|
|
'belong(s).'))
|
|
parser.add_argument(
|
|
'nodegroup',
|
|
nargs='+',
|
|
metavar='<nodegroup>',
|
|
help='ID or name of the nodegroup(s) to delete.')
|
|
|
|
return parser
|
|
|
|
def take_action(self, parsed_args):
|
|
self.log.debug("take_action(%s)", parsed_args)
|
|
|
|
mag_client = self.app.client_manager.container_infra
|
|
cluster_id = parsed_args.cluster
|
|
for ng in parsed_args.nodegroup:
|
|
mag_client.nodegroups.delete(cluster_id, ng)
|
|
print("Request to delete nodegroup %s has been accepted." % ng)
|
|
|
|
|
|
class ListNodeGroup(command.Lister):
|
|
_description = _("List nodegroups")
|
|
|
|
def get_parser(self, prog_name):
|
|
parser = super(ListNodeGroup, self).get_parser(prog_name)
|
|
|
|
parser.add_argument(
|
|
'cluster',
|
|
metavar='<cluster>',
|
|
help=_('ID or name of the cluster where the nodegroup belongs.'))
|
|
parser.add_argument(
|
|
'--limit',
|
|
metavar='<limit>',
|
|
type=int,
|
|
help=_('Maximum number of nodegroups to return'))
|
|
parser.add_argument(
|
|
'--sort-key',
|
|
metavar='<sort-key>',
|
|
help=_('Column to sort results by'))
|
|
parser.add_argument(
|
|
'--sort-dir',
|
|
metavar='<sort-dir>',
|
|
choices=['desc', 'asc'],
|
|
help=_('Direction to sort. "asc" or "desc".'))
|
|
parser.add_argument(
|
|
'--role',
|
|
metavar='<role>',
|
|
help=_('List the nodegroups in the cluster with this role'))
|
|
|
|
return parser
|
|
|
|
def take_action(self, parsed_args):
|
|
self.log.debug("take_action(%s)", parsed_args)
|
|
|
|
mag_client = self.app.client_manager.container_infra
|
|
columns = ['uuid', 'name', 'flavor_id', 'image_id', 'node_count',
|
|
'status', 'role']
|
|
cluster_id = parsed_args.cluster
|
|
nodegroups = mag_client.nodegroups.list(cluster_id,
|
|
limit=parsed_args.limit,
|
|
sort_key=parsed_args.sort_key,
|
|
sort_dir=parsed_args.sort_dir,
|
|
role=parsed_args.role)
|
|
return (
|
|
columns,
|
|
(utils.get_item_properties(n, columns) for n in nodegroups)
|
|
)
|
|
|
|
|
|
class ShowNodeGroup(command.ShowOne):
|
|
_description = _("Show a nodegroup")
|
|
|
|
def get_parser(self, prog_name):
|
|
parser = super(ShowNodeGroup, self).get_parser(prog_name)
|
|
parser.add_argument(
|
|
'cluster',
|
|
metavar='<cluster>',
|
|
help=_('ID or name of the cluster where the nodegroup belongs.'))
|
|
parser.add_argument(
|
|
'nodegroup',
|
|
metavar='<nodegroup>',
|
|
help=_('ID or name of the nodegroup to show.')
|
|
)
|
|
return parser
|
|
|
|
def take_action(self, parsed_args):
|
|
self.log.debug("take_action(%s)", parsed_args)
|
|
|
|
columns = NODEGROUP_ATTRIBUTES
|
|
|
|
mag_client = self.app.client_manager.container_infra
|
|
cluster_id = parsed_args.cluster
|
|
nodegroup = mag_client.nodegroups.get(cluster_id,
|
|
parsed_args.nodegroup)
|
|
|
|
return (columns, utils.get_item_properties(nodegroup, columns))
|
|
|
|
|
|
class UpdateNodeGroup(command.Command):
|
|
_description = _("Update a Nodegroup")
|
|
|
|
def get_parser(self, prog_name):
|
|
parser = super(UpdateNodeGroup, self).get_parser(prog_name)
|
|
parser.add_argument(
|
|
'cluster',
|
|
metavar='<cluster>',
|
|
help=_('ID or name of the cluster where the nodegroup belongs.'))
|
|
parser.add_argument(
|
|
'nodegroup',
|
|
metavar='<nodegroup>',
|
|
help=_('The name or UUID of cluster to update'))
|
|
|
|
parser.add_argument(
|
|
'op',
|
|
metavar='<op>',
|
|
choices=['add', 'replace', 'remove'],
|
|
help=_("Operations: one of 'add', 'replace' or 'remove'"))
|
|
|
|
parser.add_argument(
|
|
'attributes',
|
|
metavar='<path=value>',
|
|
nargs='+',
|
|
action='append',
|
|
default=[],
|
|
help=_(
|
|
"Attributes to add/replace or remove (only PATH is necessary "
|
|
"on remove)"))
|
|
|
|
return parser
|
|
|
|
def take_action(self, parsed_args):
|
|
self.log.debug("take_action(%s)", parsed_args)
|
|
|
|
mag_client = self.app.client_manager.container_infra
|
|
|
|
patch = magnum_utils.args_array_to_patch(parsed_args.op,
|
|
parsed_args.attributes[0])
|
|
|
|
cluster_id = parsed_args.cluster
|
|
mag_client.nodegroups.update(cluster_id, parsed_args.nodegroup,
|
|
patch)
|
|
print("Request to update nodegroup %s has been accepted." %
|
|
parsed_args.nodegroup)
|