# Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import marvin from marvin.cloudstackTestCase import * from marvin.cloudstackAPI import * from marvin.lib.utils import * from marvin.lib.base import * from marvin.lib.common import * from nose.plugins.attrib import attr from http.server import BaseHTTPRequestHandler,HTTPServer import socket import sys import _thread import time apiRequests = [] state = "Running" class MockedCloudStackServer(BaseHTTPRequestHandler): """ Mocked ACS Mgmt Server """ def do_GET(self): global apiRequests, state command = self.path.split('command=')[1].split('&')[0] if command == 'startVirtualMachine': state = "Running" elif command == 'stopVirtualMachine': state = "Stopped" elif command == 'rebootVirtualMachine': state = "Running" apiRequests.append(command) self.send_response(200) self.send_header('content-type','application/json') self.end_headers() json = "{\"listvirtualmachinesresponse\":{\"count\":1,\"virtualmachine\":[{\"id\":\"some-uuid\",\"name\":\"test-vm\",\"state\":\"%s\"}]}}" % state self.wfile.write(json.encode()) def log_message(self, format, *args): return class TestOutOfBandManagement(cloudstackTestCase): """ Test cases for out of band management """ def setUp(self): self.apiclient = self.testClient.getApiClient() self.hypervisor = self.testClient.getHypervisorInfo() self.dbclient = self.testClient.getDbConnection() self.services = self.testClient.getParsedTestDataConfig() self.mgtSvrDetails = self.config.__dict__["mgtSvr"][0].__dict__ self.zone = get_zone(self.apiclient, self.testClient.getZoneForTests()) self.host = None self.server = None # use random port for mocked-mgmt server s = socket.socket() s.bind(('', 0)) self.serverPort = s.getsockname()[1] s.close() self.cleanup = [] global state, apiRequests state = "Running" apiRequests = [] def tearDown(self): try: self.dbclient.execute("delete from oobm where driver='nestedcloudstack' and port='some-uuid'") cleanup_resources(self.apiclient, self.cleanup) if self.server: self.server.socket.close() global apiRequests apiRequests = [] except Exception as e: raise Exception("Warning: Exception during cleanup : %s" % e) def getHost(self, hostId=None): if self.host and hostId is None: return self.host response = list_hosts( self.apiclient, zoneid=self.zone.id, type='Routing', id=hostId) if len(response) > 0: self.host = response[0] return self.host raise self.skipTest("No hosts found, skipping out-of-band management test") def getServerIp(self): s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((self.mgtSvrDetails["mgtSvrIp"], self.mgtSvrDetails["port"])) return s.getsockname()[0] def getServerPort(self): return self.serverPort def getOobmConfigCmd(self): cmd = configureOutOfBandManagement.configureOutOfBandManagementCmd() cmd.driver = 'nestedcloudstack' cmd.address = 'http://%s:%s/client/api' % (self.getServerIp(), self.getServerPort()) cmd.port = 'some-uuid' cmd.username = 'admin' cmd.password = 'password' cmd.hostid = self.getHost().id return cmd def getOobmEnableCmd(self): cmd = enableOutOfBandManagementForHost.enableOutOfBandManagementForHostCmd() cmd.hostid = self.getHost().id return cmd def getOobmIssueActionCmd(self): cmd = issueOutOfBandManagementPowerAction.issueOutOfBandManagementPowerActionCmd() cmd.hostid = self.getHost().id cmd.action = 'STATUS' return cmd def issuePowerActionCmd(self, action): cmd = self.getOobmIssueActionCmd() cmd.action = action return self.apiclient.issueOutOfBandManagementPowerAction(cmd) def configureAndEnableOobm(self): self.apiclient.configureOutOfBandManagement(self.getOobmConfigCmd()) response = self.apiclient.enableOutOfBandManagementForHost(self.getOobmEnableCmd()) self.assertEqual(response.enabled, True) def startMgmtServer(self): def startMgmtServer(tname, server): self.debug("Starting ACS mocked-mgmt server") try: server.serve_forever() except Exception: pass server = HTTPServer(('0.0.0.0', self.getServerPort()), MockedCloudStackServer) _thread.start_new_thread(startMgmtServer, ("mocked-mgmt-server", server,)) self.server = server def configureAndStartMgmtServer(self): """ Configure mocked-mgmt server and enable out-of-band management for host """ self.configureAndEnableOobm() self.startMgmtServer() def assertIssueCommandState(self, command, expected): """ Asserts power action result for a given power command """ if command != 'STATUS': self.issuePowerActionCmd(command) response = self.issuePowerActionCmd('STATUS') self.assertEqual(response.powerstate, expected) @attr(tags = ["devcloud", "advanced", "advancedns", "smoke", "basic", "sg"], required_hardware="false") def test_oobm_issue_power_status(self): """ Tests out-of-band management issue power action """ self.configureAndStartMgmtServer() self.assertIssueCommandState('STATUS', 'On') @attr(tags = ["devcloud", "advanced", "advancedns", "smoke", "basic", "sg"], required_hardware="false") def test_oobm_issue_power_on(self): """ Tests out-of-band management issue power on action """ self.configureAndStartMgmtServer() self.assertIssueCommandState('ON', 'On') global apiRequests self.assertTrue('startVirtualMachine' in apiRequests) @attr(tags = ["devcloud", "advanced", "advancedns", "smoke", "basic", "sg"], required_hardware="false") def test_oobm_issue_power_off(self): """ Tests out-of-band management issue power off action """ self.configureAndStartMgmtServer() self.assertIssueCommandState('OFF', 'Off') global apiRequests self.assertTrue('stopVirtualMachine' in apiRequests) @attr(tags = ["devcloud", "advanced", "advancedns", "smoke", "basic", "sg"], required_hardware="false") def test_oobm_issue_power_cycle(self): """ Tests out-of-band management issue power cycle action """ self.configureAndStartMgmtServer() self.assertIssueCommandState('CYCLE', 'On') global apiRequests self.assertTrue('rebootVirtualMachine' in apiRequests) @attr(tags = ["devcloud", "advanced", "advancedns", "smoke", "basic", "sg"], required_hardware="false") def test_oobm_issue_power_reset(self): """ Tests out-of-band management issue power reset action """ self.configureAndStartMgmtServer() self.assertIssueCommandState('RESET', 'On') global apiRequests self.assertTrue('rebootVirtualMachine' in apiRequests) @attr(tags = ["devcloud", "advanced", "advancedns", "smoke", "basic", "sg"], required_hardware="false") def test_oobm_issue_power_soft(self): """ Tests out-of-band management issue power soft action """ self.configureAndStartMgmtServer() self.assertIssueCommandState('SOFT', 'Off') global apiRequests self.assertTrue('stopVirtualMachine' in apiRequests)