def load(self) -> None: """ Attempts to load the file from disk. If the file doesn't exist, it will create an empty JSON structure in memory. Raises: InvalidInputError: Raised when the file cannot be loaded from disk or its content cannot be parsed as a valid JSON. """ if self._file_exists(): if self._cb_retrieve_key is None: # Try to load the file as an unencrypted JSON file. try: with open(self._path, 'r+') as json_file: # Parse the file and load the content to memory. self._content = json.load(json_file) except OSError: self._content = None raise InvalidInputError( 'Failed to read the contents of JSON file {}.'.format( self._path)) except json.JSONDecodeError: self._content = None raise InvalidInputError( 'Failed to parse the content of JSON file {}.'.format( self._path)) else: # Try to load and decrypt the file raw_content = None try: with open(self._path, 'rb') as raw_file: raw_content = raw_file.read() except OSError: raise InvalidInputError( 'Failed to read the file from disk: {}.'.format( self._path)) if raw_content is not None: # Try to load as a regular JSON file try: cipher = AESCipher(self._cb_retrieve_key()) self._content = json.loads(cipher.decrypt(raw_content)) except json.JSONDecodeError: raise InvalidInputError( 'Failed to parse the content of JSON file {}. ' 'Either the decryption key was wrong or the file ' 'is not a valid JSON file.'.format(self._path)) else: # Just create an empty structure. self._content = {}
def __init__(self, counter_name: str, counter_type: PmCounterTypes, owner: ManagedObject, initial_value: int = 0, maximum_value: int = None) -> None: """ Creates a new PmCounter instance. Args: counter_name: Name of the PM counter. counter_type: Type of the PM counter. owner: The managed object that owns the counter. initial_value: The initial value of the PM counter. maximum_value: The maximum value of the PM counter. Raises: InvalidInputError: Raised when trying to create a PERCENTAGE type PM counter without setting a maximum value. """ self._name = counter_name self._type = counter_type self._owner = owner self._value = initial_value self._initial_value = initial_value if self._type == PmCounterTypes.PERCENTAGE and maximum_value is None: raise InvalidInputError( 'Trying to create a PERCENTAGE type PM counter without ' 'setting a maximum value. Counter: {}({}).{}'.format( self._owner.Name, self._owner.UUID, self.Name)) self._max_value = maximum_value
def _load_release_level(self, version_data: dict) -> None: """ Loads the release level from the configuration. """ try: release_level = version_data['release'].lower() if release_level == 'internal': self._release_level = ProductVersion.ReleaseLevels.INTERNAL elif release_level == 'alpha': self._release_level = ProductVersion.ReleaseLevels.ALPHA elif release_level == 'beta': self._release_level = ProductVersion.ReleaseLevels.BETA elif release_level == 'eap': self._release_level = ProductVersion.ReleaseLevels.EAP elif release_level == 'rc': self._release_level = ProductVersion.ReleaseLevels.RC elif release_level == 'ga': self._release_level = ProductVersion.ReleaseLevels.GA else: raise InvalidInputError( 'Unknown release level is configured: {}'.format( release_level)) except KeyError: self._release_level = ProductVersion.ReleaseLevels.GA
def _load_components(self, components: dict) -> None: """ Parses the component configuration from the passed in JSON structure. Args: components: The component configuration in JSON format. Raises: InvalidInputError: Raised when there is no component ID in the configuration of the component. """ from suisei.murasame.exceptions import InvalidInputError for component in components: try: component_id = component['id'] except KeyError: raise InvalidInputError( 'Component ID was not found in the configuration.') if component_id in self._components: continue self._components[component_id] = ComponentConfiguration(component)
def _parse_configuration(self, configuration: dict) -> None: """ Parses the configuration from the passed in JSON representation. Args: coniguration: The configuration as a JSON object. Raises: InvalidInputError: Raised when a required element is not found in the configuration. """ from suisei.murasame.exceptions import InvalidInputError self._id = configuration['id'] try: self._ut_out_dir = os.path.abspath( configuration['unittest']['outdir']) self._ut_log_format = configuration['unittest']['logformat'] self._ut_path = os.path.abspath( configuration['unittest']['testdir']) except KeyError: raise InvalidInputError( 'Unittest configuration was not found in the configuration.') try: self._ut_verbosity = int(configuration['unittest']['verbosity']) except KeyError: # Default to verbosity level 1 if the configuration is not present # in the configuration file. self._ut_verbosity = 1
def _load_patch_level(self, version_data: dict) -> None: """ Loads the patch level from the configuration. """ try: patch = int(version_data['patch']) if patch < 0: raise InvalidInputError( 'Invalid product version. Patch level cannot be a ' 'negative number.') self._patch = patch except KeyError: raise InvalidInputError( 'Invalid product version. Patch level not found.') except ValueError: raise InvalidInputError( 'Invalid product version. Patch level is not integer.')
def _load_minor_version(self, version_data: dict) -> None: """ Loads the minor product version from the configuration. """ try: minor = int(version_data['minor']) if minor < 0: raise InvalidInputError( 'Invalid product version. Minor version cannot be a ' 'negative number.') self._minor = minor except KeyError: raise InvalidInputError( 'Invalid product version. Minor version not found.') except ValueError: raise InvalidInputError( 'Invalid product version. Minor version is not integer.')
def __init__(self, name: str, logic: Callable, task_type: int = TaskTypes.NORMAL, priority: int = TaskPriorities.NORMAL, data: Any = None, frequency: int = 1000) -> None: """ Creates a new Task instance. Args: name: Name of the task. logic: A callback function to the business logic that will be executed by the task when it's scheduled. task_type: Type of the task. priority: The task execution priority. data: Custom data to be passed to the execution logic of the task. frequency: The repetition frequency of the task in milliseconds. Only valid for RECURRING type tasks. Raises: InvalidInputError: Raised when the task type is invalid. InvalidInputError: Raised when the task priority is invalid. """ if task_type not in [TaskTypes.NORMAL, TaskTypes.RECURRING]: raise InvalidInputError('Trying to configure an invalid ' 'task type: {}'.format(task_type)) if priority not in [ TaskPriorities.HIGH, TaskPriorities.NORMAL, TaskPriorities.IO ]: raise InvalidInputError('Trying to configure an invalid ' 'task priority: {}'.format(priority)) self._name = name self._type = task_type self._priority = priority self._logic = logic self._data = data self._frequency = frequency self._expected_execution = None
def decrypt(self, content: bytes) -> str: """ Decrypts the content using AES. Args: encoded_contet: The encrypted content encoded in a base64 format. Raises: InvalidInputError: Raised if the input file is not properly encoded. Returns: The decrypted content. """ import binascii from suisei.murasame.exceptions import InvalidInputError # Base64 decode the input data try: content = base64.b64decode(content) except binascii.Error: raise InvalidInputError('The input file is not properly encoded.') # Retrieve the initialization vector initialization_vector = content[:16] # Remove the initialization vector from the content content = content[16:] # Decrypt the data cipher = self._create_cipher(initialization_vector) decryptor = cipher.decryptor() content = decryptor.update(content) + decryptor.finalize() # Unpad the data unpadder = padding.PKCS7(128).unpadder() content = unpadder.update(content) content += unpadder.finalize() # Decode the content content = content.decode('utf-8') return content
def __init__(self, name: str, parent: 'ManagedObject', access_mode: MOAttributeAccessModes, data_type: MOAttributeDataTypes, initial_value: object, default_value: object = None, min_value: object = None, max_value: object = None) -> None: """ Creates a new MOAttribute instance. Args: name: Name of the MO attribute. parent: The managed object this attribute belongs to. access_mode: The access mode of the MO attribute. data_type: The data type of the MO attribute. initial_value: The initial value of the MO attribute. default_value: The default value of the MO attribute. min_value: The minimum value of the MO attribute. max_value: The maximum value of the MO attribute. Raises: InvalidInputError: Raised when trying to create an attribute without specifying a parent MO. """ self._name = name if parent is None: raise InvalidInputError('No parent MO specified when creating MO ' 'attribute {}'.format(name)) self._parent = parent self._access_mode = access_mode self._data_type = data_type self._initial_value = initial_value self._value = initial_value self._default_value = default_value self._min_value = min_value self._max_value = max_value self._changelog = []
def schedule(self, task: Task) -> None: """ Adds the task to the execution queue to be scheduled. Args: task: The task to be scheduled. """ if task is None or not isinstance(task, Task): return if task.Priority == TaskPriorities.HIGH: self._high_prio_tasks.put(task) elif task.Priority == TaskPriorities.NORMAL: self._normal_prio_tasks.put(task) elif task.Priority == TaskPriorities.IO: self._io_tasks.put(task) else: raise InvalidInputError( 'TaskExecutor.schedule() was called with an unsupported ' 'task priority {}'.format(task.Priority))