Files
python-heatclient/heatclient/osc/v1/software_deployment.py
jacky06 fcc7befd0f Cleanup of .keys() from dict_object.keys() *in* operator
Change-Id: I49bb58e5dc2618ee02424315e4e3bf1057a77068
2019-12-05 11:05:53 +08:00

357 lines
13 KiB
Python

# 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.
#
"""Orchestration v1 Software Deployment action implementations"""
import logging
from osc_lib.command import command
from osc_lib import exceptions as exc
from osc_lib import utils
from oslo_serialization import jsonutils
from heatclient._i18n import _
from heatclient.common import deployment_utils
from heatclient.common import format_utils
from heatclient.common import utils as heat_utils
from heatclient import exc as heat_exc
class CreateDeployment(format_utils.YamlFormat):
"""Create a software deployment."""
log = logging.getLogger(__name__ + '.CreateDeployment')
def get_parser(self, prog_name):
parser = super(CreateDeployment, self).get_parser(prog_name)
parser.add_argument(
'name',
metavar='<deployment-name>',
help=_('Name of the derived config associated with this '
'deployment. This is used to apply a sort order to the '
'list of configurations currently deployed to the server.')
)
parser.add_argument(
'--input-value',
metavar='<key=value>',
action='append',
help=_('Input value to set on the deployment. This can be '
'specified multiple times.')
)
parser.add_argument(
'--action',
metavar='<action>',
default='UPDATE',
help=_('Name of an action for this deployment. This can be a '
'custom action, or one of CREATE, UPDATE, DELETE, SUSPEND, '
'RESUME. Default is UPDATE')
)
parser.add_argument(
'--config',
metavar='<config>',
help=_('ID of the configuration to deploy')
)
parser.add_argument(
'--signal-transport',
metavar='<signal-transport>',
default='TEMP_URL_SIGNAL',
help=_('How the server should signal to heat with the deployment '
'output values. TEMP_URL_SIGNAL will create a Swift '
'TempURL to be signaled via HTTP PUT. ZAQAR_SIGNAL will '
'create a dedicated zaqar queue to be signaled using the '
'provided keystone credentials.NO_SIGNAL will result in '
'the resource going to the COMPLETE state without waiting '
'for any signal')
)
parser.add_argument(
'--container',
metavar='<container>',
help=_('Optional name of container to store TEMP_URL_SIGNAL '
'objects in. If not specified a container will be created '
'with a name derived from the DEPLOY_NAME')
)
parser.add_argument(
'--timeout',
metavar='<timeout>',
type=int,
default=60,
help=_('Deployment timeout in minutes')
)
parser.add_argument(
'--server',
metavar='<server>',
required=True,
help=_('ID of the server being deployed to')
)
return parser
def take_action(self, parsed_args):
self.log.debug('take_action(%s)', parsed_args)
client = self.app.client_manager.orchestration
config = {}
if parsed_args.config:
try:
config = client.software_configs.get(parsed_args.config)
except heat_exc.HTTPNotFound:
msg = (_('Software configuration not found: %s') %
parsed_args.config)
raise exc.CommandError(msg)
derived_params = deployment_utils.build_derived_config_params(
parsed_args.action,
config,
parsed_args.name,
heat_utils.format_parameters(parsed_args.input_value, False),
parsed_args.server,
parsed_args.signal_transport,
signal_id=deployment_utils.build_signal_id(client, parsed_args)
)
derived_config = client.software_configs.create(**derived_params)
sd = client.software_deployments.create(
config_id=derived_config.id,
server_id=parsed_args.server,
action=parsed_args.action,
status='IN_PROGRESS'
)
return zip(*sorted(sd.to_dict().items()))
class DeleteDeployment(command.Command):
"""Delete software deployment(s) and correlative config(s)."""
log = logging.getLogger(__name__ + '.DeleteDeployment')
def get_parser(self, prog_name):
parser = super(DeleteDeployment, self).get_parser(prog_name)
parser.add_argument(
'deployment',
metavar='<deployment>',
nargs='+',
help=_('ID of the deployment(s) to delete.')
)
return parser
def take_action(self, parsed_args):
self.log.debug("take_action(%s)", parsed_args)
hc = self.app.client_manager.orchestration
failure_count = 0
for deploy_id in parsed_args.deployment:
try:
sd = hc.software_deployments.get(deployment_id=deploy_id)
hc.software_deployments.delete(
deployment_id=deploy_id)
except Exception as e:
if isinstance(e, heat_exc.HTTPNotFound):
print(_('Deployment with ID %s not found') % deploy_id)
else:
print(_('Deployment with ID %s failed to delete')
% deploy_id)
failure_count += 1
continue
# just try best to delete the corresponding config
try:
config_id = getattr(sd, 'config_id')
hc.software_configs.delete(config_id=config_id)
except Exception:
print(_('Failed to delete the correlative config'
' %(config_id)s of deployment %(deploy_id)s') %
{'config_id': config_id, 'deploy_id': deploy_id})
if failure_count:
raise exc.CommandError(_('Unable to delete %(count)s of the '
'%(total)s deployments.') %
{'count': failure_count,
'total': len(parsed_args.deployment)})
class ListDeployment(command.Lister):
"""List software deployments."""
log = logging.getLogger(__name__ + '.ListDeployment')
def get_parser(self, prog_name):
parser = super(ListDeployment, self).get_parser(prog_name)
parser.add_argument(
'--server',
metavar='<server>',
help=_('ID of the server to fetch deployments for')
)
parser.add_argument(
'--long',
action='store_true',
help=_('List more fields in output')
)
return parser
def take_action(self, parsed_args):
self.log.debug("take_action(%s)", parsed_args)
heat_client = self.app.client_manager.orchestration
return _list_deployment(heat_client, args=parsed_args)
def _list_deployment(heat_client, args=None):
kwargs = {'server_id': args.server} if args.server else {}
columns = ['id', 'config_id', 'server_id', 'action', 'status']
if args.long:
columns.append('creation_time')
columns.append('status_reason')
deployments = heat_client.software_deployments.list(**kwargs)
return (
columns,
(utils.get_item_properties(s, columns) for s in deployments)
)
class ShowDeployment(command.ShowOne):
"""Show SoftwareDeployment Details."""
log = logging.getLogger(__name__ + ".ShowSoftwareDeployment")
def get_parser(self, prog_name):
parser = super(ShowDeployment, self).get_parser(prog_name)
parser.add_argument(
'deployment',
metavar='<deployment>',
help=_('ID of the deployment')
)
parser.add_argument(
'--long',
action='store_true',
help=_('Show more fields in output')
)
return parser
def take_action(self, parsed_args):
self.log.debug("take_action(%s)", parsed_args)
heat_client = self.app.client_manager.orchestration
try:
data = heat_client.software_deployments.get(
deployment_id=parsed_args.deployment)
except heat_exc.HTTPNotFound:
raise exc.CommandError(
_('Software Deployment not found: %s')
% parsed_args.deployment)
else:
columns = [
'id',
'server_id',
'config_id',
'creation_time',
'updated_time',
'status',
'status_reason',
'input_values',
'action',
]
if parsed_args.long:
columns.append('output_values')
return columns, utils.get_item_properties(data, columns)
class ShowMetadataDeployment(command.Command):
"""Get deployment configuration metadata for the specified server."""
log = logging.getLogger(__name__ + '.ShowMetadataDeployment')
def get_parser(self, prog_name):
parser = super(ShowMetadataDeployment, self).get_parser(prog_name)
parser.add_argument(
'server',
metavar='<server>',
help=_('ID of the server to fetch deployments for')
)
return parser
def take_action(self, parsed_args):
self.log.debug("take_action(%s)", parsed_args)
heat_client = self.app.client_manager.orchestration
md = heat_client.software_deployments.metadata(
server_id=parsed_args.server)
print(jsonutils.dumps(md, indent=2))
class ShowOutputDeployment(command.Command):
"""Show a specific deployment output."""
log = logging.getLogger(__name__ + '.ShowOutputDeployment')
def get_parser(self, prog_name):
parser = super(ShowOutputDeployment, self).get_parser(prog_name)
parser.add_argument(
'deployment',
metavar='<deployment>',
help=_('ID of deployment to show the output for')
)
parser.add_argument(
'output',
metavar='<output-name>',
nargs='?',
default=None,
help=_('Name of an output to display')
)
parser.add_argument(
'--all',
default=False,
action='store_true',
help=_('Display all deployment outputs')
)
parser.add_argument(
'--long',
action='store_true',
default=False,
help='Show full deployment logs in output',
)
return parser
def take_action(self, parsed_args):
self.log.debug("take_action(%s)", parsed_args)
heat_client = self.app.client_manager.orchestration
if (not parsed_args.all and parsed_args.output is None or
parsed_args.all and parsed_args.output is not None):
raise exc.CommandError(
_('Error: either %(output)s or %(all)s argument is needed.')
% {'output': '<output-name>', 'all': '--all'})
try:
sd = heat_client.software_deployments.get(
deployment_id=parsed_args.deployment)
except heat_exc.HTTPNotFound:
raise exc.CommandError(_('Deployment not found: %s')
% parsed_args.deployment)
outputs = sd.output_values
if outputs:
if parsed_args.all:
print('output_values:\n')
for k in outputs:
format_utils.print_software_deployment_output(
data=outputs, name=k, long=parsed_args.long)
else:
if parsed_args.output not in outputs:
msg = (_('Output %(output)s does not exist in deployment'
' %(deployment)s')
% {'output': parsed_args.output,
'deployment': parsed_args.deployment})
raise exc.CommandError(msg)
else:
print('output_value:\n')
format_utils.print_software_deployment_output(
data=outputs, name=parsed_args.output)