def _execute_command( self, reservation_id: ReservationId, target_name: str, target_type: str, # Service or Resource command_name: str, command_kwargs: dict[str, str], ) -> str: """Execute a command on the target.""" logger.debug( f"Executing command {command_name} with kwargs {command_kwargs} for the " f"target {target_name} in the reservation {reservation_id}") command_kwargs = [ InputNameValue(key, value) for key, value in command_kwargs.items() ] try: resp = self._api.ExecuteCommand( reservation_id, target_name, target_type, command_name, command_kwargs, True, ) except CloudShellAPIError as e: if "The PyPi server process might be down or inaccessible" in str( e): raise DependenciesBrokenError() from e raise e logger.debug(f"Executed command, output {resp.Output}") return resp.Output
def remove_resource_from_reservation(self, reservation_id: ReservationId, resource_name: str): msg = f"Remove a resource {resource_name} from a reservation {reservation_id}" logger.info(msg) self._api.RemoveResourcesFromReservation(reservation_id, [resource_name]) logger.debug("Removed a resource from the reservation")
def get_tosca_standards_file_names(self) -> list[str]: names = [ standard.filename for standard in self._smb_handler.ls(self._CS_STANDARDS_PATH) ] logger.debug(f"Installed tosca standards: {names}") return names
def create_resource( self, name: str, model: str, address: str, family: str = "", parent_path: str = "", ) -> str: """Create resource, can be generated new name if current is exists.""" logger.info(f"Creating the resource {name}") logger.debug( f"{name=}, {model=}, {address=}, {family=}, {parent_path=}") while True: try: self._api.CreateResource(family, model, name, address, parentResourceFullPath=parent_path) except CloudShellAPIError as e: if str(e.code) != "114": raise name = generate_new_resource_name(name) else: break logger.debug(f"Created the resource {name}") return name
def get_test_runner() -> type[TextTestRunner]: if is_running_under_teamcity(): logger.debug("Using TeamCity Test Runner") test_runner = TeamcityTestRunner else: logger.debug("Using Text Test Runner") test_runner = TextTestRunner return test_runner
def add_resource_to_reservation(self, reservation_id: ReservationId, resource_name: str): """Adding the resource to the reservation.""" logger.info( f"Adding a resource {resource_name} to a reservation {reservation_id}" ) self._api.AddResourcesToReservation(reservation_id, [resource_name]) logger.debug("Added a resource to the reservation")
def get_reservation_details( self, reservation_id: ReservationId ) -> GetReservationDescriptionResponseInfo: """Get reservation details.""" logger.info(f"Getting reservation details for the {reservation_id}") output = self._api.GetReservationDetails(reservation_id) logger.debug(f"Got reservation details {output}") return output
def get_reservation_status( self, reservation_id: ReservationId) -> ReservationSlimStatus: """Check that the reservation ready.""" logger.debug(f"Getting reservation status for a {reservation_id}") output = self._api.GetReservationStatus( reservation_id).ReservationSlimStatus logger.debug(f"Got status {output}") return output
def run_custom_config_command(self, command: str) -> str: """Execute run custom config command on the resource.""" logger.info(f'Start a "run_custom_config_command" command {command}') output = self.execute_command( "run_custom_config_command", {"custom_command": command} ) logger.debug(f"Run custom config command output: {output}") return output
def get_file_names_from_offline_pypi(self) -> list[str]: logger.debug("Getting packages names from offline PyPI") excluded = (".", "..", "PlaceHolder.txt") names = [ f.filename for f in self._smb_handler.ls(self._CS_PYPI_PATH) if f.filename not in excluded ] logger.debug(f"Got packages names {names}") return names
def get_topologies_by_category(self, category_name: str) -> list[str]: """Get available topology names by category name.""" if category_name: logger.info(f"Getting topologies for a category {category_name}") else: logger.info("Getting topologies for all categories") output = self._api.GetTopologiesByCategory(category_name).Topologies logger.debug(f"Got topologies {sorted(output)}") return output
def orchestration_save(self, mode: str, custom_params: str = "") -> str: """Execute orchestration save command.""" logger.info('Start a "orchestration save" command') logger.debug(f"Mode: {mode}, custom params: {custom_params}") output = self.execute_command( "orchestration_save", {"mode": mode, "custom_params": custom_params} ) logger.debug(f"Orchestration save command output: {output}") return output
def prepare(self): logger.info(f"Start preparing the Shell {self.model}") try: self._store_extra_files() self.install_shell() except Exception as e: self.finish() raise e logger.debug("The Shell prepared")
def get_resource_model_from_shell_definition(shell_path: Path) -> str: """Get resource family and model from shell-definition.yaml.""" with zipfile.ZipFile(shell_path) as zip_file: data = yaml.safe_load(zip_file.read("shell-definition.yaml")) node_type = next(iter(data["node_types"])) model = node_type.rsplit(".", 1)[-1] logger.debug(f"Model: {model} for the Shell {shell_path}") return model
def _start_app_sandbox(self, app_name: str) -> SandboxHandler: topology_name = self._find_topology_name_for_app(app_name) logger.debug(f"Creating Networking App {topology_name}") conf = SandboxConfig( **{ "Name": f"Networking App {app_name}", "Resources": [], "Blueprint Name": topology_name, }) return SandboxHandler.create(conf, self._do_handler)
def _start_cs_sandbox(self) -> SandboxHandler: topology_name = self._find_topology_name_for_cloudshell() logger.debug(f"Creating CloudShell {topology_name}") conf = SandboxConfig( **{ "Name": topology_name, "Resources": [], "Blueprint Name": topology_name, "Specific Version": self._cs_on_do_conf.cs_specific_version, }) return SandboxHandler.create(conf, self._do_handler)
def create_dir(self, r_dir_path: str, parents: bool = True): try: logger.debug(f"Creating directory {r_dir_path}") self.session.createDirectory(self._share, r_dir_path) except OperationFailure as e: if parents and "Create failed" in str(e): r_parent_dir = self.get_dir_path(r_dir_path) self.create_dir(r_parent_dir, parents) self.session.createDirectory(self._share, r_dir_path) else: raise e
def resource_autoload(self, resource_name: str): """Start autoload for the resource.""" logger.info(f"Start Autoload for the {resource_name}") try: self._api.AutoLoad(resource_name) except CloudShellAPIError as e: if "The PyPi server process might be down or inaccessible" in str( e): raise DependenciesBrokenError() from e raise e logger.debug("Finished Autoload")
def save(self, path_to_save: str, configuration_type: str) -> str: """Execute save command on the resource.""" logger.info('Start a "save" command') logger.debug( f"Path to save: {path_to_save}, configuration type: {configuration_type}" ) output = self.execute_command( "save", {"folder_path": path_to_save, "configuration_type": configuration_type}, ) logger.debug(f"Save command output: {output}") return output
def rename_resource(self, current_name: str, new_name: str) -> str: """Rename resource, can be generated new name if current is exists.""" logger.info(f'Renaming resource "{current_name}" to "{new_name}"') while True: try: self._api.RenameResource(current_name, new_name) except CloudShellAPIError as e: if str(e.code) != "114": raise new_name = generate_new_resource_name(new_name) else: break logger.debug(f'Resource "{current_name}" renamed to "{new_name}"') return new_name
def install_shell(self, shell_path: Path): shell_name = shell_path.name shell_path = str(shell_path) logger.info(f"Installing the Shell {shell_name}") try: self._rest_api.add_shell(shell_path) logger.debug("Installed the new Shell") except Exception as e: err_msg = e.args[0] if e.args else "" if "already exists" not in err_msg: raise e shell_name = re.search("named '(?P<name>.+)' already exists", err_msg).group("name") self._rest_api.update_shell(shell_path, shell_name) logger.debug(f"Updated {shell_name} Shell")
def orchestration_restore( self, saved_artifact_info: str, custom_params: str = "" ) -> str: """Execute orchestration restore command.""" logger.info('Start a "orchestration restore" command') logger.debug( f"Saved artifact: {saved_artifact_info}, custom params: {custom_params}" ) output = self.execute_command( "orchestration_restore", { "saved_artifact_info": saved_artifact_info, "custom_params": custom_params, }, ) logger.debug(f"Orchestration restore command output: {output}") return output
def add_service_to_reservation( self, reservation_id: ReservationId, service_model: str, service_name: str, attributes: dict[str, str], ): """Add the service to the reservation.""" logger.info( f"Adding a service {service_name} to a reservation {reservation_id}" ) attributes = [ AttributeNameValue(f"{service_model}.{key}", value) for key, value in attributes.items() ] self._api.AddServiceToReservation(reservation_id, service_model, service_name, attributes) logger.debug("Added the service to the reservation")
def wait_reservation_is_started(self, reservation_id: ReservationId): for _ in range(60): status = self.get_reservation_status(reservation_id) if (status.ProvisioningStatus == "Ready" or status.ProvisioningStatus == "Not Run" and status.Status == "Started"): break elif status.ProvisioningStatus == "Error": errors = self._get_reservation_errors(reservation_id) logger.error( f"Reservation {reservation_id} started with errors: {errors}" ) raise CreationReservationError(errors) time.sleep(30) else: raise CreationReservationError( f"The reservation {reservation_id} doesn't started") logger.debug("The reservation created")
def session(self) -> SMBConnection: if self._session: try: self._session.echo(b"test connection") except Exception as e: logger.debug(f"Session error, type - {type(e)}") self._session = None if not self._session: logger.debug(f"Creating SMB session to {self._server_ip}") try: self._session = SMBConnection(self._username, self._password, self._client, self._server_name) self._session.connect(self._server_ip) except NotConnectedError: self._session = SMBConnection( self._username, self._password, self._client, self._server_name, is_direct_tcp=True, ) self._session.connect(self._server_ip, 445) logger.debug("SMB session created") return self._session
def restore(self, path: str, configuration_type: str, restore_method: str) -> str: """Execute restore command. :param path: path to the file :param configuration_type: startup or running :param restore_method: append or override """ logger.info('Start a "restore" command') logger.debug( f"Path: {path}, configuration_type: {configuration_type}, " f"restore_method: {restore_method}" ) output = self.execute_command( "restore", { "path": path, "configuration_type": configuration_type, "restore_method": restore_method, }, ) logger.debug(f"Restore command output: {output}") return output
def download_logs(self, path_to_save: Path, start_time: datetime, reservation_ids: set[str]): logger.info("Downloading CS logs") try: with suppress(FileNotFoundError): shutil.rmtree(path_to_save) path_to_save.mkdir() shell_logs_path = path_to_save / "shell_logs" installation_logs_path = path_to_save / "installation_logs" autoload_logs_path = shell_logs_path / "inventory" shell_logs_path.mkdir() installation_logs_path.mkdir() autoload_logs_path.mkdir() self._smb_handler.download_r_dir( self._CS_LOGS_INSTALLATION_DIR, installation_logs_path, FilterByLastWriteTime(start_time), ) self._smb_handler.download_r_dir( self._CS_LOGS_SHELL_DIR, shell_logs_path, FilterByFileNameInIterable(reservation_ids), ) self._smb_handler.download_r_dir( self._CS_LOGS_AUTOLOAD_DIR, autoload_logs_path, FilterByLastWriteTime(start_time), ) except Exception as e: if "path not found" in str(e).lower(): logger.info("Cannot find log dir") else: logger.warning(f"Cannot download logs, error: {e}") logger.debug("CS logs downloaded")
def remove_shell(self, shell_name: str): logger.info(f"Deleting the Shell {shell_name}") self._rest_api.delete_shell(shell_name) logger.debug(f"The Shell {shell_name} is deleted")
def _api(self) -> CloudShellAPISession: logger.debug("Connecting to Automation API") api = CloudShellAPISession(self.conf.host, self.conf.user, self.conf.password, self.conf.domain) logger.debug("Connected to Automation API") return api
def _rest_api(self) -> PackagingRestApiClient: logger.debug("Connecting to REST API") rest_api = PackagingRestApiClient(self.conf.host, 9000, self.conf.user, self.conf.password, self.conf.domain) logger.debug("Connected to REST API") return rest_api