class SubNet(core_models.DescribableMixin, structure_models.ServiceProperty):
    network = models.ForeignKey(
        on_delete=models.CASCADE, to=Network, related_name='subnets'
    )
    cidr = models.CharField(max_length=32, blank=True)
    gateway_ip = models.GenericIPAddressField(protocol='IPv4', null=True)
    allocation_pools = JSONField(default=dict)
    ip_version = models.SmallIntegerField(default=4)
    enable_dhcp = models.BooleanField(default=True)
    dns_nameservers = JSONField(
        default=list,
        help_text=_('List of DNS name servers associated with the subnet.'),
    )

    class Meta:
        verbose_name = _('Subnet')
        verbose_name_plural = _('Subnets')
        unique_together = ('settings', 'backend_id')

    def __str__(self):
        return '%s (%s)' % (self.name, self.cidr)

    @classmethod
    def get_url_name(cls):
        return 'openstacktenant-subnet'
Exemple #2
0
class VirtualMachine(structure_models.VirtualMachine):
    service_project_link = models.ForeignKey(AzureServiceProjectLink,
                                             related_name='virtualmachines',
                                             on_delete=models.PROTECT)
    public_ips = JSONField(default=list,
                           help_text=_('List of public IP addresses'),
                           blank=True)
    private_ips = JSONField(default=list,
                            help_text=_('List of private IP addresses'),
                            blank=True)
    user_username = models.CharField(max_length=50)
    user_password = models.CharField(max_length=50)

    @classmethod
    def get_url_name(cls):
        return 'azure-virtualmachine'

    def get_access_url_name(self):
        return 'azure-virtualmachine-rdp'

    @property
    def external_ips(self):
        return self.public_ips

    @property
    def internal_ips(self):
        return self.private_ips

    @classmethod
    def get_backend_fields(cls):
        return super(VirtualMachine, cls).get_backend_fields() + (
            'public_ips', 'private_ips', 'endpoints')
class Volume(TenantQuotaMixin, structure_models.Volume):
    # backend_id is nullable on purpose, otherwise
    # it wouldn't be possible to put a unique constraint on it
    backend_id = models.CharField(max_length=255, blank=True, null=True)

    service_project_link = models.ForeignKey(OpenStackTenantServiceProjectLink,
                                             related_name='volumes',
                                             on_delete=models.PROTECT)
    instance = models.ForeignKey('Instance',
                                 related_name='volumes',
                                 blank=True,
                                 null=True)
    device = models.CharField(
        max_length=50,
        blank=True,
        validators=[
            RegexValidator(
                '^/dev/[a-zA-Z0-9]+$',
                message=_('Device should match pattern "/dev/alphanumeric+"'))
        ],
        help_text=_('Name of volume as instance device e.g. /dev/vdb.'))
    bootable = models.BooleanField(default=False)
    metadata = JSONField(blank=True)
    image = models.ForeignKey(Image,
                              blank=True,
                              null=True,
                              on_delete=models.SET_NULL)
    image_name = models.CharField(max_length=150, blank=True)
    image_metadata = JSONField(blank=True)
    type = models.CharField(max_length=100, blank=True)
    source_snapshot = models.ForeignKey('Snapshot',
                                        related_name='volumes',
                                        blank=True,
                                        null=True,
                                        on_delete=models.SET_NULL)
    # TODO: Move this fields to resource model.
    action = models.CharField(max_length=50, blank=True)
    action_details = JSONField(default=dict)

    tracker = FieldTracker()

    class Meta(object):
        unique_together = ('service_project_link', 'backend_id')

    def get_quota_deltas(self):
        return {
            TenantQuotas.volumes: 1,
            TenantQuotas.volumes_size: self.size,
            TenantQuotas.storage: self.size,
        }

    @classmethod
    def get_url_name(cls):
        return 'openstacktenant-volume'

    @classmethod
    def get_backend_fields(cls):
        return super(Volume, cls).get_backend_fields() + (
            'name', 'description', 'size', 'metadata', 'type', 'bootable',
            'runtime_state', 'device')
class Snapshot(TenantQuotaMixin, structure_models.Snapshot):
    # backend_id is nullable on purpose, otherwise
    # it wouldn't be possible to put a unique constraint on it
    backend_id = models.CharField(max_length=255, blank=True, null=True)

    service_project_link = models.ForeignKey(
        OpenStackTenantServiceProjectLink,
        related_name='snapshots',
        on_delete=models.PROTECT,
    )
    source_volume: Volume = models.ForeignKey(
        Volume, related_name='snapshots', null=True, on_delete=models.PROTECT
    )
    metadata = JSONField(blank=True)
    # TODO: Move this fields to resource model.
    action = models.CharField(max_length=50, blank=True)
    action_details = JSONField(default=dict)
    snapshot_schedule = models.ForeignKey(
        'SnapshotSchedule',
        blank=True,
        null=True,
        on_delete=models.SET_NULL,
        related_name='snapshots',
    )

    tracker = FieldTracker()

    kept_until = models.DateTimeField(
        null=True,
        blank=True,
        help_text=_('Guaranteed time of snapshot retention. If null - keep forever.'),
    )

    class Meta:
        unique_together = ('service_project_link', 'backend_id')

    @classmethod
    def get_url_name(cls):
        return 'openstacktenant-snapshot'

    def get_quota_deltas(self):
        deltas = {
            TenantQuotas.snapshots: 1,
            TenantQuotas.snapshots_size: self.size,
            TenantQuotas.storage: self.size,
        }
        if self.source_volume and self.source_volume.type:
            deltas['gigabytes_' + self.source_volume.type.backend_id] = self.size / 1024
        return deltas

    @classmethod
    def get_backend_fields(cls):
        return super(Snapshot, cls).get_backend_fields() + (
            'name',
            'description',
            'size',
            'metadata',
            'source_volume',
            'runtime_state',
        )
