def send_rpc(self, cmd_name, arg, expected_rpc_error_codes=()): """ Send RPC 'cmd_name' via RpcClient. Returns the deserialized protobuf response from the server. If 'expected_rpc_error_codes' is not empty, then we expect the RPC to fail with the given RPC error codes. """ arg_data = arg.SerializeToString() rpc_client = AgentRpcClient("127.0.0.1") ret, err = rpc_client.send_rpc(cmd_name, arg) if expected_rpc_error_codes: if err is None: self.fail("RPC '%s' should have failed with error codes '%s'" % ( cmd_name, ", ".join(map(str, expected_rpc_error_codes)))) actual_rpc_error_codes = err.error_codes actual_rpc_error_codes_set = set(actual_rpc_error_codes) expected_rpc_error_codes_set = set(expected_rpc_error_codes) self.assertEqual(actual_rpc_error_codes_set, expected_rpc_error_codes_set) else: self.assert_(ret is not None) return ret
def check_cmd(self, cmd_id, desired_state=CmdStatus.kSucceeded): """Check if a command has reached a desired state. Args: cmd_id (str): ID of the command to check. desired_state (CmdStatus): Desired command state. Returns: CmdStatus protobuf on success, and None if the command is in progress. Raises: CurieTestException if the command has reached a terminal state that is different from the desired state. """ rpc_client = AgentRpcClient(self._vm_ip) arg = charon_agent_interface_pb2.CmdStatusArg() arg.cmd_id = cmd_id ret, err = rpc_client.CmdStatus(arg) if ret.cmd_status.state == desired_state: # Command has reached the desired state. The desired state could be a # non-terminal state or a terminal state. cmd_status = ret.cmd_status CHECK(cmd_status) return cmd_status elif ret.cmd_status.state != CmdStatus.kRunning: # Command has reached a terminal state. If we're here, this implies # that the command's terminal state is not the desired state because # if it was, then we would have already returned above. CHECK_NE(ret.cmd_status.state, desired_state) error_msg = ("Command %s terminal state %s != desired state %s" % (cmd_id, CmdStatus.Type.Name(ret.cmd_status.state), CmdStatus.Type.Name(desired_state))) raise CurieTestException(error_msg) return None
def _test_body(self, user, hostname_stdout): # Test CmdExecute. arg = charon_agent_interface_pb2.CmdExecuteArg() arg.user = user arg.cmd_id = str(int(time.time() * 1e6)) arg.cmd = "hostname" self.send_rpc("CmdExecute", arg) self.send_rpc("CmdExecute", arg) # Idempotent so this shouldn't fail. # Test CmdStatus while waiting for the command to finish and CmdStop. ret = self.wait_for_cmd(arg.cmd_id, include_output=True) self.cmd_stop(arg.cmd_id) self.cmd_stop(arg.cmd_id) # Idempotent so this shouldn't fail. self.assert_(ret.cmd_status.HasField("exit_status")) self.assertEqual(ret.cmd_status.exit_status, 0) self.assert_(ret.HasField("stdout")) self.assert_(ret.HasField("stderr")) self.assertEqual(ret.stdout, hostname_stdout) self.assertEqual(ret.stderr, "") # Test CmdList. ret = self.cmd_list() self.assertEqual(len(ret.cmd_summary_list), 1) self.assertEqual(ret.cmd_summary_list[0].cmd_id, arg.cmd_id) self.assertEqual(ret.cmd_summary_list[0].cmd, "hostname") self.assertEqual(ret.cmd_summary_list[0].state, CmdStatus.kSucceeded) # Test CmdRemove. self.cmd_remove(arg.cmd_id) ret = self.cmd_list() self.assertEqual(len(ret.cmd_summary_list), 0) self.cmd_remove(arg.cmd_id) # Idempotent so this shouldn't fail. ret = self.cmd_list() self.assertEqual(len(ret.cmd_summary_list), 0) # Test method for simulating synchronous commands. rpc_client = AgentRpcClient("127.0.0.1") arg = charon_agent_interface_pb2.CmdExecuteArg() arg.user = user arg.cmd_id = str(int(time.time() * 1e6)) arg.cmd = "hostname" exit_status, stdout, stderr = \ rpc_client.cmd_execute_sync(arg, 10, include_output=True) self.assertEqual(exit_status, 0) self.assertEqual(stdout, hostname_stdout) self.assertEqual(stderr, "") ret = self.cmd_list() self.assertEqual(len(ret.cmd_summary_list), 0) # Should be removed. arg = charon_agent_interface_pb2.CmdExecuteArg() arg.user = user arg.cmd_id = str(int(time.time() * 1e6)) arg.cmd = "hostname" exit_status, stdout, stderr = \ rpc_client.cmd_execute_sync(arg, 10, include_output=False) self.assertEqual(exit_status, 0) self.assert_(stdout is None) self.assert_(stderr is None) ret = self.cmd_list() self.assertEqual(len(ret.cmd_summary_list), 0) # Should be removed.
def execute_async(self, cmd_id, cmd, user="******"): "See Vm.execute_async documentation." rpc_client = AgentRpcClient(self._vm_ip) arg = charon_agent_interface_pb2.CmdExecuteArg() arg.user = user arg.cmd_id = cmd_id arg.cmd = cmd log.debug("%s executing async command: %s", self, cmd) ret, err = rpc_client.CmdExecute(arg) if err is not None: raise CurieException( err.error_codes[0], "Command %s (%s) failed, err %s" % (cmd, cmd_id, err))
def stop_cmd(self, cmd_id): """Stop a command running on this VM. The command specified by cmd_id must already be running. Args: cmd_id: (str) ID of the command to stop. Raises: CurieException: If stopping the command fails. """ rpc_client = AgentRpcClient(self._vm_ip) arg = charon_agent_interface_pb2.CmdStopArg() arg.cmd_id = cmd_id log.debug("Stopping command with id: %s", cmd_id) ret, err = rpc_client.CmdStop(arg) if err is not None: raise CurieException( CurieError.kInternalError, "Stopping command with id '%s' failed: %s" % (cmd_id, err))
def execute_sync(self, cmd_id, cmd, timeout_secs, user="******", include_output=False): "See Vm.execute_sync documentation." rpc_client = AgentRpcClient(self._vm_ip) arg = charon_agent_interface_pb2.CmdExecuteArg() arg.user = user arg.cmd_id = cmd_id arg.cmd = cmd log.debug("%s executing synchronous command: %s", self, cmd) exit_status, stdout, stderr = \ rpc_client.cmd_execute_sync(arg, timeout_secs, include_output=include_output) if exit_status != 0: raise CurieException( CurieError.kInternalError, "Command %s (%s) failed, exit_status %d, %s, %s" % (cmd, cmd_id, exit_status, stdout, stderr)) return (exit_status, stdout, stderr)
def transfer_from(self, remote_path, local_path, timeout_secs, recursive=False): """See Vm.transfer_from documentation. """ if not recursive: # If we're fetching a single file, use a FileGet RPC which is much faster # than forking and running scp. rpc_client = AgentRpcClient(self._vm_ip) arg = charon_agent_interface_pb2.FileGetArg() arg.path = remote_path try: ret, err = rpc_client.FileGet(arg) except CurieException as ex: log.debug("Caught CurieException during FileGet") ret, err = None, ex.error_msg if err is not None: log.exception("Error fetching file %s from %s", remote_path, self._vm_ip) result = False else: open(local_path, "w").write(ret.data) result = True else: result = self._scp_client.transfer_from(remote_path, local_path, timeout_secs, recursive=recursive) if result: log.debug("Transferred %s from %s:%s", local_path, self, remote_path) else: log.error("Failed to transfer %s from %s:%s", local_path, self, remote_path) return result