diff --git a/api-ref/source/samples/instance-create-response.json b/api-ref/source/samples/instance-create-response.json index 3a7c6ca07f..14edc0aa79 100644 --- a/api-ref/source/samples/instance-create-response.json +++ b/api-ref/source/samples/instance-create-response.json @@ -6,17 +6,7 @@ "version": "5.7" }, "flavor": { - "id": "6", - "links": [ - { - "href": "https://127.0.0.1:8779/v1.0/9f8dd5eacb074c9f87d2d822c9092aa5/flavors/6", - "rel": "self" - }, - { - "href": "https://127.0.0.1:8779/flavors/6", - "rel": "bookmark" - } - ] + "id": "6" }, "id": "b76a6a76-748b-4064-adec-4c9e6c9abd68", "links": [ diff --git a/api-ref/source/samples/instance-list-detail-response.json b/api-ref/source/samples/instance-list-detail-response.json index 619c87bf9a..f253c0997e 100644 --- a/api-ref/source/samples/instance-list-detail-response.json +++ b/api-ref/source/samples/instance-list-detail-response.json @@ -17,17 +17,7 @@ "version": "5.7" }, "flavor": { - "id": "6", - "links": [ - { - "href": "https://127.0.0.1:8779/v1.0/9f8dd5eacb074c9f87d2d822c9092aa5/flavors/6", - "rel": "self" - }, - { - "href": "https://127.0.0.1:8779/flavors/6", - "rel": "bookmark" - } - ] + "id": "6" }, "id": "7de1bed8-6983-4d46-9a52-0abfbb0d27a2", "ip": [ @@ -65,17 +55,7 @@ "message": "Failed to create User port for instance b76a6a76-748b-4064-adec-4c9e6c9abd68" }, "flavor": { - "id": "6", - "links": [ - { - "href": "https://127.0.0.1:8779/v1.0/9f8dd5eacb074c9f87d2d822c9092aa5/flavors/6", - "rel": "self" - }, - { - "href": "https://127.0.0.1:8779/flavors/6", - "rel": "bookmark" - } - ] + "id": "6" }, "id": "b76a6a76-748b-4064-adec-4c9e6c9abd68", "links": [ diff --git a/api-ref/source/samples/instance-list-response.json b/api-ref/source/samples/instance-list-response.json index 35b1964ab7..df995aa17f 100644 --- a/api-ref/source/samples/instance-list-response.json +++ b/api-ref/source/samples/instance-list-response.json @@ -6,17 +6,7 @@ "version": "5.7" }, "flavor": { - "id": "6", - "links": [ - { - "href": "https://127.0.0.1:8779/v1.0/9f8dd5eacb074c9f87d2d822c9092aa5/flavors/6", - "rel": "self" - }, - { - "href": "https://127.0.0.1:8779/flavors/6", - "rel": "bookmark" - } - ] + "id": "6" }, "id": "7de1bed8-6983-4d46-9a52-0abfbb0d27a2", "ip": [ diff --git a/api-ref/source/samples/instance-mgmt-list-response.json b/api-ref/source/samples/instance-mgmt-list-response.json index f67e63253a..17ec62c2f5 100644 --- a/api-ref/source/samples/instance-mgmt-list-response.json +++ b/api-ref/source/samples/instance-mgmt-list-response.json @@ -20,17 +20,7 @@ "deleted_at": null, "encrypted_rpc_messaging": true, "flavor": { - "id": "d2", - "links": [ - { - "href": "https://127.0.0.1:8779/v1.0/2afa58fd5db34fd8b7b659d997a5341f/flavors/d2", - "rel": "self" - }, - { - "href": "https://127.0.0.1:8779/flavors/d2", - "rel": "bookmark" - } - ] + "id": "d2" }, "id": "7de1bed8-6983-4d46-9a52-0abfbb0d27a2", "ip": [ @@ -82,17 +72,7 @@ "message": "Failed to create User port for instance b76a6a76-748b-4064-adec-4c9e6c9abd68" }, "flavor": { - "id": "6", - "links": [ - { - "href": "https://127.0.0.1:8779/v1.0/2afa58fd5db34fd8b7b659d997a5341f/flavors/6", - "rel": "self" - }, - { - "href": "https://127.0.0.1:8779/flavors/6", - "rel": "bookmark" - } - ] + "id": "6" }, "id": "b76a6a76-748b-4064-adec-4c9e6c9abd68", "links": [ diff --git a/api-ref/source/samples/instance-mgmt-show-response.json b/api-ref/source/samples/instance-mgmt-show-response.json index eea90bc9bb..9ca5bd9c48 100644 --- a/api-ref/source/samples/instance-mgmt-show-response.json +++ b/api-ref/source/samples/instance-mgmt-show-response.json @@ -19,17 +19,7 @@ "deleted_at": null, "encrypted_rpc_messaging": true, "flavor": { - "id": "d2", - "links": [ - { - "href": "https://127.0.0.1:8779/v1.0/2afa58fd5db34fd8b7b659d997a5341f/flavors/d2", - "rel": "self" - }, - { - "href": "https://127.0.0.1:8779/flavors/d2", - "rel": "bookmark" - } - ] + "id": "d2" }, "guest_status": { "state_description": "healthy" diff --git a/api-ref/source/samples/instance-show-response.json b/api-ref/source/samples/instance-show-response.json index 32fa7f8be1..7b60968237 100644 --- a/api-ref/source/samples/instance-show-response.json +++ b/api-ref/source/samples/instance-show-response.json @@ -16,17 +16,7 @@ "version": "5.7" }, "flavor": { - "id": "6", - "links": [ - { - "href": "https://127.0.0.1:8779/v1.0/9f8dd5eacb074c9f87d2d822c9092aa5/flavors/6", - "rel": "self" - }, - { - "href": "https://127.0.0.1:8779/flavors/6", - "rel": "bookmark" - } - ] + "id": "6" }, "id": "7de1bed8-6983-4d46-9a52-0abfbb0d27a2", "ip": [ diff --git a/doc/source/admin/secure_oslo_messaging.rst b/doc/source/admin/secure_oslo_messaging.rst index fd040ddf6b..68553429d3 100644 --- a/doc/source/admin/secure_oslo_messaging.rst +++ b/doc/source/admin/secure_oslo_messaging.rst @@ -658,4 +658,4 @@ In the API response, note that the additional key :: - RESP BODY: {"instance": {"status": "ACTIVE", "updated": "2017-01-09T18:29:00", "name": "m10", "links": [{"href": "https://192.168.126.130:8779/v1.0/56cca8484d3e48869126ada4f355c284/instances/514ef051-0bf7-48a5-adcf-071d4a6625fb", "rel": "self"}, {"href": "https://192.168.126.130:8779/instances/514ef051-0bf7-48a5-adcf-071d4a6625fb", "rel": "bookmark"}], "created": "2017-01-09T18:28:56", "region": "RegionOne", "server_id": "2452263e-3d33-48ec-8f24-2851fe74db28", "id": "514ef051-0bf7-48a5-adcf-071d4a6625fb", "volume": {"used": 0.11, "size": 3}, "volume_id": "cee2e17b-80fa-48e5-a488-da8b7809373a", "flavor": {"id": "25", "links": [{"href": "https://192.168.126.130:8779/v1.0/56cca8484d3e48869126ada4f355c284/flavors/25", "rel": "self"}, {"href": "https://192.168.126.130:8779/flavors/25", "rel": "bookmark"}]}, "datastore": {"version": "5.6", "type": "mysql"}, "encrypted_rpc_messaging": false}} + RESP BODY: {"instance": {"status": "ACTIVE", "updated": "2017-01-09T18:29:00", "name": "m10", "links": [{"href": "https://192.168.126.130:8779/v1.0/56cca8484d3e48869126ada4f355c284/instances/514ef051-0bf7-48a5-adcf-071d4a6625fb", "rel": "self"}, {"href": "https://192.168.126.130:8779/instances/514ef051-0bf7-48a5-adcf-071d4a6625fb", "rel": "bookmark"}], "created": "2017-01-09T18:28:56", "region": "RegionOne", "server_id": "2452263e-3d33-48ec-8f24-2851fe74db28", "id": "514ef051-0bf7-48a5-adcf-071d4a6625fb", "volume": {"used": 0.11, "size": 3}, "volume_id": "cee2e17b-80fa-48e5-a488-da8b7809373a", "flavor": {"id": "25"}, "datastore": {"version": "5.6", "type": "mysql"}, "encrypted_rpc_messaging": false}} diff --git a/doc/source/user/backup-db-incremental.rst b/doc/source/user/backup-db-incremental.rst index 8ad0bbb5dd..7a296f5881 100644 --- a/doc/source/user/backup-db-incremental.rst +++ b/doc/source/user/backup-db-incremental.rst @@ -113,11 +113,7 @@ Create and use incremental backups | created | 2014-03-19T14:10:56 | | datastore | {u'version': u'mysql-5.5', u'type': u'mysql'} | | datastore_version | mysql-5.5 | - | flavor | {u'id': u'10', u'links': | - | | [{u'href': u'https://10.125.1.135:8779/v1.0/ | - | | 626734041baa4254ae316de52a20b390/flavors/10', u'rel': | - | | u'self'}, {u'href': u'https://10.125.1.135:8779/ | - | | flavors/10', u'rel': u'bookmark'}]} | + | flavor | {u'id': u'10'} | | id | a3680953-eea9-4cf2-918b-5b8e49d7e1b3 | | name | guest2 | | status | BUILD | diff --git a/trove/cluster/views.py b/trove/cluster/views.py index 174ac14fed..8c3b559ae6 100644 --- a/trove/cluster/views.py +++ b/trove/cluster/views.py @@ -102,10 +102,7 @@ class ClusterView(object): return None def _build_flavor_info(self, flavor_id): - return { - "id": flavor_id, - "links": create_links("flavors", self.req, flavor_id) - } + return {"id": flavor_id} class ClusterInstanceDetailView(InstanceDetailView): diff --git a/trove/common/api.py b/trove/common/api.py index 5dfa0935f7..0bfdf0d960 100644 --- a/trove/common/api.py +++ b/trove/common/api.py @@ -20,7 +20,6 @@ from trove.common import wsgi from trove.configuration.service import ConfigurationsController from trove.configuration.service import ParametersController from trove.datastore.service import DatastoreController -from trove.flavor.service import FlavorController from trove.instance.service import InstanceController from trove.limits.service import LimitsController from trove.module.service import ModuleController @@ -35,7 +34,6 @@ class API(wsgi.Router): self._instance_router(mapper) self._cluster_router(mapper) self._datastore_router(mapper) - self._flavor_router(mapper) self._versions_router(mapper) self._limits_router(mapper) self._backups_router(mapper) @@ -168,17 +166,6 @@ class API(wsgi.Router): action="delete", conditions={'method': ['DELETE']}) - def _flavor_router(self, mapper): - flavor_resource = FlavorController().create_resource() - mapper.connect("/{tenant_id}/flavors", - controller=flavor_resource, - action="index", - conditions={'method': ['GET']}) - mapper.connect("/{tenant_id}/flavors/{id}", - controller=flavor_resource, - action="show", - conditions={'method': ['GET']}) - def _limits_router(self, mapper): limits_resource = LimitsController().create_resource() mapper.connect("/{tenant_id}/limits", diff --git a/trove/flavor/service.py b/trove/flavor/service.py deleted file mode 100644 index 60e879359c..0000000000 --- a/trove/flavor/service.py +++ /dev/null @@ -1,54 +0,0 @@ -# Copyright 2010-2012 OpenStack Foundation -# 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 six - -from trove.common import exception -from trove.common import policy -from trove.common import wsgi -from trove.flavor import models -from trove.flavor import views - - -class FlavorController(wsgi.Controller): - """Controller for flavor functionality.""" - - def show(self, req, tenant_id, id): - """Return a single flavor.""" - context = req.environ[wsgi.CONTEXT_KEY] - self._validate_flavor_id(id) - flavor = models.Flavor(context=context, flavor_id=id) - # Flavors do not bind to a particular tenant. - # Only authorize the current tenant. - policy.authorize_on_tenant(context, 'flavor:show') - # Pass in the request to build accurate links. - return wsgi.Result(views.FlavorView(flavor, req).data(), 200) - - def index(self, req, tenant_id): - """Return all flavors.""" - context = req.environ[wsgi.CONTEXT_KEY] - policy.authorize_on_tenant(context, 'flavor:index') - flavors = models.Flavors(context=context) - return wsgi.Result(views.FlavorsView(flavors, req).data(), 200) - - def _validate_flavor_id(self, id): - if isinstance(id, six.string_types): - return - try: - if int(id) != float(id): - raise exception.NotFound(uuid=id) - except ValueError: - raise exception.NotFound(uuid=id) diff --git a/trove/instance/views.py b/trove/instance/views.py index 92fd0a58e3..ba02ebca08 100644 --- a/trove/instance/views.py +++ b/trove/instance/views.py @@ -72,13 +72,8 @@ class InstanceView(object): def _build_flavor_info(self): return { "id": self.instance.flavor_id, - "links": self._build_flavor_links() } - def _build_flavor_links(self): - return create_links("flavors", self.req, - self.instance.flavor_id) - def _build_master_info(self): return { "id": self.instance.slave_of_id, diff --git a/trove/tests/api/instances.py b/trove/tests/api/instances.py index 998529f8ca..8bf2c7954a 100644 --- a/trove/tests/api/instances.py +++ b/trove/tests/api/instances.py @@ -36,6 +36,7 @@ from trove.common.utils import poll_until from trove.datastore import models as datastore_models from trove import tests from trove.tests.config import CONFIG +from trove.tests import util from trove.tests.util.check import AttrCheck from trove.tests.util import create_dbaas_client from trove.tests.util import test_config @@ -88,6 +89,7 @@ class InstanceTestInfo(object): self.user_context = None # A regular user context self.users = None # The users created on the instance. self.consumer = create_usage_verifier() + self.flavors = None # The cache of Nova flavors. def find_default_flavor(self): if EPHEMERAL_SUPPORT: @@ -96,15 +98,17 @@ class InstanceTestInfo(object): else: flavor_name = CONFIG.values.get('instance_flavor_name', 'm1.tiny') - flavors = self.dbaas.find_flavors_by_name(flavor_name) - assert_equal(len(flavors), 1, - "Number of flavors with name '%s' " - "found was '%d'." % (flavor_name, len(flavors))) + flavor = None + flavor_href = None - flavor = flavors[0] - flavor_href = self.dbaas.find_flavor_self_href(flavor) - assert_true(flavor_href is not None, - "Flavor href '%s' not found!" % flavor_name) + for item in self.flavors: + if item.name == flavor_name: + flavor = item + flavor_href = item.id + break + + asserts.assert_is_not_none(flavor) + asserts.assert_is_not_none(flavor_href) return flavor, flavor_href @@ -190,11 +194,10 @@ class CheckInstance(AttrCheck): if 'flavor' not in self.instance: self.fail("'flavor' not found in instance.") else: - allowed_attrs = ['id', 'links'] + allowed_attrs = ['id'] self.contains_allowed_attrs( self.instance['flavor'], allowed_attrs, msg="Flavor") - self.links(self.instance['flavor']['links']) def datastore(self): if 'datastore' not in self.instance: @@ -315,6 +318,10 @@ class TestInstanceSetup(object): instance_info.user = CONFIG.users.find_user(reqs) instance_info.dbaas = create_dbaas_client(instance_info.user) + + instance_info.nova_client = util.create_nova_client(instance_info.user) + instance_info.flavors = instance_info.nova_client.flavors.list() + global dbaas dbaas = instance_info.dbaas @@ -563,10 +570,16 @@ class CreateInstanceFail(object): instance_name = "instance-failure-with-no-ephemeral-flavor" databases = [] flavor_name = CONFIG.values.get('instance_flavor_name', 'm1.tiny') - flavors = dbaas.find_flavors_by_name(flavor_name) + + flavor_id = None + for item in instance_info.flavors: + if item.name == flavor_name: + flavor_id = item.id + + asserts.assert_is_not_none(flavor_id) assert_raises(exceptions.BadRequest, dbaas.instances.create, - instance_name, flavors[0].id, None, databases, + instance_name, flavor_id, None, databases, nics=instance_info.nics) assert_equal(400, dbaas.last_http_code) diff --git a/trove/tests/api/instances_actions.py b/trove/tests/api/instances_actions.py index 456de72209..d6b192e7cb 100644 --- a/trove/tests/api/instances_actions.py +++ b/trove/tests/api/instances_actions.py @@ -367,11 +367,6 @@ class ResizeInstanceTest(ActionTestBase): def flavor_id(self): return instance_info.dbaas_flavor_href - def get_flavor_href(self, flavor_id=2): - res = instance_info.dbaas.find_flavor_and_self_href(flavor_id) - _, dbaas_flavor_href = res - return dbaas_flavor_href - def wait_for_resize(self): def is_finished_resizing(): instance = self.instance @@ -399,7 +394,12 @@ class ResizeInstanceTest(ActionTestBase): def test_instance_resize_to_ephemeral_in_volume_support_should_fail(self): flavor_name = CONFIG.values.get('instance_bigger_eph_flavor_name', 'eph.rd-smaller') - flavors = self.dbaas.find_flavors_by_name(flavor_name) + flavor_id = None + for item in instance_info.flavors: + if item.name == flavor_name: + flavor_id = item.id + + asserts.assert_is_not_none(flavor_id) def is_active(): return self.instance.status in CONFIG.running_status @@ -409,36 +409,42 @@ class ResizeInstanceTest(ActionTestBase): asserts.assert_raises(HTTPNotImplemented, self.dbaas.instances.resize_instance, - self.instance_id, flavors[0].id) + self.instance_id, flavor_id) @test(enabled=EPHEMERAL_SUPPORT) def test_instance_resize_to_non_ephemeral_flavor_should_fail(self): flavor_name = CONFIG.values.get('instance_bigger_flavor_name', 'm1-small') - flavors = self.dbaas.find_flavors_by_name(flavor_name) + flavor_id = None + for item in instance_info.flavors: + if item.name == flavor_name: + flavor_id = item.id + + asserts.assert_is_not_none(flavor_id) asserts.assert_raises(BadRequest, self.dbaas.instances.resize_instance, - self.instance_id, flavors[0].id) + self.instance_id, flavor_id) def obtain_flavor_ids(self): old_id = self.instance.flavor['id'] self.expected_old_flavor_id = old_id - res = instance_info.dbaas.find_flavor_and_self_href(old_id) - self.expected_dbaas_flavor, _ = res if EPHEMERAL_SUPPORT: flavor_name = CONFIG.values.get('instance_bigger_eph_flavor_name', 'eph.rd-smaller') else: flavor_name = CONFIG.values.get('instance_bigger_flavor_name', 'm1.small') - flavors = self.dbaas.find_flavors_by_name(flavor_name) - asserts.assert_equal(len(flavors), 1, - "Number of flavors with name '%s' " - "found was '%d'." % (flavor_name, - len(flavors))) - flavor = flavors[0] + + new_flavor = None + for item in instance_info.flavors: + if item.name == flavor_name: + new_flavor = item + break + + asserts.assert_is_not_none(new_flavor) + self.old_dbaas_flavor = instance_info.dbaas_flavor - instance_info.dbaas_flavor = flavor - self.expected_new_flavor_id = flavor.id + instance_info.dbaas_flavor = new_flavor + self.expected_new_flavor_id = new_flavor.id @test(depends_on=[test_instance_resize_same_size_should_fail]) def test_status_changed_to_resize(self): @@ -447,14 +453,14 @@ class ResizeInstanceTest(ActionTestBase): self.obtain_flavor_ids() self.dbaas.instances.resize_instance( self.instance_id, - self.get_flavor_href(flavor_id=self.expected_new_flavor_id)) + self.expected_new_flavor_id) asserts.assert_equal(202, self.dbaas.last_http_code) # (WARNING) IF THE RESIZE IS WAY TOO FAST THIS WILL FAIL assert_unprocessable( self.dbaas.instances.resize_instance, self.instance_id, - self.get_flavor_href(flavor_id=self.expected_new_flavor_id)) + self.expected_new_flavor_id) @test(depends_on=[test_status_changed_to_resize]) @time_out(TIME_OUT_TIME) @@ -493,9 +499,8 @@ class ResizeInstanceTest(ActionTestBase): @test(depends_on=[test_make_sure_mysql_is_running_after_resize]) def test_instance_has_new_flavor_after_resize(self): - actual = self.get_flavor_href(self.instance.flavor['id']) - expected = self.get_flavor_href(flavor_id=self.expected_new_flavor_id) - asserts.assert_equal(actual, expected) + actual = self.instance.flavor['id'] + asserts.assert_equal(actual, self.expected_new_flavor_id) @test(depends_on_classes=[ResizeInstanceTest], diff --git a/trove/tests/examples/__init__.py b/trove/tests/examples/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/trove/tests/examples/client.py b/trove/tests/examples/client.py deleted file mode 100644 index 06c99f563b..0000000000 --- a/trove/tests/examples/client.py +++ /dev/null @@ -1,293 +0,0 @@ -# Copyright 2014 Rackspace -# -# 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 json -import os -import re -import time - -from proboscis.asserts import fail -from six.moves.urllib.parse import urlparse -from troveclient.compat.client import TroveHTTPClient - -from trove.tests.config import CONFIG - -print_req = True - - -def shorten_url(url): - parsed = urlparse(url) - if parsed.query: - method_url = parsed.path + '?' + parsed.query - else: - method_url = parsed.path - return method_url - - -class SnippetWriter(object): - - def __init__(self, conf, get_replace_list): - self.conf = conf - self.get_replace_list = get_replace_list - - def output_request(self, user_details, name, url, output_headers, body, - content_type, method, static_auth_token=True): - headers = [] - parsed = urlparse(url) - method_url = shorten_url(url) - headers.append("%s %s HTTP/1.1" % (method, method_url)) - headers.append("User-Agent: %s" % output_headers['User-Agent']) - headers.append("Host: %s" % parsed.netloc) - # static_auth_token option for documentation purposes - if static_auth_token: - output_token = '87c6033c-9ff6-405f-943e-2deb73f278b7' - else: - output_token = output_headers['X-Auth-Token'] - headers.append("X-Auth-Token: %s" % output_token) - headers.append("Accept: %s" % output_headers['Accept']) - print("OUTPUT HEADERS: %s" % output_headers) - headers.append("Content-Type: %s" % output_headers['Content-Type']) - self.write_file(user_details, name, "-%s-http.txt" % content_type, url, - method, "request", output='\n'.join(headers)) - - pretty_body = self.format_body(body, content_type) - self.write_file(user_details, name, ".%s" % content_type, url, - method, "request", output=pretty_body) - - def output_response(self, user_details, name, content_type, url, method, - resp, body): - version = "1.1" # if resp.version == 11 else "1.0" - lines = [ - ["HTTP/%s %s %s" % (version, resp.status, resp.reason)], - ["Content-Type: %s" % resp['content-type']], - ] - if 'via' in resp: - lines.append(["Via: %s" % resp['via']]) - lines.append(["Content-Length: %s" % resp['content-length']]) - lines.append(["Date: Mon, 18 Mar 2013 19:09:17 GMT"]) - if 'server' in resp: - lines.append(["Server: %s" % resp["server"]]) - - new_lines = [x[0] for x in lines] - joined_lines = '\n'.join(new_lines) - - self.write_file(user_details, name, "-%s-http.txt" % content_type, url, - method, "response", output=joined_lines) - - if body: - pretty_body = self.format_body(body, content_type) - self.write_file(user_details, name, ".%s" % content_type, url, - method, "response", output=pretty_body) - - def format_body(self, body, content_type): - assert content_type == 'json' - try: - if self.conf['replace_dns_hostname']: - before = r'\"hostname\": \"[a-zA-Z0-9-_\.]*\"' - after = '\"hostname\": \"%s\"' % self.conf[ - 'replace_dns_hostname'] - body = re.sub(before, after, body) - return json.dumps(json.loads(body), sort_keys=True, indent=4) - except Exception: - return body or '' - - def write_request_file(self, user_details, name, content_type, url, method, - req_headers, request_body): - if print_req: - print("\t%s req url:%s" % (content_type, url)) - print("\t%s req method:%s" % (content_type, method)) - print("\t%s req headers:%s" % (content_type, req_headers)) - print("\t%s req body:%s" % (content_type, request_body)) - self.output_request(user_details, name, url, req_headers, request_body, - content_type, method) - - def write_response_file(self, user_details, name, content_type, url, - method, resp, resp_content): - if print_req: - print("\t%s resp:%s" % (content_type, resp)) - print("\t%s resp content:%s" % (content_type, resp_content)) - self.output_response(user_details, name, content_type, url, method, - resp, resp_content) - - def write_file(self, user_details, name, content_type, url, method, - in_or_out, output): - output = output.replace(user_details['tenant'], '1234') - if self.conf['replace_host']: - output = output.replace(user_details['api_url'], - self.conf['replace_host']) - pre_host_port = urlparse(user_details['service_url']).netloc - post_host = urlparse(self.conf['replace_host']).netloc - output = output.replace(pre_host_port, post_host) - output = output.replace("fake_host", "hostname") - output = output.replace("FAKE_", "") - for resource in self.get_replace_list(): - output = output.replace(str(resource[0]), str(resource[1])) - filename = "%s/db-%s-%s%s" % (self.conf['directory'], - name.replace('_', '-'), in_or_out, - content_type) - self._write_file(filename, output) - - def _write_file(self, filename, output): - empty = len(output.strip()) == 0 - # Manipulate actual data to appease doc niceness checks - actual = [line.rstrip() for line in output.split("\n")] - if not empty and actual[len(actual) - 1] != '': - actual.append("") - - def goofy_diff(a, b): - diff = [] - for i in range(len(a)): - if i < len(b): - if a[i].rstrip() != b[i].rstrip(): - diff.append('Expected line %d :%s\n' - ' Actual line %d :%s' - % (i + 1, a[i], i + 1, b[i])) - else: - diff.append("Expected line %d :%s" % (i + 1, a[i])) - for j in range(len(b) - len(a)): - i2 = len(a) + j - diff.append(" Actual line %d :%s" % (i2 + 1, b[i2])) - return diff - - def write_actual_file(): - # Always write the file. - with open(filename, "w") as file: - for line in actual: - file.write("%s\n" % line) - - def assert_output_matches(): - if os.path.isfile(filename): - with open(filename, 'r') as original_file: - original = original_file.read() - if empty: - fail('Error: output missing in new snippet generation ' - 'for %s. Old content follows:\n"""%s"""' - % (filename, original)) - elif filename.endswith('.json'): - assert_json_matches(original) - else: - assert_file_matches(original) - elif not empty: - fail('Error: new file necessary where there was no file ' - 'before. Filename=%s\nContent follows:\n"""%s"""' - % (filename, output)) - - def assert_file_matches(original): - expected = original.split('\n') - # Remove the last item which will look like a duplicated - # file ending newline - expected.pop() - diff = '\n'.join(goofy_diff(expected, actual)) - if diff: - fail('Error: output files differ for %s:\n%s' - % (filename, diff)) - - def order_json(json_obj): - """Sort the json object so that it can be compared properly.""" - if isinstance(json_obj, list): - return sorted(order_json(elem) for elem in json_obj) - if isinstance(json_obj, dict): - return sorted( - (key, order_json(value)) - for key, value in json_obj.items()) - else: - return json_obj - - def assert_json_matches(original): - try: - expected_json = json.loads(original) - actual_json = json.loads(output) - except ValueError: - fail('Invalid json!\nExpected: %s\nActual: %s' - % (original, output)) - - if order_json(expected_json) != order_json(actual_json): - # Re-Use the same failure output if the json is different - assert_file_matches(original) - - if not os.environ.get('TESTS_FIX_EXAMPLES'): - assert_output_matches() - elif not empty: - write_actual_file() - - -# This method is mixed into the client class. -# It requires the following fields: snippet_writer, content_type, and -# "name," the last of which must be set before each call. -def write_to_snippet(self, args, kwargs, resp, body): - if self.name is None: - raise RuntimeError("'name' not set before call.") - url = args[0] - method = args[1] - request_headers = kwargs['headers'] - request_body = kwargs.get('body', None) - response_headers = resp - response_body = body - - # Log request - user_details = { - 'api_url': self.service_url, - 'service_url': self.service_url, - 'tenant': self.tenant, - } - self.snippet_writer.write_request_file(user_details, self.name, - self.content_type, url, method, - request_headers, request_body) - self.snippet_writer.write_response_file(user_details, self.name, - self.content_type, url, method, - response_headers, response_body) - - # Create a short url to assert against. - short_url = url - base_url = self.service_url - for prefix in (base_url): - if short_url.startswith(prefix): - short_url = short_url[len(prefix):] - self.old_info = { - 'url': shorten_url(short_url), - 'method': method, - 'request_headers': request_headers, - 'request_body': request_body, - 'response_headers': response_headers, - 'response_body': response_body - } - - -def add_fake_response_headers(headers): - """ - Fakes other items that would appear if you were using, just to make up - an example, a proxy. - """ - conf = CONFIG.examples - if 'via' in conf and 'via' not in headers: - headers['via'] = conf['via'] - if 'server' in conf and 'server' not in headers: - headers['server'] = conf['server'] - if 'date' not in headers: - date_string = time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime()) - headers['date'] = date_string - - -class JsonClient(TroveHTTPClient): - - content_type = 'json' - - def http_log(self, args, kwargs, resp, body): - add_fake_response_headers(resp) - self.pretty_log(args, kwargs, resp, body) - - def write_snippet(): - return write_to_snippet(self, args, kwargs, resp, body.decode()) - - self.write_snippet = write_snippet diff --git a/trove/tests/examples/snippets.py b/trove/tests/examples/snippets.py deleted file mode 100644 index 27fc75b353..0000000000 --- a/trove/tests/examples/snippets.py +++ /dev/null @@ -1,1338 +0,0 @@ -# Copyright 2014 Rackspace -# -# 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 functools -import json -import time - -from oslo_log import log as logging -from proboscis import asserts -from proboscis.asserts import assert_equal -from proboscis.asserts import assert_true -from proboscis.asserts import Check -from proboscis import before_class -from proboscis import SkipTest -from proboscis import test -from proboscis import TestProgram -import six -from troveclient.compat import client as trove_client -from troveclient.compat import Dbaas -from troveclient.compat import TroveHTTPClient - -from trove.tests.config import CONFIG -from trove.tests.examples.client import JsonClient -from trove.tests.examples.client import SnippetWriter - -# troveclient.compat.client._logger was changed to LOG in 2.11.0 -if hasattr(trove_client, '_logger'): - trove_client._logger.setLevel(logging.CRITICAL) -elif hasattr(trove_client, 'LOG'): - trove_client.LOG.setLevel(logging.CRITICAL) - -FAKE_INFO = {'m': 30, 's': 0, 'uuid': 'abcdef00-aaaa-aaaa-aaaa-bbbbbbbbbbbb'} -EXAMPLE_BACKUP_ID = "a9832168-7541-4536-b8d9-a8a9b79cf1b4" -EXAMPLE_BACKUP_INCREMENTAL_ID = "2e351a71-dd28-4bcb-a7d6-d36a5b487173" -EXAMPLE_CONFIG_ID = "43a6ea86-e959-4735-9e46-a6a5d4a2d80f" -EXAMPLE_INSTANCE_ID = "44b277eb-39be-4921-be31-3d61b43651d7" -EXAMPLE_INSTANCE_ID_2 = "d5a9db64-7ef7-41c5-8e1e-4013166874bc" -EXAMPLE_CONFIG_SERVER_ID = "271898715" - - -def get_now(): - from datetime import datetime - return datetime(2014, 10, 30, hour=12, minute=FAKE_INFO['m'], - second=FAKE_INFO['s']) - - -def get_uuid(): - return FAKE_INFO['uuid'] - - -def set_fake_stuff(uuid=None, minute=None, unique_id=None): - if uuid: - FAKE_INFO['uuid'] = uuid - if minute: - FAKE_INFO['minute'] = minute - if unique_id: - from trove.common.template import SingleInstanceConfigTemplate - - def fake_calc_id(self): - return unique_id - - SingleInstanceConfigTemplate._calculate_unique_id = fake_calc_id - - -def monkey_patch_uuid_and_date(): - import uuid - uuid.uuid4 = get_uuid - from trove.common import timeutils - from trove.common import utils - timeutils.utcnow = get_now - utils.generate_uuid = get_uuid - - -@test -def load_config_file(): - global conf - if CONFIG.get("examples", None) is None: - fail("Missing 'examples' config in test config.") - conf = CONFIG.examples - global normal_user - normal_user = CONFIG.users.find_user_by_name(conf['normal_user_name']) - global admin_user - admin_user = CONFIG.users.find_user_by_name(conf['admin_user_name']) - - -def create_client_args(user): - - auth_strategy = None - - kwargs = { - 'service_type': 'trove', - 'insecure': CONFIG.values['trove_client_insecure'], - } - - def set_optional(kwargs_name, test_conf_name): - value = CONFIG.values.get(test_conf_name, None) - if value is not None: - kwargs[kwargs_name] = value - - service_url = CONFIG.get('override_trove_api_url', None) - if user.requirements.is_admin: - service_url = CONFIG.get('override_admin_trove_api_url', - service_url) - if service_url: - kwargs['service_url'] = service_url - - auth_strategy = None - if user.requirements.is_admin: - auth_strategy = CONFIG.get('admin_auth_strategy', - CONFIG.auth_strategy) - else: - auth_strategy = CONFIG.auth_strategy - set_optional('region_name', 'trove_client_region_name') - if CONFIG.values.get('override_trove_api_url_append_tenant', - False): - kwargs['service_url'] += "/" + user.tenant - - if auth_strategy == 'fake': - from troveclient.compat import auth - - class FakeAuth(auth.Authenticator): - - def authenticate(self): - class FakeCatalog(object): - def __init__(self, auth): - self.auth = auth - - def get_public_url(self): - return "%s/%s" % (CONFIG.dbaas_url, - self.auth.tenant) - - def get_token(self): - return self.auth.tenant - - return FakeCatalog(self) - - auth_strategy = FakeAuth - - if auth_strategy: - kwargs['auth_strategy'] = auth_strategy - - if not user.requirements.is_admin: - auth_url = CONFIG.trove_auth_url - else: - auth_url = CONFIG.values.get('trove_admin_auth_url', - CONFIG.trove_auth_url) - - if CONFIG.values.get('trove_client_cls'): - cls_name = CONFIG.trove_client_cls - kwargs['client_cls'] = import_class(cls_name) - - kwargs['tenant'] = user.tenant - kwargs['auth_url'] = auth_url - return (user.auth_user, user.auth_key), kwargs - - -def create_client(cls, user): - args, kwargs = create_client_args(user) - kwargs['client_cls'] = cls - client = Dbaas(*args, **kwargs) - return client - - -def make_client(user): - args, kwargs = create_client_args(user) - kwargs['client_cls'] = JsonClient - client = Dbaas(*args, **kwargs) - client.client.name = "auth" - client.authenticate() - return client - - -def write_snippet(get_replace_list, client, name, url, method, status, reason, - func, *func_args): - """ - 'name' is the name of the file, while 'url,' 'method,' 'status,' - and 'reason' are expected values that are asserted against. - If func_args is present, it is a list of lists, each one of which - is passed as the *args to the two invocations of "func". - """ - func_args = func_args or [] - snippet_writer = SnippetWriter(conf, get_replace_list) - results = [] - client.client.snippet_writer = snippet_writer - client.client.name = name - args = func_args - result = func(client, *args) - - # Now write the snippet (if this happens earlier we can't replace - # data such as the instance ID). - client.client.write_snippet() - with Check() as check: - check.equal(client.client.old_info['url'], url) - check.equal(client.client.old_info['method'], method) - check.equal(client.client.old_info['response_headers'].status, - status) - check.equal(client.client.old_info['response_headers'].reason, - reason) - results.append(result) - # To prevent this from writing a snippet somewhere else... - client.client.name = "junk" - - return results - - -JSON_INDEX = 0 - - -class Example(object): - - @classmethod - def get_replace_list(cls): - return [] - - def snippet(self, *args, **kwargs): - return write_snippet(self.get_replace_list, self.client, - *args, **kwargs) - - -@test(depends_on=[load_config_file], enabled=False) -class Versions(Example): - - @before_class - def setup(self): - self.client = make_client(normal_user) - - @test - def get_versions(self): - self.snippet( - "versions", - "", "GET", 200, "OK", - lambda client: client.versions.index(conf['version_url'])) - - @test - def get_version(self): - def version_call(client): - return client.versions.index(conf['version_url'] + "/v1.0/") - - self.snippet("versions", "/v1.0", "GET", 200, "OK", get_version) - - -@test(depends_on=[load_config_file]) -class Flavors(Example): - - @before_class - def setup(self): - self.client = make_client(normal_user) - - @test - def get_flavors(self): - self.snippet( - "flavors", - "/flavors", "GET", 200, "OK", - lambda client: client.flavors.list()) - - @test - def get_flavor_by_id(self): - self.snippet( - "flavors_by_id", - "/flavors/1", "GET", 200, "OK", - lambda client: client.flavors.get(1)) - - -@test(depends_on=[load_config_file]) -def clean_slate(): - client = create_client(TroveHTTPClient, admin_user) - client.client.name = "list" - instances = client.instances.list() - assert_equal(0, len(instances), "Instance count must be zero.") - - -@test(depends_on=[clean_slate]) -class CreateInstance(Example): - - @before_class - def setup(self): - self.client = make_client(normal_user) - - @test - def post_create_instance(self): - set_fake_stuff(uuid=EXAMPLE_INSTANCE_ID) - - def create_instance(client, name): - instance = client.instances.create( - name, 1, - volume={'size': 2}, - databases=[ - { - "name": "sampledb", - "character_set": "utf8", - "collate": "utf8_general_ci" - }, - { - "name": "nextround" - } - ], - users=[ - { - "databases": [{"name": "sampledb"}], - "name": "demouser", - "password": "demopassword" - } - ]) - assert_equal(instance.status, "BUILD") - return instance - self.instances = self.snippet( - "create_instance", - "/instances", "POST", 200, "OK", - create_instance, - "json_rack_instance") - - def an_instance_is_not_active(self): - for instance in self.instances: - instance = self.client.instances.get(instance.id) - if instance.status not in CONFIG.running_status: - assert_equal(instance.status, "BUILD") - return True - return False - - @test(depends_on=[post_create_instance]) - def wait_for_instances(self): - while self.an_instance_is_not_active(): - time.sleep(1) - global json_instance - json_instance = self.instances[0] - - -@test(depends_on=[CreateInstance], groups=['uses_instances']) -class Databases(Example): - - @before_class - def setup(self): - self.client = make_client(normal_user) - - @test - def post_create_databases(self): - self.snippet( - "create_databases", - "/instances/%s/databases" % json_instance.id, - "POST", 202, "Accepted", - lambda client: client.databases.create( - json_instance.id, - databases=[ - { - "name": "testingdb", - "character_set": "utf8", - "collate": "utf8_general_ci" - }, { - "name": "anotherdb" - }, { - "name": "oneMoreDB" - }])) - - @test(depends_on=[post_create_databases]) - def get_list_databases(self): - self.snippet( - "list_databases", - "/instances/%s/databases" % json_instance.id, - "GET", 200, "OK", - lambda client: client.databases.list(json_instance.id)) - - @test(depends_on=[post_create_databases]) - def get_list_databases_limit_two(self): - results = self.snippet( - "list_databases_pagination", - "/instances/%s/databases?limit=1" % json_instance.id, - "GET", 200, "OK", - lambda client: client.databases.list(json_instance.id, limit=1)) - assert_equal(1, len(results[JSON_INDEX])) - assert_equal("anotherdb", results[JSON_INDEX].next) - - @test(depends_on=[post_create_databases], - runs_after=[get_list_databases, get_list_databases_limit_two]) - def delete_databases(self): - self.snippet( - "delete_databases", - "/instances/%s/databases/testingdb" % json_instance.id, - "DELETE", 202, "Accepted", - lambda client: - client.databases.delete(json_instance.id, 'testingdb')) - - -@test(depends_on=[CreateInstance], groups=['uses_instances']) -class Users(Example): - - @before_class - def setup(self): - self.client = make_client(normal_user) - - @test - def post_create_users(self): - self.snippet( - "create_users", - "/instances/%s/users" % json_instance.id, - "POST", 202, "Accepted", - lambda client: client.users.create( - json_instance.id, - [{ - "name": "dbuser1", - "password": "password", - "databases": [ - { - "name": "databaseA" - } - ] - }, { - "name": "dbuser2", - "password": "password", - "databases": [ - { - "name": "databaseB" - }, - { - "name": "databaseC" - } - ] - }, { - "name": "dbuser3", - "password": "password", - "databases": [ - { - "name": "databaseD" - } - ] - }])) - - @test(depends_on=[post_create_users]) - def get_list_users(self): - self.snippet( - "list_users", - "/instances/%s/users" % json_instance.id, - "GET", 200, "OK", - lambda client: client.users.list(json_instance.id)) - - @test(depends_on=[post_create_users]) - def get_list_users_limit_two(self): - self.snippet( - "list_users_pagination", - "/instances/%s/users?limit=2" % json_instance.id, - "GET", 200, "OK", - lambda client: client.users.list(json_instance.id, limit=2)) - - @test(depends_on=[post_create_users], - runs_after=[get_list_users, get_list_users_limit_two]) - def delete_users(self): - user_name = "demouser" - self.snippet( - "delete_users", - "/instances/%s/users/%s" % (json_instance.id, user_name), - "DELETE", 202, "Accepted", - lambda client: client.users.delete(json_instance.id, - username=user_name)) - - @test(depends_on=[post_create_users]) - def modify_user_attributes(self): - old_user_name = "dbuser1" - self.snippet( - "change_user_attributes", - "/instances/%s/users/%s" % (json_instance.id, old_user_name), - "PUT", 202, "Accepted", - lambda client: client.users.update_attributes( - json_instance.id, - username=old_user_name, - newuserattr={ - "name": "new_username", - "password": "new_password" - } - ) - ) - - -@test(depends_on=[CreateInstance], groups=['uses_instances']) -class Root(Example): - - @before_class - def setup(self): - self.client = make_client(normal_user) - - @test - def post_enable_root_access(self): - self.snippet( - "enable_root_user", - "/instances/%s/root" % json_instance.id, - "POST", 200, "OK", - lambda client: client.root.create(json_instance.id)) - - @test(depends_on=[post_enable_root_access]) - def get_check_root_access(self): - results = self.snippet( - "check_root_user", - "/instances/%s/root" % json_instance.id, - "GET", 200, "OK", - lambda client: client.root.is_root_enabled(json_instance.id)) - assert_equal(results[JSON_INDEX].rootEnabled, True) - - @test(depends_on=[get_check_root_access]) - def delete_disable_root_access(self): - self.snippet( - "disable_root_user", - "/instances/%s/root" % json_instance.id, - "DELETE", 204, "No Content", - lambda client: client.root.delete(json_instance.id)) - - # restore root for subsequent tests - self.post_enable_root_access() - - -class ActiveMixin(Example): - """Adds a method to wait for instance status to become ACTIVE.""" - - def _wait_for_active(self, *acceptable_states): - global json_instance - json_instance = self.client.instances.get(json_instance.id) - while json_instance.status not in CONFIG.running_status: - assert_true( - json_instance.status in acceptable_states, - "Instance status == %s; expected it to be one of: %s" - % (json_instance.status, acceptable_states)) - time.sleep(0.1) - json_instance = self.client.instances.get(json_instance.id) - - def _wait_for_restore_active(self, *acceptable_states): - for instance in (self.json_restore, ): - instance = self.client.instances.get(instance.id) - while instance.status not in CONFIG.running_status: - assert_true( - instance.status in acceptable_states, - "Instance status == %s; expected it to be one of: %s" - % (instance.status, acceptable_states)) - time.sleep(0.1) - instance = self.client.instances.get(instance.id) - - -STATE = { - "CONFIGURATION": None, - "DATASTORE_ID": None, - "DATASTORE_VERSION_ID": None, -} - - -@test(depends_on=[CreateInstance], groups=['uses_instances']) -class Datastores(Example): - - @before_class - def setup(self): - self.client = make_client(normal_user) - - @test - def get_datastores_list(self): - self.datastores = self.snippet( - "datastores_list", - "/datastores", - "GET", 200, "OK", - lambda client: client.datastores.list()) - for result in self.datastores: - assert_equal(1, len(result)) - - @test(depends_on=[get_datastores_list]) - def get_datastore_by_id(self): - ds, = self.datastores - mysql_ds = [x for x in ds if x.name == 'mysql'] - if not mysql_ds: - fail('no mysql datastore found in list') - ds_id = STATE["DATASTORE_ID"] = mysql_ds[JSON_INDEX].id - self.datastore = self.snippet( - "datastore_by_id", - "/datastores/%s" % ds_id, - "GET", 200, "OK", - lambda client: client.datastores.get(ds_id)) - - @test(depends_on=[get_datastore_by_id]) - def get_datastore_versions_list(self): - ds_id = STATE["DATASTORE_ID"] - self.datastore_versions = self.snippet( - "datastore_versions_list", - "/datastores/%s/versions" % ds_id, - "GET", 200, "OK", - lambda client: client.datastore_versions.list(ds_id)) - - @test(depends_on=[get_datastore_versions_list]) - def get_datastore_version_by_id(self): - ds_id = STATE["DATASTORE_ID"] - ds_v_id = STATE["DATASTORE_VERSION_ID"] = ( - self.datastore_versions[JSON_INDEX][0].id - ) - self.datastore_version = self.snippet( - "datastore_version_by_id", - "/datastores/%s/versions/%s" % (ds_id, ds_v_id), - "GET", 200, "OK", - lambda client: client.datastore_versions.get(ds_id, ds_v_id)) - - -@test(depends_on=[Datastores], groups=['uses_instances']) -class Configurations(ActiveMixin): - - @before_class - def setup(self): - self.client = make_client(normal_user) - - @test - def get_configuration_parameters_for_datastore_version(self): - ds_id = STATE["DATASTORE_ID"] - ds_v_id = STATE["DATASTORE_VERSION_ID"] - self.snippet( - "configuration_parameters_for_datastore_version", - "/datastores/%s/versions/%s/parameters" % (ds_id, ds_v_id), - "GET", 200, "OK", - lambda client: client.configuration_parameters.parameters( - ds_id, ds_v_id - ) - ) - - @test - def get_configuration_parameters_without_datastore_version(self): - ds_v_id = STATE["DATASTORE_VERSION_ID"] - self.params = self.snippet( - "configuration_parameters_without_datastore_version", - "/datastores/versions/%s/parameters" % (ds_v_id), - "GET", 200, "OK", - lambda client: ( - client.configuration_parameters.parameters_by_version(ds_v_id) - ) - ) - assert_true(self.params) - - @test(depends_on=[get_configuration_parameters_without_datastore_version]) - def get_configuration_parameter_for_datastore_version(self): - ds_id = STATE["DATASTORE_ID"] - ds_v_id = STATE["DATASTORE_VERSION_ID"] - param = self.params[JSON_INDEX][0].name - self.snippet( - "configuration_parameter_for_datastore_version", - "/datastores/%s/versions/%s/parameters/%s" - % (ds_id, ds_v_id, param), - "GET", 200, "OK", - lambda client: client.configuration_parameters.get_parameter( - ds_id, ds_v_id, param)) - - @test(depends_on=[get_configuration_parameters_without_datastore_version]) - def get_configuration_parameter_without_datastore_version(self): - ds_v_id = STATE["DATASTORE_VERSION_ID"] - param = self.params[JSON_INDEX][0].name - - def get_param(client): - return client.configuration_parameters.get_parameter_by_version( - ds_v_id, - param - ) - - self.params = self.snippet( - "configuration_parameter_without_datastore_version", - "/datastores/versions/%s/parameters/%s" % (ds_v_id, param), - "GET", 200, "OK", - get_param - ) - - @test(depends_on=[get_configuration_parameter_without_datastore_version]) - def create_configuration(self): - set_fake_stuff(uuid=EXAMPLE_CONFIG_ID) - ds_id = STATE["DATASTORE_ID"] - ds_v_id = STATE["DATASTORE_VERSION_ID"] - values = { - "connect_timeout": 120, - "collation_server": "latin1_swedish_ci" - } - - def create(client): - config = client.configurations.create( - 'example-configuration-name', json.dumps(values), - 'example description', ds_id, ds_v_id) - return config - - self.configurations = self.snippet( - "configuration_create", - "/configurations", - "POST", 200, "OK", - create) - STATE["CONFIGURATION"] = self.configurations[JSON_INDEX] - - @test(depends_on=[create_configuration]) - def get_configuration(self): - config = STATE["CONFIGURATION"] - self.config = self.snippet( - "configuration_details", - "/configurations/%s" % config.id, - "GET", 200, "OK", - lambda client: client.configurations.get(config.id)) - - @test(depends_on=[create_configuration]) - def list_configurations(self): - self.configs = self.snippet( - "configuration_list", - "/configurations", - "GET", 200, "OK", - lambda client: client.configurations.list()) - - @test(depends_on=[list_configurations, get_configuration]) - def edit_configuration(self): - config = STATE["CONFIGURATION"] - values = { - 'connect_timeout': 300 - } - self.snippet( - "configuration_edit_parameters", - "/configurations/%s" % config.id, - "PATCH", 200, "OK", - lambda client: client.configurations.edit( - config.id, json.dumps(values))) - - @test(depends_on=[edit_configuration]) - def update_configuration(self): - config = STATE["CONFIGURATION"] - values = { - 'connect_timeout': 150, - 'collation_server': 'utf8_unicode_ci' - } - self.snippet( - "configuration_update_parameters", - "/configurations/%s" % config.id, - "PUT", 202, "Accepted", - lambda client: client.configurations.update( - config.id, json.dumps(values), - 'example-updated-name', 'example updated description')) - - @test(depends_on=[update_configuration]) - def attach_configuration_to_instance(self): - config = STATE["CONFIGURATION"] - self.snippet( - "configuration_attach_to_instance", - "/instances/%s" % json_instance.id, - "PUT", 202, "Accepted", - lambda client: client.instances.modify( - json_instance.id, - config.id - ) - ) - - @test(depends_on=[attach_configuration_to_instance]) - def list_configurations_instances(self): - config = STATE["CONFIGURATION"] - self.config_instances = self.snippet( - "configuration_list_instances", - "/configurations/%s/instances" % config.id, - "GET", 200, "OK", - lambda client: client.configurations.instances(config.id)) - - @test(depends_on=[list_configurations_instances]) - def detach_configuration_from_instance(self): - self.snippet( - "configuration_detach_from_instance", - "/instances/%s" % json_instance.id, - "PUT", 202, "Accepted", - lambda client: client.instances.modify( - json_instance.id, "")) - - @test(depends_on=[detach_configuration_from_instance]) - def instance_restart_after_configration_change(self): - self.client.instances.restart(json_instance.id) - self._wait_for_active("REBOOT") - - -@test(depends_on=[CreateInstance], groups=['uses_instances']) -class InstanceList(Example): - - @before_class - def setup(self): - self.client = make_client(normal_user) - - @test - def get_list_instance_index(self): - results = self.snippet( - "instances_index", - "/instances", "GET", 200, "OK", - lambda client: client.instances.list()) - for result in results: - assert_equal(1, len(result)) - - @test - def get_instance_details(self): - results = self.snippet( - "instance_status_detail", - "/instances/%s" % json_instance.id, - "GET", 200, "OK", - lambda client: client.instances.get(json_instance.id)) - assert_equal(results[JSON_INDEX].id, json_instance.id) - - @test - def get_default_instance_configuration(self): - set_fake_stuff(unique_id=EXAMPLE_CONFIG_SERVER_ID) - self.snippet( - "get_default_instance_configuration", - "/instances/%s/configuration" % json_instance.id, - "GET", 200, "OK", - lambda client: client.instances.configuration(json_instance.id)) - - @test - def get_list_instance_index_limit_two(self): - third_instance = self.client.instances.create( - "The Third Instance", 1, volume={'size': 2}) - third_instance = self.client.instances.get(third_instance.id) - while third_instance.status not in CONFIG.running_status: - time.sleep(0.1) - third_instance = self.client.instances.get(third_instance.id) - - results = self.snippet( - "instances_index_pagination", - "/instances?limit=2", "GET", 200, "OK", - lambda client: client.instances.list(limit=2)) - for result in results: - assert_equal(2, len(result)) - - self.client.instances.delete(third_instance.id) - - -@test(depends_on=[CreateInstance], groups=['uses_instances']) -class Backups(ActiveMixin): - - @before_class - def setup(self): - self.client = make_client(normal_user) - - @test - def create_backup(self): - set_fake_stuff(uuid=EXAMPLE_BACKUP_ID) - results = self.snippet( - "backup_create", "/backups", "POST", 202, "Accepted", - lambda client: client.backups.create( - name='snapshot', - instance=json_instance.id, - description="My Backup" - ) - ) - self._wait_for_active("BACKUP") - assert_equal(len(results), 1) - self.json_backup = results[JSON_INDEX] - - @test(depends_on=[create_backup]) - def create_incremental_backup(self): - set_fake_stuff(uuid=EXAMPLE_BACKUP_INCREMENTAL_ID) - results = self.snippet( - "backup_create_incremental", "/backups", "POST", 202, "Accepted", - lambda client: client.backups.create( - name='Incremental Snapshot', - instance=json_instance.id, - parent_id=EXAMPLE_BACKUP_ID, - description="My Incremental Backup" - ) - ) - - self._wait_for_active("BACKUP") - assert_equal(len(results), 1) - self.json_backup2 = results[JSON_INDEX] - - @test(depends_on=[create_incremental_backup]) - def get_backup(self): - results = self.snippet( - "backup_get", - "/backups/%s" % self.json_backup.id, - "GET", 200, "OK", - lambda client: client.backups.get(self.json_backup.id)) - assert_equal(len(results), 1) - - @test(depends_on=[create_incremental_backup]) - def get_backups_for_instance(self): - results = self.snippet( - "backups_by_instance", - "/instances/%s/backups" % json_instance.id, - "GET", 200, "OK", - lambda client: client.instances.backups(json_instance.id)) - assert_equal(len(results), 1) - - @test(depends_on=[create_incremental_backup]) - def list_backups(self): - results = self.snippet( - "backup_list", - "/backups", "GET", 200, "OK", - lambda client: client.backups.list()) - assert_equal(len(results), 1) - - @test(depends_on=[create_backup]) - def restore(self): - set_fake_stuff(uuid=EXAMPLE_INSTANCE_ID_2) - - def create_instance(client, name, backup): - instance = client.instances.create( - name, 1, - volume={'size': 2}, - restorePoint={'backupRef': backup}) - assert_equal(instance.status, "BUILD") - return instance - results = self.snippet( - "backup_restore", - "/instances", "POST", 200, "OK", - lambda client: create_instance( - client, "backup_instance", self.json_backup.id)) - assert_equal(len(results), 1) - self.json_restore = results[JSON_INDEX] - self._wait_for_restore_active("BUILD") - self.json_restore = self.client.instances.get(self.json_restore.id) - asserts.assert_true(self.json_restore.status in CONFIG.running_status) - - @test(depends_on=[restore]) - def delete_restores(self): - self.snippet( - "restore_delete", - "/instances/%s" % self.json_restore.id, - "DELETE", 202, "Accepted", - lambda client: client.instances.delete(self.json_restore.id)) - self.json_restore = self.client.instances.get(self.json_restore.id) - assert_equal(self.json_restore.status, "SHUTDOWN") - - @test(depends_on=[create_backup], - runs_after=[get_backup, list_backups, restore, - get_backups_for_instance]) - def delete_backup(self): - results = self.snippet( - "backup_delete", - "/backups/%s" % self.json_backup.id, - "DELETE", 202, "Accepted", - lambda client: client.backups.delete(self.json_backup.id)) - assert_equal(len(results), 1) - - -@test(depends_on=[CreateInstance], groups=['uses_instances']) -class Actions(ActiveMixin): - - @before_class - def setup(self): - self.client = make_client(normal_user) - - @test - def instance_restart(self): - self.snippet( - "instance_restart", - "/instances/%s/action" % json_instance.id, - "POST", 202, "Accepted", - lambda client: client.instances.restart(json_instance.id)) - self._wait_for_active("REBOOT") - - @test - def instance_resize_volume(self): - self.snippet( - "instance_resize_volume", - "/instances/%s/action" % json_instance.id, - "POST", 202, "Accepted", - lambda client: client.instances.resize_volume(json_instance.id, 4)) - self._wait_for_active("RESIZE") - assert_equal(json_instance.volume['size'], 4) - - @test - def instance_resize_flavor(self): - self.snippet( - "instance_resize_flavor", - ("/instances/%s/action" % json_instance.id), - "POST", 202, "Accepted", - lambda client: client.instances.resize_instance( - json_instance.id, 3)) - self._wait_for_active("RESIZE") - # TODO(imsplitbit): remove coercion when troveclient fixes are in - assert_equal(int(json_instance.flavor['id']), 3) - - -@test(depends_on=[CreateInstance], groups=['uses_instances', "MgmtHosts"]) -class MgmtHosts(Example): - - @before_class - def setup(self): - self.client = make_client(admin_user) - - @test - def mgmt_list_hosts(self): - results = self.snippet( - "mgmt_list_hosts", - "/mgmt/hosts", "GET", 200, "OK", - lambda client: client.mgmt.hosts.index()) - - with Check() as check: - for hosts in results: - check.equal(2, len(hosts)) - check.true("fake_host_1" == hosts[0].name - or "fake_host_1" == hosts[1].name) - check.true("fake_host_2" == hosts[0].name - or "fake_host_2" == hosts[1].name) - check.true(1 == results[0][1].instanceCount - or 1 == results[0][0].instanceCount) - - @test - def mgmt_get_host_detail(self): - results = self.snippet( - "mgmt_get_host_detail", - "/mgmt/hosts/fake_host_1", "GET", 200, "OK", - lambda client: client.mgmt.hosts.get("fake_host_1")) - with Check() as check: - for host in results: - check.equal(results[0].name, "fake_host_1") - # XML entries won't come back as these types. :( - check.true(isinstance(results[0].percentUsed, int)), - check.true(isinstance(results[0].totalRAM, int)), - check.true(isinstance(results[0].usedRAM, int)), - with Check() as check: - for host in results: - check.equal(1, len(host.instances)) - for instance in host.instances: - check.equal(instance['status'], 'HEALTHY') - check.true(isinstance(instance['name'], six.string_types)) - check.true(isinstance(instance['id'], six.string_types)) - check.true(isinstance(instance['server_id'], - six.string_types)) - check.true(isinstance(instance['tenant_id'], - six.string_types)) - - @test - def mgmt_host_update_all(self): - raise SkipTest("This isn't working... :(") - self.snippet( - "mgmt_host_update", - "/mgmt/hosts/fake_host_1/instances/action", - "POST", 202, "Accepted", - lambda client: client.mgmt.hosts.update_all("fake_host_1")) - - -@test(depends_on=[CreateInstance], groups=['uses_instances']) -class MgmtStorage(Example): - - @before_class - def setup(self): - self.client = make_client(admin_user) - - @test - def mgmt_get_storage(self): - results = self.snippet( - "mgmt_get_storage", - "/mgmt/storage", "GET", 200, "OK", - lambda client: client.mgmt.storage.index()) - for index, devices in enumerate(results): - with Check() as check: - check.equal(1, len(devices)) - device = devices[0] - check.equal(int(device.capacity['available']), 90) - check.equal(int(device.capacity['total']), 100) - check.equal(device.name, "fake_storage") - check.equal(int(device.provision['available']), 40) - check.equal(int(device.provision['percent']), 10) - check.equal(int(device.provision['total']), 50) - check.equal(device.type, "test_type") - check.equal(int(device.used), 10) - if index == JSON_INDEX: - check.true(isinstance(device.capacity['available'], int)) - check.true(isinstance(device.capacity['total'], int)) - check.true(isinstance(device.provision['available'], int)) - check.true(isinstance(device.provision['percent'], int)) - check.true(isinstance(device.provision['total'], int)) - check.true(isinstance(device.used, int)) - - -@test(depends_on=[CreateInstance], groups=['uses_instances']) -class MgmtAccount(Example): - - @before_class - def setup(self): - self.client = make_client(admin_user) - - @test - def mgmt_get_account_details(self): - results = self.snippet( - "mgmt_get_account_details", - "/mgmt/accounts/%s" % conf['normal_user_tenant'], - "GET", 200, "OK", - lambda client: client.mgmt.accounts.show( - conf['normal_user_tenant'], )) - with Check() as check: - for account_info in results: - check.equal(conf['normal_user_tenant'], account_info.id) - - @test - def mgmt_get_account_list(self): - results = self.snippet( - "mgmt_list_accounts", - "/mgmt/accounts", "GET", 200, "OK", - lambda client: client.mgmt.accounts.index()) - matches = {conf['normal_user_tenant']: 2, - conf['admin_user_tenant']: 0} - for index, result in enumerate(results): - for account in result.accounts: - if account['id'] not in matches: - fail("Did not expect this account ID: %s" % account['id']) - expected_count = matches[account['id']] - if index == JSON_INDEX: - assert_equal(2, expected_count) - else: - assert_equal(2, expected_count) - - -def for_both(func): - @functools.wraps(func) - def both(self): - for result in self.results: - func(self, result) - return both - - -@test(depends_on=[CreateInstance], groups=['uses_instances']) -class MgmtInstance(Example): - - @before_class - def mgmt_get_instance_details(self): - self.client = make_client(admin_user) - self.results = self.snippet( - "mgmt_get_instance_details", - ("/mgmt/instances/%s" % json_instance.id), - "GET", 200, "OK", - lambda client: client.mgmt.instances.show(json_instance.id)) - - @test - @for_both - def created(self, result): - assert_true(isinstance(result.created, six.string_types)) - - @test - def deleted(self): - assert_equal(self.results[JSON_INDEX].deleted, False) - - @test - @for_both - def flavor(self, result): - # TODO(imsplitbit): remove the coercion when python-troveclient fixes - # land in the public. - assert_true( - int(result.flavor['id']) == 1 or int(result.flavor['id']) == 3) - assert_equal(len(result.flavor['links']), 2) - - @test - @for_both - def guest_status(self, result): - assert_equal(result.guest_status['state_description'], 'running') - - @test(enabled=False) - @for_both - def host(self, result): - assert_equal(result.host, 'fake_host_1') - - @test - def id(self): - assert_equal(self.results[JSON_INDEX].id, json_instance.id) - - @test - @for_both - def links(self, result): - assert_true(isinstance(result.links, list)) - for link in result.links: - assert_true(isinstance(link, dict)) - assert_true(isinstance(link['href'], six.string_types)) - assert_true(isinstance(link['rel'], six.string_types)) - - @test - def local_id(self): - assert_true(isinstance(self.results[JSON_INDEX].server['local_id'], - int)) - - @test - @for_both - def name(self, result): - assert_true(isinstance(result.name, six.string_types)) - - @test - @for_both - def server_id(self, result): - assert_true(isinstance(result.server['id'], six.string_types)) - - @test - @for_both - def status(self, result): - assert_equal("ACTIVE", result.status) - - @test - @for_both - def task_description(self, result): - assert_equal(result.task_description, "No tasks for the instance.") - - @test - @for_both - def tenant_id(self, result): - assert_equal(result.tenant_id, conf['normal_user_tenant']) - - @test - @for_both - def updated(self, result): - assert_true(isinstance(result.updated, six.string_types)) - - @test - @for_both - def volume(self, result): - assert_true(isinstance(result.volume, dict)) - assert_true('id' in result.volume) - assert_true('size' in result.volume) - - -@test(depends_on=[CreateInstance], groups=['uses_instances']) -class MgmtInstanceIndex(Example): - - @before_class - def setup(self): - self.client = make_client(admin_user) - - @test - def mgmt_instance_index(self, deleted=False): - self.snippet( - "mgmt_instance_index", - "/mgmt/instances?deleted=false", "GET", 200, "OK", - lambda client: client.mgmt.instances.index(deleted=False)) - - -@test(depends_on=[CreateInstance], groups=['uses_instances']) -class MgmtInstanceDiagnostics(Example): - - @before_class - def setup(self): - self.client = make_client(admin_user) - - @test - def mgmt_get_instance_diagnostics(self): - self.snippet( - "mgmt_instance_diagnostics", - ("/mgmt/instances/%s/diagnostics" % json_instance.id), - "GET", 200, "OK", - lambda client: client.diagnostics.get(json_instance.id)) - - -@test(depends_on=[CreateInstance]) -class MgmtInstanceRoot(Example): - - @before_class - def setup(self): - self.client = make_client(admin_user) - - @test - def mgmt_get_root_details(self): - self.snippet( - "mgmt_get_root_details", - ("/mgmt/instances/%s/root" % json_instance.id), - "GET", 200, "OK", - lambda client: client.mgmt.instances.root_enabled_history( - json_instance.id) - ) - - -@test(depends_on=[CreateInstance], enabled=False) -class MgmtInstanceHWInfo(Example): - - @before_class - def setup(self): - self.client = make_client(admin_user) - - @test - def mgmt_get_hw_info(self): - self.snippet( - "mgmt_get_hw_info", - ("/mgmt/instances/%s/hwinfo" % json_instance.id), - "GET", 200, "OK", - lambda client, id: client.hw_info.get(id), - ([json_instance.id], )) - - -@test(depends_on=[CreateInstance], groups=['uses_instances']) -class MgmtInstanceReboot(Example): - - @before_class - def setup(self): - self.client = make_client(admin_user) - - @test - def mgmt_instance_reboot(self): - self.snippet( - "instance_reboot", - ("/mgmt/instances/%s/action" % json_instance.id), - "POST", 202, "Accepted", - lambda client: client.mgmt.instances.reboot(json_instance.id)) - - -@test(depends_on=[CreateInstance], - groups=['uses_instances'], enabled=False) -class MgmtInstanceGuestUpdate(Example): - - @before_class - def setup(self): - self.client = make_client(admin_user) - - @test - def mgmt_instance_guest_update(self): - self.snippet( - "guest_update", - ("/mgmt/instances/%s/action" % json_instance.id), - "POST", 202, "Accepted", - lambda client: client.mgmt.instances.update(json_instance.id)) - - -@test(depends_on=[CreateInstance], runs_after_groups=['uses_instances']) -class ZzzDeleteInstance(Example): - - @before_class - def setup(self): - self.client = make_client(normal_user) - - @test - def zzz_delete_instance(self): - global json_instance - self.snippet( - "delete_instance", - "/instances/%s" % json_instance.id, - "DELETE", 202, "Accepted", - lambda client: client.instances.delete(json_instance.id)) - json_instance = self.client.instances.get(json_instance.id) - assert_equal(json_instance.status, "SHUTDOWN") - - @test(depends_on=[zzz_delete_instance]) - def delete_configuration(self): - config = STATE["CONFIGURATION"] - self.configs = self.snippet( - "configuration_delete", - ("/configurations/%s" % config.id), - "DELETE", 202, "Accepted", - lambda client: client.configurations.delete(config.id)) - - -if __name__ == "__main__": - CONFIG.load_from_file("etc/tests/localhost.test.conf") - TestProgram().run_and_exit() diff --git a/trove/tests/scenario/runners/test_runners.py b/trove/tests/scenario/runners/test_runners.py index e3b4d01595..9786f766ff 100644 --- a/trove/tests/scenario/runners/test_runners.py +++ b/trove/tests/scenario/runners/test_runners.py @@ -183,6 +183,7 @@ class InstanceTestInfo(object): self.helper_user = None # Test helper user if exists. self.helper_database = None # Test helper database if exists. self.admin_user = None + self.flavors = None class LogOnFail(type): @@ -368,6 +369,8 @@ class TestRunner(object): inst_ids = [self.instance_info.id] self.register_debug_inst_ids(inst_ids) + self.instance_info.flavors = self.nova_client.flavors.list() + @classmethod def fail(cls, message): asserts.fail(message) @@ -817,12 +820,14 @@ class TestRunner(object): return {"flavorRef": flavor_id, "volume": {"size": volume_size}} def get_flavor(self, flavor_name): - flavors = self.auth_client.find_flavors_by_name(flavor_name) - self.assert_equal( - 1, len(flavors), - "Unexpected number of flavors with name '%s' found." % flavor_name) + flavor = None + for item in self.instance_info.flavors: + if item.name == flavor_name: + flavor = item - return flavors[0] + asserts.assert_is_not_none(flavor) + + return flavor def get_instance_flavor(self, fault_num=None): name_format = 'instance%s%s_flavor_name' @@ -841,7 +846,7 @@ class TestRunner(object): return self.get_flavor(flavor_name) def get_flavor_href(self, flavor): - return self.auth_client.find_flavor_self_href(flavor) + return flavor.id def copy_dict(self, d, ignored_keys=None): return {k: v for k, v in d.items() @@ -980,11 +985,10 @@ class CheckInstance(AttrCheck): if 'flavor' not in self.instance: self.fail("'flavor' not found in instance.") else: - allowed_attrs = ['id', 'links'] + allowed_attrs = ['id'] self.contains_allowed_attrs( self.instance['flavor'], allowed_attrs, msg="Flavor") - self.links(self.instance['flavor']['links']) def datastore(self): if 'datastore' not in self.instance: diff --git a/trove/tests/unittests/cluster/test_cluster_views.py b/trove/tests/unittests/cluster/test_cluster_views.py index b1a5ef5d99..bf061f27fd 100644 --- a/trove/tests/unittests/cluster/test_cluster_views.py +++ b/trove/tests/unittests/cluster/test_cluster_views.py @@ -140,7 +140,6 @@ class ClusterInstanceDetailViewTest(trove_testtools.TestCase): super(ClusterInstanceDetailViewTest, self).tearDown() @patch.object(ClusterInstanceDetailView, '_build_links') - @patch.object(ClusterInstanceDetailView, '_build_flavor_links') @patch.object(ClusterInstanceDetailView, '_build_configuration_info') def test_data(self, *args): view = ClusterInstanceDetailView(self.instance, self.req) @@ -154,7 +153,6 @@ class ClusterInstanceDetailViewTest(trove_testtools.TestCase): self.assertNotIn('ip', result['instance']) @patch.object(ClusterInstanceDetailView, '_build_links') - @patch.object(ClusterInstanceDetailView, '_build_flavor_links') @patch.object(ClusterInstanceDetailView, '_build_configuration_info') def test_data_ip(self, *args): self.instance.hostname = None diff --git a/trove/tests/unittests/instance/test_instance_views.py b/trove/tests/unittests/instance/test_instance_views.py index 8d5923b029..2b3f21461b 100644 --- a/trove/tests/unittests/instance/test_instance_views.py +++ b/trove/tests/unittests/instance/test_instance_views.py @@ -41,10 +41,8 @@ class InstanceDetailViewTest(trove_testtools.TestCase): def setUp(self): super(InstanceDetailViewTest, self).setUp() self.build_links_method = InstanceView._build_links - self.build_flavor_links_method = InstanceView._build_flavor_links self.build_config_method = InstanceDetailView._build_configuration_info InstanceView._build_links = Mock() - InstanceView._build_flavor_links = Mock() InstanceDetailView._build_configuration_info = Mock() self.instance = Mock() self.instance.created = 'Yesterday' @@ -79,7 +77,6 @@ class InstanceDetailViewTest(trove_testtools.TestCase): def tearDown(self): super(InstanceDetailViewTest, self).tearDown() InstanceView._build_links = self.build_links_method - InstanceView._build_flavor_links = self.build_flavor_links_method InstanceDetailView._build_configuration_info = self.build_config_method def test_data_hostname(self): diff --git a/trove/tests/util/client.py b/trove/tests/util/client.py index 106da2b27a..3501ecfce9 100644 --- a/trove/tests/util/client.py +++ b/trove/tests/util/client.py @@ -67,37 +67,6 @@ class TestClient(object): resp, body = self.real_client.client.last_response return resp.status - @staticmethod - def find_flavor_self_href(flavor): - self_links = [link for link in flavor.links if link['rel'] == 'self'] - asserts.assert_true(len(self_links) > 0, "Flavor had no self href!") - flavor_href = self_links[0]['href'] - asserts.assert_false(flavor_href is None, - "Flavor link self href missing.") - return flavor_href - - def find_flavors_by(self, condition, flavor_manager=None): - flavor_manager = flavor_manager or self.flavors - flavors = flavor_manager.list() - return [flavor for flavor in flavors if condition(flavor)] - - def find_flavors_by_name(self, name, flavor_manager=None): - return self.find_flavors_by(lambda flavor: flavor.name == name, - flavor_manager) - - def find_flavors_by_ram(self, ram, flavor_manager=None): - return self.find_flavors_by(lambda flavor: flavor.ram == ram, - flavor_manager) - - def find_flavor_and_self_href(self, flavor_id, flavor_manager=None): - """Given an ID, returns flavor and its self href.""" - flavor_manager = flavor_manager or self.flavors - asserts.assert_false(flavor_id is None) - flavor = flavor_manager.get(flavor_id) - asserts.assert_false(flavor is None) - flavor_href = self.find_flavor_self_href(flavor) - return flavor, flavor_href - def __getattr__(self, item): if item == "__setstate__": raise AttributeError(item)