Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / logic / networks.py @ a96e84cf

History | View | Annotate | Download (8.2 kB)

1 ece5581b Christos Stavrakakis
# Copyright 2011-2013 GRNET S.A. All rights reserved.
2 ece5581b Christos Stavrakakis
#
3 ece5581b Christos Stavrakakis
# Redistribution and use in source and binary forms, with or
4 ece5581b Christos Stavrakakis
# without modification, are permitted provided that the following
5 ece5581b Christos Stavrakakis
# conditions are met:
6 ece5581b Christos Stavrakakis
#
7 ece5581b Christos Stavrakakis
#   1. Redistributions of source code must retain the above
8 ece5581b Christos Stavrakakis
#      copyright notice, this list of conditions and the following
9 ece5581b Christos Stavrakakis
#      disclaimer.
10 ece5581b Christos Stavrakakis
#
11 ece5581b Christos Stavrakakis
#   2. Redistributions in binary form must reproduce the above
12 ece5581b Christos Stavrakakis
#      copyright notice, this list of conditions and the following
13 ece5581b Christos Stavrakakis
#      disclaimer in the documentation and/or other materials
14 ece5581b Christos Stavrakakis
#      provided with the distribution.
15 ece5581b Christos Stavrakakis
#
16 ece5581b Christos Stavrakakis
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 ece5581b Christos Stavrakakis
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 ece5581b Christos Stavrakakis
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 ece5581b Christos Stavrakakis
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 ece5581b Christos Stavrakakis
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 ece5581b Christos Stavrakakis
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 ece5581b Christos Stavrakakis
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 ece5581b Christos Stavrakakis
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 ece5581b Christos Stavrakakis
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 ece5581b Christos Stavrakakis
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 ece5581b Christos Stavrakakis
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 ece5581b Christos Stavrakakis
# POSSIBILITY OF SUCH DAMAGE.
28 ece5581b Christos Stavrakakis
#
29 ece5581b Christos Stavrakakis
# The views and conclusions contained in the software and
30 ece5581b Christos Stavrakakis
# documentation are those of the authors and should not be
31 ece5581b Christos Stavrakakis
# interpreted as representing official policies, either expressed
32 ece5581b Christos Stavrakakis
# or implied, of GRNET S.A.
33 a4658bbe Christos Stavrakakis
import ipaddr
34 a4658bbe Christos Stavrakakis
35 ece5581b Christos Stavrakakis
from functools import wraps
36 ece5581b Christos Stavrakakis
from django.db import transaction
37 ece5581b Christos Stavrakakis
38 a4658bbe Christos Stavrakakis
from django.conf import settings
39 ece5581b Christos Stavrakakis
from snf_django.lib.api import faults
40 ece5581b Christos Stavrakakis
from synnefo.api import util
41 ece5581b Christos Stavrakakis
from synnefo import quotas
42 8764d304 Christos Stavrakakis
from synnefo.db.models import Network, Backend, Subnet
43 ece5581b Christos Stavrakakis
from synnefo.db.utils import validate_mac
44 ece5581b Christos Stavrakakis
from synnefo.db.pools import EmptyPool
45 b47f167a Christos Stavrakakis
from synnefo.logic import backend as backend_mod
46 ece5581b Christos Stavrakakis
47 ece5581b Christos Stavrakakis
from logging import getLogger
48 ece5581b Christos Stavrakakis
log = getLogger(__name__)
49 ece5581b Christos Stavrakakis
50 ece5581b Christos Stavrakakis
51 ece5581b Christos Stavrakakis
def validate_network_action(network, action):
52 ece5581b Christos Stavrakakis
    if network.deleted:
53 ece5581b Christos Stavrakakis
        raise faults.BadRequest("Network has been deleted.")
54 ece5581b Christos Stavrakakis
55 ece5581b Christos Stavrakakis
56 ece5581b Christos Stavrakakis
def network_command(action):
57 ece5581b Christos Stavrakakis
    def decorator(func):
58 ece5581b Christos Stavrakakis
        @wraps(func)
59 ece5581b Christos Stavrakakis
        @transaction.commit_on_success()
60 ece5581b Christos Stavrakakis
        def wrapper(network, *args, **kwargs):
61 ece5581b Christos Stavrakakis
            validate_network_action(network, action)
62 ece5581b Christos Stavrakakis
            return func(network, *args, **kwargs)
