Example #1
0
    def edit_launch_config(self, request, data):
        """
        Edit the launch configuration for a scaling group, which includes the
        details of how to create a server, from what image, which load
        balancers to join it to, and what networks to add it to, and other
        metadata.  This data provided in the request body in JSON format.  If
        successful, no response body will be returned.

        Example request::

            {
                "type": "launch_server",
                "args": {
                    "server": {
                        "flavorRef": 3,
                        "name": "webhead",
                        "imageRef": "0d589460-f177-4b0f-81c1-8ab8903ac7d8",
                        "OS-DCF:diskConfig": "AUTO",
                        "metadata": {
                            "mykey": "myvalue"
                        },
                        "personality": [
                            {
                                "path": '/root/.ssh/authorized_keys',
                                "contents": "ssh-rsa A... [email protected]"
                            }
                        ],
                        "networks": [
                            {
                                "uuid": "11111111-1111-1111-1111-111111111111"
                            }
                        ],
                    },
                    "loadBalancers": [
                        {
                            "loadBalancerId": 2200,
                            "port": 8081
                        }
                    ]
                }
            }

        The exact update cases are still up in the air -- can the user provide
        a mimimal schema, and if so, what happens with defaults?

        Nova should validate the image before saving the new config.
        Users may have an invalid configuration based on dependencies.
        """
        rec = self.store.get_scaling_group(
            self.log, self.tenant_id, self.group_id)
        data = normalize_launch_config(data)
        group_schemas.validate_launch_config_servicenet(data)
        deferred = get_supervisor().validate_launch_config(
            self.log, self.tenant_id, data)
        deferred.addCallback(lambda _: rec.update_launch_config(data))
        return deferred
Example #2
0
 def test_servicenet_validation_succeeds_if_rackconnect_but_no_network_info(self):
     """
     If only RackConnect LBs are confgured on the launch configuration, and
     no ServiceNet is supplied, that's still ok because RackConnect does not
     need ServiceNet so validation succeeds.
     """
     good_schema = {
         "server": {"networks": [{'uuid': "00000000-0000-0000-0000-000000000000"}]},
         "loadBalancers": [{'loadBalancerId': '1234', 'type': 'RackConnectV3'}]
     }
     self.assertIsNone(
         group_schemas.validate_launch_config_servicenet(
             {'type': 'launch_server', 'args': good_schema}))
Example #3
0
 def test_servicenet_validation_succeeds_if_clbs_but_no_network_info(self):
     """
     If CLBs are confgured on the launch configuration, but no network
     configuration is supplied, Nova sets up both ServiceNet and public
     network, so validation succeeds.
     """
     good_schema = {
         "server": {},
         "loadBalancers": [{'loadBalancerId': 1, "port": 80}]
     }
     self.assertIsNone(
         group_schemas.validate_launch_config_servicenet(
             {'type': 'launch_server', 'args': good_schema}))
Example #4
0
 def test_servicenet_validation_succeeds_if_clbs_and_servicenet(self):
     """
     If CLBs are confgured on the launch configuration, but and ServiceNet
     is specifically provided, validation succeeds
     """
     good_schema = {
         "server": {"networks": [
             {'uuid': "00000000-0000-0000-0000-000000000000"},
             {'uuid': "11111111-1111-1111-1111-111111111111"}]},
         "loadBalancers": [{'loadBalancerId': 1, "port": 80}]
     }
     self.assertIsNone(
         group_schemas.validate_launch_config_servicenet(
             {'type': 'launch_server', 'args': good_schema}))
Example #5
0
    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")

        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
Example #6
0
    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