Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / neutron / models.py @ 0dae1b9f

History | View | Annotate | Download (10.3 kB)

1 d6b24130 Marios Kogias
# Copyright 2011-2012 GRNET S.A. All rights reserved.
2 d6b24130 Marios Kogias
#
3 d6b24130 Marios Kogias
# Redistribution and use in source and binary forms, with or without
4 d6b24130 Marios Kogias
# modification, are permitted provided that the following conditions
5 d6b24130 Marios Kogias
# are met:
6 d6b24130 Marios Kogias
#
7 d6b24130 Marios Kogias
#   1. Redistributions of source code must retain the above copyright
8 d6b24130 Marios Kogias
#      notice, this list of conditions and the following disclaimer.
9 d6b24130 Marios Kogias
#
10 d6b24130 Marios Kogias
#  2. Redistributions in binary form must reproduce the above copyright
11 d6b24130 Marios Kogias
#     notice, this list of conditions and the following disclaimer in the
12 d6b24130 Marios Kogias
#     documentation and/or other materials provided with the distribution.
13 d6b24130 Marios Kogias
#
14 d6b24130 Marios Kogias
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
15 d6b24130 Marios Kogias
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 d6b24130 Marios Kogias
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 d6b24130 Marios Kogias
# ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
18 d6b24130 Marios Kogias
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 d6b24130 Marios Kogias
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 d6b24130 Marios Kogias
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 d6b24130 Marios Kogias
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 d6b24130 Marios Kogias
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 d6b24130 Marios Kogias
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 d6b24130 Marios Kogias
# SUCH DAMAGE.
25 d6b24130 Marios Kogias
#
26 d6b24130 Marios Kogias
# The views and conclusions contained in the software and documentation are
27 d6b24130 Marios Kogias
# those of the authors and should not be interpreted as representing official
28 d6b24130 Marios Kogias
# policies, either expressed or implied, of GRNET S.A.
29 d6b24130 Marios Kogias
30 d6b24130 Marios Kogias
import datetime
31 d6b24130 Marios Kogias
32 d6b24130 Marios Kogias
from copy import deepcopy
33 d6b24130 Marios Kogias
from django.conf import settings
34 d6b24130 Marios Kogias
from django.db import models
35 d6b24130 Marios Kogias
from django.db import IntegrityError
36 d6b24130 Marios Kogias
37 d6b24130 Marios Kogias
from contextlib import contextmanager
38 d6b24130 Marios Kogias
from hashlib import sha1
39 d6b24130 Marios Kogias
from snf_django.lib.api import faults
40 d6b24130 Marios Kogias
from django.conf import settings as snf_settings
41 d6b24130 Marios Kogias
42 d6b24130 Marios Kogias
from synnefo.db.managers import ForUpdateManager, ProtectedDeleteManager
43 d6b24130 Marios Kogias
from synnefo.db import pools
44 d6b24130 Marios Kogias
45 d6b24130 Marios Kogias
from synnefo.db.models import VirtualMachine, QuotaHolderSerial
46 d6b24130 Marios Kogias
47 d6b24130 Marios Kogias
from synnefo.logic.rapi_pool import (get_rapi_client,
48 d6b24130 Marios Kogias
                                     put_rapi_client)
49 d6b24130 Marios Kogias
50 d6b24130 Marios Kogias
import logging
51 d6b24130 Marios Kogias
log = logging.getLogger(__name__)
52 d6b24130 Marios Kogias
53 d6b24130 Marios Kogias
54 d6b24130 Marios Kogias
class Network(models.Model):
55 d6b24130 Marios Kogias
    OPER_STATES = (
56 d6b24130 Marios Kogias
        ('PENDING', 'Pending'),  # Unused because of lazy networks
57 d6b24130 Marios Kogias
        ('ACTIVE', 'Active'),
58 d6b24130 Marios Kogias
        ('DELETED', 'Deleted'),
59 d6b24130 Marios Kogias
        ('ERROR', 'Error')
60 d6b24130 Marios Kogias
    )
