Source code for cloudify.manager

########
# Copyright (c) 2014 GigaSpaces Technologies Ltd. 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.

import os
import urllib2

import utils
from cloudify_rest_client import CloudifyClient
from cloudify.exceptions import HttpException, NonRecoverableError


[docs]class NodeInstance(object): """ Represents a deployment node instance. An instance of this class contains runtime information retrieved from Cloudify's runtime storage as well as the node's state. """ def __init__(self, node_instance_id, node_id, runtime_properties=None, state=None, version=None, host_id=None, relationships=None): self.id = node_instance_id self._node_id = node_id self._runtime_properties = \ DirtyTrackingDict((runtime_properties or {}).copy()) self._state = state self._version = version self._host_id = host_id self._relationships = relationships def get(self, key): return self._runtime_properties.get(key) def put(self, key, value): self._runtime_properties[key] = value
[docs] def delete(self, key): del(self._runtime_properties[key])
__setitem__ = put __getitem__ = get __delitem__ = delete def __contains__(self, key): return key in self._runtime_properties @property def runtime_properties(self): """ The node instance runtime properties. To update the properties, make changes on the returned dict and call ``update_node_instance`` with the modified instance. """ return self._runtime_properties @property def version(self): return self._version @property def state(self): """ The node instance state. To update the node instance state, change this property value and call ``update_node_instance`` with the modified instance. """ return self._state @state.setter def state(self, value): self._state = value @property def dirty(self): return self._runtime_properties.dirty @property def host_id(self): return self._host_id @property def node_id(self): return self._node_id @property def relationships(self): return self._relationships
[docs]def get_rest_client(): """ :returns: A REST client configured to connect to the manager in context :rtype: cloudify_rest_client.CloudifyClient """ return CloudifyClient(utils.get_manager_ip(), utils.get_manager_rest_service_port())
def _save_resource(logger, resource, resource_path, target_path): if not target_path: target_path = os.path.join(utils.create_temp_folder(), os.path.basename(resource_path)) with open(target_path, 'w') as f: f.write(resource) logger.info("Downloaded %s to %s" % (resource_path, target_path)) return target_path
[docs]def download_resource(resource_path, logger, target_path=None): """ Download resource from the manager file server. :param resource_path: path to resource on the file server :param logger: logger to use for info output :param target_path: optional target path for the resource :returns: path to the downloaded resource """ resource = get_resource(resource_path) return _save_resource(logger, resource, resource_path, target_path)
[docs]def download_blueprint_resource(blueprint_id, resource_path, logger, target_path=None): """ Download resource from the manager file server with path relative to the blueprint denoted by ``blueprint_id``. :param blueprint_id: the blueprint id of the blueprint to download the resource from :param resource_path: path to resource relative to blueprint folder :param logger: logger to use for info output :param target_path: optional target path for the resource :returns: path to the downloaded resource """ resource = get_blueprint_resource(blueprint_id, resource_path) return _save_resource(logger, resource, resource_path, target_path)
[docs]def get_resource(resource_path, base_url=None): """ Get resource from the manager file server. :param resource_path: path to resource on the file server :returns: resource content """ if base_url is None: base_url = utils.get_manager_file_server_url() try: url = '{0}/{1}'.format(base_url, resource_path) response = urllib2.urlopen(url) return response.read() except urllib2.HTTPError as e: raise HttpException(e.url, e.code, e.msg)
[docs]def get_blueprint_resource(blueprint_id, resource_path): """ Get resource from the manager file server with patch relative to the blueprint denoted by ``blueprint_id``. :param blueprint_id: the blueprint id of the blueprint to download the resource from :param resource_path: path to resource relative to blueprint folder :returns: resource content """ base_url = "{0}/{1}".format(utils .get_manager_file_server_blueprints_root_url(), blueprint_id) return get_resource(resource_path, base_url=base_url)
[docs]def get_node_instance(node_instance_id): """ Read node instance data from the storage. :param node_instance_id: the node instance id :rtype: NodeInstance """ client = get_rest_client() instance = client.node_instances.get(node_instance_id) return NodeInstance(node_instance_id, instance.node_id, runtime_properties=instance.runtime_properties, state=instance.state, version=instance.version, host_id=instance.host_id, relationships=instance.relationships)
[docs]def update_node_instance(node_instance): """ Update node instance data changes in the storage. :param node_instance: the node instance with the updated data """ client = get_rest_client() client.node_instances.update( node_instance.id, state=node_instance.state, runtime_properties=node_instance.runtime_properties, version=node_instance.version)
[docs]def get_node_instance_ip(node_instance_id): """ Get the IP address of the host the node instance denoted by ``node_instance_id`` is contained in. """ client = get_rest_client() instance = client.node_instances.get(node_instance_id) if instance.host_id is None: raise NonRecoverableError('node instance: {0} is missing host_id' 'property'.format(instance.id)) if node_instance_id != instance.host_id: instance = client.node_instances.get(instance.host_id) if instance.runtime_properties.get('ip'): return instance.runtime_properties['ip'] node = client.nodes.get(instance.deployment_id, instance.node_id) if node.properties.get('ip'): return node.properties['ip'] raise NonRecoverableError('could not find ip for node instance: {0} with ' 'host id: {1}'.format(node_instance_id, instance.id)) # TODO: some nasty code duplication between these two methods
[docs]def update_execution_status(execution_id, status, error=None): """ Update the execution status of the execution denoted by ``execution_id``. :returns: The updated status """ client = get_rest_client() return client.executions.update(execution_id, status, error)
[docs]def get_bootstrap_context(): """Read the manager bootstrap context.""" client = get_rest_client() context = client.manager.get_context()['context'] return context.get('cloudify', {})
[docs]def get_provider_context(): """Read the manager provider context.""" client = get_rest_client() context = client.manager.get_context() return context['context']
class DirtyTrackingDict(dict): def __init__(self, *args, **kwargs): super(DirtyTrackingDict, self).__init__(*args, **kwargs) self.modifiable = True self.dirty = False def __setitem__(self, key, value): r = super(DirtyTrackingDict, self).__setitem__(key, value) self._set_changed() return r def __delitem__(self, key): r = super(DirtyTrackingDict, self).__delitem__(key) self._set_changed() return r def update(self, E=None, **F): r = super(DirtyTrackingDict, self).update(E, **F) self._set_changed() return r def clear(self): r = super(DirtyTrackingDict, self).clear() self._set_changed() return r def pop(self, k, d=None): r = super(DirtyTrackingDict, self).pop(k, d) self._set_changed() return r def popitem(self): r = super(DirtyTrackingDict, self).popitem() self._set_changed() return r def _set_changed(self): # python 2.6 doesn't have modifiable during copy.deepcopy if hasattr(self, 'modifiable') and not self.modifiable: raise NonRecoverableError('Cannot modify runtime properties of' ' relationship node instances') self.dirty = True