[api versions]Support to specify api versions in the spec of env
Spec example: Specify cinder client version { "openstack": { "auth_url": "http://example.net:5000/v2.0/", "region_name": "RegionOne", "endpoint_type": "public", "admin": { "username": "admin", "password": "myadminpass", "tenant_name": "demo" }, "https_insecure": false, "https_cacert": "" "api_info": { "cinder": { "version": "1", "service_type": "volume" } } } } Change-Id: I74578e3b1c4e7b662ba66955ef9fb62cd4eeb788
This commit is contained in:
parent
467cc05559
commit
0a73f8ae80
@ -27,6 +27,7 @@ Added
|
|||||||
``existing@openstack`` platform to represent client certificate bundle and
|
``existing@openstack`` platform to represent client certificate bundle and
|
||||||
key files. Also the support for appropriate system environment variables (
|
key files. Also the support for appropriate system environment variables (
|
||||||
``OS_CERT``, ``OS_KEY``) is added.
|
``OS_CERT``, ``OS_KEY``) is added.
|
||||||
|
* Support client api option while deploying platform.
|
||||||
|
|
||||||
Changed
|
Changed
|
||||||
~~~~~~~
|
~~~~~~~
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import collections
|
import collections
|
||||||
|
import copy
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
from rally.common import broker
|
from rally.common import broker
|
||||||
@ -106,8 +107,14 @@ class UserGenerator(context.Context):
|
|||||||
|
|
||||||
creds = self.env["platforms"]["openstack"]
|
creds = self.env["platforms"]["openstack"]
|
||||||
if creds.get("admin"):
|
if creds.get("admin"):
|
||||||
|
admin_cred = copy.deepcopy(creds["admin"])
|
||||||
|
api_info = copy.deepcopy(creds.get("api_info", {}))
|
||||||
|
if "api_info" in admin_cred:
|
||||||
|
api_info.update(creds["admin"]["api_info"])
|
||||||
|
admin_cred["api_info"] = api_info
|
||||||
context["admin"] = {
|
context["admin"] = {
|
||||||
"credential": credential.OpenStackCredential(**creds["admin"])}
|
"credential": credential.OpenStackCredential(**admin_cred)
|
||||||
|
}
|
||||||
|
|
||||||
if creds["users"] and not (set(self.config) - {"user_choice_method"}):
|
if creds["users"] and not (set(self.config) - {"user_choice_method"}):
|
||||||
self.existing_users = creds["users"]
|
self.existing_users = creds["users"]
|
||||||
@ -218,7 +225,8 @@ class UserGenerator(context.Context):
|
|||||||
https_cacert=self.credential["https_cacert"],
|
https_cacert=self.credential["https_cacert"],
|
||||||
region_name=self.credential["region_name"],
|
region_name=self.credential["region_name"],
|
||||||
profiler_hmac_key=self.credential["profiler_hmac_key"],
|
profiler_hmac_key=self.credential["profiler_hmac_key"],
|
||||||
profiler_conn_str=self.credential["profiler_conn_str"])
|
profiler_conn_str=self.credential["profiler_conn_str"],
|
||||||
|
api_info=self.credential["api_info"])
|
||||||
users.append({"id": user.id,
|
users.append({"id": user.id,
|
||||||
"credential": user_credential,
|
"credential": user_credential,
|
||||||
"tenant_id": tenant_id})
|
"tenant_id": tenant_id})
|
||||||
@ -284,7 +292,13 @@ class UserGenerator(context.Context):
|
|||||||
|
|
||||||
def use_existing_users(self):
|
def use_existing_users(self):
|
||||||
LOG.debug("Using existing users for OpenStack platform.")
|
LOG.debug("Using existing users for OpenStack platform.")
|
||||||
|
api_info = copy.deepcopy(self.env["platforms"]["openstack"].get(
|
||||||
|
"api_info", {}))
|
||||||
for user_credential in self.existing_users:
|
for user_credential in self.existing_users:
|
||||||
|
user_credential = copy.deepcopy(user_credential)
|
||||||
|
if "api_info" in user_credential:
|
||||||
|
api_info.update(user_credential["api_info"])
|
||||||
|
user_credential["api_info"] = api_info
|
||||||
user_credential = credential.OpenStackCredential(**user_credential)
|
user_credential = credential.OpenStackCredential(**user_credential)
|
||||||
user_clients = osclients.Clients(user_credential)
|
user_clients = osclients.Clients(user_credential)
|
||||||
user_id = user_clients.keystone.auth_ref.user_id
|
user_id = user_clients.keystone.auth_ref.user_id
|
||||||
|
@ -28,7 +28,8 @@ class OpenStackCredential(dict):
|
|||||||
domain_name=None, endpoint=None, user_domain_name=None,
|
domain_name=None, endpoint=None, user_domain_name=None,
|
||||||
project_domain_name=None,
|
project_domain_name=None,
|
||||||
https_insecure=False, https_cacert=None, https_cert=None,
|
https_insecure=False, https_cacert=None, https_cert=None,
|
||||||
profiler_hmac_key=None, profiler_conn_str=None, **kwargs):
|
profiler_hmac_key=None, profiler_conn_str=None,
|
||||||
|
api_info=None, **kwargs):
|
||||||
if kwargs:
|
if kwargs:
|
||||||
raise TypeError("%s" % kwargs)
|
raise TypeError("%s" % kwargs)
|
||||||
|
|
||||||
@ -50,7 +51,8 @@ class OpenStackCredential(dict):
|
|||||||
("https_cacert", https_cacert),
|
("https_cacert", https_cacert),
|
||||||
("https_cert", https_cert),
|
("https_cert", https_cert),
|
||||||
("profiler_hmac_key", profiler_hmac_key),
|
("profiler_hmac_key", profiler_hmac_key),
|
||||||
("profiler_conn_str", profiler_conn_str)
|
("profiler_conn_str", profiler_conn_str),
|
||||||
|
("api_info", api_info or {})
|
||||||
])
|
])
|
||||||
|
|
||||||
self._clients_cache = {}
|
self._clients_cache = {}
|
||||||
|
@ -111,7 +111,8 @@ class OSClient(plugin.Plugin):
|
|||||||
self.credential = credential
|
self.credential = credential
|
||||||
if not isinstance(self.credential, oscred.OpenStackCredential):
|
if not isinstance(self.credential, oscred.OpenStackCredential):
|
||||||
self.credential = oscred.OpenStackCredential(**self.credential)
|
self.credential = oscred.OpenStackCredential(**self.credential)
|
||||||
self.api_info = api_info
|
if api_info:
|
||||||
|
self.credential.api_info.update(api_info)
|
||||||
self.cache = cache_obj
|
self.cache = cache_obj
|
||||||
|
|
||||||
def choose_version(self, version=None):
|
def choose_version(self, version=None):
|
||||||
@ -138,8 +139,8 @@ class OSClient(plugin.Plugin):
|
|||||||
# For those clients which doesn't accept string value(for example
|
# For those clients which doesn't accept string value(for example
|
||||||
# zaqarclient), this method should be overridden.
|
# zaqarclient), this method should be overridden.
|
||||||
version = (version or
|
version = (version or
|
||||||
self.api_info.get(self.get_name(), {}).get("version") or
|
self.credential.api_info.get(self.get_name(), {}).get(
|
||||||
self._meta_get("default_version"))
|
"version") or self._meta_get("default_version"))
|
||||||
if version is not None:
|
if version is not None:
|
||||||
version = str(version)
|
version = str(version)
|
||||||
return version
|
return version
|
||||||
@ -172,8 +173,8 @@ class OSClient(plugin.Plugin):
|
|||||||
service type from api_info(configured from a context) and default.
|
service type from api_info(configured from a context) and default.
|
||||||
"""
|
"""
|
||||||
return (service_type or
|
return (service_type or
|
||||||
self.api_info.get(self.get_name(), {}).get("service_type") or
|
self.credential.api_info.get(self.get_name(), {}).get(
|
||||||
self._meta_get("default_service_type"))
|
"service_type") or self._meta_get("default_service_type"))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def is_service_type_configurable(cls):
|
def is_service_type_configurable(cls):
|
||||||
@ -184,7 +185,7 @@ class OSClient(plugin.Plugin):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def keystone(self):
|
def keystone(self):
|
||||||
return OSClient.get("keystone")(self.credential, self.api_info,
|
return OSClient.get("keystone")(self.credential, None,
|
||||||
self.cache)
|
self.cache)
|
||||||
|
|
||||||
def _get_endpoint(self, service_type=None):
|
def _get_endpoint(self, service_type=None):
|
||||||
|
@ -33,6 +33,13 @@ class OpenStack(platform.Platform):
|
|||||||
|
|
||||||
It may be used to test any existing OpenStack API compatible cloud.
|
It may be used to test any existing OpenStack API compatible cloud.
|
||||||
"""
|
"""
|
||||||
|
VERSION_SCHEMA = {
|
||||||
|
"anyOf": [
|
||||||
|
{"type": "string", "description": "a string-like version."},
|
||||||
|
{"type": "number", "description": "a number-like version."}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
CONFIG_SCHEMA = {
|
CONFIG_SCHEMA = {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"definitions": {
|
"definitions": {
|
||||||
@ -63,6 +70,21 @@ class OpenStack(platform.Platform):
|
|||||||
"additionalProperties": False
|
"additionalProperties": False
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
},
|
||||||
|
"api_info": {
|
||||||
|
"type": "object",
|
||||||
|
"patternProperties": {
|
||||||
|
"^[a-z]+$": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"version": VERSION_SCHEMA,
|
||||||
|
"service_type": {"type": "string"}
|
||||||
|
},
|
||||||
|
"minProperties": 1,
|
||||||
|
"additionalProperties": False
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": False
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"properties": {
|
"properties": {
|
||||||
@ -81,7 +103,8 @@ class OpenStack(platform.Platform):
|
|||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {"$ref": "#/definitions/user"},
|
"items": {"$ref": "#/definitions/user"},
|
||||||
"minItems": 1
|
"minItems": 1
|
||||||
}
|
},
|
||||||
|
"api_info": {"$ref": "#/definitions/api_info"}
|
||||||
},
|
},
|
||||||
"anyOf": [
|
"anyOf": [
|
||||||
{
|
{
|
||||||
@ -115,6 +138,7 @@ class OpenStack(platform.Platform):
|
|||||||
del new_data["endpoint"]
|
del new_data["endpoint"]
|
||||||
admin = new_data.pop("admin", None)
|
admin = new_data.pop("admin", None)
|
||||||
users = new_data.pop("users", [])
|
users = new_data.pop("users", [])
|
||||||
|
api_info = new_data.pop("api_info", None)
|
||||||
|
|
||||||
if new_data.get("https_cert") and new_data.get("https_key"):
|
if new_data.get("https_cert") and new_data.get("https_key"):
|
||||||
new_data["https_cert"] = (new_data["https_cert"],
|
new_data["https_cert"] = (new_data["https_cert"],
|
||||||
@ -132,7 +156,10 @@ class OpenStack(platform.Platform):
|
|||||||
user.update(new_data)
|
user.update(new_data)
|
||||||
for k, v in defaults.items():
|
for k, v in defaults.items():
|
||||||
user.setdefault(k, v)
|
user.setdefault(k, v)
|
||||||
return {"admin": admin, "users": users}, {}
|
platform_data = {"admin": admin, "users": users}
|
||||||
|
if api_info:
|
||||||
|
platform_data["api_info"] = api_info
|
||||||
|
return platform_data, {}
|
||||||
|
|
||||||
def destroy(self):
|
def destroy(self):
|
||||||
# NOTE(boris-42): No action need to be performed.
|
# NOTE(boris-42): No action need to be performed.
|
||||||
|
@ -28,3 +28,9 @@ existing-with-predefined-users.json
|
|||||||
If you are using read-only backend in Keystone like LDAP, AD then
|
If you are using read-only backend in Keystone like LDAP, AD then
|
||||||
you need this sample. If you don't specify "users" rally will use already
|
you need this sample. If you don't specify "users" rally will use already
|
||||||
existing users that you provide.
|
existing users that you provide.
|
||||||
|
|
||||||
|
existing-api.json
|
||||||
|
--------------------------------
|
||||||
|
|
||||||
|
If you expect to specify version of some clients, you could register existing
|
||||||
|
Openstack cluster like this sample.
|
||||||
|
20
samples/deployments/existing-api.json
Normal file
20
samples/deployments/existing-api.json
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"openstack": {
|
||||||
|
"auth_url": "http://example.net:5000/v2.0/",
|
||||||
|
"region_name": "RegionOne",
|
||||||
|
"endpoint_type": "public",
|
||||||
|
"admin": {
|
||||||
|
"username": "admin",
|
||||||
|
"password": "myadminpass",
|
||||||
|
"tenant_name": "demo"
|
||||||
|
},
|
||||||
|
"https_insecure": false,
|
||||||
|
"https_cacert": ""
|
||||||
|
"api_info": {
|
||||||
|
"specified_client_name": {
|
||||||
|
"version": "version_number",
|
||||||
|
"service_type": "service_type"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
39
tests/functional/extra/fake_dir/fake_plugin.py
Normal file
39
tests/functional/extra/fake_dir/fake_plugin.py
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
# 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.
|
||||||
|
|
||||||
|
from rally_openstack import osclients
|
||||||
|
from rally_openstack import scenario
|
||||||
|
|
||||||
|
|
||||||
|
@osclients.configure("fakedummy", default_version="1",
|
||||||
|
default_service_type="dummy",
|
||||||
|
supported_versions=["1", "2"])
|
||||||
|
class FakeDummy(osclients.OSClient):
|
||||||
|
def create_client(self, version=None, service_type=None):
|
||||||
|
version = self.choose_version(version)
|
||||||
|
service_type = self.choose_service_type(service_type)
|
||||||
|
return {"version": version, "service_type": service_type}
|
||||||
|
|
||||||
|
|
||||||
|
@scenario.configure(name="FakeDummy.openstack_api")
|
||||||
|
class FakeDummyOpenstackAPI(scenario.OpenStackScenario):
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
admin_client = self.admin_clients("fakedummy")
|
||||||
|
self.assertEqual("dummyv2", admin_client["service_type"])
|
||||||
|
self.assertEqual("2", admin_client["version"])
|
||||||
|
|
||||||
|
client = self.clients("fakedummy")
|
||||||
|
self.assertEqual("dummyv2", client["service_type"])
|
||||||
|
self.assertEqual("2", client["version"])
|
81
tests/functional/test_cli_task.py
Normal file
81
tests/functional/test_cli_task.py
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
# 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 json
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from tests.functional import utils
|
||||||
|
|
||||||
|
|
||||||
|
class TaskTestCase(unittest.TestCase):
|
||||||
|
|
||||||
|
def test_specify_version_by_deployment(self):
|
||||||
|
rally = utils.Rally()
|
||||||
|
deployment = json.loads(rally("deployment config"))
|
||||||
|
deployment["openstack"]["api_info"] = {
|
||||||
|
"fakedummy": {
|
||||||
|
"version": "2",
|
||||||
|
"service_type": "dummyv2"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
deployment = utils.JsonTempFile(deployment)
|
||||||
|
rally("deployment create --name t_create_with_api_info "
|
||||||
|
"--filename %s" % deployment.filename)
|
||||||
|
self.assertIn("t_create_with_api_info", rally("deployment list"))
|
||||||
|
|
||||||
|
config = {
|
||||||
|
"FakeDummy.openstack_api": [
|
||||||
|
{
|
||||||
|
"runner": {
|
||||||
|
"type": "constant",
|
||||||
|
"times": 1,
|
||||||
|
"concurrency": 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
config = utils.TaskConfig(config)
|
||||||
|
plugins = "tests/functional/extra/fake_dir/fake_plugin.py"
|
||||||
|
rally("--plugin-paths %s task start --task %s" % (
|
||||||
|
plugins, config.filename))
|
||||||
|
|
||||||
|
def test_specify_version_by_deployment_with_existing_users(self):
|
||||||
|
rally = utils.Rally()
|
||||||
|
deployment = json.loads(rally("deployment config"))
|
||||||
|
deployment["openstack"]["users"] = [deployment["openstack"]["admin"]]
|
||||||
|
deployment["openstack"]["api_info"] = {
|
||||||
|
"fakedummy": {
|
||||||
|
"version": "2",
|
||||||
|
"service_type": "dummyv2"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
deployment = utils.JsonTempFile(deployment)
|
||||||
|
rally("deployment create --name t_create_with_api_info "
|
||||||
|
"--filename %s" % deployment.filename)
|
||||||
|
self.assertIn("t_create_with_api_info", rally("deployment list"))
|
||||||
|
config = {
|
||||||
|
"FakeDummy.openstack_api": [
|
||||||
|
{
|
||||||
|
"runner": {
|
||||||
|
"type": "constant",
|
||||||
|
"times": 1,
|
||||||
|
"concurrency": 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
config = utils.TaskConfig(config)
|
||||||
|
plugins = "tests/functional/extra/fake_dir/fake_plugin.py"
|
||||||
|
rally("--plugin-paths %s task start --task %s" % (
|
||||||
|
plugins, config.filename))
|
@ -75,6 +75,25 @@ class ExistingPlatformTestCase(PlatformBaseTestCase):
|
|||||||
spec, spec["existing@openstack"])
|
spec, spec["existing@openstack"])
|
||||||
self.assertNotEqual([], result)
|
self.assertNotEqual([], result)
|
||||||
|
|
||||||
|
def test_validate_spec_schema_with_api_info(self):
|
||||||
|
spec = {
|
||||||
|
"existing@openstack": {
|
||||||
|
"auth_url": "url",
|
||||||
|
"admin": {
|
||||||
|
"username": "admin",
|
||||||
|
"password": "password123",
|
||||||
|
"tenant_name": "admin"
|
||||||
|
},
|
||||||
|
"api_info": {
|
||||||
|
"nova": {"version": 1},
|
||||||
|
"cinder": {"version": 2, "service_type": "volumev2"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result = platform.Platform.validate("existing@openstack", {},
|
||||||
|
spec, spec["existing@openstack"])
|
||||||
|
self.assertEqual([], result)
|
||||||
|
|
||||||
def test_create_users_only(self):
|
def test_create_users_only(self):
|
||||||
|
|
||||||
spec = {
|
spec = {
|
||||||
|
@ -43,7 +43,8 @@ class OpenStackCredentialTestCase(test.TestCase):
|
|||||||
"project_domain_name": None,
|
"project_domain_name": None,
|
||||||
"user_domain_name": None,
|
"user_domain_name": None,
|
||||||
"profiler_hmac_key": None,
|
"profiler_hmac_key": None,
|
||||||
"profiler_conn_str": None},
|
"profiler_conn_str": None,
|
||||||
|
"api_info": {}},
|
||||||
self.credential.to_dict())
|
self.credential.to_dict())
|
||||||
|
|
||||||
@mock.patch("rally_openstack.osclients.Clients")
|
@mock.patch("rally_openstack.osclients.Clients")
|
||||||
|
Loading…
Reference in New Issue
Block a user