61 d6b24130 Marios Kogias
62 d6b24130 Marios Kogias
    ACTIONS = (
63 d6b24130 Marios Kogias
        ('CREATE', 'Create Network'),
64 d6b24130 Marios Kogias
        ('DESTROY', 'Destroy Network'),
65 d6b24130 Marios Kogias
        ('ADD', 'Add server to Network'),
66 d6b24130 Marios Kogias
        ('REMOVE', 'Remove server from Network'),
67 d6b24130 Marios Kogias
    )
68 d6b24130 Marios Kogias
69 d6b24130 Marios Kogias
    RSAPI_STATE_FROM_OPER_STATE = {
70 d6b24130 Marios Kogias
        'PENDING': 'PENDING',
71 d6b24130 Marios Kogias
        'ACTIVE': 'ACTIVE',
72 d6b24130 Marios Kogias
        'DELETED': 'DELETED',
73 d6b24130 Marios Kogias
        'ERROR': 'ERROR'
74 d6b24130 Marios Kogias
    }
75 d6b24130 Marios Kogias
76 d6b24130 Marios Kogias
    FLAVORS = {
77 d6b24130 Marios Kogias
        'CUSTOM': {
78 d6b24130 Marios Kogias
            'mode': 'bridged',
79 d6b24130 Marios Kogias
            'link': settings.DEFAULT_BRIDGE,
80 d6b24130 Marios Kogias
            'mac_prefix': settings.DEFAULT_MAC_PREFIX,
81 d6b24130 Marios Kogias
            'tags': None,
82 d6b24130 Marios Kogias
            'desc': "Basic flavor used for a bridged network",
83 d6b24130 Marios Kogias
        },
84 d6b24130 Marios Kogias
        'IP_LESS_ROUTED': {
85 d6b24130 Marios Kogias
            'mode': 'routed',
86 d6b24130 Marios Kogias
            'link': settings.DEFAULT_ROUTING_TABLE,
87 d6b24130 Marios Kogias
            'mac_prefix': settings.DEFAULT_MAC_PREFIX,
88 d6b24130 Marios Kogias
            'tags': 'ip-less-routed',
89 d6b24130 Marios Kogias
            'desc': "Flavor used for an IP-less routed network using"
90 d6b24130 Marios Kogias
                    " Proxy ARP",
91 d6b24130 Marios Kogias
        },
92 d6b24130 Marios Kogias
        'MAC_FILTERED': {
93 d6b24130 Marios Kogias
            'mode': 'bridged',
94 d6b24130 Marios Kogias
            'link': settings.DEFAULT_MAC_FILTERED_BRIDGE,
95 d6b24130 Marios Kogias
            'mac_prefix': 'pool',
96 d6b24130 Marios Kogias
            'tags': 'private-filtered',
97 d6b24130 Marios Kogias
            'desc': "Flavor used for bridged networks that offer isolation"
98 d6b24130 Marios Kogias
                    " via filtering packets based on their src "
99 d6b24130 Marios Kogias
                    " MAC (ebtables)",
100 d6b24130 Marios Kogias
        },
101 d6b24130 Marios Kogias
        'PHYSICAL_VLAN': {
102 d6b24130 Marios Kogias
            'mode': 'bridged',
103 d6b24130 Marios Kogias
            'link': 'pool',
104 d6b24130 Marios Kogias
            'mac_prefix': settings.DEFAULT_MAC_PREFIX,
105 d6b24130 Marios Kogias
            'tags': 'physical-vlan',
106 d6b24130 Marios Kogias
            'desc': "Flavor used for bridged network that offer isolation"
107 d6b24130 Marios Kogias
                    " via dedicated physical vlan",
108 d6b24130 Marios Kogias
        },
109 d6b24130 Marios Kogias
    }
110 d6b24130 Marios Kogias
111 d6b24130 Marios Kogias
    name = models.CharField('Network Name', max_length=128)
112 d6b24130 Marios Kogias
    userid = models.CharField('User ID of the owner', max_length=128,
113 d6b24130 Marios Kogias
                              null=True, db_index=True)
114 d6b24130 Marios Kogias
    flavor = models.CharField('Flavor', max_length=32, null=False)