Exemple #5
0
class Instance(structure_models.VirtualMachine):
    service_project_link = models.ForeignKey(AWSServiceProjectLink,
                                             related_name='instances',
                                             on_delete=models.PROTECT)

    region = models.ForeignKey(on_delete=models.CASCADE, to=Region)
    public_ips = JSONField(default=list,
                           help_text=_('List of public IP addresses'),
                           blank=True)
    private_ips = JSONField(default=list,
                            help_text=_('List of private IP addresses'),
                            blank=True)
    size_backend_id = models.CharField(max_length=150, blank=True)

    def increase_backend_quotas_usage(self, validate=True):
        spl = self.service_project_link
        spl.add_quota_usage(spl.Quotas.storage, self.disk, validate=validate)
        spl.add_quota_usage(spl.Quotas.ram, self.ram, validate=validate)
        spl.add_quota_usage(spl.Quotas.vcpu, self.cores, validate=validate)

    def decrease_backend_quotas_usage(self):
        self.service_project_link.add_quota_usage(
            self.service_project_link.Quotas.storage, -self.disk)
        self.service_project_link.add_quota_usage(
            self.service_project_link.Quotas.ram, -self.ram)
        self.service_project_link.add_quota_usage(
            self.service_project_link.Quotas.vcpu, -self.cores)

    @property
    def external_ips(self):
        return self.public_ips

    @property
    def internal_ips(self):
        return self.private_ips

    def detect_coordinates(self):
        if self.external_ips:
            return get_coordinates_by_ip(self.external_ips[0])
        region = self.region.backend_id
        endpoint = REGION_DETAILS[region]['endpoint']
        return get_coordinates_by_ip(endpoint)

    @classmethod
    def get_url_name(cls):
        return 'aws-instance'

    @classmethod
    def get_backend_fields(cls):
        return super(Instance, cls).get_backend_fields() + ('runtime_state', )

    @classmethod
    def get_online_state(cls):
        return 'running'

    @classmethod
    def get_offline_state(cls):
        return 'stopped'
class Snapshot(structure_models.Snapshot):
    # backend_id is nullable on purpose, otherwise
    # it wouldn't be possible to put a unique constraint on it
    backend_id = models.CharField(max_length=255, blank=True, null=True)

    service_project_link = models.ForeignKey(OpenStackTenantServiceProjectLink,
                                             related_name='snapshots',
                                             on_delete=models.PROTECT)
    source_volume = models.ForeignKey(Volume,
                                      related_name='snapshots',
                                      null=True,
                                      on_delete=models.PROTECT)
    metadata = JSONField(blank=True)
    # TODO: Move this fields to resource model.
    action = models.CharField(max_length=50, blank=True)
    action_details = JSONField(default=dict)
    snapshot_schedule = models.ForeignKey('SnapshotSchedule',
                                          blank=True,
                                          null=True,
                                          on_delete=models.SET_NULL,
                                          related_name='snapshots')

    tracker = FieldTracker()

    kept_until = models.DateTimeField(
        null=True,
        blank=True,
        help_text=_(
            'Guaranteed time of snapshot retention. If null - keep forever.'))

    class Meta(object):
        unique_together = ('service_project_link', 'backend_id')

    @classmethod
    def get_url_name(cls):
        return 'openstacktenant-snapshot'

    def increase_backend_quotas_usage(self, validate=True):
        settings = self.service_project_link.service.settings
        settings.add_quota_usage(settings.Quotas.snapshots,
                                 1,
                                 validate=validate)
        settings.add_quota_usage(settings.Quotas.storage,
                                 self.size,
                                 validate=validate)

    def decrease_backend_quotas_usage(self):
        settings = self.service_project_link.service.settings
        settings.add_quota_usage(settings.Quotas.snapshots, -1)
        settings.add_quota_usage(settings.Quotas.storage, -self.size)

    @classmethod
    def get_backend_fields(cls):
        return super(Snapshot, cls).get_backend_fields() + (
            'name', 'description', 'size', 'metadata', 'source_volume',
            'runtime_state')
Exemple #7
0
class Router(structure_models.SubResource):
    tenant: Tenant = models.ForeignKey(
        on_delete=models.CASCADE, to=Tenant, related_name='routers'
    )
    routes = JSONField(default=list)
    fixed_ips = JSONField(default=list)

    def get_backend(self):
        return self.tenant.get_backend()

    @classmethod
    def get_url_name(cls):
        return 'openstack-router'
Exemple #8
0
class EventTypesMixin(models.Model):
    """
    Mixin to add a event_types and event_groups fields.
    """
    class Meta(object):
        abstract = True

    event_types = JSONField('List of event types')
    event_groups = JSONField('List of event groups', default=list)

    @classmethod
    @lru_cache(maxsize=1)
    def get_all_models(cls):
        return [model for model in apps.get_models() if issubclass(model, cls)]
