perfkitbenchmarker/command_interface.py (66 lines of code) (raw):

# Copyright 2017 PerfKitBenchmarker Authors. All rights reserved. # # Licensed 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. """OS Mixin class, which defines abstract properties of an OS. "Mixin" because most real implementations will inherit from a child of both BaseOSMixin & BaseVirtualMachine. eg CentOs7BasedAzureVirtualMachine inherits from AzureVirtualMachine which inherits from BaseVirtualMachine & CentOs7Mixin which inherits from BaseOSMixin. Implementation & details are somewhat confusingly coupled with BaseVirtualMachine. """ import abc from typing import Tuple from absl import flags from perfkitbenchmarker import data from perfkitbenchmarker import errors from perfkitbenchmarker import vm_util FLAGS = flags.FLAGS class CommandInterface(metaclass=abc.ABCMeta): """A base class for running simple commands. Only supports a very limited set of functions (commands & file IO) which could be run on either the Runner VM or a Client VM. """ def RunCommand( self, command: str | list[str], ignore_failure: bool = False, should_pre_log: bool = True, stack_level: int = 1, timeout: float | None = None, **kwargs, ) -> Tuple[str, str, int]: """Runs a command. Additional args can be supplied & are passed to lower level functions but aren't required. Args: command: A valid bash command in string or list form. ignore_failure: Ignore any failure if set to true. should_pre_log: Whether to print the command being run or not. stack_level: Number of stack frames to skip & get an "interesting" caller, for logging. 1 skips this function, 2 skips this & its caller, etc.. timeout: The time to wait in seconds for the command before exiting. None means no timeout. **kwargs: Additional command arguments. Returns: A tuple of stdout and stderr from running the command. Raises: RemoteCommandError: If there was a problem issuing the command. """ raise NotImplementedError() def WriteTemporaryFile(self, file_contents: str) -> str: """Writes a temporary file to the VM. Args: file_contents: The contents of the file. Returns: The full filename. """ raise NotImplementedError() def PrepareResourcePath( self, resource_name: str, search_user_paths: bool = True ) -> str: """Prepares a resource from local loaders & returns path on machine. Loaders are searched in order until the resource is found. If no loader provides 'resource_name', an exception is thrown. If 'search_user_paths' is true, the directories specified by "--data_search_paths" are consulted before the default paths. Args: resource_name: string. Name of a resource. search_user_paths: boolean. Whether paths from "--data_search_paths" should be searched before the default paths. Returns: A path to the resource on the local or remote machine's filesystem. Raises: ResourceNotFound: When resource was not found. """ raise NotImplementedError() class VmUtilCommandInterface(CommandInterface): """Implemenation for CommandInterface that wraps vm_util commands.""" def RunCommand( self, command: str | list[str], ignore_failure: bool = False, should_pre_log: bool = True, stack_level: int = 1, timeout: float | None = None, **kwargs, ) -> Tuple[str, str, int]: """Runs a command. Additional args can be supplied & are passed to lower level functions but aren't required. Args: command: A valid bash command in string or list form. ignore_failure: Ignore any failure if set to true. should_pre_log: Whether to print the command being run or not. stack_level: Number of stack frames to skip & get an "interesting" caller, for logging. 1 skips this function, 2 skips this & its caller, etc.. timeout: The time to wait in seconds for the command before exiting. None means no timeout. **kwargs: Additional command arguments. Returns: A tuple of stdout, stderr, & return code from running the command. Raises: RemoteCommandError: If there was a problem issuing the command. """ if isinstance(command, str): cmd_list = command.split(' ') else: cmd_list = command stack_level += 1 if 'raise_on_failure' in kwargs: raise_on_failure = kwargs['raise_on_failure'] del kwargs['raise_on_failure'] else: raise_on_failure = not ignore_failure try: return vm_util.IssueCommand( cmd=cmd_list, timeout=timeout, should_pre_log=should_pre_log, stack_level=stack_level, raise_on_failure=raise_on_failure, **kwargs, ) except errors.VmUtil.IssueCommandError as ex: raise errors.VirtualMachine.RemoteCommandError(str(ex)) from ex except errors.VmUtil.IssueCommandTimeoutError as ex: raise errors.VirtualMachine.RemoteCommandError(str(ex)) from ex def WriteTemporaryFile(self, file_contents: str) -> str: """Writes a temporary file to the VM. Args: file_contents: The contents of the file. Returns: The full filename. """ with vm_util.NamedTemporaryFile(mode='w', delete=False) as tf: tf.write(file_contents) tf.close() return tf.name def PrepareResourcePath( self, resource_name: str, search_user_paths: bool = True ) -> str: """Prepares a resource from local loaders & returns path on machine. Loaders are searched in order until the resource is found. If no loader provides 'resource_name', an exception is thrown. If 'search_user_paths' is true, the directories specified by "--data_search_paths" are consulted before the default paths. Args: resource_name: string. Name of a resource. search_user_paths: boolean. Whether paths from "--data_search_paths" should be searched before the default paths. Returns: A path to the resource on the local or remote machine's filesystem. Raises: ResourceNotFound: When resource was not found. """ return data.ResourcePath(resource_name, search_user_paths)