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:
parent
1590e323db
commit
52d913f636
@ -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"])
|
@ -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)
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
@ -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)
|
@ -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")
|
Loading…
Reference in New Issue
Block a user