63 ece5581b Christos Stavrakakis
        return wrapper
64 ece5581b Christos Stavrakakis
    return decorator
65 ece5581b Christos Stavrakakis
66 ece5581b Christos Stavrakakis
67 ece5581b Christos Stavrakakis
@transaction.commit_on_success
68 a96e84cf Christos Stavrakakis
def create(userid, name, flavor, subnet=None, gateway=None, subnet6=None,
69 c75ab92e Christos Stavrakakis
           gateway6=None, public=False, dhcp=True, link=None, mac_prefix=None,
70 671db71c Christos Stavrakakis
           mode=None, floating_ip_pool=False, tags=None, backends=None,
71 b47f167a Christos Stavrakakis
           lazy_create=True):
72 ece5581b Christos Stavrakakis
    if flavor is None:
73 ece5581b Christos Stavrakakis
        raise faults.BadRequest("Missing request parameter 'type'")
74 ece5581b Christos Stavrakakis
    elif flavor not in Network.FLAVORS.keys():
75 ece5581b Christos Stavrakakis
        raise faults.BadRequest("Invalid network type '%s'" % flavor)
76 ece5581b Christos Stavrakakis
77 c75ab92e Christos Stavrakakis
    if mac_prefix is not None and flavor == "MAC_FILTERED":
78 c75ab92e Christos Stavrakakis
        raise faults.BadRequest("Can not override MAC_FILTERED mac-prefix")
79 c75ab92e Christos Stavrakakis
    if link is not None and flavor == "PHYSICAL_VLAN":
80 c75ab92e Christos Stavrakakis
        raise faults.BadRequest("Can not override PHYSICAL_VLAN link")
81 c75ab92e Christos Stavrakakis
82 c75ab92e Christos Stavrakakis
    if subnet is None and floating_ip_pool:
83 a96e84cf Christos Stavrakakis
        raise faults.BadRequest("IPv6 only networks can not be floating"
84 c75ab92e Christos Stavrakakis
                                " pools.")
85 ece5581b Christos Stavrakakis
    # Check that network parameters are valid
86 a4658bbe Christos Stavrakakis
    validate_network_params(subnet, gateway, subnet6, gateway6)
87 ece5581b Christos Stavrakakis
88 ece5581b Christos Stavrakakis
    try:
89 c75ab92e Christos Stavrakakis
        fmode, flink, fmac_prefix, ftags = util.values_from_flavor(flavor)
90 ece5581b Christos Stavrakakis
    except EmptyPool:
91 ece5581b Christos Stavrakakis
        log.error("Failed to allocate resources for network of type: %s",
92 ece5581b Christos Stavrakakis
                  flavor)
93 ece5581b Christos Stavrakakis
        msg = "Failed to allocate resources for network."
94 ece5581b Christos Stavrakakis
        raise faults.ServiceUnavailable(msg)
95 c75ab92e Christos Stavrakakis
96 c75ab92e Christos Stavrakakis
    mode = mode or fmode
97 c75ab92e Christos Stavrakakis
    link = link or flink
98 c75ab92e Christos Stavrakakis
    mac_prefix = mac_prefix or fmac_prefix
99 c75ab92e Christos Stavrakakis
    tags = tags or ftags
100 c75ab92e Christos Stavrakakis
101 cbf1a3f3 Christos Stavrakakis
    if (flavor == "IP_LESS_ROUTED" and
102 cbf1a3f3 Christos Stavrakakis
       Network.objects.filter(deleted=False, mode=mode, link=link).exists()):
103 cbf1a3f3 Christos Stavrakakis
        msg = "Link '%s' is already used." % link
104 cbf1a3f3 Christos Stavrakakis
        raise faults.BadRequest(msg)
105 cbf1a3f3 Christos Stavrakakis
106 ece5581b Christos Stavrakakis
    validate_mac(mac_prefix + "0:00:00:00")
