Merge "Remove fuel deployment engine"

This commit is contained in:
Jenkins 2016-02-01 12:39:19 +00:00 committed by Gerrit Code Review
commit a662609f55
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")