Exemple #9
0
class SubNet(structure_models.SubResource):
    service_project_link = models.ForeignKey(
        OpenStackServiceProjectLink, related_name='subnets', on_delete=models.PROTECT
    )
    network = models.ForeignKey(
        on_delete=models.CASCADE, to=Network, related_name='subnets'
    )
    cidr = models.CharField(max_length=32, blank=True)
    gateway_ip = models.GenericIPAddressField(protocol='IPv4', null=True)
    allocation_pools = JSONField(default=dict)
    ip_version = models.SmallIntegerField(default=4)
    disable_gateway = models.BooleanField(default=False)
    enable_dhcp = models.BooleanField(default=True)
    dns_nameservers = JSONField(
        default=list,
        help_text=_('List of DNS name servers associated with the subnet.'),
    )

    class Meta:
        verbose_name = _('Subnet')
        verbose_name_plural = _('Subnets')

    def get_backend(self):
        return self.network.get_backend()

    @classmethod
    def get_url_name(cls):
        return 'openstack-subnet'

    def increase_backend_quotas_usage(self, validate=True):
        self.network.tenant.add_quota_usage(
            self.network.tenant.Quotas.subnet_count, 1, validate=validate
        )

    def decrease_backend_quotas_usage(self):
        self.network.tenant.add_quota_usage(self.network.tenant.Quotas.subnet_count, -1)

    @classmethod
    def get_backend_fields(cls):
        return super(SubNet, cls).get_backend_fields() + (
            'name',
            'description',
            'allocation_pools',
            'cidr',
            'ip_version',
            'enable_dhcp',
            'gateway_ip',
            'dns_nameservers',
        )
Exemple #10
0
class Project(structure_models.NewResource, core_models.RuntimeStateMixin):
    class Permissions(structure_models.NewResource.Permissions):
        pass

    service_project_link = models.ForeignKey(JiraServiceProjectLink,
                                             related_name='projects',
                                             on_delete=models.PROTECT)
    template = models.ForeignKey(on_delete=models.CASCADE,
                                 to=ProjectTemplate,
                                 blank=True,
                                 null=True)
    action = models.CharField(max_length=50, blank=True)
    action_details = JSONField(default=dict)

    def get_backend(self):
        return super(Project, self).get_backend(project=self.backend_id)

    def get_access_url(self):
        base_url = self.service_project_link.service.settings.backend_url
        return urljoin(base_url, 'projects/' + self.backend_id)

    @classmethod
    def get_url_name(cls):
        return 'jira-projects'

    @property
    def priorities(self):
        return Priority.objects.filter(
            settings=self.service_project_link.service.settings)
Exemple #11
0
class BaseSubNet(models.Model):
    class Meta:
        abstract = True

    cidr = models.CharField(max_length=32, blank=True)
    gateway_ip = models.GenericIPAddressField(protocol='IPv4', null=True)
    allocation_pools = JSONField(default=dict)
    ip_version = models.SmallIntegerField(default=4)
    enable_dhcp = models.BooleanField(default=True)
    dns_nameservers = JSONField(
        default=list,
        help_text=_('List of DNS name servers associated with the subnet.'),
    )
    is_connected = models.BooleanField(
        default=True,
        help_text=_('Is subnet connected to the default tenant router.'))
Exemple #12
0
class GenericInvoiceItem(InvoiceItem):
    invoice = models.ForeignKey(Invoice, related_name='generic_items')
    content_type = models.ForeignKey(ContentType, null=True, related_name='+')
    object_id = models.PositiveIntegerField(null=True)
    quantity = models.PositiveIntegerField(default=0)

    scope = GenericForeignKey('content_type', 'object_id')
    details = JSONField(default={},
                        blank=True,
                        help_text=_('Stores data about scope'))

    objects = managers.GenericInvoiceItemManager()
    tracker = FieldTracker()

    @property
    def name(self):
        if self.details:
            return self.details['name']
        return registrators.RegistrationManager.get_name(self.scope)

    def freeze(self):
        if self.scope:
            self.details = registrators.RegistrationManager.get_details(
                self.scope)
            self.details['name'] = registrators.RegistrationManager.get_name(
                self.scope)
            self.details['scope_uuid'] = self.scope.uuid.hex
            self.save(update_fields=['details'])
Exemple #13
0
class Port(core_models.BackendModelMixin, models.Model):
    # TODO: Use dedicated field: https://github.com/django-macaddress/django-macaddress
    mac_address = models.CharField(max_length=32, blank=True)
    ip4_address = models.GenericIPAddressField(null=True,
                                               blank=True,
                                               protocol='IPv4')
    ip6_address = models.GenericIPAddressField(null=True,
                                               blank=True,
                                               protocol='IPv6')
    backend_id = models.CharField(max_length=255, blank=True)

    allowed_address_pairs = JSONField(
        default=list,
        help_text=
        _('A server can send a packet with source address which matches one of the specified allowed address pairs.'
          ),
    )

    class Meta:
        abstract = True

    def __str__(self):
        return self.ip4_address or self.ip6_address or 'Not initialized'

    @classmethod
    def get_backend_fields(cls):
        return super(Port, cls).get_backend_fields() + (
            'ip4_address',
            'ip6_address',
            'mac_address',
            'allowed_address_pairs',
        )