115 d6b24130 Marios Kogias
    mode = models.CharField('Network Mode', max_length=16, null=True)
116 d6b24130 Marios Kogias
    link = models.CharField('Network Link', max_length=32, null=True)
117 d6b24130 Marios Kogias
    mac_prefix = models.CharField('MAC Prefix', max_length=32, null=False)
118 d6b24130 Marios Kogias
    tags = models.CharField('Network Tags', max_length=128, null=True)
119 d6b24130 Marios Kogias
    public = models.BooleanField(default=False, db_index=True)
120 d6b24130 Marios Kogias
    created = models.DateTimeField(auto_now_add=True)
121 d6b24130 Marios Kogias
    updated = models.DateTimeField(auto_now=True)
122 d6b24130 Marios Kogias
    deleted = models.BooleanField('Deleted', default=False, db_index=True)
123 d6b24130 Marios Kogias
    state = models.CharField(choices=OPER_STATES, max_length=32,
124 d6b24130 Marios Kogias
                             default='PENDING')
125 d6b24130 Marios Kogias
    machines = models.ManyToManyField(VirtualMachine,
126 7eae8fce Dionysis Grigoropoulos
                                      through='NetworkInterface',
127 7eae8fce Dionysis Grigoropoulos
                                      related_name='neutron_machines')
128 d6b24130 Marios Kogias
    action = models.CharField(choices=ACTIONS, max_length=32, null=True,
129 d6b24130 Marios Kogias
                              default=None)
130 7eae8fce Dionysis Grigoropoulos
    drained = models.BooleanField("Drained", default=False, null=False)
131 7eae8fce Dionysis Grigoropoulos
    # this is the opposite of admin_state_up
132 d6b24130 Marios Kogias
    floating_ip_pool = models.BooleanField('Floating IP Pool', null=False,
133 d6b24130 Marios Kogias
                                           default=False)
134 d6b24130 Marios Kogias
    #serial = models.ForeignKey(QuotaHolderSerial, related_name='network',
135 d6b24130 Marios Kogias
    #                           null=True)
136 d6b24130 Marios Kogias
137 d6b24130 Marios Kogias
    objects = ForUpdateManager()
138 d6b24130 Marios Kogias
139 d6b24130 Marios Kogias
    def __unicode__(self):
140 d6b24130 Marios Kogias
        return "<Network: %s>" % str(self.id)
141 d6b24130 Marios Kogias
142 d6b24130 Marios Kogias
    @property
143 d6b24130 Marios Kogias
    def backend_id(self):
144 d6b24130 Marios Kogias
        """Return the backend id by prepending backend-prefix."""
145 d6b24130 Marios Kogias
        if not self.id:
146 d6b24130 Marios Kogias
            raise Network.InvalidBackendIdError("self.id is None")
147 d6b24130 Marios Kogias
        return "%snet-%s" % (settings.BACKEND_PREFIX_ID, str(self.id))
148 d6b24130 Marios Kogias
149 d6b24130 Marios Kogias
    @property
150 d6b24130 Marios Kogias
    def backend_tag(self):
151 d6b24130 Marios Kogias
        """Return the network tag to be used in backend
152 d6b24130 Marios Kogias

153 d6b24130 Marios Kogias
        """
154 d6b24130 Marios Kogias
        if self.tags:
155 d6b24130 Marios Kogias
            return self.tags.split(',')
156 d6b24130 Marios Kogias
        else:
157 d6b24130 Marios Kogias
            return []
158 d6b24130 Marios Kogias
159 d6b24130 Marios Kogias
    def create_backend_network(self, backend=None):
160 d6b24130 Marios Kogias
        """Create corresponding BackendNetwork entries."""
161 d6b24130 Marios Kogias
162 d6b24130 Marios Kogias
        backends = [backend] if backend else\
163 d6b24130 Marios Kogias
            Backend.objects.filter(offline=False)
164 d6b24130 Marios Kogias
        for backend in backends:
165 d6b24130 Marios Kogias
            backend_exists =\
