From 776e0323edac4995bde88b8af7b8766928814047 Mon Sep 17 00:00:00 2001 From: jeorryb Date: Thu, 16 Nov 2017 11:14:57 -0500 Subject: [PATCH] add functionality to manage server pools --- .../server/test_ut_server_serverpool.py | 227 +++++++++++++++ ucsm_apis/server/serverpool.py | 274 ++++++++++++++++++ 2 files changed, 501 insertions(+) create mode 100644 tests/unit_test/server/test_ut_server_serverpool.py create mode 100644 ucsm_apis/server/serverpool.py diff --git a/tests/unit_test/server/test_ut_server_serverpool.py b/tests/unit_test/server/test_ut_server_serverpool.py new file mode 100644 index 0000000..3d33828 --- /dev/null +++ b/tests/unit_test/server/test_ut_server_serverpool.py @@ -0,0 +1,227 @@ +import pytest +from ucsm_apis.server import serverpool +from ucsmsdk.ucshandle import UcsHandle + +handle = UcsHandle("10.10.10.10", "username", "password") + + +def test_server_pool_create_success(mocker): + mock_login = mocker.patch('ucsmsdk.ucshandle.UcsHandle.login', + autospec=True) + mock_login.return_value = True + mock_query_dn = mocker.patch('ucsmsdk.ucshandle.UcsHandle.query_dn', + autospec=True) + mock_query_dn.return_value = "org-root" + mock_commit = mocker.patch('ucsmsdk.ucshandle.UcsHandle.commit', + autospec=True) + mock_commit.return_value = None + mock_server_pool = mocker.patch('ucsm_apis.server.serverpool.ComputePool') + mock_add_mo = mocker.patch('ucsmsdk.ucshandle.UcsHandle.add_mo', + autospec=True) + mock_add_mo.return_value = None + + serverpool.server_pool_create(handle, name="dummypool") + + mock_query_dn.assert_called_with(handle, "org-root") + mock_server_pool.assert_called_with(name='dummypool', + descr=None, + parent_mo_or_dn='org-root') + + +def test_server_pool_create_fail_org_not_exist(mocker): + mock_login = mocker.patch.object(UcsHandle, 'login', autospec=True) + mock_login.return_value = True + mock_query_dn = mocker.patch.object(UcsHandle, 'query_dn', + autospec=True) + mock_query_dn.return_value = None + + with pytest.raises(serverpool.UcsOperationError): + serverpool.server_pool_create(handle, name="dummypool", + org_dn="dummy") + + +def test_server_pool_get_success(mocker): + mock_login = mocker.patch.object(UcsHandle, 'login', autospec=True) + mock_login.return_value = True + mock_query_dn = mocker.patch.object(UcsHandle, 'query_dn', + autospec=True) + mock_query_dn.return_value = "org-root/compute-pool-dummypool" + + serverpool.server_pool_get(handle, name="dummypool") + + mock_query_dn.assert_called_with(handle, "org-root/compute-pool-dummypool") + + +def test_server_pool_get_fail_pool_does_not_exist(mocker): + mock_login = mocker.patch.object(UcsHandle, 'login', autospec=True) + mock_login.return_value = True + mock_query_dn = mocker.patch.object(UcsHandle, 'query_dn', + autospec=True) + mock_query_dn.return_value = None + + with pytest.raises(serverpool.UcsOperationError): + serverpool.server_pool_get(handle, name="nopool") + + +def test_server_pool_exists_success(mocker): + mock_login = mocker.patch.object(UcsHandle, 'login', autospec=True) + mock_login.return_value = True + mock_query_dn = mocker.patch.object(UcsHandle, 'query_dn', + autospec=True) + mock_query_dn.return_value = "org-root/compute-pool-dummypool" + mock_check_prop = mocker.patch.object(serverpool.ComputePool, + 'check_prop_match', autospec=True) + mock_check_prop.return_value = True + mock_get = mocker.patch.object(serverpool, 'server_pool_get', + autospec=True) + + serverpool.server_pool_exists(handle, name="dummypool") + + mock_get.assert_called_with(handle=handle, caller='server_pool_exists', + name="dummypool", org_dn="org-root") + + +def test_server_pool_exists_fail_org_does_not_exist(mocker): + mock_login = mocker.patch.object(UcsHandle, 'login', autospec=True) + mock_login.return_value = True + mock_get = mocker.patch.object(serverpool, 'server_pool_get', + autospec=True) + mock_get.side_effect = serverpool.UcsOperationError("query_dn", + "pool does not exist") + + result = serverpool.server_pool_exists(handle, name="dummypool") + + assert result == (False, None) + + +def test_server_pool_modify_success(mocker): + mock_login = mocker.patch.object(UcsHandle, 'login', autospec=True) + mock_login.return_value = True + mock_get = mocker.patch.object(serverpool, 'server_pool_get', + autospec=True) + mo_mock = mocker.Mock() + mo_mock.set_prop_multiple.return_value = True + mock_get.return_value = mo_mock + mock_set_mo = mocker.patch.object(UcsHandle, 'set_mo', autospec=True) + mock_set_mo.return_value = None + mock_commit = mocker.patch.object(UcsHandle, 'commit', autospec=True) + mock_commit.return_value = None + + serverpool.server_pool_modify(handle, name="dummypool", + descr="This is a new pool") + + mock_get.assert_called_with(handle=handle, name="dummypool", + org_dn="org-root", caller="server_pool_modify") + mo_mock.set_prop_multiple.assert_called_with(descr="This is a new pool") + + +def test_server_pool_modify_failure_pool_nonexistent(mocker): + mock_login = mocker.patch.object(UcsHandle, 'login', autospec=True) + mock_login.return_value = True + mock_get = mocker.patch.object(serverpool, 'server_pool_get', + autospec=True) + mock_get.side_effect = serverpool.UcsOperationError("query_dn", + "pool does not exist") + + with pytest.raises(serverpool.UcsOperationError): + serverpool.server_pool_modify(handle, name="nopool", + descr="Pool no aqui") + + +def test_server_pool_delete_success(mocker): + mock_login = mocker.patch.object(UcsHandle, 'login', autospec=True) + mock_login.return_value = True + mock_get = mocker.patch.object(serverpool, 'server_pool_get', + autospec=True) + mock_remove_mo = mocker.patch.object(UcsHandle, 'remove_mo', + autospec=True) + mock_commit = mocker.patch.object(UcsHandle, 'commit', autospec=True) + mock_commit.return_value = None + + serverpool.server_pool_delete(handle, "dummypool") + + mock_get.assert_called_with(handle=handle, name="dummypool", + org_dn="org-root", caller="server_pool_delete") + assert mock_remove_mo.call_count == 1 + + +def test_server_pool_delete_failure_pool_nonexistent(mocker): + mock_login = mocker.patch.object(UcsHandle, 'login', autospec=True) + mock_login.return_value = True + mock_get = mocker.patch.object(serverpool, 'server_pool_get', + autospec=True) + mock_get.side_effect = serverpool.UcsOperationError("query_dn", + "pool does not exist") + + with pytest.raises(serverpool.UcsOperationError): + serverpool.server_pool_delete(handle, name="dummypool") + + +def test_server_add_success(mocker): + mock_login = mocker.patch.object(UcsHandle, 'login', autospec=True) + mock_login.return_value = True + mock_get = mocker.patch.object(serverpool, 'server_pool_get', + autospec=True) + mo_mock = mocker.Mock() + mo_mock.set_prop_multiple.return_value = True + mock_get.return_value = mo_mock + mock_computepool_slot = mocker.patch('ucsm_apis.server.' + 'serverpool.ComputePooledSlot') + mock_add_mo = mocker.patch('ucsmsdk.ucshandle.UcsHandle.add_mo', + autospec=True) + mock_add_mo.return_value = None + mock_commit = mocker.patch.object(UcsHandle, 'commit', autospec=True) + mock_commit.return_value = None + + serverpool.server_add(handle, pool_name="dummypool", + servers=["1/1", "1/2"]) + + mock_get.assert_called_with(handle=handle, name="dummypool", + org_dn="org-root", caller="server_add") + assert mo_mock.set_prop_multiple.call_count == 1 + assert mock_computepool_slot.call_count == 2 + + +def test_server_add_failure_pool_nonexistent(mocker): + mock_login = mocker.patch.object(UcsHandle, 'login', autospec=True) + mock_login.return_value = True + mock_get = mocker.patch.object(serverpool, 'server_pool_get', + autospec=True) + mock_get.side_effect = serverpool.UcsOperationError("query_dn", + "pool does not exist") + with pytest.raises(serverpool.UcsOperationError): + serverpool.server_add(handle, pool_name="dummypool", + servers=["1/1", "1/2"]) + + +def test_server_delete_success(mocker): + mock_login = mocker.patch('ucsmsdk.ucshandle.UcsHandle.login', + autospec=True) + mock_login.return_value = True + mock_query_dn = mocker.patch('ucsmsdk.ucshandle.UcsHandle.query_dn', + autospec=True) + mock_query_dn.return_value = "org-root/compute-pool-test_pool/blade-1-1" + mock_commit = mocker.patch('ucsmsdk.ucshandle.' + 'UcsHandle.commit', + autospec=True) + mock_commit.return_value = None + mock_remove_mo = mocker.patch.object(UcsHandle, 'remove_mo', autospec=True) + + serverpool.server_delete(handle, pool_name="test_pool", + servers=["1/1", "1/2"]) + + assert mock_query_dn.call_count == 2 + assert mock_remove_mo.call_count == 2 + assert mock_commit.call_count == 2 + + +def test_server_delete_failure_pool_nonexistent(mocker): + mock_login = mocker.patch.object(UcsHandle, 'login', autospec=True) + mock_login.return_value = True + mock_query_dn = mocker.patch.object(UcsHandle, 'query_dn', + autospec=True) + mock_query_dn.return_value = None + + with pytest.raises(serverpool.UcsOperationError): + serverpool.server_delete(handle, pool_name="no_aqui", + servers=["1/1", "1/2"]) diff --git a/ucsm_apis/server/serverpool.py b/ucsm_apis/server/serverpool.py new file mode 100644 index 0000000..823c66c --- /dev/null +++ b/ucsm_apis/server/serverpool.py @@ -0,0 +1,274 @@ +# Copyright 2017 Cisco Systems, 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. + +""" +This module performs operations related to server pools. +""" + +from ucsmsdk.mometa.compute.ComputePool import ComputePool +from ucsmsdk.mometa.compute.ComputePooledSlot import ComputePooledSlot +from ucsmsdk.ucsexception import UcsOperationError + + +def server_pool_create(handle, org_dn="org-root", + name=None, + descr=None, **kwargs): + + """ + Creates server pools + + Args: + handle (UCSHandle) + name (string): Name of server pool + org_dn (string): org dn + descr (string): description + **kwargs: Any additional key-value pair of managed object(MO)'s + property and value, which are not part of regular args. + This should be used for future version compatibility. + + Returns: + ComputePool: managed object + + Raises: + UcsOperationError: if Org_dn is not present + + Example: + server_pool_create(handle, + name="server_pool", + org_dn="org-root", + descr="server pool for Servers") + """ + + obj = handle.query_dn(org_dn) + if not obj: + raise UcsOperationError("server_pool_create", "Org {} \ + does not exist".format(org_dn)) + + mo = ComputePool(parent_mo_or_dn=obj, name=name, + descr=descr) + mo.set_prop_multiple(**kwargs) + handle.add_mo(mo, modify_present=True) + handle.commit() + return mo + + +def server_pool_get(handle, name=None, + org_dn="org-root", + caller="server_pool_get"): + + """ + Gets server pool + + Args: + handle (UCSHandle) + name (string): Name of server pool + org_dn (string): org dn + caller (string): caller method name + + Returns: + ComputePool: managed object + + Raises: + UcsOperationError: if ComputePool is not present + + Example: + server_pool_get(handle, + name="test_pool", + org_dn="org-root") + """ + + dn = org_dn + "/compute-pool-" + name + mo = handle.query_dn(dn) + if not mo: + raise UcsOperationError(caller, "Server Pool {} " + "does not exist".format(dn)) + return mo + + +def server_pool_exists(handle, name=None, + org_dn="org-root", **kwargs): + + """ + Checks if server pool exists + + Args: + handle (UcsHandle) + name (string): Name of server pool + org_dn (string): org dn + **kwargs: key-value pair of managed object(MO) property and value, Use + 'print(ucscoreutils.get_meta_info().config_props)' + to get all configurable properties of class + + Returns: + (True/False, ComputePool MO/None) + + Raises: + None + + Example: + server_pool_exists:(handle, + name="server_pool", + org_dn="org-root",) + """ + + try: + mo = server_pool_get(handle=handle, name=name, org_dn=org_dn, + caller="server_pool_exists") + except UcsOperationError: + return (False, None) + mo_exists = mo.check_prop_match(**kwargs) + return (mo_exists, mo if mo_exists else None) + + +def server_pool_modify(handle, name=None, + org_dn="org-root", **kwargs): + + """ + modifies server pool + + Args: + handle (UcsHandle) + name (string): Name of server pool + org_dn (string): org dn + **kwargs: key-value pair of managed object(MO) property and value, Use + 'print(ucscoreutils.get_meta_info().config_props)' + to get all configurable properties of class + + Returns: + ComputePool: managed object + + Raises: + UcsOperationError: if ComputePool is not present + + Example: + server_pool_modify(handle, + name="test-pool", + descr="prod server pool") + """ + + mo = server_pool_get(handle=handle, name=name, org_dn=org_dn, + caller="server_pool_modify") + mo.set_prop_multiple(**kwargs) + handle.set_mo(mo) + handle.commit() + return mo + + +def server_pool_delete(handle, name=None, org_dn="org-root"): + + """ + deletes server pool + + Args: + handle (UcsHandle) + name (string): Name of server pool + org_dn (string): org dn + + Returns: + None + + Raises: + UcsOperationError: if ComputePool is not present + + Example: + server_pool_delete(handle, + name="test-pool", + org_dn="org-root") + """ + + mo = server_pool_get(handle=handle, name=name, org_dn=org_dn, + caller="server_pool_delete") + handle.remove_mo(mo) + handle.commit() + + +def server_add(handle, pool_name=None, org_dn="org-root", + servers=None, **kwargs): + + """ + Adds servers to server pool + + Args: + handle (UCSHandle) + pool_name (string): Name of server pool + org_dn (string): org dn + servers (list): List of servers to add to the pool + **kwargs: Any additional key-value pair of managed object(MO)'s + property and value, which are not part of regular args. + This should be used for future version compatibility. + + Returns: + ComputePool: managed object + + Raises: + UcsOperationError: if Org_dn or pool is not present + + Example: + server_add(handle, + pool_name="server_pool", + org_dn="org-root", + servers=["1/1", "1/2"]) + """ + + mo = server_pool_get(handle=handle, name=pool_name, org_dn=org_dn, + caller="server_add") + mo.set_prop_multiple(**kwargs) + + server_list = [s.split("/") for s in servers] + mo_list = [] + for server in server_list: + mos = ComputePooledSlot(parent_mo_or_dn=mo, + chassis_id=server[0], + slot_id=server[1]) + mo_list.append(mos) + + handle.add_mo(mo, modify_present=True) + handle.commit() + return mo + + +def server_delete(handle, pool_name=None, org_dn="org-root", + servers=None): + + """ + Deletes servers from server pool + + Args: + handle (UCSHandle) + pool_name (string): Name of server pool + org_dn (string): org dn + servers (list): List of servers to delete from the pool + + Returns: + None + + Raises: + UcsOperationError: if Org_dn or pool is not present + + Example: + server_delete(handle, + pool_name="server_pool", + org_dn="org-root", + servers=["1/1", "1/2"]) + """ + + server_list = [s.split("/") for s in servers] + for server in server_list: + mo = handle.query_dn(org_dn + "/compute-pool-" + + pool_name + "/blade-" + + server[0] + "-" + server[1]) + if not mo: + raise UcsOperationError("server_delete", "Org {} " + "does not exist".format(org_dn)) + handle.remove_mo(mo) + handle.commit()