| # 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) |