Exemple #14
0
class GenericInvoiceItem(InvoiceItem):
    """
    It is expected that get_scope_type method is defined as class method in scope class
    as it is used in generic invoice item serializer.
    """
    invoice = models.ForeignKey(Invoice, related_name='generic_items')
    content_type = models.ForeignKey(ContentType, null=True, related_name='+')
    object_id = models.PositiveIntegerField(null=True)
    quantity = models.PositiveIntegerField(default=0)

    scope = GenericForeignKey('content_type', 'object_id')
    details = JSONField(default=dict, blank=True, help_text=_('Stores data about scope'))

    objects = managers.GenericInvoiceItemManager()
    tracker = FieldTracker()

    @property
    def name(self):
        if self.details.get('name'):
            return self.details.get('name')
        if self.scope:
            return registrators.RegistrationManager.get_name(self.scope)
        # Ilja: temporary workaround to unlock creation of new invoices due to issues caused by 0027 migration
        if self.details:
            return ', '.join(['%s: %s' % (k, v) for k, v in self.details.items()])
        if self.content_type:
            return '%s.%s' % (self.content_type.app_label, self.content_type.model)
        return ''

    def freeze(self):
        if self.scope:
            self.details = registrators.RegistrationManager.get_details(self.scope)
            self.details['name'] = registrators.RegistrationManager.get_name(self.scope)
            self.details['scope_uuid'] = self.scope.uuid.hex
            self.save(update_fields=['details'])
class Backup(structure_models.SubResource):
    service_project_link = models.ForeignKey(
        OpenStackTenantServiceProjectLink,
        related_name='backups',
        on_delete=models.PROTECT,
    )
    instance = models.ForeignKey(
        Instance, related_name='backups', on_delete=models.PROTECT
    )
    backup_schedule = models.ForeignKey(
        'BackupSchedule',
        blank=True,
        null=True,
        on_delete=models.SET_NULL,
        related_name='backups',
    )
    kept_until = models.DateTimeField(
        null=True,
        blank=True,
        help_text=_('Guaranteed time of backup retention. If null - keep forever.'),
    )
    metadata = JSONField(
        blank=True,
        help_text=_(
            'Additional information about backup, can be used for backup restoration or deletion'
        ),
    )
    snapshots = models.ManyToManyField('Snapshot', related_name='backups')

    @classmethod
    def get_url_name(cls):
        return 'openstacktenant-backup'
Exemple #16
0
class Router(structure_models.SubResource):
    service_project_link = models.ForeignKey(OpenStackServiceProjectLink,
                                             related_name='routers',
                                             on_delete=models.PROTECT)
    tenant: Tenant = models.ForeignKey(on_delete=models.CASCADE,
                                       to=Tenant,
                                       related_name='routers')
    routes = JSONField(default=list)
    fixed_ips = JSONField(default=list)

    def get_backend(self):
        return self.tenant.get_backend()

    @classmethod
    def get_url_name(cls):
        return 'openstack-router'
Exemple #17
0
class SystemNotification(EventTypesMixin, models.Model):
    # Model doesn't inherit NameMixin, because this is circular dependence.
    name = models.CharField(_('name'), max_length=150)
    hook_content_type = models.ForeignKey(on_delete=models.CASCADE,
                                          to=ct_models.ContentType,
                                          related_name='+')
    roles = JSONField('List of roles', default=list)

    @staticmethod
    def get_valid_roles():
        return 'admin', 'manager', 'owner'

    @classmethod
    def get_hooks(cls, event_type, project=None, customer=None):
        from waldur_core.structure import models as structure_models
        from waldur_core.logging import loggers

        groups = [
            g[0] for g in loggers.event_logger.get_all_groups().items()
            if event_type in g[1]
        ]

        for hook in cls.objects.filter(
                models.Q(event_types__contains=event_type)
                | models.Q(event_groups__has_any_keys=groups)):
            hook_class = hook.hook_content_type.model_class()
            users_qs = []

            if project:
                if 'admin' in hook.roles:
                    users_qs.append(
                        project.get_users(
                            structure_models.ProjectRole.ADMINISTRATOR))
                if 'manager' in hook.roles:
                    users_qs.append(
                        project.get_users(
                            structure_models.ProjectRole.MANAGER))
                if 'owner' in hook.roles:
                    users_qs.append(project.customer.get_owners())

            if customer:
                if 'owner' in hook.roles:
                    users_qs.append(customer.get_owners())

            if len(users_qs) > 1:
                users = users_qs[0].union(*users_qs[1:]).distinct()
            elif len(users_qs) == 1:
                users = users_qs[0]
            else:
                users = []

            for user in users:
                if user.email:
                    yield hook_class(user=user,
                                     event_types=hook.event_types,
                                     email=user.email)

    def __str__(self):
        return '%s | %s' % (self.hook_content_type, self.name)
class PrivateCloud(quotas_models.QuotaModelMixin,
                   core_models.RuntimeStateMixin, NewResource):
    extra_configuration = JSONField(
        default=dict,
        help_text=_(
            'Configuration details that are not represented on backend.'))

    class Meta(object):
        abstract = True
Exemple #19
0
class SubNet(structure_models.ServiceProperty):
    network = models.ForeignKey(Network, related_name='subnets')
    cidr = models.CharField(max_length=32)
    gateway_ip = models.GenericIPAddressField(protocol='IPv4')
    allocation_pools = JSONField()
    dns_nameservers = JSONField(
        help_text=_('List of DNS name servers associated with the subnet.'))

    class Meta(object):
        verbose_name = _('Subnet')
        verbose_name_plural = _('Subnets')
        unique_together = ('settings', 'backend_id')

    def __str__(self):
        return '%s (%s)' % (self.name, self.cidr)

    @classmethod
    def get_url_name(cls):
        return 'rijkscloud-subnet'
