def create_policies(self, request, data, audit_logger): """ Create one or many new scaling policies. Scaling policies must include a name, type, adjustment, and cooldown. The response header will point to the list policies endpoint. An array of scaling policies is provided in the request body in JSON format. Example request:: [ { "name": "scale up by one server", "change": 1, "cooldown": 150 }, { "name": 'scale down by 5.5 percent', "changePercent": -5.5, "cooldown": 6 } ] Example response:: { "policies": [ { "id": {policyId1}, "links": [ { "href": "{url_root}/v1.0/010101/groups/{groupId}/policy/{policyId1}/" "rel": "self" } ], "name": "scale up by one server", "change": 1, "cooldown": 150 }, { "id": {policyId2}, "links": [ { "href": "{url_root}/v1.0/010101/groups/{groupId}/policy/{policyId2}/" "rel": "self" } ], "name": 'scale down by 5.5 percent', "changePercent": -5.5, "cooldown": 6 } ] } """ def format_policies_and_send_redirect(policy_list): request.setHeader( "Location", get_autoscale_links(self.tenant_id, self.scaling_group_id, "", format=None) ) linkify_policy_list(policy_list, self.tenant_id, self.scaling_group_id) return {'policies': policy_list} def _add_to_bobby(policy_list, client): d = defer.succeed(policy_list) for policy_item in policy_list: if policy_item['type'] == 'cloud_monitoring': client.create_policy(self.tenant_id, self.scaling_group_id, policy_item['id'], policy_item['args']['check'], policy_item['args']['alarm_criteria']['criteria']) return d.addCallback(lambda _: policy_list) from otter.rest.bobby import get_bobby bobby = get_bobby() e = extra_policy_validation(data, bobby) if e is not None: return defer.fail(e) rec = self.store.get_scaling_group(self.log, self.tenant_id, self.scaling_group_id) deferred = rec.create_policies(data) if bobby is not None: deferred.addCallback(_add_to_bobby, bobby) deferred.addCallback(format_policies_and_send_redirect) def audit_data(result): audit_logger.add(data=result) return result deferred.addCallback(audit_data) deferred.addCallback(json.dumps) return deferred
def create_new_scaling_group(self, request, data): """ Create a new scaling group, given the general scaling group configuration, launch configuration, and optional scaling policies. This data provided in the request body in JSON format. If successful, the created group in JSON format containing id and links is returned. Example request body containing some scaling policies:: { "launchConfiguration": { "args": { "loadBalancers": [ { "port": 8080, "loadBalancerId": 9099 } ], "server": { "name": "autoscale_server", "imageRef": "0d589460-f177-4b0f-81c1-8ab8903ac7d8", "flavorRef": "2", "OS-DCF:diskConfig": "AUTO", "metadata": { "build_config": "core", "meta_key_1": "meta_value_1", "meta_key_2": "meta_value_2" }, "networks": [ { "uuid": "11111111-1111-1111-1111-111111111111" }, { "uuid": "00000000-0000-0000-0000-000000000000" } ], "personality": [ { "path": "/root/.csivh", "contents": "VGhpcyBpcyBhIHRlc3QgZmlsZS4=" } ] } }, "type": "launch_server" }, "groupConfiguration": { "maxEntities": 10, "cooldown": 360, "name": "testscalinggroup198547", "minEntities": 0, "metadata": { "gc_meta_key_2": "gc_meta_value_2", "gc_meta_key_1": "gc_meta_value_1" } }, "scalingPolicies": [ { "cooldown": 0, "type": "webhook", "name": "scale up by 1", "change": 1 } ] } The ``scalingPolicies`` attribute can also be an empty list, or just left out entirely. Example response body to the above request:: { "group": { "launchConfiguration": { "args": { "loadBalancers": [ { "port": 8080, "loadBalancerId": 9099 } ], "server": { "name": "autoscale_server", "imageRef": "0d589460-f177-4b0f-81c1-8ab8903ac7d8", "flavorRef": "2", "OS-DCF:diskConfig": "AUTO", "personality": [ { "path": "/root/.csivh", "contents": "VGhpcyBpcyBhIHRlc3QgZmlsZS4=" } ], "networks": [ { "uuid": "11111111-1111-1111-1111-111111111111" }, { "uuid": "00000000-0000-0000-0000-000000000000" } ], "metadata": { "build_config": "core", "meta_key_1": "meta_value_1", "meta_key_2": "meta_value_2" } } }, "type": "launch_server" }, "groupConfiguration": { "maxEntities": 10, "cooldown": 360, "name": "testscalinggroup198547", "minEntities": 0, "metadata": { "gc_meta_key_2": "gc_meta_value_2", "gc_meta_key_1": "gc_meta_value_1" } }, "state": { "active": [], "activeCapacity": 0, "desiredCapacity": 0, "paused": false, "pendingCapacity": 0, "name": "testscalinggroup198547" }, "scalingPolicies": [ { "name": "scale up by 1", "links": [ { "href": "https://ord.autoscale.api.rackspacecloud.com/ v1.0/829409/groups/6791761b-821a-4d07-820d-0b2afc7dd7f6/ policies/dceb14ac-b2b3-4f06-aac9-a5b6cd5d40e1/", "rel": "self" } ], "cooldown": 0, "type": "webhook", "id": "dceb14ac-b2b3-4f06-aac9-a5b6cd5d40e1", "change": 1 } ], "links": [ { "href": "https://ord.autoscale.api.rackspacecloud.com/ v1.0/829409/groups/6791761b-821a-4d07-820d-0b2afc7dd7f6/", "rel": "self" } ], "id": "6791761b-821a-4d07-820d-0b2afc7dd7f6" } } """ data['groupConfiguration'].setdefault('maxEntities', MAX_ENTITIES) data['groupConfiguration'].setdefault('metadata', {}) if data['groupConfiguration']['minEntities'] > data['groupConfiguration']['maxEntities']: raise InvalidMinEntities("minEntities must be less than or equal to maxEntities") deferred = get_supervisor().validate_launch_config( self.log, self.tenant_id, data['launchConfiguration']) deferred.addCallback( lambda _: self.store.create_scaling_group(self.log, self.tenant_id, data['groupConfiguration'], data['launchConfiguration'], data.get('scalingPolicies', None))) def _do_obey_config_change(result): group_id = result['id'] config = result['groupConfiguration'] group = self.store.get_scaling_group(self.log, self.tenant_id, group_id) d = group.modify_state(partial(controller.obey_config_change, self.log, transaction_id(request), config)) return d.addCallback(lambda _: result) deferred.addCallback(_do_obey_config_change) def _add_to_bobby(result, client): d = client.create_group(self.tenant_id, result['id']) return d.addCallback(lambda _: result) bobby = get_bobby() if bobby is not None: deferred.addCallback(_add_to_bobby, bobby) def _format_output(result): uuid = result['id'] result["state"] = format_state_dict(result["state"]) request.setHeader( "Location", get_autoscale_links(self.tenant_id, uuid, format=None)) result["links"] = get_autoscale_links(self.tenant_id, uuid) linkify_policy_list(result['scalingPolicies'], self.tenant_id, uuid) result['scalingPolicies_links'] = get_policies_links( result['scalingPolicies'], self.tenant_id, uuid, rel='policies') return {"group": result} deferred.addCallback(_format_output) deferred.addCallback(json.dumps) return deferred
def create_new_scaling_group(self, request, data): """ Create a new scaling group, given the general scaling group configuration, launch configuration, and optional scaling policies. This data provided in the request body in JSON format. If successful, the created group in JSON format containing id and links is returned. Example request body containing some scaling policies:: { "launchConfiguration": { "args": { "loadBalancers": [ { "port": 8080, "loadBalancerId": 9099 } ], "server": { "name": "autoscale_server", "imageRef": "0d589460-f177-4b0f-81c1-8ab8903ac7d8", "flavorRef": "2", "OS-DCF:diskConfig": "AUTO", "metadata": { "meta_key_1": "meta_value_1", "meta_key_2": "meta_value_2" }, "networks": [ { "uuid": "11111111-1111-1111-1111-111111111111" }, { "uuid": "00000000-0000-0000-0000-000000000000" } ], "personality": [ { "path": "/root/.csivh", "contents": "VGhpcyBpcyBhIHRlc3QgZmlsZS4=" } ] } }, "type": "launch_server" }, "groupConfiguration": { "maxEntities": 10, "cooldown": 360, "name": "testscalinggroup198547", "minEntities": 0, "metadata": { "gc_meta_key_2": "gc_meta_value_2", "gc_meta_key_1": "gc_meta_value_1" } }, "scalingPolicies": [ { "cooldown": 0, "type": "webhook", "name": "scale up by 1", "change": 1 } ] } The ``scalingPolicies`` attribute can also be an empty list, or just left out entirely. Example response body to the above request:: { "group": { "launchConfiguration": { "args": { "loadBalancers": [ { "port": 8080, "loadBalancerId": 9099 } ], "server": { "name": "autoscale_server", "imageRef": "0d589460-f177-4b0f-81c1-8ab8903ac7d8", "flavorRef": "2", "OS-DCF:diskConfig": "AUTO", "personality": [ { "path": "/root/.csivh", "contents": "VGhpcyBpcyBhIHRlc3QgZmlsZS4=" } ], "networks": [ { "uuid": "11111111-1111-1111-1111-111111111111" }, { "uuid": "00000000-0000-0000-0000-000000000000" } ], "metadata": { "meta_key_1": "meta_value_1", "meta_key_2": "meta_value_2" } } }, "type": "launch_server" }, "groupConfiguration": { "maxEntities": 10, "cooldown": 360, "name": "testscalinggroup198547", "minEntities": 0, "metadata": { "gc_meta_key_2": "gc_meta_value_2", "gc_meta_key_1": "gc_meta_value_1" } }, "state": { "active": [], "activeCapacity": 0, "desiredCapacity": 0, "paused": false, "pendingCapacity": 0, "name": "testscalinggroup198547" }, "scalingPolicies": [ { "name": "scale up by 1", "links": [ { "href": "https://ord.autoscale.api.rackspacecloud.com/ v1.0/829409/groups/6791761b-821a-4d07-820d-0b2afc7dd7f6/ policies/dceb14ac-b2b3-4f06-aac9-a5b6cd5d40e1/", "rel": "self" } ], "cooldown": 0, "type": "webhook", "id": "dceb14ac-b2b3-4f06-aac9-a5b6cd5d40e1", "change": 1 } ], "links": [ { "href": "https://ord.autoscale.api.rackspacecloud.com/ v1.0/829409/groups/6791761b-821a-4d07-820d-0b2afc7dd7f6/", "rel": "self" } ], "id": "6791761b-821a-4d07-820d-0b2afc7dd7f6" } } """ group_cfg = data['groupConfiguration'] group_cfg.setdefault('maxEntities', MAX_ENTITIES) group_cfg.setdefault('metadata', {}) if group_cfg['minEntities'] > group_cfg['maxEntities']: raise InvalidMinEntities( "minEntities must be less than or equal to maxEntities") if data['launchConfiguration']['type'] == 'launch_server': validate_launch_config_servicenet(data['launchConfiguration']) deferred = get_supervisor().validate_launch_config( self.log, self.tenant_id, data['launchConfiguration']) deferred.addCallback( lambda _: self.store.create_scaling_group( self.log, self.tenant_id, group_cfg, normalize_launch_config(data['launchConfiguration']), data.get('scalingPolicies', None))) def _do_obey_config_change(result): group_id = result['id'] config = result['groupConfiguration'] launch = result['launchConfiguration'] group = self.store.get_scaling_group( self.log, self.tenant_id, group_id) log = self.log.bind(scaling_group_id=group_id) d = controller.modify_and_trigger( self.dispatcher, group, bound_log_kwargs(log), partial( controller.obey_config_change, log, transaction_id(request), config, launch_config=launch), modify_state_reason='create_new_scaling_group') return d.addCallback(lambda _: result) deferred.addCallback(_do_obey_config_change) def _add_to_bobby(result, client): d = client.create_group(self.tenant_id, result['id']) return d.addCallback(lambda _: result) bobby = get_bobby() if bobby is not None: deferred.addCallback(_add_to_bobby, bobby) def _format_output(result): uuid = result['id'] result["state"] = format_state_dict(result["state"]) request.setHeader( "Location", get_autoscale_links(self.tenant_id, uuid, format=None)) result["links"] = get_autoscale_links(self.tenant_id, uuid) linkify_policy_list( result['scalingPolicies'], self.tenant_id, uuid) result['scalingPolicies_links'] = get_policies_links( result['scalingPolicies'], self.tenant_id, uuid, rel='policies') return {"group": result} deferred.addCallback(_format_output) deferred.addCallback(json.dumps) return deferred
def launch_server(log, region, scaling_group, service_catalog, auth_token, launch_config, undo): """ Launch a new server given the launch config auth tokens and service catalog. Possibly adding the newly launched server to a load balancer. :param BoundLog log: A bound logger. :param str region: A rackspace region as found in the service catalog. :param IScalingGroup scaling_group: The scaling group to add the launched server to. :param list service_catalog: A list of services as returned by the auth apis. :param str auth_token: The user's auth token. :param dict launch_config: A launch_config args structure as defined for the launch_server_v1 type. :param IUndoStack undo: The stack that will be rewound if undo fails. :return: Deferred that fires with a 2-tuple of server details and the list of load balancer responses from add_to_load_balancers. """ launch_config = prepare_launch_config(scaling_group.uuid, launch_config) lb_region = config_value('regionOverrides.cloudLoadBalancers') or region cloudLoadBalancers = config_value('cloudLoadBalancers') cloudServersOpenStack = config_value('cloudServersOpenStack') lb_endpoint = public_endpoint_url(service_catalog, cloudLoadBalancers, lb_region) server_endpoint = public_endpoint_url(service_catalog, cloudServersOpenStack, region) lb_config = launch_config.get('loadBalancers', []) server_config = launch_config['server'] log = log.bind(server_name=server_config['name']) ilog = [None] d = create_server(server_endpoint, auth_token, server_config, log=log) def wait_for_server(server): server_id = server['server']['id'] undo.push( verified_delete, log, server_endpoint, auth_token, server_id) ilog[0] = log.bind(server_id=server_id) return wait_for_active( ilog[0], server_endpoint, auth_token, server_id) d.addCallback(wait_for_server) def add_lb(server): ip_address = private_ip_addresses(server)[0] lbd = add_to_load_balancers( ilog[0], lb_endpoint, auth_token, lb_config, ip_address, undo) lbd.addCallback(lambda lb_response: (server, lb_response)) return lbd d.addCallback(add_lb) def _add_to_bobby(result, client): server, lb_response = result d = client.create_server(scaling_group.tenant_id, scaling_group.uuid, server["server"]["id"]) return d.addCallback(lambda _: result) from otter.rest.bobby import get_bobby bobby = get_bobby() if bobby is not None: d.addCallback(_add_to_bobby, bobby) return d
def create_policies(self, request, data, audit_logger): """ Create one or many new scaling policies. Scaling policies must include a name, type, adjustment, and cooldown. The response header will point to the list policies endpoint. An array of scaling policies is provided in the request body in JSON format. Example request:: [ { "name": "scale up by one server", "change": 1, "cooldown": 150 }, { "name": 'scale down by 5.5 percent', "changePercent": -5.5, "cooldown": 6 } ] Example response:: { "policies": [ { "id": {policyId1}, "links": [ { "href": "{url_root}/v1.0/010101/groups/{groupId}/policy/{policyId1}/" "rel": "self" } ], "name": "scale up by one server", "change": 1, "cooldown": 150 }, { "id": {policyId2}, "links": [ { "href": "{url_root}/v1.0/010101/groups/{groupId}/policy/{policyId2}/" "rel": "self" } ], "name": 'scale down by 5.5 percent', "changePercent": -5.5, "cooldown": 6 } ] } """ def format_policies_and_send_redirect(policy_list): request.setHeader( "Location", get_autoscale_links(self.tenant_id, self.scaling_group_id, "", format=None)) linkify_policy_list(policy_list, self.tenant_id, self.scaling_group_id) return {'policies': policy_list} def _add_to_bobby(policy_list, client): d = defer.succeed(policy_list) for policy_item in policy_list: if policy_item['type'] == 'cloud_monitoring': client.create_policy( self.tenant_id, self.scaling_group_id, policy_item['id'], policy_item['args']['check'], policy_item['args']['alarm_criteria']['criteria']) return d.addCallback(lambda _: policy_list) from otter.rest.bobby import get_bobby bobby = get_bobby() e = extra_policy_validation(data, bobby) if e is not None: return defer.fail(e) rec = self.store.get_scaling_group(self.log, self.tenant_id, self.scaling_group_id) deferred = rec.create_policies(data) if bobby is not None: deferred.addCallback(_add_to_bobby, bobby) deferred.addCallback(format_policies_and_send_redirect) def audit_data(result): audit_logger.add(data=result) return result deferred.addCallback(audit_data) deferred.addCallback(json.dumps) return deferred