From 52d913f6364eb1f6ce8a0bd15d1c74e7772d29bd Mon Sep 17 00:00:00 2001 From: Rodion Promyshlennikov Date: Fri, 29 Jan 2016 12:03:16 +0300 Subject: [PATCH] Remove fuel deployment engine Seems like this feature is broken and not used. Remove module fuel from deployment engines. Remove package fuel from deployment. Remove fuel samples. Remove unittests relative to fuel engine. Change-Id: I54c1a5de2028a667c35d3b6038c69a64a866451c --- rally/deployment/engines/fuel.py | 214 ----------- rally/deployment/fuel/__init__.py | 0 rally/deployment/fuel/fuelclient.py | 264 -------------- .../fuel-ha.json | 28 -- .../fuel-multinode.json | 28 -- tests/unit/deployment/engines/test_fuel.py | 144 -------- tests/unit/test_fuelclient.py | 340 ------------------ 7 files changed, 1018 deletions(-) delete mode 100644 rally/deployment/engines/fuel.py delete mode 100644 rally/deployment/fuel/__init__.py delete mode 100644 rally/deployment/fuel/fuelclient.py delete mode 100644 samples/deployments/for_deploying_openstack_with_rally/fuel-ha.json delete mode 100644 samples/deployments/for_deploying_openstack_with_rally/fuel-multinode.json delete mode 100644 tests/unit/deployment/engines/test_fuel.py delete mode 100644 tests/unit/test_fuelclient.py diff --git a/rally/deployment/engines/fuel.py b/rally/deployment/engines/fuel.py deleted file mode 100644 index cbdda6a0ef..0000000000 --- a/rally/deployment/engines/fuel.py +++ /dev/null @@ -1,214 +0,0 @@ -# Copyright 2014: Mirantis Inc. -# 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.common.i18n import _ -from rally.common import objects -from rally import consts -from rally.deployment import engine -from rally.deployment.fuel import fuelclient -from rally import exceptions - - -FILTER_SCHEMA = { - "type": "string", - "pattern": "^(ram|cpus|storage|mac)(==|<=?|>=?|!=)(.+)$", -} - -NODE_SCHEMA = { - "type": "object", - "required": ["amount"], - "properties": { - "amount": {"type": "integer"}, - "filters": { - "type": "array", - "uniqueItems": True, - "items": FILTER_SCHEMA, - }, - }, - "additionalProperties": False -} - - -IPV4_PATTERN = "(\d+\.){3}\d+" -IPV4_ADDRESS_PATTERN = "^%s$" % IPV4_PATTERN -IPV4_CIDR_PATTERN = "^%s\/\d+$" % IPV4_PATTERN - -IP_RANGE_SCHEMA = { - "type": "array", - "maxItems": 2, - "minItems": 2, - "items": { - "type": "string", - "pattern": IPV4_ADDRESS_PATTERN, - } -} - -NETWORK_SCHEMA = { - "type": "object", - "properties": { - "cidr": {"type": "string", "pattern": IPV4_CIDR_PATTERN}, - "gateway": {"type": "string", "pattern": IPV4_ADDRESS_PATTERN}, - "ip_ranges": {"type": "array", "items": IP_RANGE_SCHEMA}, - "vlan_start": {"type": "integer"}, - } -} - -NETWORKS_SCHEMA = { - "type": "object", - "properties": { - "public": NETWORK_SCHEMA, - "floating": NETWORK_SCHEMA, - "management": NETWORK_SCHEMA, - "storage": NETWORK_SCHEMA, - }, -} - - -@engine.configure(name="FuelEngine") -class FuelEngine(engine.Engine): - """Deploy with FuelWeb. - - Sample configuration: - - { - "type": "FuelEngine", - "deploy_name": "Rally multinode 01", - "release": "Havana on CentOS 6.4", - "api_url": "http://10.20.0.2:8000/api/v1/", - "mode": "multinode", - "nodes": { - "controller": {"amount": 1, "filters": ["storage>80G"]}, - "compute": {"amount": 1, "filters": ["storage>80G"]} - }, - "net_provider": "nova_network", - "dns_nameservers": ["172.18.208.44", "8.8.8.8"], - "networks": { - - "public": { - "cidr": "10.3.3.0/24", - "gateway": "10.3.3.1", - "ip_ranges": [["10.3.3.5", "10.3.3.254"]], - "vlan_start": 14 - }, - - "floating": { - "cidr": "10.3.4.0/24", - "ip_ranges": [["10.3.4.5", "10.3.4.254"]], - "vlan_start": 14 - } - } - } - """ - - CONFIG_SCHEMA = { - "type": "object", - "required": ["deploy_name", "api_url", "mode", "networks", - "nodes", "release", "net_provider"], - "properties": { - "release": {"type": "string"}, - "deploy_name": {"type": "string"}, - "api_url": {"type": "string"}, - "mode": {"type": "string"}, - "net_provider": {"type": "string"}, - "networks": NETWORKS_SCHEMA, - "nodes": { - "type": "object", - "required": ["controller"], - "properties": { - "controller": NODE_SCHEMA, - "compute": NODE_SCHEMA, - "cinder": NODE_SCHEMA, - "cinder+compute": NODE_SCHEMA, - }, - }, - }, - } - - def validate(self): - super(FuelEngine, self).validate() - if "compute" not in self.config["nodes"]: - if "cinder+compute" not in self.config["nodes"]: - raise exceptions.ValidationError( - _("At least one compute is required.")) - - def _get_nodes(self, key): - if key not in self.config["nodes"]: - return [] - amount = self.config["nodes"][key]["amount"] - filters = self.config["nodes"][key]["filters"] - nodes = [] - for i in range(amount): - node = self.nodes.pop(filters) - if node is None: - raise exceptions.NoNodesFound(filters=filters) - nodes.append(node) - return nodes - - def _get_release_id(self): - releases = self.client.get_releases() - for release in releases: - if release["name"] == self.config["release"]: - return release["id"] - raise exceptions.UnknownRelease(release=self.config["release"]) - - def deploy(self): - self.client = fuelclient.FuelClient(self.config["api_url"]) - - self.nodes = self.client.get_nodes() - - controllers = self._get_nodes("controller") - computes = self._get_nodes("compute") - cinders = self._get_nodes("cinder") - computes_cinders = self._get_nodes("cinder+compute") - - cluster = fuelclient.FuelCluster( - self.client, - name=self.config["deploy_name"], - release=self._get_release_id(), - mode=self.config["mode"], - net_provider=self.config["net_provider"], - net_segment_type=self.config.get("net_segment_type", "gre"), - ) - - cluster.set_nodes(controllers, ["controller"]) - cluster.set_nodes(computes, ["compute"]) - cluster.set_nodes(cinders, ["cinder"]) - cluster.set_nodes(computes_cinders, ["compute", "cinder"]) - - cluster.configure_network(self.config["networks"]) - cluster.deploy() - - self.deployment.add_resource("FuelEngine", - type="cloud", - info={"id": cluster.cluster["id"]}) - - ip = cluster.get_endpoint_ip() - attrs = cluster.get_attributes()["editable"]["access"] - - admin_credential = objects.Credential( - "http://%s:5000/v2.0/" % ip, - attrs["user"]["value"], - attrs["password"]["value"], - attrs["tenant"]["value"], - consts.EndpointPermission.ADMIN) - return {"admin": admin_credential} - - def cleanup(self): - resources = self.deployment.get_resources(provider_name="FuelEngine", - type="cloud") - self.client = fuelclient.FuelClient(self.config["api_url"]) - for res in resources: - self.client.delete_cluster(res["info"]["id"]) - objects.Deployment.delete_resource(res["id"]) diff --git a/rally/deployment/fuel/__init__.py b/rally/deployment/fuel/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/rally/deployment/fuel/fuelclient.py b/rally/deployment/fuel/fuelclient.py deleted file mode 100644 index 4ee7cce04f..0000000000 --- a/rally/deployment/fuel/fuelclient.py +++ /dev/null @@ -1,264 +0,0 @@ -# Copyright 2013: Mirantis Inc. -# 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 re -import time - -import requests - -from rally.common import logging - -LOG = logging.getLogger(__name__) - -FILTER_REG = re.compile(r"^([a-z]+)\s*([<>=!]=|<|>)\s*(.+)$") -INT_REG = re.compile(r"^(\d+)(K|M|G|T)?$") - - -class FuelException(Exception): - pass - - -class FuelClientException(FuelException): - - def __init__(self, code, body): - self.code = code - self.body = body - - def __str__(self): - return ("FuelClientException. " - "Code: %(code)d Body: %(body)s" % {"code": self.code, - "body": self.body}) - - -class FuelNetworkVerificationFailed(FuelException): - pass - - -class FuelNode(object): - - def __init__(self, node): - self.node = node - self.ATTRIBUTE_MAP = { - "==": lambda x, y: x == y, - "!=": lambda x, y: x != y, - "<=": lambda x, y: x <= y, - ">=": lambda x, y: x >= y, - "<": lambda x, y: x < y, - ">": lambda x, y: x > y, - } - self.FACTOR_MAP = { - "K": 1024, - "M": 1048576, - "G": 1073741824, - "T": 1099511627776, - None: 1, - } - - def __getitem__(self, key): - return self.node[key] - - def check_filters(self, filters): - return all((self.check(f) for f in filters)) - - def check(self, filter_string): - if self.node["cluster"] is not None: - return False - m = FILTER_REG.match(filter_string) - if m is None: - raise ValueError("Invalid filter: %s" % filter_string) - attribute, operator, value = m.groups() - return self._check(attribute, value, operator) - - def _check(self, attribute, value, operator): - attribute = getattr(self, "_get_" + attribute)() - checker = self.ATTRIBUTE_MAP[operator] - m = INT_REG.match(value) - if m: - value = int(m.group(1)) * self.FACTOR_MAP[m.group(2)] - return checker(attribute, value) - - def _get_ram(self): - return self.node["meta"]["memory"]["total"] - - def _get_mac(self): - return self.node["mac"] - - def _get_storage(self): - return sum((d["size"] for d in self.node["meta"]["disks"])) - - def _get_cpus(self): - return self.node["meta"]["cpu"]["total"] - - -class FuelCluster(object): - - def __init__(self, client, **config): - """Create Fuel cluster. - - :param client: FuelClient instance. - :param name: Name - :param release: Release id. Integer. - :param mode: One of multinode, ha_compact - :param net_provider: One of nova_network, neutron - :param net_segment_type: One of gre, vlan. - :param dns_nameservers: List of strings. - """ - - self.client = client - self.cluster = client.post("clusters", config) - - def get_nodes(self): - return self.client.get("nodes?cluster_id=%d" % self.cluster["id"]) - - def set_nodes(self, nodes, roles): - if not nodes: - return - node_list = [] - for n in nodes: - node_list.append({"id": n["id"], - "pending_roles": roles, - "pending_addition": True, - "cluster_id": self.cluster["id"]}) - self.client.put("nodes", node_list) - - def configure_network(self, config): - netconfig = self.get_network() - for network in netconfig["networks"]: - if network["name"] in config: - network.update(config[network["name"]]) - self.set_network(netconfig) - - def deploy(self): - self.client.put("clusters/%d/changes" % self.cluster["id"], {}) - for task in self.client.get_tasks(self.cluster["id"]): - if task["name"] == "deploy": - task_id = task["id"] - break - while 1: - time.sleep(10) - task = self.client.get_task(task_id) - if task["progress"] == 100: - return - LOG.info("Deployment in progress. %d%% done." % task["progress"]) - - def get_network(self): - args = {"cluster_id": self.cluster["id"], - "net_provider": self.cluster["net_provider"]} - url = ("clusters/%(cluster_id)d/network_configuration/" - "%(net_provider)s" % args) - return self.client.get(url) - - def set_network(self, config): - self.verify_network(config) - args = {"cluster_id": self.cluster["id"], - "net_provider": self.cluster["net_provider"]} - url = ("clusters/%(cluster_id)d/network_configuration/" - "%(net_provider)s" % args) - self.client.put(url, config) - - def verify_network(self, config): - args = {"cluster_id": self.cluster["id"], - "net_provider": self.cluster["net_provider"]} - url = ("clusters/%(cluster_id)d/network_configuration/" - "%(net_provider)s/verify" % args) - task_id = self.client.put(url, config)["id"] - while 1: - time.sleep(5) - task = self.client.get_task(task_id) - if task["progress"] == 100: - if task["message"]: - raise FuelNetworkVerificationFailed(task["message"]) - else: - return - LOG.info("Network verification in progress." - " %d%% done." % task["progress"]) - - def get_attributes(self): - return self.client.get("clusters/%d/attributes" % self.cluster["id"]) - - def get_endpoint_ip(self): - if self.cluster["mode"].startswith("ha_"): - netdata = self.get_network() - return netdata["public_vip"] - - for node in self.get_nodes(): - if "controller" in node["roles"]: - for net in node["network_data"]: - if net["name"] == "public": - return net["ip"].split("/")[0] - - raise FuelException("Unable to get endpoint ip.") - - -class FuelNodesCollection(object): - nodes = [] - - def __init__(self, nodes): - for node in nodes: - self.nodes.append(FuelNode(node)) - - def pop(self, filters): - for i, node in enumerate(self.nodes): - if node.check_filters(filters): - return self.nodes.pop(i) - - -class FuelClient(object): - - def __init__(self, base_url): - self.base_url = base_url - - def _request(self, method, url, data=None): - if data: - data = json.dumps(data) - headers = {"content-type": "application/json"} - reply = getattr(requests, method)(self.base_url + url, data=data, - headers=headers) - if reply.status_code >= 300 or reply.status_code < 200: - raise FuelClientException(code=reply.status_code, body=reply.text) - if reply.text and reply.headers["content-type"] == "application/json": - return json.loads(reply.text) - return reply - - def get(self, url): - return self._request("get", url) - - def post(self, url, data): - return self._request("post", url, data) - - def put(self, url, data): - return self._request("put", url, data) - - def delete(self, url): - return self._request("delete", url) - - def get_releases(self): - return self.get("releases") - - def get_task(self, task_id): - return self.get("tasks/%d" % task_id) - - def get_tasks(self, cluster_id): - return self.get("tasks?cluster_id=%d" % cluster_id) - - def get_node(self, node_id): - return self.get("nodes/%d" % node_id) - - def get_nodes(self): - return FuelNodesCollection(self.get("nodes")) - - def delete_cluster(self, cluster_id): - self.delete("clusters/%s" % cluster_id) diff --git a/samples/deployments/for_deploying_openstack_with_rally/fuel-ha.json b/samples/deployments/for_deploying_openstack_with_rally/fuel-ha.json deleted file mode 100644 index 5f5fcc06b0..0000000000 --- a/samples/deployments/for_deploying_openstack_with_rally/fuel-ha.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "type": "FuelEngine", - "deploy_name": "Rally HA 01", - "release": "Havana on CentOS 6.4", - "api_url": "http://10.20.0.2:8000/api/v1/", - "mode": "ha_compact", - "nodes": { - "controller": {"amount": 3, "filters": ["storage>80G"]}, - "compute": {"amount": 1, "filters": ["storage>80G"]} - }, - "net_provider": "nova_network", - "dns_nameservers": ["172.18.208.44", "8.8.8.8"], - "networks": { - - "public": { - "cidr": "10.3.5.0/24", - "gateway": "10.3.5.1", - "ip_ranges": [["10.3.5.5", "10.3.5.254"]], - "vlan_start": 15 - }, - - "floating": { - "cidr": "10.3.6.0/24", - "ip_ranges": [["10.3.6.5", "10.3.6.254"]], - "vlan_start": 15 - } - } -} diff --git a/samples/deployments/for_deploying_openstack_with_rally/fuel-multinode.json b/samples/deployments/for_deploying_openstack_with_rally/fuel-multinode.json deleted file mode 100644 index 604043aa5a..0000000000 --- a/samples/deployments/for_deploying_openstack_with_rally/fuel-multinode.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "type": "FuelEngine", - "deploy_name": "Rally multinode 01", - "release": "Havana on CentOS 6.4", - "api_url": "http://10.20.0.2:8000/api/v1/", - "mode": "multinode", - "nodes": { - "controller": {"amount": 1, "filters": ["storage>80G"]}, - "compute": {"amount": 1, "filters": ["storage>80G"]} - }, - "net_provider": "nova_network", - "dns_nameservers": ["172.18.208.44", "8.8.8.8"], - "networks": { - - "public": { - "cidr": "10.3.3.0/24", - "gateway": "10.3.3.1", - "ip_ranges": [["10.3.3.5", "10.3.3.254"]], - "vlan_start": 14 - }, - - "floating": { - "cidr": "10.3.4.0/24", - "ip_ranges": [["10.3.4.5", "10.3.4.254"]], - "vlan_start": 14 - } - } -} diff --git a/tests/unit/deployment/engines/test_fuel.py b/tests/unit/deployment/engines/test_fuel.py deleted file mode 100644 index 8e6fb54597..0000000000 --- a/tests/unit/deployment/engines/test_fuel.py +++ /dev/null @@ -1,144 +0,0 @@ -# Copyright 2014: Mirantis Inc. -# 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 import consts -from rally.deployment.engines import fuel -from rally import exceptions -from tests.unit import fakes -from tests.unit import test - -import mock - - -SAMPLE_CONFIG = { - "type": "FuelEngine", - "deploy_name": "TestDeploy01", - "net_provider": "nova_network", - "release": "Havana on Ubuntu 12.04", - "api_url": "http://example.net:8000/api/v1/", - "mode": "multinode", - "networks": {"public": {"cidr": "10.1.1.0/24"}}, - "nodes": { - "controller": {"amount": 1, "filters": ["cpus==2"]}, - "cinder+compute": {"amount": 4, "filters": ["cpus==8", - "storage>=2T"]}, - }, -} - - -class FuelEngineTestCase(test.TestCase): - - def setUp(self): - super(FuelEngineTestCase, self).setUp() - self.deployment = fakes.FakeDeployment({"config": SAMPLE_CONFIG}) - - def test_construct(self): - fuel.FuelEngine(self.deployment) - - def test_validate_no_computes(self): - config = SAMPLE_CONFIG.copy() - config["nodes"].pop("cinder+compute") - deployment = {"config": config} - engine = fuel.FuelEngine(deployment) - self.assertRaises(exceptions.ValidationError, - engine.validate) - - def test__get_nodes(self): - engine = fuel.FuelEngine(self.deployment) - engine.nodes = mock.MagicMock() - engine.nodes.pop.side_effect = [1, 2, 3, 4] - nodes = engine._get_nodes("cinder+compute") - self.assertEqual([1, 2, 3, 4], nodes) - expected_calls = [mock.call(["cpus==8", "storage>=2T"])] * 4 - self.assertEqual(expected_calls, engine.nodes.pop.mock_calls) - - def test__get_nodes_no_nodes(self): - engine = fuel.FuelEngine(self.deployment) - engine.nodes = mock.MagicMock() - engine.nodes.pop.return_value = None - self.assertRaises(exceptions.NoNodesFound, - engine._get_nodes, "controller") - - def test__get_nodes_empty(self): - engine = fuel.FuelEngine(self.deployment) - self.assertEqual([], engine._get_nodes("nonexistent")) - - def test__get_release_id(self): - engine = fuel.FuelEngine(self.deployment) - engine.client = mock.Mock() - fake_releases = [{"name": "fake", "id": 1}, - {"name": "Havana on Ubuntu 12.04", "id": 42}] - engine.client.get_releases = mock.Mock(return_value=fake_releases) - self.assertEqual(42, engine._get_release_id()) - - @mock.patch("rally.deployment.fuel.fuelclient.FuelClient") - @mock.patch("rally.deployment.fuel.fuelclient.FuelCluster") - def test_deploy(self, mock_fuel_cluster, mock_fuel_client): - attributes = {"editable": {"access": {"user": {"value": "user"}, - "password": {"value": "pw"}, - "tenant": {"value": "tn"}}}} - client = mock.Mock() - cluster = mock.Mock( - cluster={"id": 42}, - **{ - "get_endpoint_ip.return_value": "2.3.4.5", - "get_attributes.return_value": attributes - } - ) - mock_fuel_client.return_value = client - mock_fuel_cluster.return_value = cluster - self.deployment.add_resource = mock.Mock() - - engine = fuel.FuelEngine(self.deployment) - - engine._get_nodes = mock.Mock(side_effect=[1, 2, 3, 4]) - engine._get_release_id = mock.Mock() - - credential = engine.deploy() - self.assertEqual(["admin"], list(credential)) - credential = credential["admin"] - - self.assertEqual("user", credential.username) - self.assertEqual("pw", credential.password) - self.assertEqual("tn", credential.tenant_name) - self.assertEqual("http://2.3.4.5:5000/v2.0/", credential.auth_url) - self.assertEqual(consts.EndpointPermission.ADMIN, - credential.permission) - - expected_cluster_calls = [ - mock.call.set_nodes(1, ["controller"]), - mock.call.set_nodes(2, ["compute"]), - mock.call.set_nodes(3, ["cinder"]), - mock.call.set_nodes(4, ["compute", "cinder"]), - mock.call.configure_network({"public": {"cidr": "10.1.1.0/24"}}), - mock.call.deploy(), - mock.call.get_endpoint_ip(), - mock.call.get_attributes() - ] - self.assertEqual(expected_cluster_calls, cluster.mock_calls) - self.assertEqual([mock.call.get_nodes()], client.mock_calls) - - @mock.patch("rally.deployment.fuel.fuelclient.FuelClient") - @mock.patch("rally.deployment.engines.fuel.objects.Deployment") - def test_cleanup(self, mock_deployment, mock_fuel_client): - fake_resources = [{"id": 41, "info": {"id": 42}}] - self.deployment.get_resources = mock.Mock(return_value=fake_resources) - - engine = fuel.FuelEngine(self.deployment) - engine.client = mock.Mock() - engine.cleanup() - - engine.client.delete_cluster.assert_called_once_with(42) - mock_deployment.delete_resource.assert_called_once_with(41) diff --git a/tests/unit/test_fuelclient.py b/tests/unit/test_fuelclient.py deleted file mode 100644 index a9b0b30674..0000000000 --- a/tests/unit/test_fuelclient.py +++ /dev/null @@ -1,340 +0,0 @@ -# Copyright 2013: Mirantis Inc. -# 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 copy - -import mock - -from rally.deployment.fuel import fuelclient -from tests.unit import test - - -class FuelNodeTestCase(test.TestCase): - - def test_check(self): - - node = { - "cluster": None, - "mac": "00:01:02:0a:0b:0c", - "meta": { - "memory": {"total": 42}, - "cpu": {"total": 2}, - "disks": [{"size": 22}, {"size": 33}] # total 55 - }, - } - - n = fuelclient.FuelNode(node) - - self.assertFalse(n.check("ram==41")) - self.assertFalse(n.check("ram!=42")) - self.assertFalse(n.check("ram<=41")) - self.assertFalse(n.check("ram>=43")) - self.assertFalse(n.check("ram>43")) - self.assertFalse(n.check("ram<41")) - self.assertFalse(n.check("cpus>3")) - - self.assertTrue(n.check("ram==42")) - self.assertTrue(n.check("ram!=41")) - self.assertTrue(n.check("ram<=43")) - self.assertTrue(n.check("ram<=42")) - self.assertTrue(n.check("ram>=41")) - self.assertTrue(n.check("ram>=42")) - self.assertTrue(n.check("ram<43")) - self.assertTrue(n.check("ram>41")) - self.assertTrue(n.check("cpus==2")) - - self.assertTrue(n.check("mac==00:01:02:0a:0b:0c")) - self.assertTrue(n.check("mac!=00:01:02:0a:0b:0e")) - self.assertTrue(n.check("storage==55")) - self.assertTrue(n.check("storage<=1G")) - self.assertTrue(n.check("storage<1M")) - - -class FuelNodesCollectionTestCase(test.TestCase): - - def test_pop(self): - node = { - "cluster": None, - "mac": "00:01:02:0a:0b:0c", - "meta": { - "memory": {"total": 42}, - "cpu": {"total": 2}, - "disks": [{"size": 22}, {"size": 33}] # total 55 - }, - } - - nodes = [copy.deepcopy(node) for i in range(4)] - nodes[0]["meta"]["cpu"]["total"] = 1 - nodes[1]["meta"]["cpu"]["total"] = 2 - nodes[2]["meta"]["memory"]["total"] = 16 - nodes[3]["cluster"] = 42 # node with cluster is occupied - - nodes = fuelclient.FuelNodesCollection(nodes) - - node_1cpu = nodes.pop(["cpus==1"]) - self.assertEqual(node_1cpu._get_cpus(), 1) - self.assertEqual(len(nodes.nodes), 3) - - node_2cpu = nodes.pop(["cpus==2"]) - self.assertEqual(node_2cpu._get_cpus(), 2) - self.assertEqual(len(nodes.nodes), 2) - - node_16ram_2cpu = nodes.pop(["ram>=16", "cpus==2"]) - self.assertEqual(node_16ram_2cpu._get_ram(), 16) - self.assertEqual(node_16ram_2cpu._get_cpus(), 2) - self.assertEqual(len(nodes.nodes), 1) - node_none = nodes.pop(["storage>4T"]) - self.assertIsNone(node_none) - - -class FuelClusterTestCase(test.TestCase): - - def setUp(self): - super(FuelClusterTestCase, self).setUp() - self.client = mock.Mock() - self.config = {"name": "Cluster"} - self.cluster = fuelclient.FuelCluster(self.client, **self.config) - - def test_init(self): - self.client.post.assert_called_once_with("clusters", self.config) - - def test_get_nodes(self): - self.cluster.cluster = {"id": 42} - self.cluster.get_nodes() - self.client.get.assert_called_once_with("nodes?cluster_id=42") - - def test_set_nodes_empty(self): - self.assertIsNone(self.cluster.set_nodes([], [])) - - def test_set_nodes(self): - nodes = [{"id": 42}, {"id": 43}] - self.cluster.cluster = {"id": 1} - self.cluster.set_nodes(nodes, ["role1", "role2"]) - - node42_args = {"cluster_id": 1, - "pending_roles": ["role1", "role2"], - "pending_addition": True, - "id": 42} - node43_args = {"cluster_id": 1, - "pending_roles": ["role1", "role2"], - "pending_addition": True, - "id": 43} - expected = [ - mock.call.post("clusters", {"name": "Cluster"}), - mock.call.put("nodes", [node42_args, node43_args]) - ] - self.assertEqual(expected, self.client.mock_calls) - - def test_configure_network(self): - current_network = {"networks": [{"name": "public", - "key": "old_val", - "key2": "val2"}]} - - netconfig = {"public": {"key": "new_val"}} - self.cluster.get_network = mock.Mock(return_value=current_network) - self.cluster.set_network = mock.Mock() - - self.cluster.configure_network(netconfig) - - self.cluster.set_network.assert_called_once_with( - {"networks": [{"name": "public", - "key": "new_val", - "key2": "val2"}]}) - - @mock.patch("rally.deployment.fuel.fuelclient.time.sleep") - def test_deploy(self, mock_sleep): - call1 = {"progress": 50} - call2 = {"progress": 100} - self.client.get_task.side_effect = [call1, call2] - - tasks = [{"name": "deploy", "id": 41}] - self.client.get_tasks.return_value = tasks - - self.cluster.cluster = {"id": 42} - self.cluster.deploy() - - expected = [ - mock.call.post("clusters", {"name": "Cluster"}), - mock.call.put("clusters/42/changes", {}), - mock.call.get_tasks(42), - mock.call.get_task(41), - mock.call.get_task(41) - ] - self.assertEqual(expected, self.client.mock_calls) - - def test_get_network(self): - self.cluster.cluster = {"id": 42, "net_provider": "nova_network"} - self.cluster.get_network() - self.client.get.assert_called_once_with( - "clusters/42/network_configuration/nova_network") - - def test_set_network(self): - self.cluster.cluster = {"id": 42, "net_provider": "nova_network"} - self.cluster.verify_network = mock.Mock() - self.cluster.set_network({"key": "val"}) - - self.client.put.assert_called_once_with( - "clusters/42/network_configuration/nova_network", {"key": "val"}) - self.cluster.verify_network.assert_called_once_with({"key": "val"}) - - @mock.patch("rally.deployment.fuel.fuelclient.time.sleep") - def test_verify_network(self, mock_sleep): - call1 = {"progress": 50} - call2 = {"progress": 100, "message": ""} - - self.client.put.return_value = {"id": 42} - self.client.get_task.side_effect = [call1, call2] - self.cluster.cluster = {"id": 43, "net_provider": "nova_network"} - - self.cluster.verify_network({"key": "val"}) - - self.client.put.assert_called_once_with( - "clusters/43/network_configuration/nova_network/verify", - {"key": "val"}) - self.assertEqual([mock.call(42), mock.call(42)], - self.client.get_task.mock_calls) - - @mock.patch("rally.deployment.fuel.fuelclient.time.sleep") - def test_verify_network_fail(self, mock_sleep): - self.client.put.return_value = {"id": 42} - self.client.get_task.return_value = {"progress": 100, - "message": "error"} - self.cluster.cluster = {"id": 43, "net_provider": "nova_network"} - self.assertRaises(fuelclient.FuelNetworkVerificationFailed, - self.cluster.verify_network, {"key": "val"}) - - def test_get_attributes(self): - self.cluster.cluster = {"id": 52} - self.cluster.get_attributes() - self.client.get.assert_called_once_with("clusters/52/attributes") - - def test_get_endpoint_ip_multinode(self): - self.cluster.cluster = {"mode": "multinode"} - node1 = {"roles": ["compute", "cinder"]} - node2 = {"roles": ["controller"], - "network_data": [{"name": "private"}, - {"name": "public", "ip": "42.42.42.42/24"}]} - fake_nodes = [node1, node2] - self.cluster.get_nodes = mock.Mock(return_value=fake_nodes) - ip = self.cluster.get_endpoint_ip() - self.assertEqual("42.42.42.42", ip) - - def test_get_endpoint_ip_ha(self): - ip = "1.2.3.4" - self.cluster.cluster = {"id": 42, "mode": "ha_compact"} - self.cluster.get_network = mock.Mock(return_value={"public_vip": ip}) - self.assertEqual(ip, self.cluster.get_endpoint_ip()) - - -class FuelClientTestCase(test.TestCase): - - def setUp(self): - super(FuelClientTestCase, self).setUp() - self.client = fuelclient.FuelClient("http://10.20.0.2:8000/api/v1/") - - @mock.patch("rally.deployment.fuel.fuelclient.requests") - def test__request_non_json(self, mock_requests): - reply = mock.Mock() - reply.status_code = 200 - reply.headers = {"content-type": "application/x-httpd-php"} - reply.text = "{\"reply\": \"ok\"}" - mock_requests.method.return_value = reply - - retval = self.client._request("method", "url", data={"key": "value"}) - - self.assertEqual(retval, reply) - - @mock.patch("rally.deployment.fuel.fuelclient.requests") - def test__request_non_2xx(self, mock_requests): - reply = mock.Mock() - reply.status_code = 300 - reply.headers = {"content-type": "application/json"} - reply.text = "{\"reply\": \"ok\"}" - mock_requests.method.return_value = reply - self.assertRaises(fuelclient.FuelClientException, - self.client._request, "method", "url", - data={"key": "value"}) - - @mock.patch("rally.deployment.fuel.fuelclient.requests") - def test__request(self, mock_requests): - reply = mock.Mock() - reply.status_code = 202 - reply.headers = {"content-type": "application/json"} - reply.text = "{\"reply\": \"ok\"}" - mock_requests.method.return_value = reply - - retval = self.client._request("method", "url", data={"key": "value"}) - mock_requests.method.assert_called_once_with( - "http://10.20.0.2:8000/api/v1/url", - headers={"content-type": "application/json"}, - data="{\"key\": \"value\"}") - self.assertEqual(retval, {"reply": "ok"}) - - @mock.patch.object(fuelclient.FuelClient, "_request") - def test_get(self, mock_fuel_client__request): - self.client.get("url") - mock_fuel_client__request.assert_called_once_with("get", "url") - - @mock.patch.object(fuelclient.FuelClient, "_request") - def test_delete(self, mock_fuel_client__request): - self.client.delete("url") - mock_fuel_client__request.assert_called_once_with("delete", "url") - - @mock.patch.object(fuelclient.FuelClient, "_request") - def test_post(self, mock_fuel_client__request): - self.client.post("url", {"key": "val"}) - mock_fuel_client__request.assert_called_once_with( - "post", "url", {"key": "val"}) - - @mock.patch.object(fuelclient.FuelClient, "_request") - def test_put(self, mock_fuel_client__request): - self.client.put("url", {"key": "val"}) - mock_fuel_client__request.assert_called_once_with( - "put", "url", {"key": "val"}) - - @mock.patch.object(fuelclient.FuelClient, "get") - def test_get_releases(self, mock_fuel_client_get): - self.client.get_releases() - mock_fuel_client_get.assert_called_once_with("releases") - - @mock.patch.object(fuelclient.FuelClient, "get") - def test_get_task(self, mock_fuel_client_get): - self.client.get_task(42) - mock_fuel_client_get.assert_called_once_with("tasks/42") - - @mock.patch.object(fuelclient.FuelClient, "get") - def test_get_tasks(self, mock_fuel_client_get): - self.client.get_tasks(42) - mock_fuel_client_get.assert_called_once_with("tasks?cluster_id=42") - - @mock.patch.object(fuelclient.FuelClient, "get") - def test_get_node(self, mock_fuel_client_get): - self.client.get_node(42) - mock_fuel_client_get.assert_called_once_with("nodes/42") - - @mock.patch.object(fuelclient, "FuelNodesCollection") - @mock.patch.object(fuelclient.FuelClient, "get") - def test_get_nodes(self, mock_fuel_client_get, mock_fuel_nodes_collection): - mock_fuel_client_get.return_value = "fake_nodes" - mock_fuel_nodes_collection.return_value = "fake_collection" - retval = self.client.get_nodes() - self.assertEqual("fake_collection", retval) - mock_fuel_nodes_collection.assert_called_once_with("fake_nodes") - mock_fuel_client_get.assert_called_once_with("nodes") - - @mock.patch.object(fuelclient.FuelClient, "delete") - def test_delete_cluster(self, mock_fuel_client_delete): - self.client.delete_cluster(42) - mock_fuel_client_delete.assert_called_once_with("clusters/42")