[
https://issues.apache.org/jira/browse/CLOUDSTACK-9299?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15267642#comment-15267642
]
ASF GitHub Bot commented on CLOUDSTACK-9299:
--------------------------------------------
Github user jburwell commented on a diff in the pull request:
https://github.com/apache/cloudstack/pull/1502#discussion_r61816897
--- Diff: test/integration/smoke/test_outofbandmanagement.py ---
@@ -0,0 +1,561 @@
+# 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 marvin.lib.utils import (random_gen)
+from nose.plugins.attrib import attr
+
+from ipmisim.ipmisim import IpmiServerContext, IpmiServer,
ThreadedIpmiServer
+
+import socket
+import sys
+import thread
+import time
+
+
+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 ipmisim
+ s = socket.socket()
+ s.bind(('', 0))
+ self.serverPort = s.getsockname()[1]
+ s.close()
+
+ self.cleanup = []
+
+
+ def tearDown(self):
+ try:
+ self.dbclient.execute("delete from oobm where port=%d" %
self.getIpmiServerPort())
+ self.dbclient.execute("delete from mshost_peer where
peer_runid=%s" % self.getFakeMsRunId())
+ self.dbclient.execute("delete from mshost where runid=%s" %
self.getFakeMsRunId())
+ self.dbclient.execute("delete from cluster_details where
name='outOfBandManagementEnabled'")
+ self.dbclient.execute("delete from data_center_details where
name='outOfBandManagementEnabled'")
+ cleanup_resources(self.apiclient, self.cleanup)
+ if self.server:
+ self.server.shutdown()
+ self.server.server_close()
+ except Exception as e:
+ raise Exception("Warning: Exception during cleanup : %s" % e)
+
+
+ def getFakeMsId(self):
+ return 1234567890
+
+
+ def getFakeMsRunId(self):
+ return 123456
+
+
+ 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 getIpmiServerIp(self):
+ s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+ s.connect((self.mgtSvrDetails["mgtSvrIp"],
self.mgtSvrDetails["port"]))
+ return s.getsockname()[0]
+
+
+ def getIpmiServerPort(self):
+ return self.serverPort
+
+
+ def getOobmConfigCmd(self):
+ cmd =
configureOutOfBandManagement.configureOutOfBandManagementCmd()
+ cmd.driver = 'ipmitool' # The default available driver
+ cmd.address = self.getIpmiServerIp()
+ cmd.port = self.getIpmiServerPort()
+ 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 getOobmDisableCmd(self):
+ cmd =
disableOutOfBandManagementForHost.disableOutOfBandManagementForHostCmd()
+ 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, timeout=None):
+ cmd = self.getOobmIssueActionCmd()
+ cmd.action = action
+ if timeout:
+ cmd.timeout = timeout
+ 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 startIpmiServer(self):
+ def startIpmiServer(tname, server):
+ self.debug("Starting ipmisim server")
+ try:
+ server.serve_forever()
+ except Exception: pass
+ IpmiServerContext('reset')
+ ThreadedIpmiServer.allow_reuse_address = False
+ server = ThreadedIpmiServer(('0.0.0.0', self.getIpmiServerPort()),
IpmiServer)
+ thread.start_new_thread(startIpmiServer, ("ipmi-server", server,))
+ self.server = server
+
+
+ def checkSyncToState(self, state, interval):
+ self.debug("Waiting for background thread to update powerstate to
" + state)
+ time.sleep(1 + int(interval)*2/1000) # interval is in ms
+ response =
self.getHost(hostId=self.getHost().id).outofbandmanagement
+ self.assertEqual(response.powerstate, state)
+
+
+ @attr(tags=["smoke", "advanced"])
+ def test_oobm_configure_invalid_driver(self):
+ """
+ Tests out-of-band management configuration with invalid driver
+ """
+ cmd = self.getOobmConfigCmd()
+ cmd.driver = 'randomDriverThatDoesNotExist'
+ try:
+ response = self.apiclient.configureOutOfBandManagement(cmd)
+ self.fail("Expected an exception to be thrown, failing")
+ except Exception: pass
+
+
+ @attr(tags=["smoke", "advanced"])
+ def test_oobm_configure_default_driver(self):
+ """
+ Tests out-of-band management configuration with valid data
+ """
+ cmd = self.getOobmConfigCmd()
+ response = self.apiclient.configureOutOfBandManagement(cmd)
+ self.assertEqual(response.hostid, cmd.hostid)
+ self.assertEqual(response.driver, cmd.driver)
+ self.assertEqual(response.address, cmd.address)
+ self.assertEqual(response.port, str(cmd.port))
+ self.assertEqual(response.username, cmd.username)
+
+
+ @attr(tags=["smoke", "advanced"])
+ def test_oobm_enable_feature_invalid(self):
+ """
+ Tests out-of-band management host enable feature with
+ invalid options
+ """
+ cmd = self.getOobmEnableCmd()
+ cmd.hostid = -1
+ try:
+ response = self.apiclient.enableOutOfBandManagementForHost(cmd)
+ self.fail("Expected an exception to be thrown, failing")
+ except Exception: pass
+
+ try:
+ cmd =
enableOutOfBandManagementForCluster.enableOutOfBandManagementForClusterCmd()
+ response =
self.apiclient.enableOutOfBandManagementForCluster(cmd)
+ self.fail("Expected an exception to be thrown, failing")
+ except Exception: pass
+
+ try:
+ cmd =
enableOutOfBandManagementForZone.enableOutOfBandManagementForZoneCmd()
+ response = self.apiclient.enableOutOfBandManagementForZone(cmd)
+ self.fail("Expected an exception to be thrown, failing")
+ except Exception: pass
+
+
+ @attr(tags=["smoke", "advanced"])
+ def test_oobm_disable_feature_invalid(self):
+ """
+ Tests out-of-band management host disable feature with
+ invalid options
+ """
+ cmd = self.getOobmDisableCmd()
+ cmd.hostid = -1
+ try:
+ response =
self.apiclient.disableOutOfBandManagementForHost(cmd)
+ self.fail("Expected an exception to be thrown, failing")
+ except Exception: pass
+
+ try:
+ cmd =
disableOutOfBandManagementForCluster.disableOutOfBandManagementForClusterCmd()
+ response =
self.apiclient.disableOutOfBandManagementForCluster(cmd)
+ self.fail("Expected an exception to be thrown, failing")
+ except Exception: pass
+
+ try:
+ cmd =
disableOutOfBandManagementForZone.disableOutOfBandManagementForZoneCmd()
+ response =
self.apiclient.disableOutOfBandManagementForZone(cmd)
+ self.fail("Expected an exception to be thrown, failing")
+ except Exception: pass
+
+
+ @attr(tags=["smoke", "advanced"])
+ def test_oobm_enable_feature_valid(self):
+ """
+ Tests out-of-band management host enable feature with
+ valid options
+ """
+
self.apiclient.configureOutOfBandManagement(self.getOobmConfigCmd())
+ cmd = self.getOobmEnableCmd()
+ response = self.apiclient.enableOutOfBandManagementForHost(cmd)
+ self.assertEqual(response.hostid, cmd.hostid)
+ self.assertEqual(response.enabled, True)
+
+
+ @attr(tags=["smoke", "advanced"])
+ def test_oobm_disable_feature_valid(self):
+ """
+ Tests out-of-band management host disable feature with
+ valid options
+ """
+
+
self.apiclient.configureOutOfBandManagement(self.getOobmConfigCmd())
+ cmd = self.getOobmDisableCmd()
+ response = self.apiclient.disableOutOfBandManagementForHost(cmd)
+ self.assertEqual(response.hostid, cmd.hostid)
+ self.assertEqual(response.enabled, False)
+
+ response = self.getHost(hostId=cmd.hostid).outofbandmanagement
+ self.assertEqual(response.powerstate, 'Disabled')
+
+
+ @attr(tags=["smoke", "advanced"])
+ def test_oobm_enabledisable_across_clusterzones(self):
+ """
+ Tests out-of-band management enable/disable feature at cluster
+ and zone level sequentially Zone > Cluster > Host
+ """
+ self.configureAndEnableOobm()
+ self.startIpmiServer()
+ bmc = IpmiServerContext().bmc
+ bmc.powerstate = 'off'
+
+ host = self.getHost()
+
+ # Disable at zone level
+ cmd =
disableOutOfBandManagementForZone.disableOutOfBandManagementForZoneCmd()
+ cmd.zoneid = host.zoneid
+ response = self.apiclient.disableOutOfBandManagementForZone(cmd)
+
+ # Disable at cluster level
+ cmd =
disableOutOfBandManagementForCluster.disableOutOfBandManagementForClusterCmd()
+ cmd.clusterid = host.clusterid
+ response = self.apiclient.disableOutOfBandManagementForCluster(cmd)
+
+ # Disable at host level
+ cmd =
disableOutOfBandManagementForHost.disableOutOfBandManagementForHostCmd()
+ cmd.hostid = host.id
+ response = self.apiclient.disableOutOfBandManagementForHost(cmd)
+
+ try:
+ self.issuePowerActionCmd('STATUS')
+ self.fail("Exception was expected, oobm is disabled at zone
level")
+ except Exception: pass
+
+ # Enable at zone level
+ cmd =
enableOutOfBandManagementForZone.enableOutOfBandManagementForZoneCmd()
+ cmd.zoneid = host.zoneid
+ response = self.apiclient.enableOutOfBandManagementForZone(cmd)
+
+ try:
+ self.issuePowerActionCmd('STATUS')
+ self.fail("Exception was expected, oobm is disabled at cluster
level")
+ except Exception: pass
+
+ # Check background thread syncs state to Disabled
+ response = self.getHost(hostId=host.id).outofbandmanagement
+ self.assertEqual(response.powerstate, 'Disabled')
+ self.dbclient.execute("update oobm set power_state='On' where
port=%d" % self.getIpmiServerPort())
+ interval = list_configurations(
+ self.apiclient,
+ name='outofbandmanagement.sync.interval'
+ )[0].value
+ self.checkSyncToState('Disabled', interval)
+
+ # Enable at cluster level
+ cmd =
enableOutOfBandManagementForCluster.enableOutOfBandManagementForClusterCmd()
+ cmd.clusterid = host.clusterid
+ response = self.apiclient.enableOutOfBandManagementForCluster(cmd)
+
+ try:
+ self.issuePowerActionCmd('STATUS')
+ self.fail("Exception was expected, oobm is disabled at host
level")
+ except Exception: pass
+
+ # Enable at host level
+ cmd =
enableOutOfBandManagementForHost.enableOutOfBandManagementForHostCmd()
+ cmd.hostid = host.id
+ response = self.apiclient.enableOutOfBandManagementForHost(cmd)
+
+ response = self.issuePowerActionCmd('STATUS')
+ self.assertEqual(response.powerstate, 'Off')
+
+
+ @attr(tags=["smoke", "advanced"])
+ def test_oobm_issue_power_status(self):
+ """
+ Tests out-of-band management issue power action
+ """
+ self.configureAndEnableOobm()
+ self.startIpmiServer()
+ bmc = IpmiServerContext().bmc
+ bmc.powerstate = 'on'
+ response = self.issuePowerActionCmd('STATUS')
+ self.assertEqual(response.powerstate, 'On')
+
+
+ @attr(tags=["smoke", "advanced"])
+ def test_oobm_issue_power_on(self):
+ """
+ Tests out-of-band management issue power on action
+ """
+ self.configureAndEnableOobm()
+ self.startIpmiServer()
+ self.issuePowerActionCmd('ON')
+ response = self.issuePowerActionCmd('STATUS')
+ self.assertEqual(response.powerstate, 'On')
+
+
+ @attr(tags=["smoke", "advanced"])
+ def test_oobm_issue_power_off(self):
+ """
+ Tests out-of-band management issue power off action
+ """
+ self.configureAndEnableOobm()
+ self.startIpmiServer()
+ self.issuePowerActionCmd('OFF')
+ response = self.issuePowerActionCmd('STATUS')
+ self.assertEqual(response.powerstate, 'Off')
+
+
+ @attr(tags=["smoke", "advanced"])
+ def test_oobm_issue_power_cycle(self):
+ """
+ Tests out-of-band management issue power cycle action
+ """
+ self.configureAndEnableOobm()
+ self.startIpmiServer()
+ self.issuePowerActionCmd('CYCLE')
+ response = self.issuePowerActionCmd('STATUS')
+ self.assertEqual(response.powerstate, 'On')
+
+
+ @attr(tags=["smoke", "advanced"])
+ def test_oobm_issue_power_reset(self):
+ """
+ Tests out-of-band management issue power reset action
+ """
+ self.configureAndEnableOobm()
+ self.startIpmiServer()
+ self.issuePowerActionCmd('RESET')
+ response = self.issuePowerActionCmd('STATUS')
+ self.assertEqual(response.powerstate, 'On')
+
+
+ @attr(tags=["smoke", "advanced"])
+ def test_oobm_issue_power_soft(self):
+ """
+ Tests out-of-band management issue power soft action
+ """
+ self.configureAndEnableOobm()
+ self.startIpmiServer()
+ self.issuePowerActionCmd('SOFT')
+ response = self.issuePowerActionCmd('STATUS')
+ self.assertEqual(response.powerstate, 'Off')
+
+
+ @attr(tags=["smoke", "advanced"])
+ def test_oobm_background_powerstate_sync(self):
+ """
+ Tests out-of-band management background powerstate sync
+ """
+ self.debug("Testing oobm background sync")
+ interval = list_configurations(
+ self.apiclient,
+ name='outofbandmanagement.sync.interval'
+ )[0].value
+
+ self.configureAndEnableOobm()
+ self.startIpmiServer()
+ bmc = IpmiServerContext().bmc
+
+ bmc.powerstate = 'on'
+ self.checkSyncToState('On', interval)
+
+ bmc.powerstate = 'off'
+ self.checkSyncToState('Off', interval)
+
+ self.server.shutdown()
+ self.server.server_close()
+
+ # Check for unknown state (ipmi server not reachable)
+ self.checkSyncToState('Unknown', interval)
+
+
+ @attr(tags=["smoke", "advanced"])
+ def test_oobm_multiple_mgmt_server_ownership(self):
+ """
+ Tests out-of-band management ownership expiry across
multi-mgmt server
+ """
+ self.configureAndEnableOobm()
+
+ cloudstackVersion =
Configurations.listCapabilities(self.apiclient).cloudstackversion
+
+ currentMsHosts = []
+ mshosts = self.dbclient.execute("select msid from mshost where
version='%s' and removed is NULL and state='Up'" % (cloudstackVersion))
+ if len(mshosts) > 0:
+ currentMsHosts = map(lambda row: row[0], mshosts)
+
+ # Inject fake ms host
+ self.dbclient.execute("insert into mshost
(msid,runid,name,state,version,service_ip,service_port,last_update) values
(%s,%s,'oobm-marvin-fakebox', 'Down', '%s', '127.0.0.1', '22', NOW())" %
(self.getFakeMsId(), self.getFakeMsRunId(), cloudstackVersion))
+
+ # Pass ownership to the fake ms id
+ self.dbclient.execute("update oobm set mgmt_server_id=%d where
port=%d" % (self.getFakeMsId(), self.getIpmiServerPort()))
+
+ self.debug("Testing oobm background sync")
+ pingInterval = float(list_configurations(
+ self.apiclient,
+ name='ping.interval'
+ )[0].value)
+
+ pingTimeout = float(list_configurations(
+ self.apiclient,
+ name='ping.timeout'
+ )[0].value)
+
+ # Sleep until the ownership gets expired as the fake ms id is not
reachable
+ for _ in range(10):
+ rows = self.dbclient.execute("select * from mshost_peer where
peer_runid=%s" % self.getFakeMsRunId())
+ if len(rows) > 0:
+ self.debug("Mgmt server is now trying to contact the fake
mgmt server")
+ self.dbclient.execute("update mshost set removed=now()
where runid=%s" % self.getFakeMsRunId())
+ self.dbclient.execute("update mshost_peer set
peer_state='Down' where peer_runid=%s" % self.getFakeMsRunId())
+ break
+ time.sleep(1 + (pingInterval * pingTimeout / 10))
+
+ for _ in range(100):
+ rows = self.dbclient.execute("select mgmt_server_id from oobm
where port=%d" % (self.getIpmiServerPort()))
+ if len(rows) > 0 and rows[0][0] != self.getFakeMsId():
+ self.debug("Out-of-band management ownership expired as
node was detected to be gone")
+ break
+ time.sleep(1 + (pingInterval * pingTimeout / 10))
--- End diff --
Consider using the ``wait_until`` function to collapse both of these wait
loops.
> Out-of-band Management for CloudStack
> -------------------------------------
>
> Key: CLOUDSTACK-9299
> URL: https://issues.apache.org/jira/browse/CLOUDSTACK-9299
> Project: CloudStack
> Issue Type: New Feature
> Security Level: Public(Anyone can view this level - this is the
> default.)
> Reporter: Rohit Yadav
> Assignee: Rohit Yadav
> Fix For: 4.9.0, Future
>
>
> Support access to a host’s out-of-band management interface (e.g. IPMI, iLO,
> DRAC, etc.) to manage host power operations (on/off etc.) and querying
> current power state.
> FS:
> https://cwiki.apache.org/confluence/display/CLOUDSTACK/Out-of-band+Management+for+CloudStack
--
This message was sent by Atlassian JIRA
(v6.3.4#6332)