166 d6b24130 Marios Kogias
                BackendNetwork.objects.filter(backend=backend, network=self)\
167 d6b24130 Marios Kogias
                                      .exists()
168 d6b24130 Marios Kogias
            if not backend_exists:
169 d6b24130 Marios Kogias
                BackendNetwork.objects.create(backend=backend, network=self)
170 d6b24130 Marios Kogias
171 d6b24130 Marios Kogias
    def get_pool(self, with_lock=True):
172 d6b24130 Marios Kogias
        if not self.pool_id:
173 d6b24130 Marios Kogias
            self.pool = IPPoolTable.objects.create(available_map='',
174 d6b24130 Marios Kogias
                                                   reserved_map='',
175 d6b24130 Marios Kogias
                                                   size=0)
176 d6b24130 Marios Kogias
            self.save()
177 d6b24130 Marios Kogias
        objects = IPPoolTable.objects
178 d6b24130 Marios Kogias
        if with_lock:
179 d6b24130 Marios Kogias
            objects = objects.select_for_update()
180 d6b24130 Marios Kogias
        return objects.get(id=self.pool_id).pool
181 d6b24130 Marios Kogias
182 d6b24130 Marios Kogias
    def reserve_address(self, address):
183 d6b24130 Marios Kogias
        pool = self.get_pool()
184 d6b24130 Marios Kogias
        pool.reserve(address)
185 d6b24130 Marios Kogias
        pool.save()
186 d6b24130 Marios Kogias
187 d6b24130 Marios Kogias
    def release_address(self, address):
188 d6b24130 Marios Kogias
        pool = self.get_pool()
189 d6b24130 Marios Kogias
        pool.put(address)
190 d6b24130 Marios Kogias
        pool.save()
191 d6b24130 Marios Kogias
192 d6b24130 Marios Kogias
    class InvalidBackendIdError(Exception):
193 d6b24130 Marios Kogias
        def __init__(self, value):
194 d6b24130 Marios Kogias
            self.value = value
195 d6b24130 Marios Kogias
196 d6b24130 Marios Kogias
        def __str__(self):
197 d6b24130 Marios Kogias
            return repr(self.value)
198 d6b24130 Marios Kogias
199 d6b24130 Marios Kogias
    class InvalidBackendMsgError(Exception):
200 d6b24130 Marios Kogias
        def __init__(self, opcode, status):
201 d6b24130 Marios Kogias
            self.opcode = opcode
202 d6b24130 Marios Kogias
            self.status = status
203 d6b24130 Marios Kogias
204 d6b24130 Marios Kogias
        def __str__(self):
205 d6b24130 Marios Kogias
            return repr('<opcode: %s, status: %s>'
206 d6b24130 Marios Kogias
                        % (self.opcode, self.status))
207 d6b24130 Marios Kogias
208 d6b24130 Marios Kogias
    class InvalidActionError(Exception):
209 d6b24130 Marios Kogias
        def __init__(self, action):
210 d6b24130 Marios Kogias
            self._action = action
211 d6b24130 Marios Kogias
212 d6b24130 Marios Kogias
        def __str__(self):
213 d6b24130 Marios Kogias
            return repr(str(self._action))
214 d6b24130 Marios Kogias
215 7eae8fce Dionysis Grigoropoulos
216 d6b24130 Marios Kogias
class Subnet(models.Model):
217 882b662f Dionysis Grigoropoulos
    SUBNET_NAME_LENGTH = 128
218 882b662f Dionysis Grigoropoulos
219 7eae8fce Dionysis Grigoropoulos
    network = models.ForeignKey('Network')
220 0dae1b9f Dionysis Grigoropoulos
    name = models.CharField('Network Name', max_length=SUBNET_NAME_LENGTH,
221 0dae1b9f Dionysis Grigoropoulos
                            null=True)
222 7eae8fce Dionysis Grigoropoulos
    ipversion = models.IntegerField('IP Version', default=4)
223 7eae8fce Dionysis Grigoropoulos
    cidr = models.CharField('Subnet', max_length=32, null=True)
224 7eae8fce Dionysis Grigoropoulos
    gateway = models.CharField('Gateway', max_length=32, null=True)