107 ece5581b Christos Stavrakakis
108 ece5581b Christos Stavrakakis
    network = Network.objects.create(
109 ece5581b Christos Stavrakakis
        name=name,
110 a96e84cf Christos Stavrakakis
        userid=userid,
111 ece5581b Christos Stavrakakis
        flavor=flavor,
112 ece5581b Christos Stavrakakis
        mode=mode,
113 ece5581b Christos Stavrakakis
        link=link,
114 ece5581b Christos Stavrakakis
        mac_prefix=mac_prefix,
115 ece5581b Christos Stavrakakis
        tags=tags,
116 c75ab92e Christos Stavrakakis
        public=public,
117 c75ab92e Christos Stavrakakis
        floating_ip_pool=floating_ip_pool,
118 ece5581b Christos Stavrakakis
        action='CREATE',
119 ece5581b Christos Stavrakakis
        state='ACTIVE')
120 ece5581b Christos Stavrakakis
121 8764d304 Christos Stavrakakis
    if subnet:
122 8764d304 Christos Stavrakakis
        Subnet.objects.create(network=network,
123 8764d304 Christos Stavrakakis
                              ipversion=4,
124 8764d304 Christos Stavrakakis
                              cidr=subnet,
125 8764d304 Christos Stavrakakis
                              gateway=gateway,
126 8764d304 Christos Stavrakakis
                              dhcp=dhcp)
127 8764d304 Christos Stavrakakis
    if subnet6:
128 8764d304 Christos Stavrakakis
        Subnet.objects.create(network=network,
129 8764d304 Christos Stavrakakis
                              ipversion=6,
130 8764d304 Christos Stavrakakis
                              cidr=subnet6,
131 8764d304 Christos Stavrakakis
                              gateway=gateway6,
132 8764d304 Christos Stavrakakis
                              dhcp=dhcp)
133 8764d304 Christos Stavrakakis
134 ece5581b Christos Stavrakakis
    # Issue commission to Quotaholder and accept it since at the end of
135 ece5581b Christos Stavrakakis
    # this transaction the Network object will be created in the DB.
136 ece5581b Christos Stavrakakis
    # Note: the following call does a commit!
137 48f5b1bc Christos Stavrakakis
    if not public:
138 48f5b1bc Christos Stavrakakis
        quotas.issue_and_accept_commission(network)
139 b47f167a Christos Stavrakakis
140 b47f167a Christos Stavrakakis
    if not lazy_create:
141 b47f167a Christos Stavrakakis
        if floating_ip_pool:
142 b47f167a Christos Stavrakakis
            backends = Backend.objects.filter(offline=False)
143 671db71c Christos Stavrakakis
        elif backends is None:
144 b47f167a Christos Stavrakakis
            backends = []
145 b47f167a Christos Stavrakakis
146 b47f167a Christos Stavrakakis
        for bend in backends:
147 b47f167a Christos Stavrakakis
            network.create_backend_network(bend)
148 b47f167a Christos Stavrakakis
            backend_mod.create_network(network=network, backend=bend,
149 b47f167a Christos Stavrakakis
                                       connect=True)
150 ece5581b Christos Stavrakakis
    return network
151 ece5581b Christos Stavrakakis
152 ece5581b Christos Stavrakakis
153 ece5581b Christos Stavrakakis
@network_command("RENAME")
154 ece5581b Christos Stavrakakis
def rename(network, name):
155 ece5581b Christos Stavrakakis
    network.name = name
156 ece5581b Christos Stavrakakis
    network.save()
157 ece5581b Christos Stavrakakis
    return network
158 ece5581b Christos Stavrakakis
159 ece5581b Christos Stavrakakis
160 ece5581b Christos Stavrakakis
@network_command("DESTROY")
161 ece5581b Christos Stavrakakis
def delete(network):
162 ece5581b Christos Stavrakakis
    if network.machines.exists():
163 a96e84cf Christos Stavrakakis
        raise faults.Conflict("Can not delete network. Servers connected"
164 a96e84cf Christos Stavrakakis
                              " to this network exists.")
165 a96e84cf Christos Stavrakakis
    if network.ips.filter(deleted=False, floating_ip=True).exists():
166 ece5581b Christos Stavrakakis
        msg = "Can not delete netowrk. Network has allocated floating IPs."
167 a96e84cf Christos Stavrakakis
        raise faults.Conflict(msg)
168 ece5581b Christos Stavrakakis
169 ece5581b Christos Stavrakakis
    network.action = "DESTROY"
170 ece5581b Christos Stavrakakis
    network.save()
171 ece5581b Christos Stavrakakis
172 ece5581b Christos Stavrakakis
    # Delete network to all backends that exists
173 b47f167a Christos Stavrakakis
    for bnet in network.backend_networks.exclude(operstate="DELETED"):
