def load_ucs_manager_config(): """ loads the test configuration into the UCS Manger """ logs.info_1('Loading UCSPE emulator from {0}'.format( fit_common.fitcfg()['ucsm_config_file'])) try: handle = ucshandle.UcsHandle(UCSM_IP, UCSM_USER, UCSM_PASS) if not handle.login(): logs.error('Failed to log into UCS Manger!') return False except Exception as e: logs.info_1("error trying to log into UCS Manger!") logs.info_1(str(e)) return False # now try to update the UCSPE config, if this fails we can still continue try: path, file = os.path.split(fit_common.fitcfg()['ucsm_config_file']) import_ucs_backup(handle, file_dir=path, file_name=file) except Exception as e: logs.info_1("error trying to configure UCSPE, continuing to test") logs.info_1(str(e)) # log the error but do not return a failure, we can still run some tests with the default config if not handle.logout(): logs.error('Failed to log out of UCS Manger during exit!') return False return True
def load_ucs_manager_config(): """ loads the test configuration into the UCS Manger """ logs.info_1('Loading UCSPE emulator from {0}'.format(fit_common.fitcfg()['ucsm_config_file'])) try: handle = ucshandle.UcsHandle(UCSM_IP, UCSM_USER, UCSM_PASS) if not handle.login(): logs.error('Failed to log into UCS Manger!') return False except Exception as e: logs.info_1("error trying to log into UCS Manger!") logs.info_1(str(e)) return False # now try to update the UCSPE config, if this fails we can still continue try: path, file = os.path.split(fit_common.fitcfg()['ucsm_config_file']) import_ucs_backup(handle, file_dir=path, file_name=file) except Exception as e: logs.info_1("error trying to configure UCSPE, continuing to test") logs.info_1(str(e)) # log the error but do not return a failure, we can still run some tests with the default config if not handle.logout(): logs.error('Failed to log out of UCS Manger during exit!') return False return True
def is_ucs_valid(): if UCSM_IP is None: logs.error("Expected value for UCSM_IP other then None and found {0}".format(UCSM_IP)) return False if UCS_SERVICE_URI is None: logs.error("Expected value for UCS_SERVICE_URI other then None and found {0}".format(UCS_SERVICE_URI)) return False if "ucsm_config_file" in fit_common.fitcfg(): # configure the UCSPE emulator if not load_ucs_manager_config(): # error configureing UCSPE emulaotr, skip all tests logs.error("Error Configuring UCSPE emulator, skipping all UCS tests") return False # wait up to 2 min for config to be valid timeout = 120 ucsCount = get_physical_server_count() while (ucsCount) != EXPECTED_UCS_PHYSICAL_NODES: if timeout <= 0: logs.error("Only found {0} of {1} nodes, skipping all UCS tests" .format(ucsCount, EXPECTED_UCS_PHYSICAL_NODES)) return False logs.info_1("Only found {0} of {1} ucs nodes, retrying in 30 seconds" .format(ucsCount, EXPECTED_UCS_PHYSICAL_NODES)) timeout -= 5 time.sleep(5) ucsCount = get_physical_server_count() return True
def test_check_ucs_params(self): self.assertNotEqual(UCSM_IP, None, "Expected value for UCSM_IP other then None and found {0}" .format(UCSM_IP)) self.assertNotEqual(UCS_SERVICE_URI, None, "Expected value for UCS_SERVICE_URI other then None and found {0}" .format(UCS_SERVICE_URI)) if "ucsm_config_file" in fit_common.fitcfg(): # configure the UCSPE emulator if not load_ucs_manager_config(): # error configureing UCSPE emulaotr, skip all tests raise unittest.SkipTest("Error Configuring UCSPE emulator, skipping all UCS tests") # wait up to 2 min for config to be valid timeout = 120 ucsCount = self.get_physical_server_count() while (ucsCount) != self.EXPECTED_UCS_PHYSICAL_NODES: if timeout <= 0: raise unittest.SkipTest("Only found {0} of {1} nodes, skipping all UCS tests" .format(ucsCount, self.EXPECTED_UCS_PHYSICAL_NODES)) logs.info_1("Only found {0} of {1} ucs nodes, retrying in 30 seconds" .format(ucsCount, self.EXPECTED_UCS_PHYSICAL_NODES)) timeout -= 5 time.sleep(5) ucsCount = self.get_physical_server_count()
def is_ucs_valid(): if UCSM_IP is None: logs.error("Expected value for UCSM_IP other then None and found {0}".format(UCSM_IP)) return False if UCS_SERVICE_URI is None: logs.error("Expected value for UCS_SERVICE_URI other then None and found {0}".format(UCS_SERVICE_URI)) return False if "ucsm_config_file" in fit_common.fitcfg(): # configure the UCSPE emulator if not load_ucs_manager_config(): # error configureing UCSPE emulaotr, skip all tests logs.error("Error Configuring UCSPE emulator, skipping all UCS tests") return False # wait up to 2 min for config to be valid timeout = 120 ucsCount = get_physical_server_count() while (ucsCount) != EXPECTED_UCS_PHYSICAL_NODES: if timeout <= 0: logs.error("Only found {0} of {1} nodes, skipping all UCS tests" .format(ucsCount, EXPECTED_UCS_PHYSICAL_NODES)) return False logs.info_1("Only found {0} of {1} ucs nodes, retrying in 30 seconds" .format(ucsCount, EXPECTED_UCS_PHYSICAL_NODES)) timeout -= 5 time.sleep(5) ucsCount = get_physical_server_count() return True
def test_check_ucs_params(self): self.assertNotEqual( UCSM_IP, None, "Expected value for UCSM_IP other then None and found {0}".format( UCSM_IP)) self.assertNotEqual( UCS_SERVICE_URI, None, "Expected value for UCS_SERVICE_URI other then None and found {0}". format(UCS_SERVICE_URI)) if "ucsm_config_file" in fit_common.fitcfg(): # configure the UCSPE emulator if not load_ucs_manager_config(): # error configureing UCSPE emulaotr, skip all tests raise unittest.SkipTest( "Error Configuring UCSPE emulator, skipping all UCS tests") # wait up to 2 min for config to be valid timeout = 120 ucsCount = self.get_physical_server_count() while (ucsCount) != self.EXPECTED_UCS_PHYSICAL_NODES: if timeout <= 0: raise unittest.SkipTest( "Only found {0} of {1} nodes, skipping all UCS tests". format(ucsCount, self.EXPECTED_UCS_PHYSICAL_NODES)) logs.info_1( "Only found {0} of {1} ucs nodes, retrying in 30 seconds". format(ucsCount, self.EXPECTED_UCS_PHYSICAL_NODES)) timeout -= 5 time.sleep(5) ucsCount = self.get_physical_server_count()
import unittest from common import fit_common import time from nosedep import depends import flogging from nose.plugins.attrib import attr from config.settings import get_ucs_cred from ucsmsdk import ucshandle from ucsmsdk.utils.ucsbackup import import_ucs_backup import os logs = flogging.get_loggers() INITIAL_NODES = {} INITIAL_OBMS = {} UCSM_IP = fit_common.fitcfg().get('ucsm_ip') UCSM_USER, UCSM_PASS = get_ucs_cred() UCS_SERVICE_URI = fit_common.fitcfg().get('ucs_service_uri') def get_nodes_utility(): """ Takes inventory of the nodes available before discovering the UCS nodes. We will restore the nodes collection to this snapshot :return: return False on failure, or True otherwise """ api_data = fit_common.rackhdapi('/api/2.0/nodes') if api_data['status'] != 200: logs.error( "get /api/2.0/nodes returned status {}, expected 200".format( api_data['status']))
class rackhd20_ucs_redfish_api(unittest.TestCase): def validate_simple_storage_data(self, body, url): """ Validate simple storage non-empty data body """ errData = '' schema = { "str": ["Name", "Id", "Description"], "list": ["Devices"] } errStr = ucs_common.validate_redfish_data_payload(body, schema, url) if errStr: errData += errStr if not re.compile('^\w{0,}_\w{1,3}_\w{1,}_\w{1}$').match(body['Id']): errData += "Invalid simpleStorage Id \"{}\" for {}, \n".format(body['Id'], url) return errData @classmethod def setUpClass(cls): if not ucs_common.get_nodes_utility(): raise Exception("error getting node list") if not ucs_common.get_obms_utility(): raise Exception("error getting obms list") @classmethod def tearDownClass(cls): if not ucs_common.restore_node_utility(): raise Exception("error restoring node list") if not ucs_common.restore_obms_utility(): raise Exception("error restoring obms list") @unittest.skipUnless("ucsm_ip" in fit_common.fitcfg(), "") def test_check_ucs_params(self): if not ucs_common.is_ucs_valid(): raise unittest.SkipTest("Ucs parameters are not valid or UCSPE emulator is not ready, skipping all UCS tests") @depends(after=test_check_ucs_params) def test_api_20_ucs_discovery(self): """ Tests the UCS Discovery workflow in rackHD :return: """ initialNodeCount = len(ucs_common.get_ucs_node_list()) data_payload = { "name": "Graph.Ucs.Discovery", "options": { "defaults": { "username": ucs_common.UCSM_USER, "password": ucs_common.UCSM_PASS, "ucs": ucs_common.UCSM_IP, "uri": ucs_common.UCS_SERVICE_URI }, "when-discover-logical-ucs": { "discoverLogicalServer": "false" } } } expected_ucs_physical_nodes = ucs_common.get_physical_server_count() header = {"Content-Type": "application/json"} api_data = fit_common.rackhdapi("/api/2.0/workflows", action="post", headers=header, payload=data_payload) id = api_data["json"]["context"]["graphId"] self.assertEqual(api_data['status'], 201, 'Incorrect HTTP return code, expected 201, got:' + str(api_data['status'])) status = ucs_common.wait_utility(str(id), 0, "Discovery") self.assertEqual(status, 'succeeded', 'Discovery graph returned status {}'.format(status)) newNodeCount = len(ucs_common.get_ucs_node_list()) logs.info_1("Found {0} Nodes after cataloging the UCS".format(len(api_data['json']))) self.assertEqual(newNodeCount - initialNodeCount, expected_ucs_physical_nodes, 'Expected to discover {0} UCS nodes, got: {1}' .format(expected_ucs_physical_nodes, newNodeCount - initialNodeCount)) @depends(after=[test_api_20_ucs_discovery]) def test_api_redfish_chassis(self): """ Tests the redfish /Chassis APIs with UCS nodes :return: """ ucsEnclList = ucs_common.get_ucs_encl_id_list() errUrls = '' api_data = fit_common.rackhdapi('/redfish/v1/Chassis') self.assertEqual(api_data['status'], 200, 'Incorrect HTTP return code, expected 200, got:' + str(api_data['status'])) for chassis in api_data['json']['Members']: url = chassis['@odata.id'] id = url[len('/redfish/v1/Chassis/'):] if id in ucsEnclList: ucsEnclList.remove(id) api_data = fit_common.rackhdapi(url) if api_data['status'] != 200: errUrls += url + ' returned status ' + str(api_data['status']) + ',\n' _body = api_data['json'] schema = { "str": ["Name", "ChassisType", "Manufacturer", "Model", "SerialNumber", "IndicatorLED"], "dict": ["Thermal", "Power", "Links"] } errData = ucs_common.validate_redfish_data_payload(_body, schema, url) if errData: errUrls += errData self.assertEqual(len(ucsEnclList), 0, 'not all UCS chassis were listed under /chassis') self.assertEqual(len(errUrls), 0, errUrls) @depends(after=[test_api_redfish_chassis]) def test_api_redfish_chassis_thermal(self): """ Tests the redfish /Chassis/{identifier}/Thermal APIs with UCS nodes :return: """ ucsEnclList = ucs_common.get_ucs_encl_id_list() errUrls = '' for chassis in ucsEnclList: url = '/redfish/v1/Chassis/{}/Thermal'.format(chassis) api_data = fit_common.rackhdapi(url) if api_data['status'] != 200: errUrls += url + ' returned status ' + str(api_data['status']) + ',\n' self.assertEqual(len(errUrls), 0, errUrls) @depends(after=[test_api_redfish_chassis]) def test_api_redfish_chassis_power(self): """ Tests the redfish /Chassis/{identifier}/Power APIs with UCS nodes :return: """ ucsEnclList = ucs_common.get_ucs_encl_id_list() errUrls = '' for chassis in ucsEnclList: url = '/redfish/v1/Chassis/{}/Power'.format(chassis) api_data = fit_common.rackhdapi(url) if api_data['status'] != 200: errUrls += url + ' returned status ' + str(api_data['status']) + ',\n' self.assertEqual(len(errUrls), 0, errUrls) @depends(after=[test_api_20_ucs_discovery]) def test_api_redfish_system(self): """ Tests the redfish /Systems APIs with UCS nodes :return: """ ucsComputeList = ucs_common.get_ucs_compute_id_list() errUrls = '' api_data = fit_common.rackhdapi('/redfish/v1/Systems') self.assertEqual(api_data['status'], 200, 'Incorrect HTTP return code, expected 200, got:' + str(api_data['status'])) for chassis in api_data['json']['Members']: url = chassis['@odata.id'] id = url[len('/redfish/v1/Systems/'):] if id in ucsComputeList: ucsComputeList.remove(id) api_data = fit_common.rackhdapi(url) if api_data['status'] != 200: errUrls += url + ' returned status ' + str(api_data['status']) + ',\n' _body = api_data['json'] schema = { "str": ["Name", "SystemType", "Manufacturer", "Model", "SerialNumber", "IndicatorLED", "PowerState", "BiosVersion"], "dict": ["ProcessorSummary", "MemorySummary", "Actions", "Processors", "EthernetInterfaces", "SimpleStorage", "LogServices", "Links", "Storage"] } errData = ucs_common.validate_redfish_data_payload(_body, schema, url) if errData: errUrls += errData self.assertEqual(len(ucsComputeList), 0, 'not all UCS computes were listed under /System') self.assertEqual(len(errUrls), 0, errUrls) @depends(after=[test_api_redfish_system]) def test_api_redfish_processor(self): """ Tests the /Systems/{identifier}/processors APIs with UCS nodes :return: """ ucsComputeList = ucs_common.get_ucs_compute_id_list() errUrls = '' for node in ucsComputeList: url = "/redfish/v1/Systems/{}/Processors".format(node) api_data = fit_common.rackhdapi(url) if api_data['status'] != 200: errUrls += url + ' returned status ' + str(api_data['status']) + \ ', Expected 200,\n' continue if len(api_data['json']['Members']) == 0: errUrls += url + ' CPU count is 0,\n' continue for member in api_data['json']['Members']: _url = member['@odata.id'] _api_data = fit_common.rackhdapi(_url) if _api_data['status'] != 200: errUrls += _url + ' returned status ' + str(api_data['status']) + \ ', Expected 200,\n' _body = _api_data['json'] schema = { "str": ["Socket", "ProcessorType", "ProcessorArchitecture", "InstructionSet", "Manufacturer", "Model"], "int": ["MaxSpeedMHz", "TotalCores", "TotalThreads"] } errData = ucs_common.validate_redfish_data_payload(_body, schema, url) if errData: errUrls += errData self.assertEqual(len(errUrls), 0, errUrls) @depends(after=[test_api_redfish_system]) def test_api_redfish_simple_storage(self): """ Tests the redfish /Systems/{identifier}/simpleStorage APIs with UCS nodes :return: """ ucsComputeList = ucs_common.get_ucs_compute_id_list() errUrls = '' for node in ucsComputeList: url = "/redfish/v1/Systems/{}/SimpleStorage".format(node) api_data = fit_common.rackhdapi(url) if api_data['status'] != 200: errUrls += url + ' returned status ' + str(api_data['status']) + \ ', Expected 200,\n' continue for member in api_data['json']['Members']: _url = member['@odata.id'] _api_data = fit_common.rackhdapi(_url) if _api_data['status'] != 200: errUrls += _url + ' returned status ' + str(api_data['status']) + \ ', Expected 200,\n' _body = _api_data['json'] errData = self.validate_simple_storage_data(_body, _url) if errData: errUrls += errData self.assertEqual(len(errUrls), 0, errUrls)
class rackhd_ucs_api(unittest.TestCase): MAX_WAIT = 180 INITIAL_CATALOGS = {} UCS_NODES = [] UCS_COMPUTE_NODES = [] EXPECTED_UCS_PHYSICAL_NODES = 22 EXPECTED_UCS_LOGICAL_NODES = 18 @classmethod def setUpClass(cls): if not get_nodes_utility(): raise Exception("error getting node list") if not get_obms_utility(): raise Exception("error getting obms list") @classmethod def tearDownClass(cls): if not restore_node_utility(): raise Exception("error restoring node list") if not restore_obms_utility(): raise Exception("error restoring obms list") def get_physical_server_count(self): """ Get a count of the number of Service Proviles defined by the UCS Manager """ url = UCS_SERVICE_URI + "/rackmount" headers = {"ucs-user": UCSM_USER, "ucs-password": UCSM_PASS, "ucs-host": UCSM_IP} api_data = fit_common.restful(url, rest_headers=headers) self.assertEqual(api_data['status'], 200, 'Incorrect HTTP return code, expected 200, got:' + str(api_data['status'])) count = len(api_data["json"]) url = UCS_SERVICE_URI + "/chassis" api_data = fit_common.restful(url, rest_headers=headers) self.assertEqual(api_data['status'], 200, 'Incorrect HTTP return code, expected 200, got:' + str(api_data['status'])) count += len(api_data["json"]) for element in api_data["json"]: count += len(element["members"]) return count def get_service_profile_count(self): """ Get a count of the number of Service Proviles defined by the UCS Manager """ url = UCS_SERVICE_URI + "/serviceProfile" headers = {"ucs-user": UCSM_USER, "ucs-password": UCSM_PASS, "ucs-host": UCSM_IP} api_data = fit_common.restful(url, rest_headers=headers) self.assertEqual(api_data['status'], 200, 'Incorrect HTTP return code, expected 200, got:' + str(api_data['status'])) return len(api_data["json"]["ServiceProfile"]["members"]) def wait_utility(self, id, counter, name): """ Recursevily wait for the ucs discovery workflow to finish :param id: Graph ID :param counter: Safeguard for the number of times we can check the status of the graph :param name: Description of graph we are waiting for :return: returns status of the taskgraph, or "timeout" if count is exceeded """ api_data = fit_common.rackhdapi('/api/2.0/workflows/' + str(id)) status = api_data["json"]["status"] if status == "running" and counter < self.MAX_WAIT: time.sleep(1) logs.info_1("In the wait_utility: Workflow status is {0} for the {1}'s run. ID: {2}, name: {3}" .format(status, counter, id, name)) counter += 1 return self.wait_utility(id, counter, name) elif status == "running" and counter >= self.MAX_WAIT: logs.info_1("In the wait_utility: Timed out after trying {0} times. ID: {1}, name: {2}" .format(self.MAX_WAIT, id, name)) return 'timeout' else: logs.info_1("In the wait_utility: Waiting for workflow {0}. The status is: {1} for run: {2}. ID: {3}" .format(name, status, counter, id)) return status def get_ucs_node_list(self): nodeList = [] api_data = fit_common.rackhdapi('/api/2.0/nodes') self.assertEqual(api_data['status'], 200, 'Incorrect HTTP return code, expected 200, got:' + str(api_data['status'])) for node in api_data['json']: if node["obms"] != [] and node["obms"][0]["service"] == "ucs-obm-service": nodeList.append(node) return (nodeList) @unittest.skipUnless("ucsm_ip" in fit_common.fitcfg(), "") def test_check_ucs_params(self): self.assertNotEqual(UCSM_IP, None, "Expected value for UCSM_IP other then None and found {0}" .format(UCSM_IP)) self.assertNotEqual(UCS_SERVICE_URI, None, "Expected value for UCS_SERVICE_URI other then None and found {0}" .format(UCS_SERVICE_URI)) @depends(after=test_check_ucs_params) def test_api_20_ucs_discovery(self): """ Tests the UCS Discovery workflow in rackHD :return: """ initialNodeCount = len(self.get_ucs_node_list()) data_payload = { "name": "Graph.Ucs.Discovery", "options": { "defaults": { "username": UCSM_USER, "password": UCSM_PASS, "ucs": UCSM_IP, "uri": UCS_SERVICE_URI }, "when-discover-physical-ucs": { "discoverPhysicalServers": "true", }, "when-discover-logical-ucs": { "discoverLogicalServer": "false" }, "when-catalog-ucs": { "autoCatalogUcs": "false" } } } expected_ucs_physical_nodes = self.get_physical_server_count() header = {"Content-Type": "application/json"} api_data = fit_common.rackhdapi("/api/2.0/workflows", action="post", headers=header, payload=data_payload) id = api_data["json"]["context"]["graphId"] self.assertEqual(api_data['status'], 201, 'Incorrect HTTP return code, expected 201, got:' + str(api_data['status'])) status = self.wait_utility(str(id), 0, "Discovery") self.assertEqual(status, 'succeeded', 'Discovery graph returned status {}'.format(status)) newNodeCount = len(self.get_ucs_node_list()) logs.info_1("Found {0} Nodes after cataloging the UCS".format(len(api_data['json']))) self.assertEqual(newNodeCount - initialNodeCount, expected_ucs_physical_nodes, 'Expected to discover {0} UCS nodes, got: {1}' .format(expected_ucs_physical_nodes, newNodeCount - initialNodeCount)) # rerun discovery and verify duplicate nodes are not created api_data = fit_common.rackhdapi("/api/2.0/workflows", action="post", headers=header, payload=data_payload) id = api_data["json"]["context"]["graphId"] self.assertEqual(api_data['status'], 201, 'Incorrect HTTP return code, expected 201, got:' + str(api_data['status'])) status = self.wait_utility(str(id), 0, "Discovery") self.assertEqual(status, 'succeeded', 'Discovery graph returned status {}'.format(status)) newNodeCount = len(self.get_ucs_node_list()) logs.info_1("Found {0} Nodes after cataloging the UCS".format(len(api_data['json']))) self.assertGreaterEqual(newNodeCount - initialNodeCount, 0, 'Expected to discover {0} UCS nodes, got: {1}' .format(0, newNodeCount - initialNodeCount)) @depends(after=test_api_20_ucs_discovery) def test_api_20_ucs_serviceProfile_discovery(self): """ Tests the UCS Service Profile Discovery workflow in rackHD :return: """ expected_ucs_logical_nodes = self.get_service_profile_count() if (expected_ucs_logical_nodes == 0): raise unittest.SkipTest("No Service Profiles Defined") initialNodeCount = len(self.get_ucs_node_list()) data_payload = { "name": "Graph.Ucs.Discovery", "options": { "defaults": { "username": UCSM_USER, "password": UCSM_PASS, "ucs": UCSM_IP, "uri": UCS_SERVICE_URI }, "when-discover-physical-ucs": { "discoverPhysicalServers": "false", }, "when-discover-logical-ucs": { "discoverLogicalServer": "true" }, "when-catalog-ucs": { "autoCatalogUcs": "false" } } } header = {"Content-Type": "application/json"} api_data = fit_common.rackhdapi("/api/2.0/workflows", action="post", headers=header, payload=data_payload) self.assertEqual(api_data['status'], 201, 'Incorrect HTTP return code, expected 201, got:' + str(api_data['status'])) id = api_data["json"]["context"]["graphId"] status = self.wait_utility(str(id), 0, "Service Profile Discovery") self.assertEqual(status, 'succeeded', 'Service Profile Discovery graph returned status {}'.format(status)) newNodeCount = len(self.get_ucs_node_list()) self.assertEqual(newNodeCount - initialNodeCount, expected_ucs_logical_nodes, 'Expected to discover {0} UCS nodes, got: {1}' .format(expected_ucs_logical_nodes, newNodeCount - initialNodeCount)) logs.info_1("Found {0} UCS nodes {1}".format(len(self.UCS_COMPUTE_NODES), self.UCS_COMPUTE_NODES)) # rerun discovery graph and verify duplicate nodes are not created api_data = fit_common.rackhdapi("/api/2.0/workflows", action="post", headers=header, payload=data_payload) id = api_data["json"]["context"]["graphId"] self.assertEqual(api_data['status'], 201, 'Incorrect HTTP return code, expected 201, got:' + str(api_data['status'])) status = self.wait_utility(str(id), 0, "Service Profile Discovery") self.assertEqual(status, 'succeeded', 'Service Profile Discovery graph returned status {}'.format(status)) newNodeCount = len(self.get_ucs_node_list()) self.assertGreaterEqual(newNodeCount - initialNodeCount, 0, 'Expected to discover {0} UCS nodes, got: {1}' .format(0, newNodeCount - initialNodeCount)) @depends(after=[test_api_20_ucs_discovery]) def test_api_20_ucs_catalog(self): """ Tests the UCS Catalog workflow in rackHD :return: """ ucsNodes = self.get_ucs_node_list() errNodes = '' errGraphs = '' for x in range(len(ucsNodes)): postUrl = '/api/2.0/nodes/' + str(ucsNodes[x]["id"]) + "/workflows?name=Graph.Ucs.Catalog" header = {"Content-Type": "application/json"} api_data = fit_common.rackhdapi(postUrl, headers=header, action="post", payload={}) if api_data['status'] != 201: errNodes += 'POST for node {} returned {}, '.format(ucsNodes[x]['id'], api_data['status']) status = self.wait_utility(api_data["json"]["instanceId"], 0, "Catalog") if status != 'succeeded': errGraphs += 'graph id {} finished with status: {}, '.format(api_data["json"]["instanceId"], status) logs.info_1("Posted URL: {0} with status: {1}".format(postUrl, api_data['status'])) self.assertEqual(len(errNodes), 0, errNodes) self.assertEqual(len(errGraphs), 0, errGraphs) @depends(after=[test_api_20_ucs_catalog]) def test_api_20_ucs_discover_and_catalog_all(self): """ Tests the UCS Discovery and Catalon All workflow in rackHD :return: """ # delete all previously discovered nodes and catalogs self.assertTrue(restore_node_utility(), "failed to restore nodes") self.assertTrue(restore_obms_utility(), "failed to restore obms") initialNodeCount = len(self.get_ucs_node_list()) expected_ucs_logical_nodes = self.get_service_profile_count() expected_ucs_physical_nodes = self.get_physical_server_count() data_payload = { "name": "Graph.Ucs.Discovery", "options": { "defaults": { "username": UCSM_USER, "password": UCSM_PASS, "ucs": UCSM_IP, "uri": UCS_SERVICE_URI }, "when-discover-physical-ucs": { "discoverPhysicalServers": "true", }, "when-discover-logical-ucs": { "discoverLogicalServer": "true" }, "when-catalog-ucs": { "autoCatalogUcs": "true" } } } header = {"Content-Type": "application/json"} api_data = fit_common.rackhdapi("/api/2.0/workflows", action="post", headers=header, payload=data_payload) id = api_data["json"]["context"]["graphId"] self.assertEqual(api_data['status'], 201, 'Incorrect HTTP return code, expected 201, got:' + str(api_data['status'])) status = self.wait_utility(str(id), 0, "Discovery") self.assertEqual(status, 'succeeded', 'Discovery graph returned status {}'.format(status)) newNodeCount = len(self.get_ucs_node_list()) logs.info_1("Found {0} Nodes after cataloging the UCS".format(len(api_data['json']))) self.assertEqual(newNodeCount - initialNodeCount, expected_ucs_physical_nodes + expected_ucs_logical_nodes, 'Expected to discover {0} UCS nodes, got: {1}' .format(expected_ucs_physical_nodes + expected_ucs_logical_nodes, newNodeCount - initialNodeCount))
class rackhd20_ucs_discovery(unittest.TestCase): UCS_COMPUTE_NODES = [] @classmethod def setUpClass(cls): if not ucs_common.get_nodes_utility(): raise Exception("error getting node list") if not ucs_common.get_obms_utility(): raise Exception("error getting obms list") @classmethod def tearDownClass(cls): if not ucs_common.restore_node_utility(): raise Exception("error restoring node list") if not ucs_common.restore_obms_utility(): raise Exception("error restoring obms list") def get_ucs_node_list(self): nodeList = [] api_data = fit_common.rackhdapi('/api/2.0/nodes') self.assertEqual( api_data['status'], 200, 'Incorrect HTTP return code, expected 200, got:' + str(api_data['status'])) for node in api_data['json']: if node["obms"] != [] and node["obms"][0][ "service"] == "ucs-obm-service": nodeList.append(node) return (nodeList) def get_ucs_encl_id_list(self): enclIdList = [] nodeList = self.get_ucs_node_list() for node in nodeList: if node["type"] == 'enclosure': enclIdList.append(node['id']) return (enclIdList) @unittest.skipUnless("ucsm_ip" in fit_common.fitcfg(), "") def test_check_ucs_params(self): if not ucs_common.is_ucs_valid(): raise unittest.SkipTest( "Ucs parameters are not valid or UCSPE emulator is not ready, skipping all UCS tests" ) @depends(after=test_check_ucs_params) def test_api_20_ucs_discovery(self): """ Tests the UCS Discovery workflow in rackHD :return: """ initialNodeCount = len(self.get_ucs_node_list()) data_payload = { "name": "Graph.Ucs.Discovery", "options": { "defaults": { "username": ucs_common.UCSM_USER, "password": ucs_common.UCSM_PASS, "ucs": ucs_common.UCSM_IP, "uri": ucs_common.UCS_SERVICE_URI }, "when-discover-physical-ucs": { "discoverPhysicalServers": "true", }, "when-discover-logical-ucs": { "discoverLogicalServer": "false" }, "when-catalog-ucs": { "autoCatalogUcs": "false" } } } expected_ucs_physical_nodes = ucs_common.get_physical_server_count() header = {"Content-Type": "application/json"} api_data = fit_common.rackhdapi("/api/2.0/workflows", action="post", headers=header, payload=data_payload) id = api_data["json"]["context"]["graphId"] self.assertEqual( api_data['status'], 201, 'Incorrect HTTP return code, expected 201, got:' + str(api_data['status'])) status = ucs_common.wait_utility(str(id), 0, "Discovery") self.assertEqual(status, 'succeeded', 'Discovery graph returned status {}'.format(status)) newNodeCount = len(self.get_ucs_node_list()) logs.info_1("Found {0} Nodes after cataloging the UCS".format( len(api_data['json']))) self.assertEqual( newNodeCount - initialNodeCount, expected_ucs_physical_nodes, 'Expected to discover {0} UCS nodes, got: {1}'.format( expected_ucs_physical_nodes, newNodeCount - initialNodeCount)) # rerun discovery and verify duplicate nodes are not created initialNodeCount = len(self.get_ucs_node_list()) api_data = fit_common.rackhdapi("/api/2.0/workflows", action="post", headers=header, payload=data_payload) id = api_data["json"]["context"]["graphId"] self.assertEqual( api_data['status'], 201, 'Incorrect HTTP return code, expected 201, got:' + str(api_data['status'])) status = ucs_common.wait_utility(str(id), 0, "Discovery") self.assertEqual(status, 'succeeded', 'Discovery graph returned status {}'.format(status)) newNodeCount = len(self.get_ucs_node_list()) logs.info_1("Found {0} Nodes after cataloging the UCS".format( len(api_data['json']))) self.assertEqual( newNodeCount - initialNodeCount, 0, 'Expected to discover {0} UCS nodes, got: {1}'.format( 0, newNodeCount - initialNodeCount)) @depends(after=[test_api_20_ucs_discovery]) @unittest.skip("Skipping 'test_api_redfish_chassis' bug RAC-5358") def test_api_redfish_chassis(self): """ Tests the redfish/chassis routes with UCS nodes :return: """ ucsEnclList = self.get_ucs_encl_id_list() errUrls = '' api_data = fit_common.rackhdapi('/redfish/v1/Chassis') self.assertEqual( api_data['status'], 200, 'Incorrect HTTP return code, expected 200, got:' + str(api_data['status'])) for chassis in api_data['json']['Members']: url = chassis['@odata.id'] id = url[len('/redfish/v1/Chassis/'):] if id in ucsEnclList: ucsEnclList.remove(id) api_data = fit_common.rackhdapi(url) if api_data['status'] != 200: errUrls += url + ' returned status ' + str( api_data['status']) + ',\n' self.assertEqual(len(ucsEnclList), 0, 'not all UCS chassis were listed under /chassis') self.assertEqual(len(errUrls), 0, errUrls) @depends(after=[test_api_20_ucs_discovery]) def test_api_20_ucs_discover_and_catalog_all(self): """ Tests the UCS Discovery and Catalon All workflow in rackHD :return: """ # delete all previously discovered nodes and catalogs self.assertTrue(ucs_common.restore_node_utility(), "failed to restore nodes") self.assertTrue(ucs_common.restore_obms_utility(), "failed to restore obms") initialNodeCount = len(self.get_ucs_node_list()) expected_ucs_logical_nodes = ucs_common.get_service_profile_count() expected_ucs_physical_nodes = ucs_common.get_physical_server_count() data_payload = { "name": "Graph.Ucs.Discovery", "options": { "defaults": { "username": ucs_common.UCSM_USER, "password": ucs_common.UCSM_PASS, "ucs": ucs_common.UCSM_IP, "uri": ucs_common.UCS_SERVICE_URI }, "when-discover-physical-ucs": { "discoverPhysicalServers": "true", }, "when-discover-logical-ucs": { "discoverLogicalServer": "true" }, "when-catalog-ucs": { "autoCatalogUcs": "true" } } } header = {"Content-Type": "application/json"} api_data = fit_common.rackhdapi("/api/2.0/workflows", action="post", headers=header, payload=data_payload) id = api_data["json"]["context"]["graphId"] self.assertEqual( api_data['status'], 201, 'Incorrect HTTP return code, expected 201, got:' + str(api_data['status'])) status = ucs_common.wait_utility(str(id), 0, "Discovery", 240) self.assertEqual(status, 'succeeded', 'Discovery graph returned status {}'.format(status)) newNodeCount = len(self.get_ucs_node_list()) logs.info_1("Found {0} Nodes after cataloging the UCS".format( len(api_data['json']))) self.assertEqual( newNodeCount - initialNodeCount, expected_ucs_physical_nodes + expected_ucs_logical_nodes, 'Expected to discover {0} UCS nodes, got: {1}'.format( expected_ucs_physical_nodes + expected_ucs_logical_nodes, newNodeCount - initialNodeCount)) @depends(after=test_api_20_ucs_discover_and_catalog_all) def test_api_20_ucs_serviceProfile_discovery(self): """ Tests the UCS Service Profile Discovery workflow in rackHD :return: """ # delete all previously discovered nodes and catalogs self.assertTrue(ucs_common.restore_node_utility(), "failed to restore nodes") self.assertTrue(ucs_common.restore_obms_utility(), "failed to restore obms") expected_ucs_logical_nodes = ucs_common.get_service_profile_count() if (expected_ucs_logical_nodes == 0): raise unittest.SkipTest("No Service Profiles Defined") initialNodeCount = len(self.get_ucs_node_list()) data_payload = { "name": "Graph.Ucs.Discovery", "options": { "defaults": { "username": ucs_common.UCSM_USER, "password": ucs_common.UCSM_PASS, "ucs": ucs_common.UCSM_IP, "uri": ucs_common.UCS_SERVICE_URI }, "when-discover-physical-ucs": { "discoverPhysicalServers": "false", }, "when-discover-logical-ucs": { "discoverLogicalServer": "true" }, "when-catalog-ucs": { "autoCatalogUcs": "false" } } } header = {"Content-Type": "application/json"} api_data = fit_common.rackhdapi("/api/2.0/workflows", action="post", headers=header, payload=data_payload) self.assertEqual( api_data['status'], 201, 'Incorrect HTTP return code, expected 201, got:' + str(api_data['status'])) id = api_data["json"]["context"]["graphId"] status = ucs_common.wait_utility(str(id), 0, "Service Profile Discovery") self.assertEqual( status, 'succeeded', 'Service Profile Discovery graph returned status {}'.format( status)) newNodeCount = len(self.get_ucs_node_list()) self.assertEqual( newNodeCount - initialNodeCount, expected_ucs_logical_nodes, 'Expected to discover {0} UCS nodes, got: {1}'.format( expected_ucs_logical_nodes, newNodeCount - initialNodeCount)) logs.info_1("Found {0} UCS nodes {1}".format( len(self.UCS_COMPUTE_NODES), self.UCS_COMPUTE_NODES)) # rerun discovery graph and verify duplicate nodes are not created api_data = fit_common.rackhdapi("/api/2.0/workflows", action="post", headers=header, payload=data_payload) id = api_data["json"]["context"]["graphId"] self.assertEqual( api_data['status'], 201, 'Incorrect HTTP return code, expected 201, got:' + str(api_data['status'])) status = ucs_common.wait_utility(str(id), 0, "Service Profile Discovery") self.assertEqual( status, 'succeeded', 'Service Profile Discovery graph returned status {}'.format( status)) newNodeCount = len(self.get_ucs_node_list()) self.assertGreaterEqual( newNodeCount - initialNodeCount, 0, 'Expected to discover {0} UCS nodes, got: {1}'.format( 0, newNodeCount - initialNodeCount))
-All the ucs service APIs -The Discovery workflow -The Catalog workflow ''' import fit_path # NOQA: unused import import unittest from common import fit_common from nosedep import depends import flogging from nose.plugins.attrib import attr logs = flogging.get_loggers() UCSM_IP = fit_common.fitcfg().get('ucsm_ip') UCSM_USER = fit_common.fitcfg().get('ucsm_user') UCSM_PASS = fit_common.fitcfg().get('ucsm_pass') UCS_SERVICE_URI = fit_common.fitcfg().get('ucs_service_uri') @attr(all=True, regression=True, smoke=True, ucs=True) class ucs_api(unittest.TestCase): def ucs_url_factory(self, api, identifier=None): """ returns a fully qualified UCS API :param api:UCS API :param identifier: identify the ucs element in the catalog API :return: """
import unittest from common import fit_common import time from nosedep import depends import flogging from nose.plugins.attrib import attr from config.settings import get_ucs_cred from ucsmsdk import ucshandle from ucsmsdk.utils.ucsbackup import import_ucs_backup import os logs = flogging.get_loggers() INITIAL_NODES = {} INITIAL_OBMS = {} UCSM_IP = fit_common.fitcfg().get('ucsm_ip') UCSM_USER, UCSM_PASS = get_ucs_cred() UCS_SERVICE_URI = fit_common.fitcfg().get('ucs_service_uri') def get_nodes_utility(): """ Takes inventory of the nodes available before discovering the UCS nodes. We will restore the nodes collection to this snapshot :return: return False on failure, or True otherwise """ api_data = fit_common.rackhdapi('/api/2.0/nodes') if api_data['status'] != 200: logs.error("get /api/2.0/nodes returned status {}, expected 200".format(api_data['status'])) return False
class rackhd20_ucs_pollers(unittest.TestCase): NODELIST = [] POLLERS = {} @classmethod def setUpClass(cls): if not ucs_common.get_nodes_utility(): raise Exception("error getting node list") if not ucs_common.get_obms_utility(): raise Exception("error getting obms list") @classmethod def tearDownClass(cls): if not ucs_common.restore_node_utility(): raise Exception("error restoring node list") if not ucs_common.restore_obms_utility(): raise Exception("error restoring obms list") def get_ucs_node_list(self): api_data = fit_common.rackhdapi('/api/2.0/nodes') self.assertEqual( api_data['status'], 200, 'Incorrect HTTP return code, expected 200, got:' + str(api_data['status'])) for node in api_data['json']: if node["obms"] != [] and node["obms"][0][ "service"] == "ucs-obm-service": self.NODELIST.append(node["id"]) @unittest.skipUnless("ucsm_ip" in fit_common.fitcfg(), "") def test_check_ucs_params(self): if not ucs_common.is_ucs_valid(): raise unittest.SkipTest( "Ucs parameters are not valid or UCSPE emulator is not ready, skipping all UCS tests" ) @depends(after=[test_check_ucs_params]) def test_api_20_workflow_ucs_pollers(self): """ Tests the UCS Poller workflow in rackHD :return: """ data_payload = { "name": "Graph.Ucs.Discovery", "options": { "defaults": { "username": ucs_common.UCSM_USER, "password": ucs_common.UCSM_PASS, "ucs": ucs_common.UCSM_IP, "uri": ucs_common.UCS_SERVICE_URI }, "when-discover-physical-ucs": { "discoverPhysicalServers": "true", }, "when-discover-logical-ucs": { "discoverLogicalServer": "false" }, "when-catalog-ucs": { "autoCatalogUcs": "false" } } } header = {"Content-Type": "application/json"} api_data = fit_common.rackhdapi("/api/2.0/workflows", action="post", headers=header, payload=data_payload) self.assertEqual( api_data['status'], 201, 'Incorrect HTTP return code, expected 201, got:' + str(api_data['status'])) id = api_data["json"]["context"]["graphId"] status = ucs_common.wait_utility(str(id), 0, "Ucs Discovery") self.assertEqual( status, 'succeeded', 'Ucs Discovery graph returned status {}'.format(status)) self.get_ucs_node_list() errNodes = '' errGraphs = '' for node in self.NODELIST: postUrl = '/api/2.0/nodes/' + node + "/workflows?name=Graph.Ucs.Poller" header = {"Content-Type": "application/json"} api_data = fit_common.rackhdapi(postUrl, headers=header, action="post", payload={}) if api_data['status'] != 201: errNodes += 'POST for node {} returned {}, '.format( node, api_data['status']) status = ucs_common.wait_utility(api_data["json"]["instanceId"], 0, "Poller") if status != 'succeeded': errGraphs += 'graph id {} finished with status: {}, '.format( api_data["json"]["instanceId"], status) logs.info_1("Posted URL: {0} with status: {1}".format( postUrl, api_data['status'])) self.assertEqual(len(errNodes), 0, errNodes) self.assertEqual(len(errGraphs), 0, errGraphs) @depends(after=[test_api_20_workflow_ucs_pollers]) def test_api_20_get_pollers_by_id(self): msg = "Description: Display the poller data per node." logs.info_2("\t{0}".format(msg)) for node in self.NODELIST: api_data = fit_common.rackhdapi("/api/2.0/nodes/" + node + "/pollers") self.assertEqual( api_data['status'], 200, "Incorrect HTTP return code, expected 200, got:{0}".format( str(api_data['status']))) for item in api_data['json']: # check required fields self.assertGreater(item['pollInterval'], 0, 'pollInterval field error') for subitem in [ 'node', 'config', 'createdAt', 'id', 'name', 'failureCount', 'leaseExpires', 'leaseToken', 'updatedAt' ]: self.assertIn(subitem, item, subitem + ' field error') logs.info_2("\nNode: ") poller_dict = test_api_utils.get_supported_pollers(node) self.POLLERS[node] = poller_dict for poller in poller_dict: poller_id = poller_dict[poller]["poller_id"] logs.info_2("\nPoller: " + poller + " ID: " + str(poller_id)) poll_data = fit_common.rackhdapi("/api/2.0/pollers/" + poller_id) logs.info_5(fit_common.json.dumps(poll_data['json'], indent=4)) @depends(after=[test_api_20_get_pollers_by_id]) def test_api_20_vefify_pollers_data(self): msg = "Description: Check pollers created for node" logs.info_2("\t{0}".format(msg)) errorlist = [] poller_list = [ 'ucs.led', 'ucs.disk', 'ucs.psu', 'ucs.fan', 'ucs.sel', 'ucs.powerthermal' ] logs.info_2("Expected Pollers for a Node: ".format(poller_list)) for node in self.NODELIST: poller_dict = self.POLLERS[node] if set(poller_list) == set(poller_dict): logs.info_5("Expected pollers instantiated on node") logs.info_5("Poller list retreived", poller_dict) else: if list(set(poller_list) - set(poller_dict)): errorlist.append( "Error: Node {} Pollers not running {}".format( node, list(set(poller_list) - set(poller_dict)))) if list(set(poller_dict) - set(poller_list)): errorlist.append( "Error: Node {} Unexpected Pollers running {}".format( node, list(set(poller_dict) - set(poller_list)))) if errorlist != []: logs.info_2("{}".format(fit_common.json.dumps(errorlist, indent=4))) self.assertEqual(errorlist, [], "Error reported.") @depends(after=[test_api_20_get_pollers_by_id]) def test_api_20_verify_poller_headers(self): msg = "Description: Verify header data reported on the poller" logs.info_2("\t{0}".format(msg)) errorlist = [] for node in self.NODELIST: poller_dict = self.POLLERS[node] for poller in poller_dict: poller_id = poller_dict[poller]["poller_id"] logs.info_2("Poller: {} ID: {} ".format( poller, str(poller_id))) poller_data = test_api_utils.get_poller_data_by_id(poller_id) if poller_data == []: errorlist.append( "Error: Node {} Poller ID {}, {} failed to return any data" .format(node, poller_id, poller)) logs.info_5(fit_common.json.dumps(poller_data, indent=4)) if errorlist != []: logs.info_2("{}".format(fit_common.json.dumps(errorlist, indent=4))) self.assertEqual(errorlist, [], "Error reported.") @depends(after=[test_api_20_get_pollers_by_id]) def test_api_20_verify_poller_default_cache(self): msg = "Description: Check number of polls being kept for poller ID" logs.info_2("\t{0}".format(msg)) errorlist = [] for node in self.NODELIST: poller_dict = self.POLLERS[node] for poller in poller_dict: poller_id = poller_dict[poller]["poller_id"] poller_data = test_api_utils.get_poller_data_by_id(poller_id) poll_len = len(poller_data) logs.info_2("Poller: {} ID: {} ".format( poller, str(poller_id))) logs.info_2("Number of polls for " + str(poller_id) + ": " + str(len(poller_data))) if poll_len > 10: errorlist.append( 'Error: Poller {} ID: {} - Number of cached polls should not exceed 10' .format(poller_id, poller)) elif poll_len == 0: errorlist.append( 'Error: Poller {} ID: {} - Pollers not running'.format( poller_id, poller)) if errorlist != []: logs.info_2("{}".format(fit_common.json.dumps(errorlist, indent=4))) self.assertEqual(errorlist, [], "Error reported.") @depends(after=[test_api_20_get_pollers_by_id]) def test_api_20_verify_poller_current_data(self): msg = "Description: Display most current data from poller" logs.info_2("\t{0}".format(msg)) errorlist = [] for node in self.NODELIST: poller_dict = self.POLLERS[node] for poller in poller_dict: poller_id = poller_dict[poller]["poller_id"] logs.info_2("Poller: {} ID: {} ".format( poller, str(poller_id))) monurl = "/api/2.0/pollers/" + str(poller_id) + "/data/current" api_data = fit_common.rackhdapi(url_cmd=monurl) if api_data['status'] not in [200, 201, 202, 204]: errorlist.append( "Error: Node {} Poller_ID {} Failed to get current poller data, status {}" .format(node, poller_id, api_data['status'])) else: logs.info_5( fit_common.json.dumps(api_data['json'], indent=4)) if errorlist != []: logs.info_2("{}".format(fit_common.json.dumps(errorlist, indent=4))) self.assertEqual(errorlist, [], "Error reported.")
''' import fit_path # NOQA: unused import from common import fit_common import time import flogging from ucsmsdk import ucshandle from ucsmsdk.utils.ucsbackup import import_ucs_backup import os logs = flogging.get_loggers() INITIAL_NODES = {} INITIAL_OBMS = {} MAX_WAIT = 240 UCSM_IP = fit_common.fitcfg().get('ucsm_ip') UCSM_USER = fit_common.fitcfg().get('ucsm_user') UCSM_PASS = fit_common.fitcfg().get('ucsm_pass') EXPECTED_UCS_PHYSICAL_NODES = 22 if fit_common.fitcfg().get('physical_nodes_count') is not None: EXPECTED_UCS_PHYSICAL_NODES = int(fit_common.fitcfg().get('physical_nodes_count')) UCS_SERVICE_URI = fit_common.fitcfg().get('ucs_service_uri') def get_nodes_utility(): """ Takes inventory of the nodes available before discovering the UCS nodes. We will restore the nodes collection to this snapshot :return: return False on failure, or True otherwise """ api_data = fit_common.rackhdapi('/api/2.0/nodes')
class rackhd_ucs_api(unittest.TestCase): UCS_IP = fit_common.fitcfg().get("ucs_ip") UCS_PORT = fit_common.fitcfg().get("ucs_port") RACKHD_IP = fit_common.fitcfg().get("rackhd_host") MAX_WAIT = 60 INITIAL_NODES = {} INITIAL_OBMS = {} INITIAL_CATALOGS = {} UCS_NODES = [] UCS_COMPUTE_NODES = [] EXPECTED_UCS_NODES = 22 MAX_WAIT_ON_DELETE = 0 def wait_utility(self, id, counter, name): """ Recursevily wait for the ucs discovery workflow to finish :param id: Graph ID :param counter: Safeguard for the number of times we can check the status of the graph :param name: Description of graph we are waiting for :return: return False on failure, or True otherwise """ api_data = fit_common.rackhdapi('/api/2.0/workflows/' + str(id)) status = api_data["json"]["status"] if status == "running" and counter < self.MAX_WAIT: time.sleep(1) logs.info_1( "In the wait_utility: Workflow status is {0} for the {1}'s run. ID: {2}, name: {3}" .format(status, counter, id, name)) counter += 1 self.wait_utility(id, counter, name) elif status == "running" and counter >= self.MAX_WAIT: logs.info_1( "In the wait_utility: Timed out after trying {0} times. ID: {1}, name: {2}" .format(self.MAX_WAIT, id, name)) return False else: logs.info_1( "In the wait_utility: Waiting for workflow {0}. The status is: {1} for run: {2}. ID: {3}" .format(name, status, counter, id)) return True def get_nodes_utility(self): """ Takes inventory of the nodes available before discovering the UCS nodes. We will restore the nodes collection to this snapshot :return: """ api_data = fit_common.rackhdapi('/api/2.0/nodes') self.assertEqual( api_data['status'], 200, 'Incorrect HTTP return code, expected 200, got:' + str(api_data['status'])) for node in api_data['json']: self.INITIAL_NODES[node['id']] = node['type'] logs.info_1("Found {0} Nodes before cataloging the UCS. {1}".format( len(self.INITIAL_NODES), self.INITIAL_NODES)) def get_obms_utility(self): """ Takes inventory of the obms available before discovering the UCS obms. We will restore the obms collection to this snapshot. :return: """ api_data = fit_common.rackhdapi('/api/2.0/obms') self.assertEqual( api_data['status'], 200, 'Incorrect HTTP return code, expected 200, got:' + str(api_data['status'])) for obm in api_data['json']: self.INITIAL_OBMS[obm['id']] = obm['service'] logs.info_1("Found {0} obms before cataloging the UCS: {1}".format( len(self.INITIAL_OBMS), self.INITIAL_OBMS)) def restore_node_utility(self, catalog_workflows): """ Deletes all the added ucs nodes by the test. :param catalog_workflows: A list of the catalog workflow IDs that will wait for their completion . :return: """ logs.info_1("Restoring Nodes") api_data = fit_common.rackhdapi('/api/2.0/nodes') self.assertEqual( api_data['status'], 200, 'Incorrect HTTP return code, expected 200, got:' + str(api_data['status'])) for catalog_workflow in catalog_workflows: self.wait_utility(str(catalog_workflow), 0, "Catalog") for node in api_data['json']: if node['id'] not in self.INITIAL_NODES: api_data = fit_common.rackhdapi('/api/2.0/nodes/' + node['id'], action="delete") logs.info_1("Deleting Node: {0}. Status was: {1}".format( node['id'], api_data['status'])) time.sleep(self.MAX_WAIT_ON_DELETE) api_data = fit_common.rackhdapi('/api/2.0/nodes') self.assertEqual( api_data['status'], 200, 'Incorrect HTTP return code, expected 200, got:' + str(api_data['status'])) temp = {} for node in api_data['json']: temp[node['id']] = node['name'] self.assertEqual( len(temp), len(self.INITIAL_NODES), "Found {0} nodes remaining after restoring the nodes, should be {1}, Remaining nodes: {2}" .format(len(temp), len(self.INITIAL_NODES), temp)) def restore_obms_utility(self): """ Deletes all the added ucs obms by this test. :return: """ logs.info_1("Restoring OBMs") api_data = fit_common.rackhdapi('/api/2.0/obms') self.assertEqual( api_data['status'], 200, 'Incorrect HTTP return code, expected 200, got:' + str(api_data['status'])) for obm in api_data['json']: if obm['id'] not in self.INITIAL_OBMS: api_data = fit_common.rackhdapi('/api/2.0/obms/' + obm['id'], action="delete") logs.info_1("Deleting OBM: {0}. Status was: {1}".format( obm['id'], str(api_data['status']))) time.sleep(self.MAX_WAIT_ON_DELETE) api_data = fit_common.rackhdapi('/api/2.0/obms') self.assertEqual( api_data['status'], 200, 'Incorrect HTTP return code, expected 200, got:' + str(api_data['status'])) temp = {} for obm in api_data['json']: temp[obm['id']] = obm['service'] self.assertEqual( len(temp), len(self.INITIAL_OBMS), "Found {0} ucs obms remaining after restoring the obms, should be {1}. Remaining OBMs: {2}" .format(len(temp), len(self.INITIAL_OBMS), temp)) @unittest.skipUnless("ucs_ip" in fit_common.fitcfg(), "") def test_check_ucs_params(self): self.assertNotEqual( self.UCS_IP, None, "Expected value for UCS_IP other then None and found {0}".format( self.UCS_IP)) self.assertNotEqual( self.UCS_PORT, None, "Expected value for UCS_PORT other then None and found {0}".format( self.UCS_IP)) @depends(after=test_check_ucs_params) def test_api_20_ucs_discovery(self): """ Tests the UCS Discovery workflow in rackHD :return: """ self.get_nodes_utility() self.get_obms_utility() data_payload = { "name": "Graph.Ucs.Discovery", "options": { "defaults": { "username": "******", "password": "******", "ucs": self.UCS_IP, "uri": "http://" + self.RACKHD_IP + ":7080/sys" } } } header = {"Content-Type": "application/json"} api_data = fit_common.rackhdapi("/api/2.0/workflows", action="post", headers=header, payload=data_payload) id = api_data["json"]["context"]["graphId"] self.assertEqual( api_data['status'], 201, 'Incorrect HTTP return code, expected 201, got:' + str(api_data['status'])) self.wait_utility(str(id), 0, "Discovery") api_data = fit_common.rackhdapi('/api/2.0/nodes') self.assertEqual( api_data['status'], 200, 'Incorrect HTTP return code, expected 200, got:' + str(api_data['status'])) logs.info_1("Found {0} Nodes after cataloging the UCS".format( len(api_data['json']))) for node in api_data['json']: if node["obms"] != [] and node["obms"][0][ "service"] == "ucs-obm-service": self.UCS_NODES.append(node) if node["type"] == "compute": self.UCS_COMPUTE_NODES.append(node) self.assertGreaterEqual( len(self.UCS_NODES), self.EXPECTED_UCS_NODES, 'Expected to discover {0} UCS nodes, got: {1}'.format( self.EXPECTED_UCS_NODES, len(self.UCS_NODES))) logs.info_1("Found {0} UCS nodes {1}".format( len(self.UCS_COMPUTE_NODES), self.UCS_COMPUTE_NODES)) @depends(after=[test_check_ucs_params, test_api_20_ucs_discovery]) def test_api_20_ucs_catalog(self): """ Tests the UCS Catalog workflow in rackHD :return: """ catalog_workflows = [] for x in range(len(self.UCS_NODES)): postUrl = '/api/2.0/nodes/' + str( self.UCS_NODES[x]["id"]) + "/workflows?name=Graph.Ucs.Catalog" header = {"Content-Type": "application/json"} api_data = fit_common.rackhdapi(postUrl, headers=header, action="post") self.assertEqual( api_data['status'], 201, 'Expected to catalog {0} UCS nodes with status {1}, got: {2}'. format(self.UCS_NODES[x]["id"], 201, api_data['status'])) catalog_workflows.append(api_data["json"]["instanceId"]) logs.info_1("Posted URL: {0} with status: {1}".format( postUrl, api_data['status'])) # Restore the nodes, obms, and catalogs to their state before the UCS discovery # in order to avoid any failure in other tests logs.info_1( "Restoring the database to the state it was in before the UCS discovery and catalog" ) self.restore_node_utility(catalog_workflows) self.restore_obms_utility()
class rackhd_ucs_api(unittest.TestCase): MAX_WAIT = 240 INITIAL_CATALOGS = {} UCS_NODES = [] UCS_COMPUTE_NODES = [] EXPECTED_UCS_PHYSICAL_NODES = 22 EXPECTED_UCS_LOGICAL_NODES = 18 @classmethod def setUpClass(cls): if not get_nodes_utility(): raise Exception("error getting node list") if not get_obms_utility(): raise Exception("error getting obms list") @classmethod def tearDownClass(cls): if not restore_node_utility(): raise Exception("error restoring node list") if not restore_obms_utility(): raise Exception("error restoring obms list") def get_physical_server_count(self): """ Get a count of the number of Service Proviles defined by the UCS Manager """ url = UCS_SERVICE_URI + "/rackmount" headers = { "ucs-user": UCSM_USER, "ucs-password": UCSM_PASS, "ucs-host": UCSM_IP } api_data = fit_common.restful(url, rest_headers=headers) if api_data['status'] != 200: logs.error( 'Incorrect HTTP return code, expected 200, got: {0}'.format( api_data['status'])) return 0 count = len(api_data["json"]) url = UCS_SERVICE_URI + "/chassis" api_data = fit_common.restful(url, rest_headers=headers) if api_data['status'] != 200: logs.error( 'Incorrect HTTP return code, expected 200, got: {0}'.format( api_data['status'])) return 0 count += len(api_data["json"]) for element in api_data["json"]: count += len(element["members"]) return count def get_service_profile_count(self): """ Get a count of the number of Service Proviles defined by the UCS Manager """ url = UCS_SERVICE_URI + "/serviceProfile" headers = { "ucs-user": UCSM_USER, "ucs-password": UCSM_PASS, "ucs-host": UCSM_IP } api_data = fit_common.restful(url, rest_headers=headers) if api_data['status'] != 200: logs.error( 'Incorrect HTTP return code, expected 200, got: {0}'.format( api_data['status'])) return 0 return len(api_data["json"]["ServiceProfile"]["members"]) def wait_utility(self, id, counter, name, max_wait=MAX_WAIT): """ Wait for the specified graph to finish :param id: Graph ID :param counter: Safeguard for the number of times we can check the status of the graph :param name: Description of graph we are waiting for :return: returns status of the taskgraph, or "timeout" if count is exceeded """ api_data = fit_common.rackhdapi('/api/2.0/workflows/' + str(id)) status = api_data["json"]["status"] logs.info_1( "Waiting up to {0} seconds for {1} Workflow, ID: {2}".format( max_wait, name, id)) while (status == 'running' and counter < max_wait): time.sleep(1) counter += 1 api_data = fit_common.rackhdapi('/api/2.0/workflows/' + str(id)) status = api_data["json"]["status"] if counter >= max_wait: logs.info_1( "wait_utility() timed out after {0} attemps. status: {1}, ID: {2}, name: {3}" .format(counter, id, name)) return 'timeout' else: logs.info_1( "wait_utility() copleted with status: {0} for run: {1}. ID: {2}, name: {3}" .format(status, counter, id, name)) return status def get_ucs_node_list(self): nodeList = [] api_data = fit_common.rackhdapi('/api/2.0/nodes') self.assertEqual( api_data['status'], 200, 'Incorrect HTTP return code, expected 200, got:' + str(api_data['status'])) for node in api_data['json']: if node["obms"] != [] and node["obms"][0][ "service"] == "ucs-obm-service": nodeList.append(node) return (nodeList) def get_ucs_encl_id_list(self): enclIdList = [] nodeList = self.get_ucs_node_list() for node in nodeList: if node["type"] == 'enclosure': enclIdList.append(node['id']) return (enclIdList) @unittest.skipUnless("ucsm_ip" in fit_common.fitcfg(), "") def test_check_ucs_params(self): self.assertNotEqual( UCSM_IP, None, "Expected value for UCSM_IP other then None and found {0}".format( UCSM_IP)) self.assertNotEqual( UCS_SERVICE_URI, None, "Expected value for UCS_SERVICE_URI other then None and found {0}". format(UCS_SERVICE_URI)) if "ucsm_config_file" in fit_common.fitcfg(): # configure the UCSPE emulator if not load_ucs_manager_config(): # error configureing UCSPE emulaotr, skip all tests raise unittest.SkipTest( "Error Configuring UCSPE emulator, skipping all UCS tests") # wait up to 2 min for config to be valid timeout = 120 ucsCount = self.get_physical_server_count() while (ucsCount) != self.EXPECTED_UCS_PHYSICAL_NODES: if timeout <= 0: raise unittest.SkipTest( "Only found {0} of {1} nodes, skipping all UCS tests". format(ucsCount, self.EXPECTED_UCS_PHYSICAL_NODES)) logs.info_1( "Only found {0} of {1} ucs nodes, retrying in 30 seconds". format(ucsCount, self.EXPECTED_UCS_PHYSICAL_NODES)) timeout -= 5 time.sleep(5) ucsCount = self.get_physical_server_count() @depends(after=test_check_ucs_params) def test_api_20_ucs_discovery(self): """ Tests the UCS Discovery workflow in rackHD :return: """ initialNodeCount = len(self.get_ucs_node_list()) data_payload = { "name": "Graph.Ucs.Discovery", "options": { "defaults": { "username": UCSM_USER, "password": UCSM_PASS, "ucs": UCSM_IP, "uri": UCS_SERVICE_URI }, "when-discover-physical-ucs": { "discoverPhysicalServers": "true", }, "when-discover-logical-ucs": { "discoverLogicalServer": "false" }, "when-catalog-ucs": { "autoCatalogUcs": "false" } } } expected_ucs_physical_nodes = self.get_physical_server_count() header = {"Content-Type": "application/json"} api_data = fit_common.rackhdapi("/api/2.0/workflows", action="post", headers=header, payload=data_payload) id = api_data["json"]["context"]["graphId"] self.assertEqual( api_data['status'], 201, 'Incorrect HTTP return code, expected 201, got:' + str(api_data['status'])) status = self.wait_utility(str(id), 0, "Discovery") self.assertEqual(status, 'succeeded', 'Discovery graph returned status {}'.format(status)) newNodeCount = len(self.get_ucs_node_list()) logs.info_1("Found {0} Nodes after cataloging the UCS".format( len(api_data['json']))) self.assertEqual( newNodeCount - initialNodeCount, expected_ucs_physical_nodes, 'Expected to discover {0} UCS nodes, got: {1}'.format( expected_ucs_physical_nodes, newNodeCount - initialNodeCount)) # rerun discovery and verify duplicate nodes are not created api_data = fit_common.rackhdapi("/api/2.0/workflows", action="post", headers=header, payload=data_payload) id = api_data["json"]["context"]["graphId"] self.assertEqual( api_data['status'], 201, 'Incorrect HTTP return code, expected 201, got:' + str(api_data['status'])) status = self.wait_utility(str(id), 0, "Discovery") self.assertEqual(status, 'succeeded', 'Discovery graph returned status {}'.format(status)) newNodeCount = len(self.get_ucs_node_list()) logs.info_1("Found {0} Nodes after cataloging the UCS".format( len(api_data['json']))) self.assertGreaterEqual( newNodeCount - initialNodeCount, 0, 'Expected to discover {0} UCS nodes, got: {1}'.format( 0, newNodeCount - initialNodeCount)) @depends(after=test_api_20_ucs_discovery) def test_api_20_ucs_serviceProfile_discovery(self): """ Tests the UCS Service Profile Discovery workflow in rackHD :return: """ expected_ucs_logical_nodes = self.get_service_profile_count() if (expected_ucs_logical_nodes == 0): raise unittest.SkipTest("No Service Profiles Defined") initialNodeCount = len(self.get_ucs_node_list()) data_payload = { "name": "Graph.Ucs.Discovery", "options": { "defaults": { "username": UCSM_USER, "password": UCSM_PASS, "ucs": UCSM_IP, "uri": UCS_SERVICE_URI }, "when-discover-physical-ucs": { "discoverPhysicalServers": "false", }, "when-discover-logical-ucs": { "discoverLogicalServer": "true" }, "when-catalog-ucs": { "autoCatalogUcs": "false" } } } header = {"Content-Type": "application/json"} api_data = fit_common.rackhdapi("/api/2.0/workflows", action="post", headers=header, payload=data_payload) self.assertEqual( api_data['status'], 201, 'Incorrect HTTP return code, expected 201, got:' + str(api_data['status'])) id = api_data["json"]["context"]["graphId"] status = self.wait_utility(str(id), 0, "Service Profile Discovery") self.assertEqual( status, 'succeeded', 'Service Profile Discovery graph returned status {}'.format( status)) newNodeCount = len(self.get_ucs_node_list()) self.assertEqual( newNodeCount - initialNodeCount, expected_ucs_logical_nodes, 'Expected to discover {0} UCS nodes, got: {1}'.format( expected_ucs_logical_nodes, newNodeCount - initialNodeCount)) logs.info_1("Found {0} UCS nodes {1}".format( len(self.UCS_COMPUTE_NODES), self.UCS_COMPUTE_NODES)) # rerun discovery graph and verify duplicate nodes are not created api_data = fit_common.rackhdapi("/api/2.0/workflows", action="post", headers=header, payload=data_payload) id = api_data["json"]["context"]["graphId"] self.assertEqual( api_data['status'], 201, 'Incorrect HTTP return code, expected 201, got:' + str(api_data['status'])) status = self.wait_utility(str(id), 0, "Service Profile Discovery") self.assertEqual( status, 'succeeded', 'Service Profile Discovery graph returned status {}'.format( status)) newNodeCount = len(self.get_ucs_node_list()) self.assertGreaterEqual( newNodeCount - initialNodeCount, 0, 'Expected to discover {0} UCS nodes, got: {1}'.format( 0, newNodeCount - initialNodeCount)) @depends(after=[test_api_20_ucs_discovery]) def test_api_20_ucs_catalog(self): """ Tests the UCS Catalog workflow in rackHD :return: """ ucsNodes = self.get_ucs_node_list() errNodes = '' errGraphs = '' for x in range(len(ucsNodes)): postUrl = '/api/2.0/nodes/' + str( ucsNodes[x]["id"]) + "/workflows?name=Graph.Ucs.Catalog" header = {"Content-Type": "application/json"} api_data = fit_common.rackhdapi(postUrl, headers=header, action="post", payload={}) if api_data['status'] != 201: errNodes += 'POST for node {} returned {}, '.format( ucsNodes[x]['id'], api_data['status']) status = self.wait_utility(api_data["json"]["instanceId"], 0, "Catalog") if status != 'succeeded': errGraphs += 'graph id {} finished with status: {}, '.format( api_data["json"]["instanceId"], status) logs.info_1("Posted URL: {0} with status: {1}".format( postUrl, api_data['status'])) self.assertEqual(len(errNodes), 0, errNodes) self.assertEqual(len(errGraphs), 0, errGraphs) @depends(after=[test_api_20_ucs_discovery]) @unittest.skip("Skipping 'test_api_redfish_chassis' bug RAC-5358") def test_api_redfish_chassis(self): """ Tests the redfish/chassis routes with UCS nodes :return: """ ucsEnclList = self.get_ucs_encl_id_list() errUrls = '' api_data = fit_common.rackhdapi('/redfish/v1/Chassis') self.assertEqual( api_data['status'], 200, 'Incorrect HTTP return code, expected 200, got:' + str(api_data['status'])) for chassis in api_data['json']['Members']: url = chassis['@odata.id'] id = url[len('/redfish/v1/Chassis/'):] if id in ucsEnclList: ucsEnclList.remove(id) api_data = fit_common.rackhdapi(url) if api_data['status'] != 200: errUrls += url + ' returned status ' + str( api_data['status']) + ',\n' self.assertEqual(len(ucsEnclList), 0, 'not all UCS chassis were listed under /chassis') self.assertEqual(len(errUrls), 0, errUrls) @depends(after=[test_api_20_ucs_catalog]) def test_api_20_ucs_discover_and_catalog_all(self): """ Tests the UCS Discovery and Catalon All workflow in rackHD :return: """ # delete all previously discovered nodes and catalogs self.assertTrue(restore_node_utility(), "failed to restore nodes") self.assertTrue(restore_obms_utility(), "failed to restore obms") initialNodeCount = len(self.get_ucs_node_list()) expected_ucs_logical_nodes = self.get_service_profile_count() expected_ucs_physical_nodes = self.get_physical_server_count() data_payload = { "name": "Graph.Ucs.Discovery", "options": { "defaults": { "username": UCSM_USER, "password": UCSM_PASS, "ucs": UCSM_IP, "uri": UCS_SERVICE_URI }, "when-discover-physical-ucs": { "discoverPhysicalServers": "true", }, "when-discover-logical-ucs": { "discoverLogicalServer": "true" }, "when-catalog-ucs": { "autoCatalogUcs": "true" } } } header = {"Content-Type": "application/json"} api_data = fit_common.rackhdapi("/api/2.0/workflows", action="post", headers=header, payload=data_payload) id = api_data["json"]["context"]["graphId"] self.assertEqual( api_data['status'], 201, 'Incorrect HTTP return code, expected 201, got:' + str(api_data['status'])) status = self.wait_utility(str(id), 0, "Discovery", 240) self.assertEqual(status, 'succeeded', 'Discovery graph returned status {}'.format(status)) newNodeCount = len(self.get_ucs_node_list()) logs.info_1("Found {0} Nodes after cataloging the UCS".format( len(api_data['json']))) self.assertEqual( newNodeCount - initialNodeCount, expected_ucs_physical_nodes + expected_ucs_logical_nodes, 'Expected to discover {0} UCS nodes, got: {1}'.format( expected_ucs_physical_nodes + expected_ucs_logical_nodes, newNodeCount - initialNodeCount))
class rackhd20_ucs_catalogs(unittest.TestCase): NODELIST = [] RACK_NODELIST = [] CHASSIS_NODELIST = [] BLADE_NODELIST = [] CATALOGS = {} @classmethod def setUpClass(cls): if not ucs_common.get_nodes_utility(): raise Exception("error getting node list") if not ucs_common.get_obms_utility(): raise Exception("error getting obms list") @classmethod def tearDownClass(cls): if not ucs_common.restore_node_utility(): raise Exception("error restoring node list") if not ucs_common.restore_obms_utility(): raise Exception("error restoring obms list") def get_ucs_node_list(self): api_data = fit_common.rackhdapi('/api/2.0/nodes') self.assertEqual( api_data['status'], 200, 'Incorrect HTTP return code, expected 200, got:' + str(api_data['status'])) for node in api_data['json']: if node["obms"] != [] and node["obms"][0][ "service"] == "ucs-obm-service": self.NODELIST.append(node["id"]) node_name = node["name"].split("/")[-1] if "rack" in node_name: self.RACK_NODELIST.append(node["id"]) elif "blade" in node_name: self.BLADE_NODELIST.append(node["id"]) elif "chassis" in node_name: self.CHASSIS_NODELIST.append(node["id"]) @unittest.skipUnless("ucsm_ip" in fit_common.fitcfg(), "") def test_check_ucs_params(self): if not ucs_common.is_ucs_valid(): raise unittest.SkipTest( "Ucs parameters are not valid or UCSPE emulator is not ready, skipping all UCS tests" ) @depends(after=[test_check_ucs_params]) def test_api_20_workflow_ucs_catalogs(self): """ Tests the UCS Poller workflow in rackHD :return: """ data_payload = { "name": "Graph.Ucs.Discovery", "options": { "defaults": { "username": ucs_common.UCSM_USER, "password": ucs_common.UCSM_PASS, "ucs": ucs_common.UCSM_IP, "uri": ucs_common.UCS_SERVICE_URI }, "when-discover-physical-ucs": { "discoverPhysicalServers": "true", }, "when-discover-logical-ucs": { "discoverLogicalServer": "false" }, "when-catalog-ucs": { "autoCatalogUcs": "false" } } } header = {"Content-Type": "application/json"} api_data = fit_common.rackhdapi("/api/2.0/workflows", action="post", headers=header, payload=data_payload) self.assertEqual( api_data['status'], 201, 'Incorrect HTTP return code, expected 201, got:' + str(api_data['status'])) id = api_data["json"]["context"]["graphId"] status = ucs_common.wait_utility(str(id), 0, "Ucs Discovery") self.assertEqual( status, 'succeeded', 'Ucs Discovery graph returned status {}'.format(status)) self.get_ucs_node_list() errNodes = '' errGraphs = '' for node in self.NODELIST: postUrl = '/api/2.0/nodes/' + node + "/workflows?name=Graph.Ucs.Catalog" header = {"Content-Type": "application/json"} api_data = fit_common.rackhdapi(postUrl, headers=header, action="post", payload={}) if api_data['status'] != 201: errNodes += 'POST for node {} returned {}, '.format( node, api_data['status']) status = ucs_common.wait_utility(api_data["json"]["instanceId"], 0, "Catalog") if status != 'succeeded': errGraphs += 'graph id {} finished with status: {}, '.format( api_data["json"]["instanceId"], status) logs.info_1("Posted URL: {0} with status: {1}".format( postUrl, api_data['status'])) self.assertEqual(len(errNodes), 0, errNodes) self.assertEqual(len(errGraphs), 0, errGraphs) @depends(after=[test_api_20_workflow_ucs_catalogs]) def test_api_20_get_catalogs(self): msg = "Description: Check catalogs data per node." logs.info_2("\t{0}".format(msg)) for node in self.NODELIST: api_data = fit_common.rackhdapi("/api/2.0/nodes/" + node + "/catalogs") self.assertEqual( api_data['status'], 200, "Incorrect HTTP return code, expected 200, got:{0}".format( str(api_data['status']))) self.CATALOGS[node] = api_data['json'] for item in api_data['json']: for subitem in ['node', 'id', 'source', 'data']: self.assertIn(subitem, item, subitem + ' field error') @depends(after=[test_api_20_get_catalogs]) def test_api_20_verify_catalogs_source(self): msg = "Description: Check source of catalogs created for node" logs.info_2("\t{0}".format(msg)) for node in self.NODELIST: sources = [] for item in self.CATALOGS[node]: sources.append(item['source']) logs.info_5("Node {0} contains source: {1}".format(node, sources)) self.assertIn("UCS", sources, node + " catalogs doesn't contain UCS source") for node in self.RACK_NODELIST + self.BLADE_NODELIST: sources = [] for item in self.CATALOGS[node]: sources.append(item['source']) self.assertIn("UCS:board", sources, node + " catalogs doesn't contain UCS:board source") @depends(after=[test_api_20_get_catalogs]) def test_api_20_vefify_catalogs_source_data(self): msg = "Description: Check source data of catalogs created for node" logs.info_2("\t{0}".format(msg)) for node in self.NODELIST: for item in self.CATALOGS[node]: logs.info_2("Checking source:{0}".format(item['source'])) self.assertNotEqual(item, '', 'Empty JSON Field') sourcedata = fit_common.rackhdapi("/api/2.0/nodes/" + node + "/catalogs/" + item['source']) self.assertGreater(len(sourcedata['json']['id']), 0, 'id field error') self.assertGreater(len(sourcedata['json']['node']), 0, 'node field error') self.assertGreater(len(sourcedata['json']['source']), 0, 'source field error') self.assertGreater(len(sourcedata['json']['updatedAt']), 0, 'updatedAt field error') self.assertGreater(len(sourcedata['json']['createdAt']), 0, 'createdAt field error')
class ucs_api(unittest.TestCase): UCS_IP = fit_common.fitcfg().get("ucs_ip") UCS_PORT = fit_common.fitcfg().get("ucs_port") RACKHD_IP = fit_common.fitcfg().get("rackhd_host") def ucs_url_factory(self, api, identifier=None): """ returns a fully qualified UCS API :param api:UCS API :param identifier: identify the ucs element in the catalog API :return: """ ucs_service = self.RACKHD_IP + ":" + self.UCS_PORT + "/" ucs_manager = self.UCS_IP if identifier is None: url = "https://" + ucs_service + api else: url = "https://" + ucs_service + api + "?identifier=" + identifier headers = {"ucs-user": "******", "ucs-password": "******", "ucs-host": ucs_manager} return (url, headers) @unittest.skipUnless("ucs_ip" in fit_common.fitcfg(), "") def test_check_ucs_params(self): self.assertNotEqual(self.UCS_IP, None, "Expected value for UCS_IP other then None and found {0}" .format(self.UCS_IP)) self.assertNotEqual(self.UCS_PORT, None, "Expected value for UCS_PORT other then None and found {0}" .format(self.UCS_IP)) @depends(after=test_check_ucs_params) def test_ucs_log_in(self): """ Test the /logIn ucs API :return: """ url, headers = self.ucs_url_factory("login") api_data = fit_common.restful(url, rest_headers=headers) self.assertEqual(api_data['status'], 200, 'Incorrect HTTP return code, expected 200, got:' + str(api_data['status'])) self.assertNotEqual(api_data["json"], None, "Expected a token to be returned on login and received None") self.assertNotEqual(type(api_data["json"]), "unicode", "Unexpected Token was received on Login") @depends(after=test_check_ucs_params) def test_ucs_get_sys(self): """ Test the /sys ucs API :return: """ url, headers = self.ucs_url_factory("sys") api_data = fit_common.restful(url, rest_headers=headers) self.assertEqual(api_data['status'], 200, 'Incorrect HTTP return code, expected 200, got:' + str(api_data['status'])) self.assertEqual(len(api_data["json"]["Fabric Interconnects"]), 2, "Expected 2 Fabric Interconnects but found {0}" .format(len(api_data["json"]["Fabric Interconnects"]))) self.assertEqual(len(api_data["json"]["Servers"]), 7, "Expected 7 Servers but found {0}" .format(len(api_data["json"]["Servers"]))) self.assertEqual(len(api_data["json"]["FEX"]), 2, "Expected 2 FEX but found {0}" .format(len(api_data["json"]["FEX"]))) self.assertEqual(len(api_data["json"]["Chassis"]), 4, "Expected 2 Chassis but found {0}" .format(len(api_data["json"]["Chassis"]))) @depends(after=test_check_ucs_params) def test_ucs_get_rackmount(self): """ Test the /rackmount ucs API :return: """ url, headers = self.ucs_url_factory("rackmount") api_data = fit_common.restful(url, rest_headers=headers) self.assertEqual(api_data['status'], 200, 'Incorrect HTTP return code, expected 200, got:' + str(api_data['status'])) self.assertGreaterEqual(len(api_data["json"]), 1, "Expected 1 or more Rackmounts but found {0}". format(len(api_data["json"]))) # TO DO more in depth testing for the returned content such as mac validation, etc... @depends(after=test_check_ucs_params) def test_ucs_get_chassis(self): """ Test the /chassis ucs API :return: """ url, headers = self.ucs_url_factory("chassis") api_data = fit_common.restful(url, rest_headers=headers) self.assertEqual(api_data['status'], 200, 'Incorrect HTTP return code, expected 200, got:' + str(api_data['status'])) self.assertGreaterEqual(len(api_data["json"]), 4, "Expected 4 chassis or more but found {0}". format(len(api_data["json"]))) # TO DO more in depth testing for the returned content such as mac validation, etc... @depends(after=test_check_ucs_params) def test_api_20_ucs_get_catalog(self): """ Test the /sys ucs API :return: """ url, headers = self.ucs_url_factory("sys") api_data = fit_common.restful(url, rest_headers=headers) self.assertEqual(api_data['status'], 200, 'Incorrect HTTP return code, expected 200, got:' + str(api_data['status'])) total_elements = 0 for elementTypes in api_data["json"]: for element in api_data["json"][str(elementTypes)]: url, headers = self.ucs_url_factory("catalog", identifier=element["relative_path"].split("/")[-1]) api_data_c = fit_common.restful(url, rest_headers=headers) self.assertEqual(api_data['status'], 200, 'Incorrect HTTP return code, expected 200, got:' + str(api_data_c['status'])) total_elements += 1 self.assertGreaterEqual(total_elements, 15, "Expected at least 15 elements but found {0}" .format(total_elements))
class ucs_api(unittest.TestCase): def ucs_url_factory(self, api, identifier=None): """ returns a fully qualified UCS API :param api:UCS API :param identifier: identify the ucs element in the catalog API :return: """ if identifier is None: url = UCS_SERVICE_URI + "/" + api else: url = UCS_SERVICE_URI + "/" + api + "?identifier=" + identifier headers = {"ucs-user": UCSM_USER, "ucs-password": UCSM_PASS, "ucs-host": UCSM_IP} return (url, headers) @unittest.skipUnless("ucsm_ip" in fit_common.fitcfg(), "") def test_check_ucs_params(self): self.assertNotEqual(UCSM_IP, None, "Expected value for UCSM_IP other then None and found {0}" .format(UCSM_IP)) self.assertNotEqual(UCS_SERVICE_URI, None, "Expected value for UCS_SERVICE_URI other then None and found {0}" .format(UCS_SERVICE_URI)) @depends(after=test_check_ucs_params) def test_ucs_log_in(self): """ Test the /logIn ucs API :return: """ url, headers = self.ucs_url_factory("login") api_data = fit_common.restful(url, rest_headers=headers) self.assertEqual(api_data['status'], 200, 'Incorrect HTTP return code, expected 200, got:' + str(api_data['status'])) self.assertNotEqual(api_data["json"], None, "Expected a token to be returned on login and received None") self.assertNotEqual(type(api_data["json"]), "unicode", "Unexpected Token was received on Login") @depends(after=test_check_ucs_params) def test_ucs_get_sys(self): """ Test the /sys ucs API :return: """ url, headers = self.ucs_url_factory("sys") api_data = fit_common.restful(url, rest_headers=headers) self.assertEqual(api_data['status'], 200, 'Incorrect HTTP return code, expected 200, got:' + str(api_data['status'])) self.assertEqual(len(api_data["json"]["Fabric Interconnects"]), 2, "Expected 2 Fabric Interconnects but found {0}" .format(len(api_data["json"]["Fabric Interconnects"]))) self.assertEqual(len(api_data["json"]["Servers"]), 7, "Expected 7 Servers but found {0}" .format(len(api_data["json"]["Servers"]))) self.assertEqual(len(api_data["json"]["FEX"]), 2, "Expected 2 FEX but found {0}" .format(len(api_data["json"]["FEX"]))) self.assertEqual(len(api_data["json"]["Chassis"]), 4, "Expected 2 Chassis but found {0}" .format(len(api_data["json"]["Chassis"]))) @depends(after=test_check_ucs_params) def test_ucs_get_rackmount(self): """ Test the /rackmount ucs API :return: """ url, headers = self.ucs_url_factory("rackmount") api_data = fit_common.restful(url, rest_headers=headers) self.assertEqual(api_data['status'], 200, 'Incorrect HTTP return code, expected 200, got:' + str(api_data['status'])) self.assertEqual(len(api_data["json"]), 7, "Expected 7 Rackmounts but found {0}". format(len(api_data["json"]))) # TO DO more in depth testing for the returned content such as mac validation, etc... @depends(after=test_check_ucs_params) def test_ucs_get_chassis(self): """ Test the /chassis ucs API :return: """ url, headers = self.ucs_url_factory("chassis") api_data = fit_common.restful(url, rest_headers=headers) self.assertEqual(api_data['status'], 200, 'Incorrect HTTP return code, expected 200, got:' + str(api_data['status'])) self.assertEqual(len(api_data["json"]), 4, "Expected 4 chassis but found {0}". format(len(api_data["json"]))) # TO DO more in depth testing for the returned content such as mac validation, etc... @depends(after=test_ucs_get_chassis) def test_ucs_get_serviceProfile(self): """ Test the /serviceProfile ucs API :return: """ url, headers = self.ucs_url_factory("serviceProfile") api_data = fit_common.restful(url, rest_headers=headers) self.assertEqual(api_data['status'], 200, 'Incorrect HTTP return code, expected 200, got:' + str(api_data['status'])) self.assertEqual(len(api_data["json"]["ServiceProfile"]["members"]), 18, "Expected 18 chassis or more but found {0}" .format(len(api_data["json"]["ServiceProfile"]["members"]))) # TO DO more in depth testing for the returned content such as mac validation, etc... @depends(after=test_check_ucs_params) def test_api_20_ucs_get_catalog(self): """ Test the /sys ucs API :return: """ url, headers = self.ucs_url_factory("sys") api_data = fit_common.restful(url, rest_headers=headers) self.assertEqual(api_data['status'], 200, 'Incorrect HTTP return code, expected 200, got:' + str(api_data['status'])) total_elements = 0 for elementTypes in api_data["json"]: for element in api_data["json"][str(elementTypes)]: url, headers = self.ucs_url_factory("catalog", identifier=element["relative_path"].split("/")[-1]) api_data_c = fit_common.restful(url, rest_headers=headers) self.assertEqual(api_data_c['status'], 200, 'Incorrect HTTP return code, expected 200, got:' + str(api_data_c['status'])) total_elements += 1 self.assertEqual(total_elements, 15, "Expected 15 elements but found {0}" .format(total_elements)) # TO DO: deeper check on the catalog data def check_all_server_power_state(self, state): """ Test to see if all Associated servers are in the specified state :return: True or False """ url, headers = self.ucs_url_factory("serviceProfile") api_data = fit_common.restful(url, rest_headers=headers) self.assertEqual(api_data['status'], 200, 'Incorrect HTTP return code, expected 200, got:' + str(api_data['status'])) total_elements = 0 for server in api_data["json"]["ServiceProfile"]["members"]: url, headers = self.ucs_url_factory("power", identifier=str(server["path"])) api_data_c = fit_common.restful(url, rest_headers=headers) self.assertEqual(api_data_c['status'], 200, 'Incorrect HTTP return code, expected 200, got:' + str(api_data_c['status'])) self.assertEqual(api_data_c["json"]["serverState"], state, 'Server ' + str(server["path"]) + ' reported power state ' + str(api_data_c["json"]["serverState"]) + ' expected: ' + state) total_elements += 1 self.assertEqual(total_elements, 18, "Expected 18 elements but found {0}" .format(total_elements)) def set_all_server_power_state(self, state): """ Use the POST /power ucs API to set the state of all servers :return: """ url, headers = self.ucs_url_factory("serviceProfile") api_data = fit_common.restful(url, rest_headers=headers) self.assertEqual(api_data['status'], 200, 'Incorrect HTTP return code, expected 200, got:' + str(api_data['status'])) total_elements = 0 for server in api_data["json"]["ServiceProfile"]["members"]: url, headers = self.ucs_url_factory("power", identifier=str(server["path"])) api_data_c = fit_common.restful(url + "&action=" + state, rest_headers=headers, rest_action='post') self.assertEqual(api_data_c['status'], 200, 'Incorrect HTTP return code, expected 200, got:' + str(api_data_c['status'])) total_elements += 1 self.assertEqual(total_elements, 18, "Expected 18 elements but found {0}" .format(total_elements)) @depends(after=test_check_ucs_params) def test_api_20_ucs_power(self): """ Test the GET and POST api for server power state :return: """ # first power off all servers self.set_all_server_power_state("off") # verify power state is down self.check_all_server_power_state("down") # now power on the servers self.set_all_server_power_state("on") # verify power state is up self.check_all_server_power_state("up")
''' import fit_path # NOQA: unused import from common import fit_common import time import flogging from ucsmsdk import ucshandle from ucsmsdk.utils.ucsbackup import import_ucs_backup import os logs = flogging.get_loggers() INITIAL_NODES = {} INITIAL_OBMS = {} MAX_WAIT = 240 UCSM_IP = fit_common.fitcfg().get('ucsm_ip') UCSM_USER = fit_common.fitcfg().get('ucsm_user') UCSM_PASS = fit_common.fitcfg().get('ucsm_pass') EXPECTED_UCS_PHYSICAL_NODES = 22 if fit_common.fitcfg().get('physical_nodes_count') is not None: EXPECTED_UCS_PHYSICAL_NODES = int( fit_common.fitcfg().get('physical_nodes_count')) UCS_SERVICE_URI = fit_common.fitcfg().get('ucs_service_uri') def get_nodes_utility(): """ Takes inventory of the nodes available before discovering the UCS nodes. We will restore the nodes collection to this snapshot :return: return False on failure, or True otherwise """