Exemple #20
0
class Instance(structure_models.VirtualMachine):
    region = models.ForeignKey(on_delete=models.CASCADE, to=Region)
    public_ips = JSONField(default=list,
                           help_text=_('List of public IP addresses'),
                           blank=True)
    private_ips = JSONField(default=list,
                            help_text=_('List of private IP addresses'),
                            blank=True)
    size_backend_id = models.CharField(max_length=150, blank=True)

    @property
    def external_ips(self):
        return self.public_ips

    @property
    def internal_ips(self):
        return self.private_ips

    def detect_coordinates(self):
        if self.external_ips:
            return get_coordinates_by_ip(self.external_ips[0])
        region = self.region.backend_id
        endpoint = REGION_DETAILS[region]['endpoint']
        return get_coordinates_by_ip(endpoint)

    @classmethod
    def get_url_name(cls):
        return 'aws-instance'

    @classmethod
    def get_backend_fields(cls):
        return super(Instance, cls).get_backend_fields() + ('runtime_state', )

    @classmethod
    def get_online_state(cls):
        return 'running'

    @classmethod
    def get_offline_state(cls):
        return 'stopped'
Exemple #21
0
class Port(core_models.BackendModelMixin, models.Model):
    # TODO: Use dedicated field: https://github.com/django-macaddress/django-macaddress
    mac_address = models.CharField(max_length=32, blank=True)
    fixed_ips = JSONField(
        default=list,
        help_text=_(
            'A list of tuples (ip_address, subnet_id), where ip_address can be both IPv4 and IPv6 '
            'and subnet_id is a backend id of the subnet'),
    )
    backend_id = models.CharField(max_length=255, blank=True)
    allowed_address_pairs = JSONField(
        default=list,
        help_text=
        _('A server can send a packet with source address which matches one of the specified allowed address pairs.'
          ),
    )
    device_id = models.CharField(
        max_length=255,
        null=True,
        blank=True,
    )
    device_owner = models.CharField(
        max_length=100,
        null=True,
        blank=True,
    )

    class Meta:
        abstract = True

    @classmethod
    def get_backend_fields(cls):
        return super(Port, cls).get_backend_fields() + (
            'fixed_ips',
            'mac_address',
            'allowed_address_pairs',
            'device_id',
            'device_owner',
        )
class Offering(core_models.UuidMixin, core_models.NameMixin,
               core_models.DescribableMixin, quotas_models.QuotaModelMixin,
               structure_models.StructureModel,
               structure_models.TimeStampedModel):
    thumbnail = models.ImageField(
        upload_to='marketplace_service_offering_thumbnails',
        blank=True,
        null=True)
    full_description = models.TextField(blank=True)
    rating = models.IntegerField(
        null=True,
        validators=[MaxValueValidator(5),
                    MinValueValidator(1)],
        help_text=_('Rating is value from 1 to 5.'))
    category = models.ForeignKey(Category, related_name='offerings')
    customer = models.ForeignKey(structure_models.Customer,
                                 related_name='+',
                                 null=True)
    attributes = BetterJSONField(blank=True, default=dict)
    geolocations = JSONField(
        default=list,
        blank=True,
        help_text=_(
            'List of latitudes and longitudes. For example: '
            '[{"latitude": 123, "longitude": 345}, {"latitude": 456, "longitude": 678}]'
        ))
    is_active = models.BooleanField(default=True)

    native_name = models.CharField(max_length=160, default='', blank=True)
    native_description = models.CharField(max_length=500,
                                          default='',
                                          blank=True)

    class Permissions(object):
        customer_path = 'customer'

    class Meta(object):
        verbose_name = _('Offering')

    class Quotas(quotas_models.QuotaModelMixin.Quotas):
        order_item_count = quotas_fields.CounterQuotaField(
            target_models=lambda: [OrderItem],
            path_to_scope='offering',
        )

    def __str__(self):
        return six.text_type(self.name)

    @classmethod
    def get_url_name(cls):
        return 'marketplace-offering'
Exemple #23
0
class Volume(structure_models.Volume):
    service_project_link = models.ForeignKey(RijkscloudServiceProjectLink,
                                             related_name='volumes',
                                             on_delete=models.PROTECT)
    metadata = JSONField(blank=True)

    @classmethod
    def get_url_name(cls):
        return 'rijkscloud-volume'

    @classmethod
    def get_backend_fields(cls):
        return super(Volume, cls).get_backend_fields() + (
            'name', 'size', 'metadata', 'runtime_state')
Exemple #24
0
class SubNet(openstack_base_models.BaseSubNet, structure_models.SubResource):
    service_project_link = models.ForeignKey(OpenStackServiceProjectLink,
                                             related_name='subnets',
                                             on_delete=models.PROTECT)
    network = models.ForeignKey(on_delete=models.CASCADE,
                                to=Network,
                                related_name='subnets')
    disable_gateway = models.BooleanField(default=False)
    host_routes = JSONField(
        default=list,
        help_text=_('List of additional routes for the subnet.'),
    )

    class Meta:
        verbose_name = _('Subnet')
        verbose_name_plural = _('Subnets')

    def get_backend(self):
        return self.network.get_backend()

    @classmethod
    def get_url_name(cls):
        return 'openstack-subnet'

    def increase_backend_quotas_usage(self, validate=True):
        self.network.tenant.add_quota_usage(
            self.network.tenant.Quotas.subnet_count, 1, validate=validate)

    def decrease_backend_quotas_usage(self):
        self.network.tenant.add_quota_usage(
            self.network.tenant.Quotas.subnet_count, -1)

    @classmethod
    def get_backend_fields(cls):
        return super(SubNet, cls).get_backend_fields() + (
            'name',
            'description',
            'allocation_pools',
            'cidr',
            'ip_version',
            'enable_dhcp',
            'gateway_ip',
            'dns_nameservers',
            'host_routes',
            'is_connected',
        )
