d4361580ba
Add a "hidden_stack_tags" option that contains a list of tag names. Stacks that have one or more of these tags will be hidden. Add an option to show hidden stacks in the stack listing. blueprint stack-tags Change-Id: I45a5ac6d73a9a61629a56f88270e3a97fafb378a
588 lines
26 KiB
Python
588 lines
26 KiB
Python
#
|
|
# Copyright 2012, Red Hat, 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.
|
|
|
|
"""
|
|
Client side of the heat engine RPC API.
|
|
"""
|
|
|
|
from heat.common import messaging
|
|
from heat.rpc import api as rpc_api
|
|
|
|
|
|
class EngineClient(object):
|
|
'''Client side of the heat engine rpc API.
|
|
|
|
API version history::
|
|
|
|
1.0 - Initial version.
|
|
1.1 - Add support_status argument to list_resource_types()
|
|
1.4 - Add support for service list
|
|
'''
|
|
|
|
BASE_RPC_API_VERSION = '1.0'
|
|
|
|
def __init__(self):
|
|
self._client = messaging.get_rpc_client(
|
|
topic=rpc_api.ENGINE_TOPIC,
|
|
version=self.BASE_RPC_API_VERSION)
|
|
|
|
@staticmethod
|
|
def make_msg(method, **kwargs):
|
|
return method, kwargs
|
|
|
|
def call(self, ctxt, msg, version=None):
|
|
method, kwargs = msg
|
|
if version is not None:
|
|
client = self._client.prepare(version=version)
|
|
else:
|
|
client = self._client
|
|
return client.call(ctxt, method, **kwargs)
|
|
|
|
def cast(self, ctxt, msg, version=None):
|
|
method, kwargs = msg
|
|
if version is not None:
|
|
client = self._client.prepare(version=version)
|
|
else:
|
|
client = self._client
|
|
return client.cast(ctxt, method, **kwargs)
|
|
|
|
def local_error_name(self, error):
|
|
"""
|
|
Returns the name of the error with any _Remote postfix removed.
|
|
|
|
:param error: Remote raised error to derive the name from.
|
|
"""
|
|
error_name = error.__class__.__name__
|
|
return error_name.split('_Remote')[0]
|
|
|
|
def ignore_error_named(self, error, name):
|
|
"""
|
|
Raises the error unless its local name matches the supplied name
|
|
|
|
:param error: Remote raised error to derive the local name from.
|
|
:param name: Name to compare local name to.
|
|
"""
|
|
if self.local_error_name(error) != name:
|
|
raise error
|
|
|
|
def identify_stack(self, ctxt, stack_name):
|
|
"""
|
|
The identify_stack method returns the full stack identifier for a
|
|
single, live stack given the stack name.
|
|
|
|
:param ctxt: RPC context.
|
|
:param stack_name: Name of the stack you want to see,
|
|
or None to see all
|
|
"""
|
|
return self.call(ctxt, self.make_msg('identify_stack',
|
|
stack_name=stack_name))
|
|
|
|
def list_stacks(self, ctxt, limit=None, marker=None, sort_keys=None,
|
|
sort_dir=None, filters=None, tenant_safe=True,
|
|
show_deleted=False, show_nested=False, show_hidden=False):
|
|
"""
|
|
The list_stacks method returns attributes of all stacks. It supports
|
|
pagination (``limit`` and ``marker``), sorting (``sort_keys`` and
|
|
``sort_dir``) and filtering (``filters``) of the results.
|
|
|
|
:param ctxt: RPC context.
|
|
:param limit: the number of stacks to list (integer or string)
|
|
:param marker: the ID of the last item in the previous page
|
|
:param sort_keys: an array of fields used to sort the list
|
|
:param sort_dir: the direction of the sort ('asc' or 'desc')
|
|
:param filters: a dict with attribute:value to filter the list
|
|
:param tenant_safe: if true, scope the request by the current tenant
|
|
:param show_deleted: if true, show soft-deleted stacks
|
|
:param show_nested: if true, show nested stacks
|
|
:param show_hidden: if true, show hidden stacks
|
|
:returns: a list of stacks
|
|
"""
|
|
return self.call(ctxt,
|
|
self.make_msg('list_stacks', limit=limit,
|
|
sort_keys=sort_keys, marker=marker,
|
|
sort_dir=sort_dir, filters=filters,
|
|
tenant_safe=tenant_safe,
|
|
show_deleted=show_deleted,
|
|
show_nested=show_nested,
|
|
show_hidden=show_hidden))
|
|
|
|
def count_stacks(self, ctxt, filters=None, tenant_safe=True,
|
|
show_deleted=False, show_nested=False, show_hidden=False):
|
|
"""
|
|
Return the number of stacks that match the given filters
|
|
:param ctxt: RPC context.
|
|
:param filters: a dict of ATTR:VALUE to match against stacks
|
|
:param tenant_safe: if true, scope the request by the current tenant
|
|
:param show_deleted: if true, count will include the deleted stacks
|
|
:param show_nested: if true, count will include nested stacks
|
|
:param show_hidden: if true, show hidden stacks
|
|
:returns: a integer representing the number of matched stacks
|
|
"""
|
|
return self.call(ctxt, self.make_msg('count_stacks',
|
|
filters=filters,
|
|
tenant_safe=tenant_safe,
|
|
show_deleted=show_deleted,
|
|
show_nested=show_nested,
|
|
show_hidden=show_hidden))
|
|
|
|
def show_stack(self, ctxt, stack_identity):
|
|
"""
|
|
Return detailed information about one or all stacks.
|
|
:param ctxt: RPC context.
|
|
:param stack_identity: Name of the stack you want to show, or None to
|
|
show all
|
|
"""
|
|
return self.call(ctxt, self.make_msg('show_stack',
|
|
stack_identity=stack_identity))
|
|
|
|
def preview_stack(self, ctxt, stack_name, template, params, files, args):
|
|
"""
|
|
Simulates a new stack using the provided template.
|
|
|
|
Note that at this stage the template has already been fetched from the
|
|
heat-api process if using a template-url.
|
|
|
|
:param ctxt: RPC context.
|
|
:param stack_name: Name of the stack you want to create.
|
|
:param template: Template of stack you want to create.
|
|
:param params: Stack Input Params/Environment
|
|
:param files: files referenced from the environment.
|
|
:param args: Request parameters/args passed from API
|
|
"""
|
|
return self.call(ctxt,
|
|
self.make_msg('preview_stack', stack_name=stack_name,
|
|
template=template,
|
|
params=params, files=files, args=args))
|
|
|
|
def create_stack(self, ctxt, stack_name, template, params, files, args):
|
|
"""
|
|
The create_stack method creates a new stack using the template
|
|
provided.
|
|
Note that at this stage the template has already been fetched from the
|
|
heat-api process if using a template-url.
|
|
|
|
:param ctxt: RPC context.
|
|
:param stack_name: Name of the stack you want to create.
|
|
:param template: Template of stack you want to create.
|
|
:param params: Stack Input Params/Environment
|
|
:param files: files referenced from the environment.
|
|
:param args: Request parameters/args passed from API
|
|
"""
|
|
return self._create_stack(ctxt, stack_name, template, params, files,
|
|
args)
|
|
|
|
def _create_stack(self, ctxt, stack_name, template, params, files, args,
|
|
owner_id=None, nested_depth=0, user_creds_id=None,
|
|
stack_user_project_id=None):
|
|
"""
|
|
Internal create_stack interface for engine-to-engine communication via
|
|
RPC. Allows some additional options which should not be exposed to
|
|
users via the API:
|
|
:param owner_id: parent stack ID for nested stacks
|
|
:param nested_depth: nested depth for nested stacks
|
|
:param user_creds_id: user_creds record for nested stack
|
|
:param stack_user_project_id: stack user project for nested stack
|
|
"""
|
|
return self.call(
|
|
ctxt, self.make_msg('create_stack', stack_name=stack_name,
|
|
template=template,
|
|
params=params, files=files, args=args,
|
|
owner_id=owner_id,
|
|
nested_depth=nested_depth,
|
|
user_creds_id=user_creds_id,
|
|
stack_user_project_id=stack_user_project_id),
|
|
version='1.2')
|
|
|
|
def update_stack(self, ctxt, stack_identity, template, params,
|
|
files, args):
|
|
"""
|
|
The update_stack method updates an existing stack based on the
|
|
provided template and parameters.
|
|
Note that at this stage the template has already been fetched from the
|
|
heat-api process if using a template-url.
|
|
|
|
:param ctxt: RPC context.
|
|
:param stack_name: Name of the stack you want to create.
|
|
:param template: Template of stack you want to create.
|
|
:param params: Stack Input Params/Environment
|
|
:param files: files referenced from the environment.
|
|
:param args: Request parameters/args passed from API
|
|
"""
|
|
return self.call(ctxt, self.make_msg('update_stack',
|
|
stack_identity=stack_identity,
|
|
template=template,
|
|
params=params,
|
|
files=files,
|
|
args=args))
|
|
|
|
def validate_template(self, ctxt, template, params=None):
|
|
"""
|
|
The validate_template method uses the stack parser to check
|
|
the validity of a template.
|
|
|
|
:param ctxt: RPC context.
|
|
:param template: Template of stack you want to create.
|
|
:param params: Stack Input Params/Environment
|
|
"""
|
|
return self.call(ctxt, self.make_msg('validate_template',
|
|
template=template,
|
|
params=params))
|
|
|
|
def authenticated_to_backend(self, ctxt):
|
|
"""
|
|
Verify that the credentials in the RPC context are valid for the
|
|
current cloud backend.
|
|
|
|
:param ctxt: RPC context.
|
|
"""
|
|
return self.call(ctxt, self.make_msg('authenticated_to_backend'))
|
|
|
|
def get_template(self, ctxt, stack_identity):
|
|
"""
|
|
Get the template.
|
|
|
|
:param ctxt: RPC context.
|
|
:param stack_name: Name of the stack you want to see.
|
|
"""
|
|
return self.call(ctxt, self.make_msg('get_template',
|
|
stack_identity=stack_identity))
|
|
|
|
def delete_stack(self, ctxt, stack_identity, cast=True):
|
|
"""
|
|
The delete_stack method deletes a given stack.
|
|
|
|
:param ctxt: RPC context.
|
|
:param stack_identity: Name of the stack you want to delete.
|
|
:param cast: cast the message or use call (default: True)
|
|
"""
|
|
rpc_method = self.cast if cast else self.call
|
|
return rpc_method(ctxt,
|
|
self.make_msg('delete_stack',
|
|
stack_identity=stack_identity))
|
|
|
|
def abandon_stack(self, ctxt, stack_identity):
|
|
"""
|
|
The abandon_stack method deletes a given stack but
|
|
resources would not be deleted.
|
|
|
|
:param ctxt: RPC context.
|
|
:param stack_identity: Name of the stack you want to abandon.
|
|
"""
|
|
return self.call(ctxt,
|
|
self.make_msg('abandon_stack',
|
|
stack_identity=stack_identity))
|
|
|
|
def list_resource_types(self, ctxt, support_status=None):
|
|
"""
|
|
Get a list of valid resource types.
|
|
|
|
:param ctxt: RPC context.
|
|
"""
|
|
return self.call(ctxt, self.make_msg('list_resource_types',
|
|
support_status=support_status),
|
|
version='1.1')
|
|
|
|
def resource_schema(self, ctxt, type_name):
|
|
"""
|
|
Get the schema for a resource type.
|
|
|
|
:param ctxt: RPC context.
|
|
"""
|
|
return self.call(ctxt, self.make_msg('resource_schema',
|
|
type_name=type_name))
|
|
|
|
def generate_template(self, ctxt, type_name):
|
|
"""
|
|
Generate a template based on the specified type.
|
|
|
|
:param ctxt: RPC context.
|
|
:param type_name: The resource type name to generate a template for.
|
|
"""
|
|
return self.call(ctxt, self.make_msg('generate_template',
|
|
type_name=type_name))
|
|
|
|
def list_events(self, ctxt, stack_identity, filters=None, limit=None,
|
|
marker=None, sort_keys=None, sort_dir=None,):
|
|
"""
|
|
The list_events method lists all events associated with a given stack.
|
|
It supports pagination (``limit`` and ``marker``),
|
|
sorting (``sort_keys`` and ``sort_dir``) and filtering(filters)
|
|
of the results.
|
|
|
|
:param ctxt: RPC context.
|
|
:param stack_identity: Name of the stack you want to get events for
|
|
:param filters: a dict with attribute:value to filter the list
|
|
:param limit: the number of events to list (integer or string)
|
|
:param marker: the ID of the last event in the previous page
|
|
:param sort_keys: an array of fields used to sort the list
|
|
:param sort_dir: the direction of the sort ('asc' or 'desc').
|
|
"""
|
|
return self.call(ctxt, self.make_msg('list_events',
|
|
stack_identity=stack_identity,
|
|
filters=filters,
|
|
limit=limit,
|
|
marker=marker,
|
|
sort_keys=sort_keys,
|
|
sort_dir=sort_dir))
|
|
|
|
def describe_stack_resource(self, ctxt, stack_identity, resource_name,
|
|
with_attr=None):
|
|
"""
|
|
Get detailed resource information about a particular resource.
|
|
:param ctxt: RPC context.
|
|
:param stack_identity: Name of the stack.
|
|
:param resource_name: the Resource.
|
|
"""
|
|
return self.call(ctxt,
|
|
self.make_msg('describe_stack_resource',
|
|
stack_identity=stack_identity,
|
|
resource_name=resource_name,
|
|
with_attr=with_attr),
|
|
version='1.2')
|
|
|
|
def find_physical_resource(self, ctxt, physical_resource_id):
|
|
"""
|
|
Return an identifier for the resource with the specified physical
|
|
resource ID.
|
|
:param ctxt RPC context.
|
|
:param physcial_resource_id The physical resource ID to look up.
|
|
"""
|
|
return self.call(ctxt,
|
|
self.make_msg(
|
|
'find_physical_resource',
|
|
physical_resource_id=physical_resource_id))
|
|
|
|
def describe_stack_resources(self, ctxt, stack_identity, resource_name):
|
|
"""
|
|
Get detailed resource information about one or more resources.
|
|
:param ctxt: RPC context.
|
|
:param stack_identity: Name of the stack.
|
|
:param resource_name: the Resource.
|
|
"""
|
|
return self.call(ctxt, self.make_msg('describe_stack_resources',
|
|
stack_identity=stack_identity,
|
|
resource_name=resource_name))
|
|
|
|
def list_stack_resources(self, ctxt, stack_identity, nested_depth=0):
|
|
"""
|
|
List the resources belonging to a stack.
|
|
:param ctxt: RPC context.
|
|
:param stack_identity: Name of the stack.
|
|
:param nested_depth: Levels of nested stacks of which list resources.
|
|
"""
|
|
return self.call(ctxt, self.make_msg('list_stack_resources',
|
|
stack_identity=stack_identity,
|
|
nested_depth=nested_depth))
|
|
|
|
def stack_suspend(self, ctxt, stack_identity):
|
|
return self.call(ctxt, self.make_msg('stack_suspend',
|
|
stack_identity=stack_identity))
|
|
|
|
def stack_resume(self, ctxt, stack_identity):
|
|
return self.call(ctxt, self.make_msg('stack_resume',
|
|
stack_identity=stack_identity))
|
|
|
|
def stack_check(self, ctxt, stack_identity):
|
|
return self.call(ctxt, self.make_msg('stack_check',
|
|
stack_identity=stack_identity))
|
|
|
|
def stack_cancel_update(self, ctxt, stack_identity):
|
|
return self.call(ctxt, self.make_msg('stack_cancel_update',
|
|
stack_identity=stack_identity))
|
|
|
|
def metadata_update(self, ctxt, stack_identity, resource_name, metadata):
|
|
"""
|
|
Update the metadata for the given resource.
|
|
"""
|
|
return self.call(ctxt, self.make_msg('metadata_update',
|
|
stack_identity=stack_identity,
|
|
resource_name=resource_name,
|
|
metadata=metadata))
|
|
|
|
def resource_signal(self, ctxt, stack_identity, resource_name, details,
|
|
sync_call=False):
|
|
"""
|
|
Generate an alarm on the resource.
|
|
:param ctxt: RPC context.
|
|
:param stack_identity: Name of the stack.
|
|
:param resource_name: the Resource.
|
|
:param details: the details of the signal.
|
|
"""
|
|
return self.call(ctxt, self.make_msg('resource_signal',
|
|
stack_identity=stack_identity,
|
|
resource_name=resource_name,
|
|
details=details,
|
|
sync_call=sync_call),
|
|
|
|
version='1.3')
|
|
|
|
def create_watch_data(self, ctxt, watch_name, stats_data):
|
|
'''
|
|
This could be used by CloudWatch and WaitConditions
|
|
and treat HA service events like any other CloudWatch.
|
|
:param ctxt: RPC context.
|
|
:param watch_name: Name of the watch/alarm
|
|
:param stats_data: The data to post.
|
|
'''
|
|
return self.call(ctxt, self.make_msg('create_watch_data',
|
|
watch_name=watch_name,
|
|
stats_data=stats_data))
|
|
|
|
def show_watch(self, ctxt, watch_name):
|
|
"""
|
|
The show_watch method returns the attributes of one watch
|
|
or all watches if no watch_name is passed
|
|
|
|
:param ctxt: RPC context.
|
|
:param watch_name: Name of the watch/alarm you want to see,
|
|
or None to see all
|
|
"""
|
|
return self.call(ctxt, self.make_msg('show_watch',
|
|
watch_name=watch_name))
|
|
|
|
def show_watch_metric(self, ctxt, metric_namespace=None, metric_name=None):
|
|
"""
|
|
The show_watch_metric method returns the datapoints associated
|
|
with a specified metric, or all metrics if no metric_name is passed
|
|
|
|
:param ctxt: RPC context.
|
|
:param metric_namespace: Name of the namespace you want to see,
|
|
or None to see all
|
|
:param metric_name: Name of the metric you want to see,
|
|
or None to see all
|
|
"""
|
|
return self.call(ctxt, self.make_msg('show_watch_metric',
|
|
metric_namespace=metric_namespace,
|
|
metric_name=metric_name))
|
|
|
|
def set_watch_state(self, ctxt, watch_name, state):
|
|
'''
|
|
Temporarily set the state of a given watch
|
|
:param ctxt: RPC context.
|
|
:param watch_name: Name of the watch
|
|
:param state: State (must be one defined in WatchRule class)
|
|
'''
|
|
return self.call(ctxt, self.make_msg('set_watch_state',
|
|
watch_name=watch_name,
|
|
state=state))
|
|
|
|
def get_revision(self, ctxt):
|
|
return self.call(ctxt, self.make_msg('get_revision'))
|
|
|
|
def show_software_config(self, cnxt, config_id):
|
|
return self.call(cnxt, self.make_msg('show_software_config',
|
|
config_id=config_id))
|
|
|
|
def create_software_config(self, cnxt, group, name, config,
|
|
inputs=None, outputs=None, options=None):
|
|
inputs = inputs or []
|
|
outputs = outputs or []
|
|
options = options or {}
|
|
return self.call(cnxt, self.make_msg('create_software_config',
|
|
group=group,
|
|
name=name,
|
|
config=config,
|
|
inputs=inputs,
|
|
outputs=outputs,
|
|
options=options))
|
|
|
|
def delete_software_config(self, cnxt, config_id):
|
|
return self.call(cnxt, self.make_msg('delete_software_config',
|
|
config_id=config_id))
|
|
|
|
def list_software_deployments(self, cnxt, server_id=None):
|
|
return self.call(cnxt, self.make_msg('list_software_deployments',
|
|
server_id=server_id))
|
|
|
|
def metadata_software_deployments(self, cnxt, server_id):
|
|
return self.call(cnxt, self.make_msg('metadata_software_deployments',
|
|
server_id=server_id))
|
|
|
|
def show_software_deployment(self, cnxt, deployment_id):
|
|
return self.call(cnxt, self.make_msg('show_software_deployment',
|
|
deployment_id=deployment_id))
|
|
|
|
def create_software_deployment(self, cnxt, server_id, config_id=None,
|
|
input_values=None, action='INIT',
|
|
status='COMPLETE', status_reason='',
|
|
stack_user_project_id=None):
|
|
input_values = input_values or {}
|
|
return self.call(cnxt, self.make_msg(
|
|
'create_software_deployment',
|
|
server_id=server_id,
|
|
config_id=config_id,
|
|
input_values=input_values,
|
|
action=action,
|
|
status=status,
|
|
status_reason=status_reason,
|
|
stack_user_project_id=stack_user_project_id))
|
|
|
|
def update_software_deployment(self, cnxt, deployment_id,
|
|
config_id=None, input_values=None,
|
|
output_values=None, action=None,
|
|
status=None, status_reason=None,
|
|
updated_at=None):
|
|
return self.call(
|
|
cnxt, self.make_msg('update_software_deployment',
|
|
deployment_id=deployment_id,
|
|
config_id=config_id,
|
|
input_values=input_values,
|
|
output_values=output_values,
|
|
action=action,
|
|
status=status,
|
|
status_reason=status_reason,
|
|
updated_at=updated_at),
|
|
version='1.5')
|
|
|
|
def delete_software_deployment(self, cnxt, deployment_id):
|
|
return self.call(cnxt, self.make_msg('delete_software_deployment',
|
|
deployment_id=deployment_id))
|
|
|
|
def signal_software_deployment(self, cnxt, deployment_id, details,
|
|
updated_at=None):
|
|
return self.call(
|
|
cnxt, self.make_msg('signal_software_deployment',
|
|
deployment_id=deployment_id,
|
|
details=details,
|
|
updated_at=updated_at),
|
|
version='1.6')
|
|
|
|
def stack_snapshot(self, ctxt, stack_identity, name):
|
|
return self.call(ctxt, self.make_msg('stack_snapshot',
|
|
stack_identity=stack_identity,
|
|
name=name))
|
|
|
|
def show_snapshot(self, cnxt, stack_identity, snapshot_id):
|
|
return self.call(cnxt, self.make_msg('show_snapshot',
|
|
stack_identity=stack_identity,
|
|
snapshot_id=snapshot_id))
|
|
|
|
def delete_snapshot(self, cnxt, stack_identity, snapshot_id):
|
|
return self.call(cnxt, self.make_msg('delete_snapshot',
|
|
stack_identity=stack_identity,
|
|
snapshot_id=snapshot_id))
|
|
|
|
def stack_list_snapshots(self, cnxt, stack_identity):
|
|
return self.call(cnxt, self.make_msg('stack_list_snapshots',
|
|
stack_identity=stack_identity))
|
|
|
|
def stack_restore(self, cnxt, stack_identity, snapshot_id):
|
|
return self.call(cnxt, self.make_msg('stack_restore',
|
|
stack_identity=stack_identity,
|
|
snapshot_id=snapshot_id))
|
|
|
|
def list_services(self, cnxt):
|
|
return self.call(cnxt, self.make_msg('list_services'), version='1.4')
|