def delete_network(self, network): """Deletes a network. Subclasses SHOULD NOT override or extend this method. If a subclass needs to override the way networks are deleted, it should override the private method `_delete_network` instead. """ # FIXME: Move these imports to the top of the file when circular # import issues are resolved from mist.api.networks.models import Subnet assert network.cloud == self.cloud for subnet in Subnet.objects(network=network, missing_since=None): subnet.ctl.delete() libcloud_network = self._get_libcloud_network(network) try: self._delete_network(network, libcloud_network) except mist.api.exceptions.MistError as exc: log.error("Could not delete network %s", network) raise self.list_networks() from mist.api.poller.models import ListNetworksPollingSchedule ListNetworksPollingSchedule.add(cloud=self.cloud, interval=10, ttl=120)
def create_subnet(self, subnet, **kwargs): """Create a new Subnet. This method receives a Subnet mongoengine object, parses the arguments provided and populates all cloud-specific fields, performs early field validation using the constraints specified in the corresponding Subnet subclass, performs the necessary libcloud call, and, finally, saves the Subnet objects to the database. Subclasses SHOULD NOT override or extend this method. There are instead a number of methods that are called from this method, to allow subclasses to modify the data according to the specific of their cloud type. These methods currently are: `self._create_subnet` `self._create_subnet__prepare_args` Subclasses that require special handling should override these, by default, dummy methods. :param subnet: A Subnet mongoengine model. The model may not have yet been saved in the database. :param kwargs: A dict of parameters required for subnet creation. """ for key, value in kwargs.items(): if key not in subnet._subnet_specific_fields: raise mist.api.exceptions.BadRequestError(key) setattr(subnet, key, value) # Perform early validation. try: subnet.validate(clean=True) except mongoengine.errors.ValidationError as err: raise mist.api.exceptions.BadRequestError(err) kwargs['cidr'] = subnet.cidr kwargs['name'] = subnet.name or '' # Cloud-specific kwargs processing. self._create_subnet__prepare_args(subnet, kwargs) # Increase network polling frequency from mist.api.poller.models import ListNetworksPollingSchedule ListNetworksPollingSchedule.add(cloud=self.cloud, interval=10, ttl=120) # Create the subnet. libcloud_subnet = self._create_subnet(kwargs) # Invoke `self.list_networks` to update the UI and return the Network # object at the API. Try 3 times before failing from mist.api.networks.models import Subnet for _ in range(3): for n in self.list_networks(): if n.network_id == subnet.network.network_id: for s in Subnet.objects(network=n, missing_since=None): if s.subnet_id == libcloud_subnet.id: return s time.sleep(1) raise mist.api.exceptions.SubnetListingError()
def list_cached_subnets(self, network): """Returns subnets stored in database for a specific network """ assert self.cloud == network.cloud # FIXME: Move these imports to the top of the file when circular # import issues are resolved from mist.api.networks.models import Subnet return Subnet.objects(network=network, missing_since=None)
def delete_network(self, network): """Deletes a network. Subclasses SHOULD NOT override or extend this method. If a subclass needs to override the way networks are deleted, it should override the private method `_delete_network` instead. """ # FIXME: Move these imports to the top of the file when circular # import issues are resolved from mist.api.networks.models import Subnet assert network.cloud == self.cloud for subnet in Subnet.objects(network=network, missing_since=None): subnet.ctl.delete() libcloud_network = self._get_libcloud_network(network) self._delete_network(network, libcloud_network)
def list_subnets(self, network, **kwargs): """Lists all Subnets attached to a Network present on the Cloud. Fetches all Subnets via libcloud, applies cloud-specific processing, and syncs the state of the database with the state of the Cloud. Subclasses SHOULD NOT override or extend this method. There are instead a number of methods that are called from this method, to allow subclasses to modify the data according to the specific of their cloud type. These methods currently are: `self._list_subnets__fetch_subnets` `self._list_subnets__cidr_range` `self._list_subnets__postparse_subnet` More private methods may be added in the future. Subclasses that require special handling should override this, by default, dummy method. """ # FIXME: Move these imports to the top of the file when circular # import issues are resolved from mist.api.networks.models import Subnet, SUBNETS libcloud_subnets = self._list_subnets__fetch_subnets(network) # List of Subnet mongoengine objects to be returned to the API. subnets = [] for libcloud_subnet in libcloud_subnets: try: subnet = Subnet.objects.get(network=network, subnet_id=libcloud_subnet.id) except Subnet.DoesNotExist: subnet = SUBNETS[self.provider](network=network, subnet_id=libcloud_subnet.id) subnet.name = libcloud_subnet.name subnet.extra = copy.copy(libcloud_subnet.extra) # Get the Subnet's CIDR. try: subnet.cidr = self._list_subnets__cidr_range( subnet, libcloud_subnet) except Exception as exc: log.exception('Failed to get the CIDR of %s: %s', subnet, exc) # Apply cloud-specific processing. try: self._list_subnets__postparse_subnet(subnet, libcloud_subnet) except Exception as exc: log.exception('Error while post-parsing %s: %s', subnet, exc) # Ensure JSON-encoding. for key, value in subnet.extra.iteritems(): try: json.dumps(value) except TypeError: subnet.extra[key] = str(value) try: subnet.save() except mongoengine.errors.ValidationError as exc: log.error("Error updating %s: %s", subnet, exc.to_dict()) raise mist.api.exceptions.BadRequestError({ "msg": exc.message, "errors": exc.to_dict() }) except mongoengine.errors.NotUniqueError as exc: log.error("Subnet %s not unique error: %s", subnet.name, exc) raise mist.api.exceptions.SubnetExistsError() subnets.append(subnet) # Delete missing subnets. Subnet.objects(network=network, id__nin=[s.id for s in subnets]).delete() return subnets