Exemple #25
0
class Alert(UuidMixin, TimeStampedModel):
    class Meta:
        unique_together = ("content_type", "object_id", "alert_type",
                           "is_closed")

    class SeverityChoices(object):
        DEBUG = 10
        INFO = 20
        WARNING = 30
        ERROR = 40
        CHOICES = ((DEBUG, 'Debug'), (INFO, 'Info'), (WARNING, 'Warning'),
                   (ERROR, 'Error'))

    alert_type = models.CharField(max_length=50, db_index=True)
    message = models.CharField(max_length=255)
    severity = models.SmallIntegerField(choices=SeverityChoices.CHOICES)
    closed = models.DateTimeField(null=True, blank=True)
    # Hack: This field stays blank until alert closing.
    #       After closing it gets unique value to avoid unique together constraint break.
    is_closed = models.CharField(blank=True, max_length=32)
    acknowledged = models.BooleanField(default=False)
    context = JSONField(blank=True)

    content_type = models.ForeignKey(ct_models.ContentType,
                                     null=True,
                                     on_delete=models.SET_NULL)
    object_id = models.PositiveIntegerField(null=True)
    scope = ct_fields.GenericForeignKey('content_type', 'object_id')

    objects = managers.AlertManager()

    def close(self):
        self.closed = timezone.now()
        self.is_closed = uuid.uuid4().hex
        self.save()

    def acknowledge(self):
        self.acknowledged = True
        self.save()

    def cancel_acknowledgment(self):
        self.acknowledged = False
        self.save()
Exemple #26
0
class OfferingItem(InvoiceItem):
    """ OfferingItem stores details for invoices about purchased custom offering item. """
    invoice = models.ForeignKey(Invoice, related_name='offering_items')
    offering = models.ForeignKey(support_models.Offering,
                                 on_delete=models.SET_NULL,
                                 null=True,
                                 related_name='+')
    offering_details = JSONField(default=dict,
                                 blank=True,
                                 help_text=_('Stores data about offering'))
    tracker = FieldTracker()

    @property
    def name(self):
        if self.offering_details:
            name = self.offering_details.get('offering_name',
                                             self.project_name)
            return '%s (%s)' % (name, self.offering_details['offering_type'])

        return '%s (%s)' % (self.offering.name, self.offering.type)

    def freeze(self):
        """
        Saves offering type and offering name in "offering_details" if offering exists
        """
        if self.offering:
            self.offering_details['offering_type'] = self.offering.type
            self.offering_details['offering_name'] = self.offering.name
            self.offering_details['offering_uuid'] = self.offering.uuid.hex
            self.offering = None
            self.save(update_fields=['offering_details', 'offering'])

    def get_offering_uuid(self):
        if self.offering:
            return self.offering.uuid.hex
        else:
            return self.offering_details.get('offering_uuid')

    def get_offering_type(self):
        if self.offering:
            return self.offering.type
        else:
            return self.offering_details.get('offering_type')