225 7eae8fce Dionysis Grigoropoulos
    dhcp = models.BooleanField('DHCP', default=True)
226 7eae8fce Dionysis Grigoropoulos
227 7eae8fce Dionysis Grigoropoulos
    # Synnefo related fields
228 d6b24130 Marios Kogias
    # subnet6 will be null for IPv4 only networks
229 d6b24130 Marios Kogias
    #pool = models.OneToOneField('IPPoolTable', related_name='network',
230 d6b24130 Marios Kogias
    #                            default=lambda: IPPoolTable.objects.create(
231 d6b24130 Marios Kogias
    #                                                        available_map='',
232 d6b24130 Marios Kogias
    #                                                        reserved_map='',
233 d6b24130 Marios Kogias
    #                                                        size=0),
234 d6b24130 Marios Kogias
    #                           null=True)
235 d6b24130 Marios Kogias
236 0dae1b9f Dionysis Grigoropoulos
    def __unicode__(self):
237 0dae1b9f Dionysis Grigoropoulos
        return "<Subnet %s>" % str(self.id)
238 0dae1b9f Dionysis Grigoropoulos
239 7eae8fce Dionysis Grigoropoulos
240 d6b24130 Marios Kogias
class NetworkInterface(models.Model):
241 d6b24130 Marios Kogias
    STATES = (
242 d6b24130 Marios Kogias
        ("ACTIVE", "Active"),
243 d6b24130 Marios Kogias
        ("BUILDING", "Building"),
244 d6b24130 Marios Kogias
    )
245 d6b24130 Marios Kogias
246 d6b24130 Marios Kogias
    name = models.CharField('Network Name', max_length=128)
247 d6b24130 Marios Kogias
    machine = models.ForeignKey(VirtualMachine, related_name='neutron_nics')
248 d6b24130 Marios Kogias
    network = models.ForeignKey(Network, related_name='neutron_nics')
249 d6b24130 Marios Kogias
    created = models.DateTimeField(auto_now_add=True)
250 d6b24130 Marios Kogias
    updated = models.DateTimeField(auto_now=True)
251 d6b24130 Marios Kogias
    index = models.IntegerField(null=True)
252 d6b24130 Marios Kogias
    mac = models.CharField(max_length=32, null=True, unique=True)
253 d6b24130 Marios Kogias
    ipv4 = models.CharField(max_length=15, null=True)
254 d6b24130 Marios Kogias
    ipv6 = models.CharField(max_length=100, null=True)
255 d6b24130 Marios Kogias
    #firewall_profile = models.CharField(choices=FIREWALL_PROFILES,
256 d6b24130 Marios Kogias
    #                                    max_length=30, null=True)
257 d6b24130 Marios Kogias
    dirty = models.BooleanField(default=False)
258 d6b24130 Marios Kogias
    state = models.CharField(max_length=32, null=False, default="ACTIVE",
259 d6b24130 Marios Kogias
                             choices=STATES)
260 d6b24130 Marios Kogias
    admin_state_up = models.BooleanField(default=False, db_index=True)
261 d6b24130 Marios Kogias
262 d6b24130 Marios Kogias
    def __unicode__(self):
263 d6b24130 Marios Kogias
        return "<%s:vm:%s network:%s ipv4:%s ipv6:%s>" % \
264 d6b24130 Marios Kogias
            (self.index, self.machine_id, self.network_id, self.ipv4,
265 d6b24130 Marios Kogias
             self.ipv6)
266 d6b24130 Marios Kogias
267 d6b24130 Marios Kogias
    @property
268 d6b24130 Marios Kogias
    def is_floating_ip(self):
269 d6b24130 Marios Kogias
        network = self.network
270 d6b24130 Marios Kogias
        if self.ipv4 and network.floating_ip_pool:
271 d6b24130 Marios Kogias
            return network.floating_ips.filter(machine=self.machine,
272 d6b24130 Marios Kogias
                                               ipv4=self.ipv4,
273 d6b24130 Marios Kogias
                                               deleted=False).exists()