blob: b15240d36fc84ee578ff93438ab43f89428b835c [file] [log] [blame]
# Copyright 2017-present Open Networking Foundation
#
# 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 unittest
from mock import patch
import mock
import pdb
import os
import sys
from xosconfig import Config
test_path = os.path.abspath(os.path.dirname(os.path.realpath(__file__)))
sync_lib_dir = os.path.join(test_path, "..", "xossynchronizer")
xos_dir = os.path.join(test_path, "..", "..", "..", "xos")
class TestModelPolicyTenantWithContainer(unittest.TestCase):
def setUp(self):
global TenantWithContainerPolicy, LeastLoadedNodeScheduler, MockObjectList
self.sys_path_save = sys.path
self.cwd_save = os.getcwd()
config = basic_conf = os.path.abspath(
os.path.dirname(os.path.realpath(__file__)) + "/test_config.yaml"
)
Config.clear() # in case left unclean by a previous test case
Config.init(config, "synchronizer-config-schema.yaml")
from xossynchronizer.mock_modelaccessor_build import (
build_mock_modelaccessor,
)
build_mock_modelaccessor(sync_lib_dir, xos_dir, services_dir=None, service_xprotos=[])
import xossynchronizer.model_policies.model_policy_tenantwithcontainer
from xossynchronizer.model_policies.model_policy_tenantwithcontainer import (
TenantWithContainerPolicy,
LeastLoadedNodeScheduler,
)
from xossynchronizer.mock_modelaccessor import MockObjectList
# import all class names to globals
for (
k,
v,
) in xossynchronizer.model_policies.model_policy_tenantwithcontainer.model_accessor.all_model_classes.items():
globals()[k] = v
from xossynchronizer.modelaccessor import model_accessor
self.policy = TenantWithContainerPolicy(model_accessor=model_accessor)
self.user = User(email="testadmin@test.org")
self.tenant = TenantWithContainer(creator=self.user)
self.flavor = Flavor(name="m1.small")
def tearDown(self):
Config.clear()
sys.path = self.sys_path_save
os.chdir(self.cwd_save)
def test_manage_container_no_slices(self):
with patch.object(TenantWithContainer, "owner") as owner:
owner.slices.count.return_value = 0
with self.assertRaises(Exception) as e:
self.policy.manage_container(self.tenant)
self.assertEqual(e.exception.message, "The service has no slices")
def test_manage_container(self):
with patch.object(TenantWithContainer, "owner") as owner, patch.object(
TenantWithContainer, "save"
) as tenant_save, patch.object(
Node, "site_deployment"
) as site_deployment, patch.object(
Instance, "save"
) as instance_save, patch.object(
Instance, "delete"
) as instance_delete, patch.object(
TenantWithContainerPolicy, "get_image"
) as get_image, patch.object(
LeastLoadedNodeScheduler, "pick"
) as pick:
# setup mocks
node = Node(hostname="my.node.com")
slice = Slice(
name="mysite_test1", default_flavor=self.flavor, default_isolation="vm"
)
image = Image(name="trusty-server-multi-nic")
deployment = Deployment(name="testdeployment")
owner.slices.count.return_value = 1
owner.slices.all.return_value = [slice]
owner.slices.first.return_value = slice
get_image.return_value = image
pick.return_value = (node, None)
site_deployment.deployment = deployment
# done setup mocks
# call manage_container
self.policy.manage_container(self.tenant)
# make sure manage_container did what it is supposed to do
self.assertNotEqual(self.tenant.instance, None)
self.assertEqual(self.tenant.instance.creator.email, "testadmin@test.org")
self.assertEqual(self.tenant.instance.image.name, "trusty-server-multi-nic")
self.assertEqual(self.tenant.instance.flavor.name, "m1.small")
self.assertEqual(self.tenant.instance.isolation, "vm")
self.assertEqual(self.tenant.instance.node.hostname, "my.node.com")
self.assertEqual(self.tenant.instance.slice.name, "mysite_test1")
self.assertEqual(self.tenant.instance.parent, None)
instance_save.assert_called()
instance_delete.assert_not_called()
tenant_save.assert_called()
def test_manage_container_delete(self):
self.tenant.deleted = True
# call manage_container
self.policy.manage_container(self.tenant)
# make sure manage_container did what it is supposed to do
self.assertEqual(self.tenant.instance, None)
def test_manage_container_no_m1_small(self):
with patch.object(TenantWithContainer, "owner") as owner, patch.object(
Node, "site_deployment"
) as site_deployment, patch.object(
Flavor, "objects"
) as flavor_objects, patch.object(
TenantWithContainerPolicy, "get_image"
) as get_image, patch.object(
LeastLoadedNodeScheduler, "pick"
) as pick:
# setup mocks
node = Node(hostname="my.node.com")
slice = Slice(
name="mysite_test1", default_flavor=None, default_isolation="vm"
)
image = Image(name="trusty-server-multi-nic")
deployment = Deployment(name="testdeployment")
owner.slices.count.return_value = 1
owner.slices.all.return_value = [slice]
owner.slices.first.return_value = slice
get_image.return_value = image
pick.return_value = (node, None)
site_deployment.deployment = deployment
flavor_objects.filter.return_value = []
# done setup mocks
with self.assertRaises(Exception) as e:
self.policy.manage_container(self.tenant)
self.assertEqual(e.exception.message, "No m1.small flavor")
def test_least_loaded_node_scheduler(self):
with patch.object(Node.objects, "get_items") as node_objects:
slice = Slice(
name="mysite_test1", default_flavor=None, default_isolation="vm"
)
node = Node(hostname="my.node.com", id=4567)
node.instances = MockObjectList(initial=[])
node_objects.return_value = [node]
sched = LeastLoadedNodeScheduler(slice)
(picked_node, parent) = sched.pick()
self.assertNotEqual(picked_node, None)
self.assertEqual(picked_node.id, node.id)
def test_least_loaded_node_scheduler_two_nodes(self):
with patch.object(Node.objects, "get_items") as node_objects:
slice = Slice(
name="mysite_test1", default_flavor=None, default_isolation="vm"
)
instance1 = Instance(id=1)
node1 = Node(hostname="my.node.com", id=4567)
node1.instances = MockObjectList(initial=[])
node2 = Node(hostname="my.node.com", id=8910)
node2.instances = MockObjectList(initial=[instance1])
node_objects.return_value = [node1, node2]
# should pick the node with the fewest instance (node1)
sched = LeastLoadedNodeScheduler(slice)
(picked_node, parent) = sched.pick()
self.assertNotEqual(picked_node, None)
self.assertEqual(picked_node.id, node1.id)
def test_least_loaded_node_scheduler_two_nodes_multi(self):
with patch.object(Node.objects, "get_items") as node_objects:
slice = Slice(
name="mysite_test1", default_flavor=None, default_isolation="vm"
)
instance1 = Instance(id=1)
instance2 = Instance(id=2)
instance3 = Instance(id=3)
node1 = Node(hostname="my.node.com", id=4567)
node1.instances = MockObjectList(initial=[instance2, instance3])
node2 = Node(hostname="my.node.com", id=8910)
node2.instances = MockObjectList(initial=[instance1])
node_objects.return_value = [node1, node2]
# should pick the node with the fewest instance (node2)
sched = LeastLoadedNodeScheduler(slice)
(picked_node, parent) = sched.pick()
self.assertNotEqual(picked_node, None)
self.assertEqual(picked_node.id, node2.id)
def test_least_loaded_node_scheduler_with_label(self):
with patch.object(Node.objects, "get_items") as node_objects:
slice = Slice(
name="mysite_test1", default_flavor=None, default_isolation="vm"
)
instance1 = Instance(id=1)
node1 = Node(hostname="my.node.com", id=4567)
node1.instances = MockObjectList(initial=[])
node2 = Node(hostname="my.node.com", id=8910)
node2.instances = MockObjectList(initial=[instance1])
# Fake out the existence of a NodeLabel object. TODO: Extend the mock framework to support the model__field
# syntax.
node1.nodelabels__name = None
node2.nodelabels__name = "foo"
node_objects.return_value = [node1, node2]
# should pick the node with the label, even if it has a greater number of instances
sched = LeastLoadedNodeScheduler(slice, label="foo")
(picked_node, parent) = sched.pick()
self.assertNotEqual(picked_node, None)
self.assertEqual(picked_node.id, node2.id)
def test_least_loaded_node_scheduler_create_label(self):
with patch.object(Node.objects, "get_items") as node_objects, patch.object(
NodeLabel, "save", autospec=True
) as nodelabel_save, patch.object(NodeLabel, "node") as nodelabel_node_add:
slice = Slice(
name="mysite_test1", default_flavor=None, default_isolation="vm"
)
instance1 = Instance(id=1)
node1 = Node(hostname="my.node.com", id=4567)
node1.instances = MockObjectList(initial=[])
node2 = Node(hostname="my.node.com", id=8910)
node2.instances = MockObjectList(initial=[instance1])
# Fake out the existence of a NodeLabel object. TODO: Extend the mock framework to support the model__field
# syntax.
node1.nodelabels__name = None
node2.nodelabels__name = None
node_objects.return_value = [node1, node2]
# should pick the node with the least number of instances
sched = LeastLoadedNodeScheduler(
slice, label="foo", constrain_by_service_instance=True
)
(picked_node, parent) = sched.pick()
self.assertNotEqual(picked_node, None)
self.assertEqual(picked_node.id, node1.id)
# NodeLabel should have been created and saved
self.assertEqual(nodelabel_save.call_count, 1)
self.assertEqual(nodelabel_save.call_args[0][0].name, "foo")
# The NodeLabel's node field should have been added to
NodeLabel.node.add.assert_called_with(node1)
if __name__ == "__main__":
unittest.main()