Ejemplo n.º 1
0
class Subnet(models.Model):
    SUBNET_NAME_LENGTH = 128

    userid = models.CharField('User ID of the owner', max_length=128,
                              null=True, db_index=True)
    public = models.BooleanField(default=False, db_index=True)

    network = models.ForeignKey('Network', null=False, db_index=True,
                                related_name="subnets",
                                on_delete=models.PROTECT)
    name = models.CharField('Subnet Name', max_length=SUBNET_NAME_LENGTH,
                            null=True, default="")
    ipversion = models.IntegerField('IP Version', default=4, null=False)
    cidr = models.CharField('Subnet', max_length=64, null=False)
    gateway = models.CharField('Gateway', max_length=64, null=True)
    dhcp = models.BooleanField('DHCP', default=True, null=False)
    deleted = models.BooleanField('Deleted', default=False, db_index=True,
                                  null=False)
    host_routes = fields.SeparatedValuesField('Host Routes', null=True)
    dns_nameservers = fields.SeparatedValuesField('DNS Nameservers', null=True)
    created = models.DateTimeField(auto_now_add=True)
    updated = models.DateTimeField(auto_now=True)

    def __str__(self):
        return self.__unicode__()

    def __unicode__(self):
        msg = u"<Subnet %s, Network: %s, CIDR: %s>"
        return msg % (self.id, self.network_id, self.cidr)

    def get_ip_pools(self, locked=True):
        ip_pools = self.ip_pools
        if locked:
            ip_pools = ip_pools.select_for_update()
        return map(lambda ip_pool: ip_pool.pool, ip_pools.all())
Ejemplo n.º 2
0
class Backend(models.Model):
    clustername = models.CharField('Cluster Name', max_length=128, unique=True)
    port = models.PositiveIntegerField('Port', default=5080)
    username = models.CharField('Username',
                                max_length=64,
                                blank=True,
                                null=True)
    password_hash = models.CharField('Password',
                                     max_length=128,
                                     blank=True,
                                     null=True)
    # Sha1 is up to 40 characters long
    hash = models.CharField('Hash', max_length=40, editable=False, null=False)
    # Unique index of the Backend, used for the mac-prefixes of the
    # BackendNetworks
    index = models.PositiveIntegerField('Index',
                                        null=False,
                                        unique=True,
                                        default=0)
    drained = models.BooleanField('Drained', default=False, null=False)
    offline = models.BooleanField('Offline', default=False, null=False)
    # Type of hypervisor
    hypervisor = models.CharField('Hypervisor',
                                  max_length=32,
                                  default="kvm",
                                  null=False)
    disk_templates = fields.SeparatedValuesField("Disk Templates", null=True)
    # Last refresh of backend resources
    updated = models.DateTimeField(auto_now_add=True)
    # Backend resources
    mfree = models.PositiveIntegerField('Free Memory', default=0, null=False)
    mtotal = models.PositiveIntegerField('Total Memory', default=0, null=False)
    dfree = models.PositiveIntegerField('Free Disk', default=0, null=False)
    dtotal = models.PositiveIntegerField('Total Disk', default=0, null=False)
    pinst_cnt = models.PositiveIntegerField('Primary Instances',
                                            default=0,
                                            null=False)
    ctotal = models.PositiveIntegerField('Total number of logical processors',
                                         default=0,
                                         null=False)

    HYPERVISORS = (
        ("kvm", "Linux KVM hypervisor"),
        ("xen-pvm", "Xen PVM hypervisor"),
        ("xen-hvm", "Xen KVM hypervisor"),
    )

    class Meta:
        verbose_name = u'Backend'
        ordering = ["clustername"]

    def __unicode__(self):
        return self.clustername + "(id=" + str(self.id) + ")"

    @property
    def backend_id(self):
        return self.id

    def get_client(self):
        """Get or create a client. """
        if self.offline:
            raise faults.ServiceUnavailable("Backend '%s' is offline" % self)
        return get_rapi_client(self.id, self.hash, self.clustername, self.port,
                               self.username, self.password)

    @staticmethod
    def put_client(client):
        put_rapi_client(client)

    def create_hash(self):
        """Create a hash for this backend. """
        sha = sha1('%s%s%s%s' %
                   (self.clustername, self.port, self.username, self.password))
        return sha.hexdigest()

    @property
    def password(self):
        return decrypt_db_charfield(self.password_hash)

    @password.setter
    def password(self, value):
        self.password_hash = encrypt_db_charfield(value)

    def save(self, *args, **kwargs):
        # Create a new hash each time a Backend is saved
        old_hash = self.hash
        self.hash = self.create_hash()
        super(Backend, self).save(*args, **kwargs)
        if self.hash != old_hash:
            # Populate the new hash to the new instances
            self.virtual_machines.filter(deleted=False)\
                                 .update(backend_hash=self.hash)

    def __init__(self, *args, **kwargs):
        super(Backend, self).__init__(*args, **kwargs)
        if not self.pk:
            # Generate a unique index for the Backend
            indexes = Backend.objects.all().values_list('index', flat=True)
            try:
                first_free = [x for x in xrange(0, 16) if x not in indexes][0]
                self.index = first_free
            except IndexError:
                raise Exception("Cannot create more than 16 backends")

    def use_hotplug(self):
        return self.hypervisor == "kvm" and snf_settings.GANETI_USE_HOTPLUG

    def get_create_params(self):
        params = deepcopy(snf_settings.GANETI_CREATEINSTANCE_KWARGS)
        params["hvparams"] = params.get("hvparams", {})\
                                   .get(self.hypervisor, {})
        return params
