fuel-web/nailgun/nailgun/test/unit/test_vmware_attributes_vali...

444 lines
17 KiB
Python

# -*- coding: utf-8 -*-
# Copyright 2015 Mirantis, Inc.
#
# 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 copy import deepcopy
from mock import patch
from nailgun.api.v1.validators.cluster import VmwareAttributesValidator
from nailgun import consts
from nailgun import errors
from nailgun import objects
from nailgun.test.base import BaseTestCase
class TestAttributesValidator(BaseTestCase):
def setUp(self):
super(TestAttributesValidator, self).setUp()
self.cluster = self.env.create(
cluster_kwargs={
"api": False,
"vmware_attributes": {
"editable": self._get_value_vmware_attributes()
}
},
nodes_kwargs=[{
"hostname": "controller-node",
"status": consts.NODE_STATUSES.ready
}]
)
self.ready_compute_node = self.env.create_node(
hostname="node-1",
name="Node 1",
roles=["compute-vmware"],
status=consts.NODE_STATUSES.ready,
cluster_id=self.cluster.id
)
def _get_target_id(self, nova_compute):
return nova_compute["target_node"]["current"]["id"]
def _get_default_nova_computes(self):
return [
{
"datastore_regex": ".*",
"vsphere_cluster": "Cluster1",
"target_node": {
"current": {
"id": "node-1",
"label": "node-1"
}
},
"service_name": "ns1"
},
{
"datastore_regex": ".*",
"vsphere_cluster": "Cluster0",
"target_node": {
"current": {
"id": "controllers",
"label": "controllers"
}
},
"service_name": "ns0"
}
]
def _get_value_vmware_attributes(self, nova_computes=None):
return {
"value": {
"availability_zones": [{
"vcenter_username": "admin",
"az_name": "vcenter",
"vcenter_password": "pass",
"vcenter_host": "172.16.0.254",
"nova_computes":
nova_computes or self._get_default_nova_computes()
}]
}
}
def validate_nova_compute_raises_regexp(self, nova_computes, error_msg):
with self.assertRaisesRegexp(errors.InvalidData, error_msg):
VmwareAttributesValidator._validate_nova_computes(
{"editable": self._get_value_vmware_attributes(nova_computes)},
self.cluster.vmware_attributes
)
def test_change_exist_nova_compute(self):
nova_computes = self._get_default_nova_computes()
changed_attribute = 'vsphere_cluster'
for nc in nova_computes:
if self._get_target_id(nc) == self.ready_compute_node.hostname:
nc[changed_attribute] = "ClusterXX"
break
self.validate_nova_compute_raises_regexp(
nova_computes,
"Parameter '{0}' of nova compute instance with target node '{1}' "
"couldn't be changed".format(
changed_attribute, self.ready_compute_node.name
)
)
def test_delete_operational_nova_compute_node(self):
nova_computes = [
nc for nc in self._get_default_nova_computes() if
self._get_target_id(nc) != self.ready_compute_node.hostname
]
self.validate_nova_compute_raises_regexp(
nova_computes,
"The following compute-vmware node couldn't be deleted from "
"vSphere cluster: {0}".format(self.ready_compute_node.name)
)
def test_duplicate_values_for_nova_computes(self):
for attr in ("vsphere_cluster", "target_node", "service_name"):
exist_nova_computes = self._get_default_nova_computes()
duplicate_value = exist_nova_computes[0][attr]
new_nova_compute = {
"datastore_regex": ".*",
"vsphere_cluster": "ClusterXX",
"target_node": {
"current": {
"id": "node-X",
"label": "node-X"
},
},
"service_name": "nsXX"
}
new_nova_compute.update({attr: duplicate_value})
exist_nova_computes.append(new_nova_compute)
duplicate_value = duplicate_value if attr != "target_node" \
else duplicate_value["current"]["id"]
self.validate_nova_compute_raises_regexp(
exist_nova_computes,
"Duplicate value '{0}' for attribute '{1}' is not allowed".
format(duplicate_value, attr)
)
def test_empty_values_for_nova_computes(self):
nova_computes = self._get_default_nova_computes()
nova_computes[0]["vsphere_cluster"] = ""
self.validate_nova_compute_raises_regexp(
nova_computes,
"Empty value for attribute 'vsphere_cluster' is not allowed"
)
def test_nova_compute_setting_validate_pass(self):
new_compute_vmware_node = self.env.create_node(
hostname="node-2",
name="Node 2",
pending_roles=["compute-vmware"],
pending_addition=True,
cluster_id=self.cluster.id
)
self.env.create_node(
hostname="node-3",
name="Node 3",
roles=["compute-vmware"],
pending_deletion=True,
cluster_id=self.cluster.id
)
attributes = self.cluster.vmware_attributes
new_nova_computes = self._get_default_nova_computes()
new_nova_computes.extend([{
"datastore_regex": ".*",
"vsphere_cluster": "Cluster2",
"target_node": {
"current": {
"id": new_compute_vmware_node.hostname,
"label": new_compute_vmware_node.name
}
},
"service_name": "ns2"
}])
self.assertNotRaises(errors.InvalidData,
VmwareAttributesValidator._validate_nova_computes,
{"editable": self._get_value_vmware_attributes(
new_nova_computes)},
attributes)
def test_change_controller_nova_computes_pass(self):
cluster = self.env.create(
cluster_kwargs={
"api": False,
"status": consts.CLUSTER_STATUSES.new,
"vmware_attributes": {
"editable": self._get_value_vmware_attributes()
}
}
)
new_nova_computes = [nc for nc in self._get_default_nova_computes()
if self._get_target_id(nc) == "controllers"]
new_nova_computes[0]["vsphere_cluster"] = "new vsphere name"
new_nova_computes.append({
"datastore_regex": ".*",
"vsphere_cluster": "Cluster10",
"target_node": {
"current": {
"id": "controllers",
"label": "controllers"
}
},
"service_name": "ns10"
})
self.assertNotRaises(errors.InvalidData,
VmwareAttributesValidator._validate_nova_computes,
{"editable": self._get_value_vmware_attributes(
new_nova_computes)},
cluster.vmware_attributes)
@patch("nailgun.db.sqlalchemy.models.Cluster.is_locked", return_value=True)
def test_change_controllers_nova_compute_setting(self, lock_mock):
new_nova_computes = self._get_default_nova_computes()
changed_vsphere_cluster = None
changed_attribute = "service_name"
for nc in new_nova_computes:
if self._get_target_id(nc) == "controllers":
nc[changed_attribute] = "new_service_name"
changed_vsphere_cluster = nc
break
self.validate_nova_compute_raises_regexp(
new_nova_computes,
"Parameter '{0}' of nova compute instance with vSphere cluster "
"name '{1}' couldn't be changed".format(
changed_attribute, changed_vsphere_cluster["vsphere_cluster"])
)
@patch("nailgun.db.sqlalchemy.models.Cluster.is_locked", return_value=True)
def test_add_controllers_nova_compute_setting(self, lock_mock):
new_nova_computes = self._get_default_nova_computes()
new_nova_computes.extend([{
"datastore_regex": ".*",
"vsphere_cluster": "Cluster20",
"target_node": {
"current": {
"id": "controllers",
"label": "controllers"
}
},
"service_name": "ns20"
}, {
"datastore_regex": ".*",
"vsphere_cluster": "Cluster30",
"target_node": {
"current": {
"id": "controllers",
"label": "controllers"
}
},
"service_name": "ns30"
}])
self.validate_nova_compute_raises_regexp(
new_nova_computes,
"Nova compute instances with target 'controllers' couldn't be "
"added to operational environment. Check nova compute instances "
"with the following vSphere cluster names: {0}".format(
", ".join(sorted(["Cluster30", "Cluster20"]))
)
)
@patch("nailgun.db.sqlalchemy.models.Cluster.is_locked", return_value=True)
def test_remove_controllers_nova_compute_setting(self, lock_mock):
new_nova_computes = [nc for nc in self._get_default_nova_computes()
if self._get_target_id(nc) != "controllers"]
self.validate_nova_compute_raises_regexp(
new_nova_computes,
"Nova compute instance with target 'controllers' and vSphere "
"cluster {0} couldn't be deleted from operational environment."
.format("Cluster0")
)
def test_update_non_editable_attributes(self):
metadata = [
{
"name": "foo",
"label": "foo",
"type": "object",
"fields": [{
"name": "foo_field_name",
"label": "foo_field_name",
}]
}, {
"name": "availability_zones",
"label": "availability_zones",
"type": "array",
"fields": [{
"name": "az_name",
"label": "az_name",
}, {
"name": "nova_computes",
"type": "array",
"fields": [{
"name": "vsphere_cluster",
"label": "vsphere_cluster",
}, {
"name": "target_node",
"label": "target_node",
}]
}, {
"name": "vcenter_host",
"label": "vcenter_host",
}]
}
]
db_attributes_value = {
"availability_zones": [{
"az_name": "az_1",
"vcenter_host": "127.0.0.1",
"nova_computes": [{
"vsphere_cluster": "Cluster1",
"target_node": {
"current": {"id": "node-1"}
}
}]
}],
"foo": {
"foo_field_name": "foo_field_value"
}
}
instance = objects.VmwareAttributes.create(
{"editable": {"metadata": metadata, "value": db_attributes_value}}
)
new_attributes = deepcopy(db_attributes_value)
new_attributes["foo"] = ["foo_field_name"]
msg = "Value type of 'foo_field_name' attribute couldn't be changed."
with self.assertRaisesRegexp(errors.InvalidData, msg):
VmwareAttributesValidator._validate_updated_attributes(
{"editable": {"value": new_attributes}},
instance)
new_attributes = deepcopy(db_attributes_value)
new_attributes["foo"]["foo_field_name"] = "new_foo_field_value"
msg = "Value of 'foo_field_name' attribute couldn't be changed."
with self.assertRaisesRegexp(errors.InvalidData, msg):
VmwareAttributesValidator._validate_updated_attributes(
{"editable": {"value": new_attributes}},
instance)
new_attributes = deepcopy(db_attributes_value)
new_attributes["availability_zones"].append({
"az_name": "az_2",
"vcenter_host": "127.0.0.1",
"nova_computes": []
})
msg = "Value of 'availability_zones' attribute couldn't be changed."
with self.assertRaisesRegexp(errors.InvalidData, msg):
VmwareAttributesValidator._validate_updated_attributes(
{"editable": {"value": new_attributes}}, instance)
new_attributes = deepcopy(db_attributes_value)
new_attributes["availability_zones"][0]["nova_computes"][0].update(
{"target_node": {"current": {"id": "node-2"}}}
)
msg = "Value of 'target_node' attribute couldn't be changed."
with self.assertRaisesRegexp(errors.InvalidData, msg):
VmwareAttributesValidator._validate_updated_attributes(
{"editable": {"value": new_attributes}}, instance)
def test_update_editable_attributes(self):
metadata = [
{
"name": "foo",
"label": "foo",
"type": "object",
"editable_for_deployed": True,
"fields": [{
"name": "foo_field_name",
"label": "foo_field_name",
}]
}, {
"name": "availability_zones",
"type": "array",
"label": "availability_zones",
"fields": [{
"name": "az_name",
"label": "az_name",
}, {
"name": "nova_computes",
"editable_for_deployed": True,
"type": "array",
"fields": [{
"name": "vsphere_cluster",
"label": "vsphere_cluster",
}, {
"name": "target_node",
"label": "target_node",
}]
}, {
"name": "vcenter_host",
"label": "vcenter_host",
}]
}
]
db_attributes_value = {
"availability_zones": [{
"az_name": "az_1",
"vcenter_host": "127.0.0.1",
"nova_computes": [{
"vsphere_cluster": "Cluster1",
"target_node": {
"current": {"id": "node-1"}
}
}]
}],
"foo": {
"foo_field_name": "foo_field_value"
}
}
instance = objects.VmwareAttributes.create(
{"editable": {"metadata": metadata, "value": db_attributes_value}}
)
new_attributes = deepcopy(db_attributes_value)
new_attributes["foo"]["foo_field_name"] = 1
new_attributes["availability_zones"][0]["nova_computes"][0].update(
{"target_node": {"current": {"id": "node-2"}}}
)
new_attributes["availability_zones"][0]["nova_computes"].append({
"vsphere_cluster": "Cluster2",
"target_node": {
"current": {"id": "node-2"}
}
})
self.assertNotRaises(
errors.InvalidData,
VmwareAttributesValidator._validate_updated_attributes,
{"editable": {"value": new_attributes}},
instance)