def get(self, command, context, params=None): """Dispatch a GET request to a Microsoft OCS chassis.""" if params is None: params = [] else: params = [param for param in params if bool(param)] url_base = "http://{power_address}:{power_port}/".format(**context) url = urllib.parse.urljoin(url_base, command) + "?" + "&".join(params) authinfo = urllib.request.HTTPPasswordMgrWithDefaultRealm() authinfo.add_password(None, url, context["power_user"], context["power_pass"]) proxy_handler = urllib.request.ProxyHandler({}) auth_handler = urllib.request.HTTPBasicAuthHandler(authinfo) opener = urllib.request.build_opener(proxy_handler, auth_handler) urllib.request.install_opener(opener) try: response = urllib.request.urlopen(url) except urllib.error.HTTPError as e: raise PowerConnError( "Could not make proper connection to Microsoft OCS Chassis." " HTTP error code: %s" % e.code) except urllib.error.URLError as e: raise PowerConnError( "Could not make proper connection to Microsoft OCS Chassis." " Server could not be reached: %s" % e.reason) else: return response.read()
def post(self, command, urlparams=[], params={}): """Dispatch a POST request to a RECS_Master.""" url = self.build_url(command, urlparams) authinfo = urllib.request.HTTPPasswordMgrWithDefaultRealm() authinfo.add_password(None, url, self.username, self.password) proxy_handler = urllib.request.ProxyHandler({}) auth_handler = urllib.request.HTTPBasicAuthHandler(authinfo) opener = urllib.request.build_opener(proxy_handler, auth_handler) urllib.request.install_opener(opener) data = urllib.parse.urlencode(params).encode() req = urllib.request.Request(url, data, method="POST") try: response = urllib.request.urlopen(req) except urllib.error.HTTPError as e: raise PowerConnError( "Could not make proper connection to RECS|Box." " HTTP error code: %s" % e.code ) except urllib.error.URLError as e: raise PowerConnError( "Could not make proper connection to RECS|Box." " Server could not be reached: %s" % e.reason ) else: return response.read()
class TestGetErrorMessage(MAASTestCase): scenarios = [ ('auth', dict( exception=PowerAuthError('auth'), message="Could not authenticate to node's BMC: auth", )), ('conn', dict( exception=PowerConnError('conn'), message="Could not contact node's BMC: conn", )), ('setting', dict( exception=PowerSettingError('setting'), message="Missing or invalid power setting: setting", )), ('tool', dict( exception=PowerToolError('tool'), message="Missing power tool: tool", )), ('action', dict( exception=PowerActionError('action'), message="Failed to complete power action: action", )), ('unknown', dict( exception=PowerError('unknown error'), message="Failed talking to node's BMC: unknown error", )), ] def test_return_msg(self): self.assertEqual(self.message, get_error_message(self.exception))
def _get_amt_command(self, ip_address, power_pass): """Retrieve AMT command to use, either amttool or wsman (if AMT version > 8), for the given system. """ # XXX bug=1331214 # Check if the AMT ver > 8 # If so, we need wsman, not amttool env = self._get_amt_environment(power_pass) process = Popen( ('amttool', ip_address, 'info'), stdout=PIPE, stderr=PIPE, env=env) stdout, stderr = process.communicate() stdout = stdout.decode("utf-8") stderr = stderr.decode("utf-8") if stdout == "" or stdout.isspace(): for error, error_info in AMT_ERRORS.items(): if error in stderr: raise error_info.get( 'exception')(error_info.get('message')) raise PowerConnError( "Unable to retrieve AMT version: %s" % stderr) else: match = re.search("AMT version:\s*([0-9]+)", stdout) if match is None: raise PowerActionError( "Unable to extract AMT version from " "amttool output: %s" % stdout) else: version = match.group(1) if int(version) > 8: return 'wsman' else: return 'amttool'
def run_wedge_command( self, command, power_address=None, power_user=None, power_pass=None, **extra ): """Run a single command and return unparsed text from stdout.""" try: ssh_client = SSHClient() ssh_client.set_missing_host_key_policy(AutoAddPolicy()) ssh_client.connect( power_address, username=power_user, password=power_pass ) _, stdout, _ = ssh_client.exec_command(command) output = stdout.read().decode("utf-8").strip() except (SSHException, EOFError, SOCKETError) as e: raise PowerConnError( "Could not make SSH connection to Wedge for " "%s on %s - %s" % (power_user, power_address, e) ) finally: ssh_client.close() return output
def test_power_off_crashes_for_connection_error(self): driver = MicrosoftOCSPowerDriver() context = make_context() system_id = factory.make_name("system_id") mock_get = self.patch(driver, "get") mock_get.side_effect = PowerConnError("Connection Error") self.assertRaises(PowerActionError, driver.power_off, system_id, context)
def test_power_query_crashes_for_connection_error(self): driver = MSCMPowerDriver() system_id = factory.make_name("system_id") context = make_context() run_mscm_command = self.patch(driver, "run_mscm_command") run_mscm_command.side_effect = PowerConnError("Connection Error") self.assertRaises(PowerActionError, driver.power_query, system_id, context)
def test_power_off_crashes_for_connection_error(self): driver = WedgePowerDriver() system_id = factory.make_name('system_id') context = make_context() run_wedge_command = self.patch(driver, "run_wedge_command") run_wedge_command.side_effect = PowerConnError("Connection Error") self.assertRaises( PowerActionError, driver.power_off, system_id, context)
def test_power_on_crashes_for_connection_error(self): driver = MicrosoftOCSPowerDriver() context = make_context() system_id = factory.make_name("system_id") self.patch(driver, "power_query", Mock(return_value="off")) self.patch(driver, "set_next_boot_device") mock_get = self.patch(driver, "get") mock_get.side_effect = PowerConnError("Connection Error") self.assertRaises(PowerActionError, driver.power_on, system_id, context)
def test_power_on_crashes_for_connection_error(self): driver = HMCPowerDriver() system_id = factory.make_name("system_id") context = make_context() power_query = self.patch(driver, "power_query") power_query.return_value = "off" run_hmc_command = self.patch(driver, "run_hmc_command") run_hmc_command.side_effect = PowerConnError("Connection Error") self.assertRaises(PowerActionError, driver.power_on, system_id, context)
def test_power_query_crashes_for_connection_error(self): driver = MicrosoftOCSPowerDriver() context = make_context() system_id = factory.make_name("system_id") mock_extract_from_response = self.patch(driver, "extract_from_response") mock_extract_from_response.side_effect = PowerConnError( "Connection Error") self.patch(driver, "get") self.assertRaises(PowerActionError, driver.power_query, system_id, context)
def test_power_on_crashes_for_connection_error(self): driver = MSCMPowerDriver() system_id = factory.make_name('system_id') context = make_context() power_query = self.patch(driver, "power_query") power_query.return_value = 'off' self.patch(driver, "configure_node_bootonce_pxe") run_mscm_command = self.patch(driver, "run_mscm_command") run_mscm_command.side_effect = PowerConnError("Connection Error") self.assertRaises(PowerActionError, driver.power_on, system_id, context)
def _get_amt_command(self, ip_address, power_pass): """Retrieve AMT command to use, either amttool or wsman (if AMT version > 8), for the given system. """ # XXX bug=1331214 # Check if the AMT ver > 8 # If so, we need wsman, not amttool env = self._get_amt_environment(power_pass) process = Popen( ( "wsman", "identify", "--port", "16992", "--hostname", ip_address, "--username", "admin", "--password", power_pass, ), stdout=PIPE, stderr=PIPE, env=env, ) stdout, stderr = process.communicate() stdout = stdout.decode("utf-8") stderr = stderr.decode("utf-8") if stdout == "" or stdout.isspace(): for error, error_info in AMT_ERRORS.items(): if error in stderr: raise error_info.get("exception")( error_info.get("message")) raise PowerConnError("Unable to retrieve AMT version: %s" % stderr) else: match = re.search(r"ProductVersion>AMT\s*([0-9]+)", stdout) if match is None: raise PowerActionError("Unable to extract AMT version from " "amttool output: %s" % stdout) else: version = match.group(1) if int(version) > 8: return "wsman" else: return "amttool"
def _get_amt_command(self, ip_address, power_pass): """Retrieve AMT command to use, either amttool or wsman (if AMT version > 8), for the given system. """ # XXX bug=1331214 # Check if the AMT ver > 8 # If so, we need wsman, not amttool result = shell.run_command( "wsman", "identify", "--port", "16992", "--hostname", ip_address, "--username", "admin", "--password", power_pass, ) if not result.stdout: for error, error_info in AMT_ERRORS.items(): if error in result.stderr: raise error_info.get("exception")( error_info.get("message")) raise PowerConnError( f"Unable to retrieve AMT version: {result.stderr}") else: match = re.search(r"ProductVersion>AMT\s*([0-9]+)", result.stdout) if match is None: raise PowerActionError("Unable to extract AMT version from " f"amttool output: {result.stdout}") else: version = match.group(1) if int(version) > 8: return "wsman" else: return "amttool"