Пример #1
0
    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)
Пример #2
0
    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()
Пример #3
0
 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)
Пример #4
0
    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)
Пример #5
0
    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