Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / neutron / models.py @ 5cf968ab

History | View | Annotate | Download (8.2 kB)

1
# Copyright 2011-2012 GRNET S.A. All rights reserved.
2
#
3
# Redistribution and use in source and binary forms, with or without
4
# modification, are permitted provided that the following conditions
5
# are met:
6
#
7
#   1. Redistributions of source code must retain the above copyright
8
#      notice, this list of conditions and the following disclaimer.
9
#
10
#  2. Redistributions in binary form must reproduce the above copyright
11
#     notice, this list of conditions and the following disclaimer in the
12
#     documentation and/or other materials provided with the distribution.
13
#
14
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
15
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17
# ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
18
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24
# SUCH DAMAGE.
25
#
26
# The views and conclusions contained in the software and documentation are
27
# those of the authors and should not be interpreted as representing official
28
# policies, either expressed or implied, of GRNET S.A.
29

    
30
import datetime
31

    
32
from copy import deepcopy
33
from django.conf import settings
34
from django.db import models
35
from django.db import IntegrityError
36

    
37
from contextlib import contextmanager
38
from hashlib import sha1
39
from snf_django.lib.api import faults
40
from django.conf import settings as snf_settings
41

    
42
from synnefo.db.managers import ForUpdateManager, ProtectedDeleteManager
43
from synnefo.db import pools
44

    
45
from synnefo.db.models import VirtualMachine, QuotaHolderSerial
46

    
47
from synnefo.logic.rapi_pool import (get_rapi_client,
48
                                     put_rapi_client)
49

    
50
import logging
51
log = logging.getLogger(__name__)
52

    
53

    
54
class Network(models.Model):
55
    OPER_STATES = (
56
        ('PENDING', 'Pending'),  # Unused because of lazy networks
57
        ('ACTIVE', 'Active'),
58
        ('DELETED', 'Deleted'),
59
        ('ERROR', 'Error')
60
    )
61

    
62
    ACTIONS = (
63
        ('CREATE', 'Create Network'),
64
        ('DESTROY', 'Destroy Network'),
65
        ('ADD', 'Add server to Network'),
66
        ('REMOVE', 'Remove server from Network'),
67
    )
68

    
69
    RSAPI_STATE_FROM_OPER_STATE = {
70
        'PENDING': 'PENDING',
71
        'ACTIVE': 'ACTIVE',
72
        'DELETED': 'DELETED',
73
        'ERROR': 'ERROR'
74
    }
75

    
76
    FLAVORS = {
77
        'CUSTOM': {
78
            'mode': 'bridged',
79
            'link': settings.DEFAULT_BRIDGE,
80
            'mac_prefix': settings.DEFAULT_MAC_PREFIX,
81
            'tags': None,
82
            'desc': "Basic flavor used for a bridged network",
83
        },
84
        'IP_LESS_ROUTED': {
85
            'mode': 'routed',
86
            'link': settings.DEFAULT_ROUTING_TABLE,
87
            'mac_prefix': settings.DEFAULT_MAC_PREFIX,
88
            'tags': 'ip-less-routed',
89
            'desc': "Flavor used for an IP-less routed network using"
90
                    " Proxy ARP",
91
        },
92
        'MAC_FILTERED': {
93
            'mode': 'bridged',
94
            'link': settings.DEFAULT_MAC_FILTERED_BRIDGE,
95
            'mac_prefix': 'pool',
96
            'tags': 'private-filtered',
97
            'desc': "Flavor used for bridged networks that offer isolation"
98
                    " via filtering packets based on their src "
99
                    " MAC (ebtables)",
100
        },
101
        'PHYSICAL_VLAN': {
102
            'mode': 'bridged',
103
            'link': 'pool',
104
            'mac_prefix': settings.DEFAULT_MAC_PREFIX,
105
            'tags': 'physical-vlan',
106
            'desc': "Flavor used for bridged network that offer isolation"
107
                    " via dedicated physical vlan",
108
        },
109
    }
110

    
111
    name = models.CharField('Network Name', max_length=128)
112
    userid = models.CharField('User ID of the owner', max_length=128,
113
                              null=True, db_index=True)
114
    flavor = models.CharField('Flavor', max_length=32, null=False)
