def open(self):
        """
        Load topology elements
        """
        if self._status == "opened":
            return

        self.reset()
        self._loading = True
        self._status = "opened"

        path = self._topology_file()
        if not os.path.exists(path):
            self._loading = False
            return
        try:
            shutil.copy(path, path + ".backup")
        except OSError:
            pass
        try:
            project_data = load_topology(path)

            #load meta of project
            keys_to_load = [
                "auto_start",
                "auto_close",
                "auto_open",
                "scene_height",
                "scene_width",
                "zoom",
                "show_layers",
                "snap_to_grid",
                "show_grid",
                "show_interface_labels"
            ]

            for key in keys_to_load:
                val = project_data.get(key, None)
                if val is not None:
                    setattr(self, key, val)

            topology = project_data["topology"]
            for compute in topology.get("computes", []):
                yield from self.controller.add_compute(**compute)
            for node in topology.get("nodes", []):
                compute = self.controller.get_compute(node.pop("compute_id"))
                name = node.pop("name")
                node_id = node.pop("node_id", str(uuid.uuid4()))
                yield from self.add_node(compute, name, node_id, dump=False, **node)
            for link_data in topology.get("links", []):
                if 'link_id' not in link_data.keys():
                    # skip the link
                    continue
                link = yield from self.add_link(link_id=link_data["link_id"])
                if "filters" in link_data:
                    yield from link.update_filters(link_data["filters"])
                for node_link in link_data["nodes"]:
                    node = self.get_node(node_link["node_id"])
                    port = node.get_port(node_link["adapter_number"], node_link["port_number"])
                    if port is None:
                        log.warning("Port {}/{} for {} not found".format(node_link["adapter_number"], node_link["port_number"], node.name))
                        continue
                    if port.link is not None:
                        log.warning("Port {}/{} is already connected to link ID {}".format(node_link["adapter_number"], node_link["port_number"], port.link.id))
                        continue
                    yield from link.add_node(node, node_link["adapter_number"], node_link["port_number"], label=node_link.get("label"), dump=False)
                if len(link.nodes) != 2:
                    # a link should have 2 attached nodes, this can happen with corrupted projects
                    yield from self.delete_link(link.id, force_delete=True)
            for drawing_data in topology.get("drawings", []):
                yield from self.add_drawing(dump=False, **drawing_data)

            self.dump()
        # We catch all error to be able to rollback the .gns3 to the previous state
        except Exception as e:
            for compute in list(self._project_created_on_compute):
                try:
                    yield from compute.post("/projects/{}/close".format(self._id))
                # We don't care if a compute is down at this step
                except (ComputeError, aiohttp.web.HTTPNotFound, aiohttp.web.HTTPConflict, aiohttp.ServerDisconnectedError):
                    pass
            try:
                if os.path.exists(path + ".backup"):
                    shutil.copy(path + ".backup", path)
            except (PermissionError, OSError):
                pass
            self._status = "closed"
            self._loading = False
            if isinstance(e, ComputeError):
                raise aiohttp.web.HTTPConflict(text=str(e))
            else:
                raise e
        try:
            os.remove(path + ".backup")
        except OSError:
            pass

        self._loading = False
        # Should we start the nodes when project is open
        if self._auto_start:
            # Start all in the background without waiting for completion
            # we ignore errors because we want to let the user open
            # their project and fix it
            asyncio.async(self.start_all())
def open ( self ) : if self . _status == "opened" : return self . reset ( ) self . _loading = True self . _status = "opened" path = self . _topology_file ( ) if not os . path . exists ( path ) : self . _loading = False return try : shutil . copy ( path , path + ".backup" ) except OSError : pass try : project_data = load_topology ( path ) keys_to_load = [ "auto_start" , "auto_close" , "auto_open" , "scene_height" , "scene_width" , "zoom" , "show_layers" , "snap_to_grid" , "show_grid" , "show_interface_labels" ] for key in keys_to_load : val = project_data . get ( key , None ) if val is not None : setattr ( self , key , val ) topology = project_data [ "topology" ] for compute in topology . get ( "computes" , [ ] ) : yield from self . controller . add_compute ( ** compute ) for node in topology . get ( "nodes" , [ ] ) : compute = self . controller . get_compute ( node . pop ( "compute_id" ) ) name = node . pop ( "name" ) node_id = node . pop ( "node_id" , str ( uuid . uuid4 ( ) ) ) yield from self . add_node ( compute , name , node_id , dump = False , ** node ) for link_data in topology . get ( "links" , [ ] ) : if 'link_id' not in link_data . keys ( ) : continue link = yield from self . add_link ( link_id = link_data [ "link_id" ] ) if "filters" in link_data : yield from link . update_filters ( link_data [ "filters" ] ) for node_link in link_data [ "nodes" ] : node = self . get_node ( node_link [ "node_id" ] ) port = node . get_port ( node_link [ "adapter_number" ] , node_link [ "port_number" ] ) if port is None : log . warning ( "Port {}/{} for {} not found" . format ( node_link [ "adapter_number" ] , node_link [ "port_number" ] , node . name ) ) continue if port . link is not None : log . warning ( "Port {}/{} is already connected to link ID {}" . format ( node_link [ "adapter_number" ] , node_link [ "port_number" ] , port . link . id ) ) continue yield from link . add_node ( node , node_link [ "adapter_number" ] , node_link [ "port_number" ] , label = node_link . get ( "label" ) , dump = False ) if len ( link . nodes ) != 2 : yield from self . delete_link ( link . id , force_delete = True ) for drawing_data in topology . get ( "drawings" , [ ] ) : yield from self . add_drawing ( dump = False , ** drawing_data ) self . dump ( ) except Exception as e : for compute in list ( self . _project_created_on_compute ) : try : yield from compute . post ( "/projects/{}/close" . format ( self . _id ) ) except ( ComputeError , aiohttp . web . HTTPNotFound , aiohttp . web . HTTPConflict , aiohttp . ServerDisconnectedError ) : pass try : if os . path . exists ( path + ".backup" ) : shutil . copy ( path + ".backup" , path ) except ( PermissionError , OSError ) : pass self . _status = "closed" self . _loading = False if isinstance ( e , ComputeError ) : raise aiohttp . web . HTTPConflict ( text = str ( e ) ) else : raise e try : os . remove ( path + ".backup" ) except OSError : pass self . _loading = False if self . _auto_start : asyncio . async ( self . start_all ( ) )
Load topology elements