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
This commit is contained in:
Rodion Promyshlennikov 2016-01-29 12:03:16 +03:00
parent 1590e323db
commit 52d913f636
7 changed files with 0 additions and 1018 deletions

View File

@ -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"])

View File

@ -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)

View File

@ -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
}
}
}

View File

@ -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
}
}
}

View File

@ -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)

View File

@ -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")