You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
652 lines
29 KiB
652 lines
29 KiB
# |
|
# 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 |
|
1.9 - Add template_type option to generate_template() |
|
1.10 - Add support for software config list |
|
1.11 - Add support for template versions list |
|
1.12 - Add with_detail option for stack resources list |
|
1.13 - Add support for template functions 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, |
|
tags=None, tags_any=None, not_tags=None, |
|
not_tags_any=None): |
|
""" |
|
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 |
|
:param tags: show stacks containing these tags, combine multiple |
|
tags using the boolean AND expression |
|
:param tags_any: show stacks containing these tags, combine multiple |
|
tags using the boolean OR expression |
|
:param not_tags: show stacks not containing these tags, combine |
|
multiple tags using the boolean AND expression |
|
:param not_tags_any: show stacks not containing these tags, combine |
|
multiple tags using the boolean OR expression |
|
: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, |
|
tags=tags, tags_any=tags_any, |
|
not_tags=not_tags, |
|
not_tags_any=not_tags_any), |
|
version='1.8') |
|
|
|
def count_stacks(self, ctxt, filters=None, tenant_safe=True, |
|
show_deleted=False, show_nested=False, show_hidden=False, |
|
tags=None, tags_any=None, not_tags=None, |
|
not_tags_any=None): |
|
""" |
|
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, count will include hidden stacks |
|
:param tags: count stacks containing these tags, combine multiple tags |
|
using the boolean AND expression |
|
:param tags_any: count stacks containing these tags, combine multiple |
|
tags using the boolean OR expression |
|
:param not_tags: count stacks not containing these tags, combine |
|
multiple tags using the boolean AND expression |
|
:param not_tags_any: count stacks not containing these tags, combine |
|
multiple tags using the boolean OR expression |
|
: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, |
|
tags=tags, |
|
tags_any=tags_any, |
|
not_tags=not_tags, |
|
not_tags_any=not_tags_any), |
|
version='1.8') |
|
|
|
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, parent_resource_name=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 |
|
:param parent_resource_name: the parent resource name |
|
""" |
|
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, |
|
parent_resource_name=parent_resource_name), |
|
version='1.8') |
|
|
|
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 list_template_versions(self, ctxt): |
|
""" |
|
Get a list of available template versions |
|
|
|
:param ctxt: RPC context. |
|
""" |
|
return self.call(ctxt, self.make_msg('list_template_versions'), |
|
version='1.11') |
|
|
|
def list_template_functions(self, ctxt, template_version): |
|
""" |
|
Get a list of available functions in a given template |
|
|
|
:param ctxt: RPC context |
|
:param template_name : name of the template which function list you |
|
want to get |
|
""" |
|
return self.call(ctxt, self.make_msg( |
|
'list_template_functions', template_version=template_version), |
|
version='1.13') |
|
|
|
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, template_type='cfn'): |
|
""" |
|
Generate a template based on the specified type. |
|
|
|
:param ctxt: RPC context. |
|
:param type_name: The resource type name to generate a template for. |
|
:param template_type: the template type to generate, cfn or hot. |
|
""" |
|
return self.call(ctxt, self.make_msg('generate_template', |
|
type_name=type_name, |
|
template_type=template_type), |
|
version='1.9') |
|
|
|
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, with_detail=False): |
|
""" |
|
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. |
|
:param with_detail: show detail for resoruces in list. |
|
""" |
|
return self.call(ctxt, |
|
self.make_msg('list_stack_resources', |
|
stack_identity=stack_identity, |
|
nested_depth=nested_depth, |
|
with_detail=with_detail), |
|
version='1.12') |
|
|
|
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 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 list_software_configs(self, cnxt, limit=None, marker=None, |
|
tenant_safe=True): |
|
return self.call(cnxt, |
|
self.make_msg('list_software_configs', |
|
limit=limit, |
|
marker=marker, |
|
tenant_safe=tenant_safe), |
|
version='1.10') |
|
|
|
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')
|
|
|