115
    mode = models.CharField('Network Mode', max_length=16, null=True)
116
    link = models.CharField('Network Link', max_length=32, null=True)
117
    mac_prefix = models.CharField('MAC Prefix', max_length=32, null=False)
118
    tags = models.CharField('Network Tags', max_length=128, null=True)
119
    public = models.BooleanField(default=False, db_index=True)
120
    created = models.DateTimeField(auto_now_add=True)
121
    updated = models.DateTimeField(auto_now=True)
122
    deleted = models.BooleanField('Deleted', default=False, db_index=True)
123
    state = models.CharField(choices=OPER_STATES, max_length=32,
124
                             default='PENDING')
125
    machines = models.ManyToManyField(VirtualMachine,
126
                                      through='NetworkInterface',
127
                                      related_name='neutron_networks')
128
    action = models.CharField(choices=ACTIONS, max_length=32, null=True,
129
                              default=None)
130
    drained = models.BooleanField("Drained", default=False, null=False)
131
    # this is the opposite of admin_state_up
132
    floating_ip_pool = models.BooleanField('Floating IP Pool', null=False,
133
                                           default=False)
134
    #serial = models.ForeignKey(QuotaHolderSerial, related_name='network',
135
    #                           null=True)
136

    
137
    public = models.BooleanField('public', default=True)
138
    objects = ForUpdateManager()
139

    
140

    
141
class Subnet(models.Model):
142
    SUBNET_NAME_LENGTH = 128
143

    
144
    network = models.ForeignKey('Network')
145
    name = models.CharField('Network Name', max_length=SUBNET_NAME_LENGTH,
146
                            null=True)
147
    ipversion = models.IntegerField('IP Version', default=4)
148
    cidr = models.CharField('Subnet', max_length=32, null=True)
149
    gateway = models.CharField('Gateway', max_length=32, null=True)
150
    dhcp = models.BooleanField('DHCP', default=True)
151

    
152
    # Synnefo related fields
153
    # subnet6 will be null for IPv4 only networks
154
    #pool = models.OneToOneField('IPPoolTable', related_name='network',
155
    #                            default=lambda: IPPoolTable.objects.create(
156
    #                                                        available_map='',
157
    #                                                        reserved_map='',
158
    #                                                        size=0),
159
    #                           null=True)
160

    
161
    def __unicode__(self):
162
        return "<Subnet %s>" % str(self.id)
163

    
164

    
165
class NetworkInterface(models.Model):
166
    STATES = (
167
        ("ACTIVE", "Active"),
168
        ("BUILDING", "Building"),
169
    )
170

    
171
    name = models.CharField('nic name', max_length=128)
172
    machine = models.ForeignKey(VirtualMachine, null=True,
173
                                related_name='neutron_nics')
174
    network = models.ForeignKey(Network, related_name='neutron_nics')
175
    subnet = models.ForeignKey(Subnet, related_name='neutron_nics', null=True)
176
    created = models.DateTimeField(auto_now_add=True)
177
    updated = models.DateTimeField(auto_now=True)
178
    index = models.IntegerField(null=True)
179
    mac = models.CharField(max_length=32, null=True, unique=True)
180
    ipv4 = models.CharField(max_length=15, null=True)
181
    ipv6 = models.CharField(max_length=100, null=True)
182
    #firewall_profile = models.CharField(choices=FIREWALL_PROFILES,
183
    #                                    max_length=30, null=True)
184
    dirty = models.BooleanField(default=False)
185
    state = models.CharField(max_length=32, null=False, default="ACTIVE",
186
                             choices=STATES)
187
    admin_state_up = models.BooleanField(default=False, db_index=True)
188

    
189
    def __unicode__(self):
190
        return "<%s:vm:%s network:%s ipv4:%s ipv6:%s>" % \
191
            (self.index, self.machine_id, self.network_id, self.ipv4,
192
             self.ipv6)
193

    
194
    @property
195
    def is_floating_ip(self):
196
        network = self.network
197
        if self.ipv4 and network.floating_ip_pool:
198
            return network.floating_ips.filter(machine=self.machine,
199
                                               ipv4=self.ipv4,
200
                                               deleted=False).exists()