root / snf-cyclades-app / synnefo / neutron / models.py @ 2e0916f2
History | View | Annotate | Download (8.1 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, related_name='neutron_nics')
|
173 |
network = models.ForeignKey(Network, related_name='neutron_nics')
|
174 |
subnet = models.ForeignKey(Subnet, related_names='neutron_nics')
|
175 |
created = models.DateTimeField(auto_now_add=True)
|
176 |
updated = models.DateTimeField(auto_now=True)
|
177 |
index = models.IntegerField(null=True)
|
178 |
mac = models.CharField(max_length=32, null=True, unique=True) |
179 |
ipv4 = models.CharField(max_length=15, null=True) |
180 |
ipv6 = models.CharField(max_length=100, null=True) |
181 |
#firewall_profile = models.CharField(choices=FIREWALL_PROFILES,
|
182 |
# max_length=30, null=True)
|
183 |
dirty = models.BooleanField(default=False)
|
184 |
state = models.CharField(max_length=32, null=False, default="ACTIVE", |
185 |
choices=STATES) |
186 |
admin_state_up = models.BooleanField(default=False, db_index=True) |
187 |
|
188 |
def __unicode__(self): |
189 |
return "<%s:vm:%s network:%s ipv4:%s ipv6:%s>" % \ |
190 |
(self.index, self.machine_id, self.network_id, self.ipv4, |
191 |
self.ipv6)
|
192 |
|
193 |
@property
|
194 |
def is_floating_ip(self): |
195 |
network = self.network
|
196 |
if self.ipv4 and network.floating_ip_pool: |
197 |
return network.floating_ips.filter(machine=self.machine, |
198 |
ipv4=self.ipv4,
|
199 |
deleted=False).exists()
|
200 |
|
201 |
|
202 |
|