class Instance(TenantQuotaMixin, structure_models.VirtualMachine):
    class RuntimeStates:
        # All possible OpenStack Instance states on backend.
        # See https://docs.openstack.org/developer/nova/vmstates.html
        ACTIVE = 'ACTIVE'
        BUILDING = 'BUILDING'
        DELETED = 'DELETED'
        SOFT_DELETED = 'SOFT_DELETED'
        ERROR = 'ERROR'
        UNKNOWN = 'UNKNOWN'
        HARD_REBOOT = 'HARD_REBOOT'
        REBOOT = 'REBOOT'
        REBUILD = 'REBUILD'
        PASSWORD = '******'
        PAUSED = 'PAUSED'
        RESCUED = 'RESCUED'
        RESIZED = 'RESIZED'
        REVERT_RESIZE = 'REVERT_RESIZE'
        SHUTOFF = 'SHUTOFF'
        STOPPED = 'STOPPED'
        SUSPENDED = 'SUSPENDED'
        VERIFY_RESIZE = 'VERIFY_RESIZE'

    # backend_id is nullable on purpose, otherwise
    # it wouldn't be possible to put a unique constraint on it
    backend_id = models.CharField(max_length=255, blank=True, null=True)
    service_project_link = models.ForeignKey(
        OpenStackTenantServiceProjectLink,
        related_name='instances',
        on_delete=models.PROTECT,
    )

    availability_zone = models.ForeignKey(
        InstanceAvailabilityZone, blank=True, null=True, on_delete=models.SET_NULL
    )
    flavor_name = models.CharField(max_length=255, blank=True)
    flavor_disk = models.PositiveIntegerField(
        default=0, help_text=_('Flavor disk size in MiB')
    )
    security_groups = models.ManyToManyField(SecurityGroup, related_name='instances')
    # TODO: Move this fields to resource model.
    action = models.CharField(max_length=50, blank=True)
    action_details = JSONField(default=dict)
    subnets = models.ManyToManyField('SubNet', through='InternalIP')

    tracker = FieldTracker()

    class Meta:
        unique_together = ('service_project_link', 'backend_id')

    @property
    def external_ips(self):
        return list(self.floating_ips.values_list('address', flat=True))

    @property
    def internal_ips(self):
        return list(self.internal_ips_set.values_list('ip4_address', flat=True))

    @property
    def size(self):
        return self.volumes.aggregate(models.Sum('size'))['size__sum']

    @classmethod
    def get_url_name(cls):
        return 'openstacktenant-instance'

    def get_log_fields(self):
        return (
            'uuid',
            'name',
            'type',
            'service_project_link',
            'ram',
            'cores',
        )

    def detect_coordinates(self):
        settings = self.service_project_link.service.settings
        options = settings.options or {}
        if 'latitude' in options and 'longitude' in options:
            return structure_utils.Coordinates(
                latitude=settings['latitude'], longitude=settings['longitude']
            )
        else:
            hostname = urlparse(settings.backend_url).hostname
            if hostname:
                return get_coordinates_by_ip(hostname)

    def get_quota_deltas(self):
        return {
            TenantQuotas.instances: 1,
            TenantQuotas.ram: self.ram,
            TenantQuotas.vcpu: self.cores,
        }

    @property
    def floating_ips(self):
        return FloatingIP.objects.filter(internal_ip__instance=self)

    @classmethod
    def get_backend_fields(cls):
        return super(Instance, cls).get_backend_fields() + (
            'flavor_name',
            'flavor_disk',
            'ram',
            'cores',
            'disk',
            'runtime_state',
            'availability_zone',
        )

    @classmethod
    def get_online_state(cls):
        return Instance.RuntimeStates.ACTIVE

    @classmethod
    def get_offline_state(cls):
        return Instance.RuntimeStates.SHUTOFF
Exemple #28
0
class ServiceSettings(quotas_models.ExtendableQuotaModelMixin,
                      core_models.UuidMixin,
                      core_models.NameMixin,
                      core_models.StateMixin,
                      TagMixin,
                      LoggableMixin):

    class Meta:
        verbose_name = "Service settings"
        verbose_name_plural = "Service settings"

    class Permissions(object):
        customer_path = 'customer'
        extra_query = dict(shared=True)

    customer = models.ForeignKey(Customer,
                                 verbose_name=_('organization'),
                                 related_name='service_settings',
                                 blank=True,
                                 null=True)
    backend_url = core_fields.BackendURLField(max_length=200, blank=True, null=True)
    username = models.CharField(max_length=100, blank=True, null=True)
    password = models.CharField(max_length=100, blank=True, null=True)
    domain = models.CharField(max_length=200, blank=True, null=True)
    token = models.CharField(max_length=255, blank=True, null=True)
    certificate = models.FileField(upload_to='certs', blank=True, null=True,
                                   validators=[FileTypeValidator(
                                       allowed_types=[
                                           'application/x-pem-file',
                                           'application/x-x509-ca-cert',
                                           'text/plain'],
                                       allowed_extensions=['pem'])])
    type = models.CharField(max_length=255, db_index=True, validators=[validate_service_type])
    options = JSONField(default={}, help_text=_('Extra options'), blank=True)
    geolocations = JSONField(default=[], blank=True,
                             help_text=_('List of latitudes and longitudes. For example: '
                                         '[{"latitude": 123, "longitude": 345}, {"latitude": 456, "longitude": 678}]'))
    shared = models.BooleanField(default=False, help_text=_('Anybody can use it'))
    homepage = models.URLField(max_length=255, blank=True)
    terms_of_services = models.URLField(max_length=255, blank=True)
    certifications = models.ManyToManyField(to='ServiceCertification', related_name='service_settings', blank=True)

    tracker = FieldTracker()

    # service settings scope - VM that contains service
    content_type = models.ForeignKey(ContentType, null=True)
    object_id = models.PositiveIntegerField(null=True)
    scope = GenericForeignKey('content_type', 'object_id')

    objects = ServiceSettingsManager('scope')

    def get_backend(self, **kwargs):
        return SupportedServices.get_service_backend(self.type)(self, **kwargs)

    def get_option(self, name):
        options = self.options or {}
        if name in options:
            return options.get(name)
        else:
            defaults = self.get_backend().DEFAULTS
            return defaults.get(name)

    def __str__(self):
        return '%s (%s)' % (self.name, self.get_type_display())

    def get_log_fields(self):
        return ('uuid', 'name', 'customer')

    def _get_log_context(self, entity_name):
        context = super(ServiceSettings, self)._get_log_context(entity_name)
        context['service_settings_type'] = self.get_type_display()
        return context

    def get_type_display(self):
        return SupportedServices.get_name_for_type(self.type)

    def get_services(self):
        service_model = SupportedServices.get_service_models()[self.type]['service']
        return service_model.objects.filter(settings=self)

    def unlink_descendants(self):
        for service in self.get_services():
            service.unlink_descendants()
            service.delete()