174 b47f167a Christos Stavrakakis
        backend_mod.delete_network(network, bnet.backend)
175 b47f167a Christos Stavrakakis
    else:
176 b47f167a Christos Stavrakakis
        # If network does not exist in any backend, update the network state
177 b47f167a Christos Stavrakakis
        backend_mod.update_network_state(network)
178 ece5581b Christos Stavrakakis
    return network
179 a4658bbe Christos Stavrakakis
180 a4658bbe Christos Stavrakakis
181 a4658bbe Christos Stavrakakis
def validate_network_params(subnet=None, gateway=None, subnet6=None,
182 a4658bbe Christos Stavrakakis
                            gateway6=None):
183 a4658bbe Christos Stavrakakis
    if subnet:
184 a4658bbe Christos Stavrakakis
        try:
185 a4658bbe Christos Stavrakakis
            # Use strict option to not all subnets with host bits set
186 a4658bbe Christos Stavrakakis
            network = ipaddr.IPv4Network(subnet, strict=True)
187 a4658bbe Christos Stavrakakis
        except ValueError:
188 a4658bbe Christos Stavrakakis
            raise faults.BadRequest("Invalid network IPv4 subnet")
189 a4658bbe Christos Stavrakakis
190 a4658bbe Christos Stavrakakis
        # Check that network size is allowed!
191 a4658bbe Christos Stavrakakis
        prefixlen = network.prefixlen
192 d311e54f Christos Stavrakakis
        if prefixlen > 29 or prefixlen <= settings.MAX_CIDR_BLOCK:
193 108ef251 Christos Stavrakakis
            raise faults.OverLimit(
194 108ef251 Christos Stavrakakis
                message="Unsupported network size",
195 108ef251 Christos Stavrakakis
                details="Netmask must be in range: (%s, 29]" %
196 108ef251 Christos Stavrakakis
                settings.MAX_CIDR_BLOCK)
197 a4658bbe Christos Stavrakakis
        if gateway:  # Check that gateway belongs to network
198 a4658bbe Christos Stavrakakis
            try:
199 a4658bbe Christos Stavrakakis
                gateway = ipaddr.IPv4Address(gateway)
200 a4658bbe Christos Stavrakakis
            except ValueError:
201 a4658bbe Christos Stavrakakis
                raise faults.BadRequest("Invalid network IPv4 gateway")
202 a4658bbe Christos Stavrakakis
            if not gateway in network:
203 a4658bbe Christos Stavrakakis
                raise faults.BadRequest("Invalid network IPv4 gateway")
204 a4658bbe Christos Stavrakakis
205 a4658bbe Christos Stavrakakis
    if subnet6:
206 a4658bbe Christos Stavrakakis
        try:
207 a4658bbe Christos Stavrakakis
            # Use strict option to not all subnets with host bits set
208 a4658bbe Christos Stavrakakis
            network6 = ipaddr.IPv6Network(subnet6, strict=True)
209 a4658bbe Christos Stavrakakis
        except ValueError:
210 a4658bbe Christos Stavrakakis
            raise faults.BadRequest("Invalid network IPv6 subnet")
211 108ef251 Christos Stavrakakis
        # Check that network6 is an /64 subnet, because this is imposed by
212 108ef251 Christos Stavrakakis
        # 'mac2eui64' utiity.
213 108ef251 Christos Stavrakakis
        if network6.prefixlen != 64:
214 108ef251 Christos Stavrakakis
            msg = ("Unsupported IPv6 subnet size. Network netmask must be"
215 108ef251 Christos Stavrakakis
                   " /64")
216 108ef251 Christos Stavrakakis
            raise faults.BadRequest(msg)
217 a4658bbe Christos Stavrakakis
        if gateway6:
218 a4658bbe Christos Stavrakakis
            try:
219 a4658bbe Christos Stavrakakis
                gateway6 = ipaddr.IPv6Address(gateway6)
220 a4658bbe Christos Stavrakakis
            except ValueError:
221 a4658bbe Christos Stavrakakis
                raise faults.BadRequest("Invalid network IPv6 gateway")
222 a4658bbe Christos Stavrakakis
            if not gateway6 in network6:
223 a4658bbe Christos Stavrakakis
                raise faults.BadRequest("Invalid network IPv6 gateway")