Ejemplo n.º 3
0
class Network(models.Model):
    OPER_STATES = (
        ('PENDING', 'Pending'),  # Unused because of lazy networks
        ('ACTIVE', 'Active'),
        ('DELETED', 'Deleted'),
        ('ERROR', 'Error')
    )

    ACTIONS = (
        ('CREATE', 'Create Network'),
        ('DESTROY', 'Destroy Network'),
        ('ADD', 'Add server to Network'),
        ('REMOVE', 'Remove server from Network'),
    )

    RSAPI_STATE_FROM_OPER_STATE = {
        'PENDING': 'PENDING',
        'ACTIVE': 'ACTIVE',
        'DELETED': 'DELETED',
        'ERROR': 'ERROR'
    }

    FLAVORS = {
        'CUSTOM': {
            'mode': 'bridged',
            'link': settings.DEFAULT_BRIDGE,
            'mac_prefix': settings.DEFAULT_MAC_PREFIX,
            'tags': None,
            'desc': "Basic flavor used for a bridged network",
        },
        'IP_LESS_ROUTED': {
            'mode': 'routed',
            'link': None,
            'mac_prefix': settings.DEFAULT_MAC_PREFIX,
            'tags': 'ip-less-routed',
            'desc': "Flavor used for an IP-less routed network using"
                    " Proxy ARP",
        },
        'MAC_FILTERED': {
            'mode': 'bridged',
            'link': settings.DEFAULT_MAC_FILTERED_BRIDGE,
            'mac_prefix': 'pool',
            'tags': 'private-filtered',
            'desc': "Flavor used for bridged networks that offer isolation"
                    " via filtering packets based on their src "
                    " MAC (ebtables)",
        },
        'PHYSICAL_VLAN': {
            'mode': 'bridged',
            'link': 'pool',
            'mac_prefix': settings.DEFAULT_MAC_PREFIX,
            'tags': 'physical-vlan',
            'desc': "Flavor used for bridged network that offer isolation"
                    " via dedicated physical vlan",
        },
    }

    NETWORK_NAME_LENGTH = 128

    objects = NetworkManager()

    name = models.CharField('Network Name', max_length=NETWORK_NAME_LENGTH)
    userid = models.CharField('User ID of the owner', max_length=128,
                              null=True, db_index=True)
    project = models.CharField(max_length=255, null=True, db_index=True)
    shared_to_project = models.BooleanField('Shared to project',
                                            default=False)
    flavor = models.CharField('Flavor', max_length=32, null=False)
    mode = models.CharField('Network Mode', max_length=16, null=True)
    link = models.CharField('Network Link', max_length=32, null=True)
    mac_prefix = models.CharField('MAC Prefix', max_length=32, null=False)
    tags = models.CharField('Network Tags', max_length=128, null=True)
    public = models.BooleanField(default=False, db_index=True)
    created = models.DateTimeField(auto_now_add=True)
    updated = models.DateTimeField(auto_now=True)
    deleted = models.BooleanField('Deleted', default=False, db_index=True)
    state = models.CharField(choices=OPER_STATES, max_length=32,
                             default='PENDING')
    machines = models.ManyToManyField(VirtualMachine,
                                      through='NetworkInterface')
    action = models.CharField(choices=ACTIONS, max_length=32, null=True,
                              default=None)
    drained = models.BooleanField("Drained", default=False, null=False)
    floating_ip_pool = models.BooleanField('Floating IP Pool', null=False,
                                           default=False)
    external_router = models.BooleanField(default=False)
    serial = models.ForeignKey(QuotaHolderSerial, related_name='network',
                               null=True, on_delete=models.SET_NULL)
    subnet_ids = fields.SeparatedValuesField("Subnet IDs", null=True)

    def __str__(self):
        return self.__unicode__()

    def __unicode__(self):
        return u"<Network: %s>" % self.id

    @property
    def backend_id(self):
        """Return the backend id by prepending backend-prefix."""
        if not self.id:
            raise Network.InvalidBackendIdError("self.id is None")
        return "%snet-%s" % (settings.BACKEND_PREFIX_ID, str(self.id))

    @property
    def backend_tag(self):
        """Return the network tag to be used in backend

        """
        if self.tags:
            return self.tags.split(',')
        else:
            return []

    def create_backend_network(self, backend=None):
        """Create corresponding BackendNetwork entries."""

        backends = [backend] if backend else\
            Backend.objects.filter(offline=False)
        for backend in backends:
            backend_exists =\
                BackendNetwork.objects.filter(backend=backend, network=self)\
                                      .exists()
            if not backend_exists:
                BackendNetwork.objects.create(backend=backend, network=self)

    def get_ip_pools(self, locked=True):
        subnets = self.subnets.filter(ipversion=4, deleted=False)\
                              .prefetch_related("ip_pools")
        return [ip_pool for subnet in subnets
                for ip_pool in subnet.get_ip_pools(locked=locked)]

    def reserve_address(self, address, external=False):
        for ip_pool in self.get_ip_pools():
            if ip_pool.contains(address):
                ip_pool.reserve(address, external=external)
                ip_pool.save()
                return
        raise pools.InvalidValue("Network %s does not have an IP pool that"
                                 " contains address %s" % (self, address))

    def release_address(self, address, external=False):
        for ip_pool in self.get_ip_pools():
            if ip_pool.contains(address):
                ip_pool.put(address, external=external)
                ip_pool.save()
                return
        raise pools.InvalidValue("Network %s does not have an IP pool that"
                                 " contains address %s" % (self, address))

    @property
    def subnet4(self):
        return self.get_subnet(version=4)

    @property
    def subnet6(self):
        return self.get_subnet(version=6)

    def get_subnet(self, version=4):
        for subnet in self.subnets.all():
            if subnet.ipversion == version:
                return subnet
        return None

    def ip_count(self):
        """Return the total and free IPv4 addresses of the network."""
        total, free = 0, 0
        ip_pools = self.get_ip_pools(locked=False)
        for ip_pool in ip_pools:
            total += ip_pool.pool_size
            free += ip_pool.count_available()
        return total, free

    class InvalidBackendIdError(ValueError):
        def __init__(self, value):
            self.value = value

        def __str__(self):
            return repr(self.value)

    class InvalidBackendMsgError(Exception):
        def __init__(self, opcode, status):
            self.opcode = opcode
            self.status = status

        def __str__(self):
            return repr('<opcode: %s, status: %s>'
                        % (self.opcode, self.status))

    class InvalidActionError(Exception):
        def __init__(self, action):
            self._action = action

        def __str__(self):
            return repr(str(self._action))