Exemple #29
0
class Offering(core_models.UuidMixin, core_models.NameMixin,
               core_models.DescribableMixin, quotas_models.QuotaModelMixin,
               structure_models.StructureModel,
               structure_models.TimeStampedModel, ScopeMixin):
    class States(object):
        DRAFT = 1
        ACTIVE = 2
        PAUSED = 3
        ARCHIVED = 4

        CHOICES = (
            (DRAFT, 'Draft'),
            (ACTIVE, 'Active'),
            (PAUSED, 'Paused'),
            (ARCHIVED, 'Archived'),
        )

    thumbnail = models.FileField(
        upload_to='marketplace_service_offering_thumbnails',
        blank=True,
        null=True,
        validators=[VectorizedImageValidator])
    full_description = models.TextField(blank=True)
    vendor_details = models.TextField(blank=True)
    rating = models.IntegerField(
        null=True,
        validators=[MaxValueValidator(5),
                    MinValueValidator(1)],
        help_text=_('Rating is value from 1 to 5.'))
    category = models.ForeignKey(Category, related_name='offerings')
    customer = models.ForeignKey(structure_models.Customer,
                                 related_name='+',
                                 null=True)
    attributes = BetterJSONField(blank=True,
                                 default=dict,
                                 help_text=_('Fields describing Category.'))
    options = BetterJSONField(
        blank=True,
        default=dict,
        help_text=_('Fields describing Offering request form.'))
    geolocations = JSONField(
        default=list,
        blank=True,
        help_text=_(
            'List of latitudes and longitudes. For example: '
            '[{"latitude": 123, "longitude": 345}, {"latitude": 456, "longitude": 678}]'
        ))

    native_name = models.CharField(max_length=160, default='', blank=True)
    native_description = models.CharField(max_length=500,
                                          default='',
                                          blank=True)

    type = models.CharField(max_length=100)
    state = FSMIntegerField(default=States.DRAFT, choices=States.CHOICES)

    # If offering is not shared, it is available only to following user categories:
    # 1) staff user;
    # 2) global support user;
    # 3) users with active permission in original customer;
    # 4) users with active permission in allowed customers and nested projects.
    shared = models.BooleanField(default=False,
                                 help_text=_('Anybody can use it'))
    allowed_customers = models.ManyToManyField(structure_models.Customer,
                                               blank=True)

    objects = managers.MixinManager('scope')
    tracker = FieldTracker()

    class Permissions(object):
        customer_path = 'customer'

    class Meta(object):
        verbose_name = _('Offering')

    class Quotas(quotas_models.QuotaModelMixin.Quotas):
        order_item_count = quotas_fields.CounterQuotaField(
            target_models=lambda: [OrderItem],
            path_to_scope='offering',
        )

    @transition(field=state, source=States.DRAFT, target=States.ACTIVE)
    def activate(self):
        pass

    @transition(field=state, source=States.ACTIVE, target=States.PAUSED)
    def pause(self):
        pass

    @transition(field=state, source='*', target=States.ARCHIVED)
    def archive(self):
        pass

    def __str__(self):
        return six.text_type(self.name)

    @classmethod
    def get_url_name(cls):
        return 'marketplace-offering'
Exemple #30
0
class ServiceSettings(
        quotas_models.ExtendableQuotaModelMixin,
        core_models.UuidMixin,
        core_models.NameMixin,
        core_models.StateMixin,
        TagMixin,
        StructureLoggableMixin,
):
    class Meta:
        verbose_name = "Service settings"
        verbose_name_plural = "Service settings"
        ordering = ('name', )

    class Permissions:
        customer_path = 'customer'
        build_query = build_service_settings_query

    customer = models.ForeignKey(
        on_delete=models.CASCADE,
        to=Customer,
        verbose_name=_('organization'),
        related_name='service_settings',
        blank=True,
        null=True,
    )
    backend_url = core_fields.BackendURLField(max_length=200,
                                              blank=True,
                                              null=True)
    username = models.CharField(max_length=100, blank=True, null=True)
    password = models.CharField(max_length=100, blank=True, null=True)
    domain = models.CharField(max_length=200, blank=True, null=True)
    token = models.CharField(max_length=255, blank=True, null=True)
    certificate = models.FileField(upload_to='certs',
                                   blank=True,
                                   null=True,
                                   validators=[CertificateValidator])
    type = models.CharField(max_length=255,
                            db_index=True,
                            validators=[validate_service_type])
    options = JSONField(default=dict, help_text=_('Extra options'), blank=True)
    shared = models.BooleanField(default=False,
                                 help_text=_('Anybody can use it'))
    terms_of_services = models.URLField(max_length=255, blank=True)

    tracker = FieldTracker()

    # service settings scope - VM that contains service
    content_type = models.ForeignKey(on_delete=models.CASCADE,
                                     to=ContentType,
                                     null=True)
    object_id = models.PositiveIntegerField(null=True)
    scope = GenericForeignKey('content_type', 'object_id')

    objects = ServiceSettingsManager('scope')

    is_active = models.BooleanField(
        default=True,
        help_text=
        'Information about inactive service settings will not be updated in the background',
    )

    def get_backend(self, **kwargs):
        return SupportedServices.get_service_backend(self.type)(self, **kwargs)

    def get_option(self, name):
        options = self.options or {}
        if name in options:
            return options.get(name)
        else:
            defaults = self.get_backend().DEFAULTS
            return defaults.get(name)

    def __str__(self):
        return '%s (%s)' % (self.name, self.type)

    def get_log_fields(self):
        return ('uuid', 'name', 'customer')

    def _get_log_context(self, entity_name):
        context = super(ServiceSettings, self)._get_log_context(entity_name)
        context['service_settings_type'] = self.type
        return context

    def get_type_display(self):
        return self.type