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 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 update_driver_for_the_resource(self, resource_name: str, driver_name: str): """Update driver for the resource.""" logger.info( f'Update Driver "{driver_name}" for the Resource "{resource_name}"' ) self._api.UpdateResourceDriver(resource_name, driver_name)
def remove_connector(self, reservation_id: ReservationId, port1: str, port2: str): """Remove connector between ports.""" logger.info(f"Removing connector between {port1} and {port2}") self._api.DisconnectRoutesInReservation(reservation_id, [port1, port2]) self._api.RemoveConnectorsFromReservation(reservation_id, [port1, port2])
def create_topology_reservation( self, name: str, topology_name: str, duration: int = 24 * 60, specific_version: str = "", ) -> ReservationId: """Create topology reservation, return uuid.""" if specific_version: global_input_req = [ UpdateTopologyGlobalInputsRequest("Version", specific_version) ] else: global_input_req = [] str_specific_version = f" - {specific_version}" if specific_version else "" logger.info(f"Creating a topology reservation {name} for " f"{topology_name}{str_specific_version}") resp = self._api.CreateImmediateTopologyReservation( name, self._api.username, duration, topologyFullPath=topology_name, globalInputs=global_input_req, ) return resp.Reservation.Id
def _delete_file(self, file_path: str): logger.info(f"Deleting file {file_path}") try: self.session.delete(file_path) except ftplib.Error as e: if str(e).startswith("550 No such file"): raise FtpFileNotFoundError(file_path) raise e
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 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 add_python_driver(self): if not self._driver_added: logger.info("Add Python driver to the package") with ZipFile(self.zip_path, "a") as zf: zf.write( PYTHON_DRIVER_PATH, f"Topology Drivers/{PYTHON_DRIVER_PATH.name}" ) self._driver_added = True
def create_reservation(self, name: str, duration: int = 120) -> ReservationId: """Create reservation, returns uuid.""" logger.info(f"Creating the reservation {name}") resp = self._api.CreateImmediateReservation(name, self._api.username, duration) return resp.Reservation.Id
def path(self) -> Path: if not self._is_url(self.original_path): return Path(self.original_path) path = self.tmp_dir / get_file_name(self.original_path) logger.info(f"Downloading a file {path.name}") urlretrieve(self.original_path, path) self.downloaded_files.append(self) return path
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 finish(self): if self._conf.do_conf.cs_on_do_conf is not None: if self._conf.do_conf.cs_on_do_conf.delete_cs: self._cs_creator.finish() else: ip = self._conf.cs_conf.host msg = f"The CS is not deleted, you can still use it - http://{ip}" logger.info(msg) self._networking_apps_handler.finish()
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_resources_names_in_reservation( self, reservation_id: ReservationId) -> list[str]: """Get resources names in the reservation.""" logger.info(f"Get resources names in the reservation {reservation_id}") resources_info = self._api.GetReservationResourcesPositions( reservation_id).ResourceDiagramLayouts names = [resource.ResourceName for resource in resources_info] logger.info(f"Resources names are: {names}") return names
def connect_ports_with_connector(self, reservation_id: ReservationId, port1: str, port2: str, connector_name: str): """Connect two ports with connector.""" logger.info(f"Creating connector between {port1} and {port2}") connector = SetConnectorRequest(port1, port2, "bi", connector_name) self._api.SetConnectorsInReservation(reservation_id, [connector]) self._api.ConnectRoutesInReservation(reservation_id, [port1, port2], "bi")
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 add_physical_connection(self, reservation_id: ReservationId, port1: str, port2: str): """Add physical connection between two ports. :param reservation_id: :param port1: ex, Cisco-IOS-device/Chassis 0/FastEthernet0-1 :param port2: ex, Cisco-IOS-device-1/Chassis 0/FastEthernet0-10 """ logger.info(f"Create physical connection between {port1} and {port2}") self._api.UpdatePhysicalConnection(port1, port2)
def create_resource( cls, conf: DeploymentResourceConfig, sandbox_handler: "SandboxHandler" ) -> "DeploymentResourceHandler": logger.info(f"Start preparing the resource {conf.name}") vm_name = sandbox_handler.get_deployment_resource_name() resource = cls(conf, vm_name, sandbox_handler) if conf.attributes: resource.set_attributes(conf.attributes) logger.info(f"The resource {resource.name} prepared") return resource
def _read_file(self, file_path: str) -> bytes: logger.info(f"Reading file {file_path} from TFTP") bio = BytesIO() try: self.session.download(file_path, bio) except Exception as e: if str(e).startswith("No such file"): raise TftpFileNotFoundError(file_path) raise e return bio.getvalue()
def _read_file(self, file_path: str) -> bytes: logger.info(f"Reading file {file_path} from FTP") b_io = BytesIO() try: self.session.retrbinary(f"RETR {file_path}", b_io.write) except ftplib.Error as e: if str(e).startswith("550 No such file"): raise FtpFileNotFoundError(file_path) raise e return b_io.getvalue()
def _delete_file(self, file_path: str): logger.info(f"Deleting file {file_path}") try: self.session.remove(file_path) except FileNotFoundError: raise ScpFileNotFoundError(file_path) except Exception as e: if "No such file" in str(e): raise ScpFileNotFoundError(file_path) 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 set_resource_attributes(self, resource_name: str, namespace: str, attributes: dict[str, str]): """Set attributes for the resource.""" logger.info(f"Setting attributes for {resource_name}\n{attributes}") namespace += "." if namespace else "" attributes = [ AttributeNameValue(f"{namespace}{key}", value) for key, value in attributes.items() ] self._api.SetAttributesValues( [ResourceAttributesUpdateRequest(resource_name, attributes)])
def _read_file(self, file_path: str) -> bytes: logger.info(f"Reading file {file_path} from SCP") try: resp = self.session.open(file_path) data = resp.read() except FileNotFoundError: raise ScpFileNotFoundError(file_path) except Exception as e: if "No such file" in str(e): raise ScpFileNotFoundError(file_path) raise e return data
def create( cls, conf: ResourceConfig, cs_handler: "CloudShellHandler", shell_handler: "ShellHandler", ) -> "ResourceHandler": set_thread_name_with_suffix(conf.name) logger.info(f"Start preparing the resource {conf.name}") resource = cls(conf, cs_handler, shell_handler) resource._create_resource() logger.info(f"The resource {resource.name} prepared") return resource
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 _get_cs_config(self, sandbox_handler: SandboxHandler) -> CloudShellConfig: resource = self._get_cs_resource(sandbox_handler) info = resource.get_details() attrs = {attr.Name: attr.Value for attr in info.ResourceAttributes} data = { "Host": info.Address, "User": "******", "Password": "******", "OS User": attrs["OS Login"], "OS Password": attrs["OS Password"], } logger.info(f"CloudShell created IP: {info.Address}") return CloudShellConfig(**data)
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