Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / logic / ips.py @ 0d1f9117

History | View | Annotate | Download (7 kB)

1 3c96580c Christos Stavrakakis
import logging
2 3c96580c Christos Stavrakakis
3 3c96580c Christos Stavrakakis
from snf_django.lib.api import faults
4 3c96580c Christos Stavrakakis
from django.db import transaction
5 3c96580c Christos Stavrakakis
from synnefo import quotas
6 3c96580c Christos Stavrakakis
from synnefo.db import pools
7 3c96580c Christos Stavrakakis
from synnefo.db.models import (IPPoolTable, IPAddress)
8 3c96580c Christos Stavrakakis
log = logging.getLogger(__name__)
9 3c96580c Christos Stavrakakis
10 3c96580c Christos Stavrakakis
11 3c96580c Christos Stavrakakis
def allocate_ip_from_pools(pool_rows, userid, address=None, floating_ip=False):
12 3c96580c Christos Stavrakakis
    """Try to allocate a value from a number of pools.
13 3c96580c Christos Stavrakakis

14 3c96580c Christos Stavrakakis
    This function takes as argument a number of PoolTable objects and tries to
15 3c96580c Christos Stavrakakis
    allocate a value from them. If all pools are empty EmptyPool is raised.
16 3c96580c Christos Stavrakakis
    If an address is specified and does not belong to any of the pools,
17 3c96580c Christos Stavrakakis
    InvalidValue is raised.
18 3c96580c Christos Stavrakakis

19 3c96580c Christos Stavrakakis
    """
20 3c96580c Christos Stavrakakis
    for pool_row in pool_rows:
21 3c96580c Christos Stavrakakis
        pool = pool_row.pool
22 3c96580c Christos Stavrakakis
        try:
23 3c96580c Christos Stavrakakis
            value = pool.get(value=address)
24 3c96580c Christos Stavrakakis
            pool.save()
25 3c96580c Christos Stavrakakis
            subnet = pool_row.subnet
26 3c96580c Christos Stavrakakis
            ipaddress = IPAddress.objects.create(subnet=subnet,
27 3c96580c Christos Stavrakakis
                                                 network=subnet.network,
28 3c96580c Christos Stavrakakis
                                                 userid=userid,
29 3c96580c Christos Stavrakakis
                                                 address=value,
30 3c96580c Christos Stavrakakis
                                                 floating_ip=floating_ip)
31 3c96580c Christos Stavrakakis
            return ipaddress
32 3c96580c Christos Stavrakakis
        except pools.EmptyPool:
33 3c96580c Christos Stavrakakis
            pass
34 3c96580c Christos Stavrakakis
        except pools.InvalidValue:
35 3c96580c Christos Stavrakakis
            pass
36 3c96580c Christos Stavrakakis
    if address is None:
37 3c96580c Christos Stavrakakis
        raise pools.EmptyPool("No more IP addresses available on pools %s" %
38 3c96580c Christos Stavrakakis
                              pool_rows)
39 3c96580c Christos Stavrakakis
    else:
40 3c96580c Christos Stavrakakis
        raise pools.InvalidValue("Address %s does not belong to pools %s" %
41 3c96580c Christos Stavrakakis
                                 (address, pool_rows))
42 3c96580c Christos Stavrakakis
43 3c96580c Christos Stavrakakis
44 3c96580c Christos Stavrakakis
def allocate_ip(network, userid, address=None, floating_ip=False):
45 3c96580c Christos Stavrakakis
    """Try to allocate an IP from networks IP pools."""
46 3c96580c Christos Stavrakakis
    if network.action == "DESTROY":
47 8d5795b4 Christos Stavrakakis
        raise faults.Conflict("Cannot allocate IP. Network %s is being"
48 3c96580c Christos Stavrakakis
                              " deleted" % network.id)
49 8f335041 Christos Stavrakakis
    elif network.drained:
50 8f335041 Christos Stavrakakis
        raise faults.Conflict("Can not allocate IP while network '%s' is in"
51 8f335041 Christos Stavrakakis
                              " 'SNF:DRAINED' status" % network.id)
52 8f335041 Christos Stavrakakis
53 3c96580c Christos Stavrakakis
    ip_pools = IPPoolTable.objects.select_for_update()\
54 3c96580c Christos Stavrakakis
        .filter(subnet__network=network)
55 3c96580c Christos Stavrakakis
    try:
56 3c96580c Christos Stavrakakis
        return allocate_ip_from_pools(ip_pools, userid, address=address,
57 3c96580c Christos Stavrakakis
                                      floating_ip=floating_ip)
58 3c96580c Christos Stavrakakis
    except pools.EmptyPool:
59 3c96580c Christos Stavrakakis
        raise faults.Conflict("No more IP addresses available on network %s"
60 3c96580c Christos Stavrakakis
                              % network.id)
61 3c96580c Christos Stavrakakis
    except pools.ValueNotAvailable:
62 3c96580c Christos Stavrakakis
        raise faults.Conflict("IP address %s is already used." % address)
63 3c96580c Christos Stavrakakis
    except pools.InvalidValue:
64 3c96580c Christos Stavrakakis
        raise faults.BadRequest("Address %s does not belong to network %s" %
65 3c96580c Christos Stavrakakis
                                (address, network.id))
66 3c96580c Christos Stavrakakis
67 3c96580c Christos Stavrakakis
68 3aecadc8 Christos Stavrakakis
def allocate_public_ip(userid, floating_ip=False, backend=None, networks=None):
69 3c96580c Christos Stavrakakis
    """Try to allocate a public or floating IP address.
70 3c96580c Christos Stavrakakis

71 3c96580c Christos Stavrakakis
    Try to allocate a a public IPv4 address from one of the available networks.
72 3c96580c Christos Stavrakakis
    If 'floating_ip' is set, only networks which are floating IP pools will be
73 3c96580c Christos Stavrakakis
    used and the IPAddress that will be created will be marked as a floating
74 3c96580c Christos Stavrakakis
    IP. If 'backend' is set, only the networks that exist in this backend will
75 3c96580c Christos Stavrakakis
    be used.
76 3c96580c Christos Stavrakakis

77 3c96580c Christos Stavrakakis
    """
78 3c96580c Christos Stavrakakis
79 3c96580c Christos Stavrakakis
    ip_pool_rows = IPPoolTable.objects.select_for_update()\
80 3c96580c Christos Stavrakakis
        .prefetch_related("subnet__network")\
81 3c96580c Christos Stavrakakis
        .filter(subnet__deleted=False)\
82 3c96580c Christos Stavrakakis
        .filter(subnet__network__deleted=False)\
83 3c96580c Christos Stavrakakis
        .filter(subnet__network__public=True)\
84 3c96580c Christos Stavrakakis
        .filter(subnet__network__drained=False)
85 3aecadc8 Christos Stavrakakis
    if networks is not None:
86 3aecadc8 Christos Stavrakakis
        ip_pool_rows = ip_pool_rows.filter(subnet__network__in=networks)
87 3c96580c Christos Stavrakakis
    if floating_ip:
88 3c96580c Christos Stavrakakis
        ip_pool_rows = ip_pool_rows\
89 3c96580c Christos Stavrakakis
            .filter(subnet__network__floating_ip_pool=True)
90 3c96580c Christos Stavrakakis
    if backend is not None:
91 3c96580c Christos Stavrakakis
        ip_pool_rows = ip_pool_rows\
92 3c96580c Christos Stavrakakis
            .filter(subnet__network__backend_networks__backend=backend)
93 3c96580c Christos Stavrakakis
94 3c96580c Christos Stavrakakis
    try:
95 3c96580c Christos Stavrakakis
        return allocate_ip_from_pools(ip_pool_rows, userid,
96 3c96580c Christos Stavrakakis
                                      floating_ip=floating_ip)
97 3c96580c Christos Stavrakakis
    except pools.EmptyPool:
98 3c96580c Christos Stavrakakis
        ip_type = "floating" if floating_ip else "public"
99 3c96580c Christos Stavrakakis
        log_msg = "Failed to allocate a %s IP. Reason:" % ip_type
100 3c96580c Christos Stavrakakis
        if ip_pool_rows:
101 3c96580c Christos Stavrakakis
            log_msg += " No network exists."
102 3c96580c Christos Stavrakakis
        else:
103 3c96580c Christos Stavrakakis
            log_msg += " All network are full."
104 3c96580c Christos Stavrakakis
        if backend is not None:
105 3c96580c Christos Stavrakakis
            log_msg += " Backend: %s" % backend
106 3c96580c Christos Stavrakakis
        log.error(log_msg)
107 8d5795b4 Christos Stavrakakis
        exception_msg = "Cannot allocate a %s IP address." % ip_type
108 3aecadc8 Christos Stavrakakis
        raise faults.Conflict(exception_msg)
109 3c96580c Christos Stavrakakis
110 3c96580c Christos Stavrakakis
111 3c96580c Christos Stavrakakis
@transaction.commit_on_success
112 3c96580c Christos Stavrakakis
def create_floating_ip(userid, network=None, address=None):
113 3c96580c Christos Stavrakakis
    if network is None:
114 3c96580c Christos Stavrakakis
        floating_ip = allocate_public_ip(userid, floating_ip=True)
115 3c96580c Christos Stavrakakis
    else:
116 3c96580c Christos Stavrakakis
        if not network.floating_ip_pool:
117 8d5795b4 Christos Stavrakakis
            msg = ("Cannot allocate floating IP. Network %s is"
118 3c96580c Christos Stavrakakis
                   " not a floating IP pool.")
119 3c96580c Christos Stavrakakis
            raise faults.Conflict(msg % network.id)
120 3c96580c Christos Stavrakakis
        if network.action == "DESTROY":
121 8d5795b4 Christos Stavrakakis
            msg = "Cannot allocate floating IP. Network %s is being deleted."
122 3c96580c Christos Stavrakakis
            raise faults.Conflict(msg % network.id)
123 3c96580c Christos Stavrakakis
124 3c96580c Christos Stavrakakis
        # Allocate the floating IP
125 3c96580c Christos Stavrakakis
        floating_ip = allocate_ip(network, userid, address=address,
126 3c96580c Christos Stavrakakis
                                  floating_ip=True)
127 3c96580c Christos Stavrakakis
128 3c96580c Christos Stavrakakis
    # Issue commission (quotas)
129 3c96580c Christos Stavrakakis
    quotas.issue_and_accept_commission(floating_ip)
130 3c96580c Christos Stavrakakis
    transaction.commit()
131 3c96580c Christos Stavrakakis
132 3c96580c Christos Stavrakakis
    log.info("Created floating IP '%s' for user IP '%s'", floating_ip, userid)
133 3c96580c Christos Stavrakakis
134 3c96580c Christos Stavrakakis
    return floating_ip
135 3c96580c Christos Stavrakakis
136 3c96580c Christos Stavrakakis
137 3aecadc8 Christos Stavrakakis
def get_free_floating_ip(userid, network=None):
138 3aecadc8 Christos Stavrakakis
    """Get one of the free available floating IPs of the user.
139 3aecadc8 Christos Stavrakakis

140 3aecadc8 Christos Stavrakakis
    Get one of the users floating IPs that is not connected to any port
141 3aecadc8 Christos Stavrakakis
    or server. If network is specified, the floating IP must be from
142 3aecadc8 Christos Stavrakakis
    that network.
143 3aecadc8 Christos Stavrakakis

144 3aecadc8 Christos Stavrakakis
    """
145 3aecadc8 Christos Stavrakakis
    floating_ips = IPAddress.objects\
146 3aecadc8 Christos Stavrakakis
                            .filter(userid=userid, deleted=False, nic=None)
147 3aecadc8 Christos Stavrakakis
    if network is not None:
148 3aecadc8 Christos Stavrakakis
        floating_ips = floating_ips.filter(network=network)
149 3aecadc8 Christos Stavrakakis
150 3aecadc8 Christos Stavrakakis
    for floating_ip in floating_ips:
151 3aecadc8 Christos Stavrakakis
        floating_ip = IPAddress.objects.select_for_update()\
152 3aecadc8 Christos Stavrakakis
                                       .get(id=floating_ip.id)
153 3aecadc8 Christos Stavrakakis
        if floating_ip.nic is None:
154 3aecadc8 Christos Stavrakakis
            return floating_ip
155 3aecadc8 Christos Stavrakakis
156 3aecadc8 Christos Stavrakakis
    msg = "Cannot allocate a floating IP for connecting new server to"
157 3aecadc8 Christos Stavrakakis
    if network is not None:
158 3aecadc8 Christos Stavrakakis
        msg += " network '%s'." % network.id
159 3aecadc8 Christos Stavrakakis
    else:
160 3aecadc8 Christos Stavrakakis
        msg += " a public network."
161 3aecadc8 Christos Stavrakakis
    msg += " Please create more floating IPs."
162 3aecadc8 Christos Stavrakakis
    raise faults.Conflict(msg)
163 3aecadc8 Christos Stavrakakis
164 3aecadc8 Christos Stavrakakis
165 3c96580c Christos Stavrakakis
@transaction.commit_on_success
166 3c96580c Christos Stavrakakis
def delete_floating_ip(floating_ip):
167 3c96580c Christos Stavrakakis
    if floating_ip.nic:
168 3c96580c Christos Stavrakakis
        # This is safe, you also need for_update to attach floating IP to
169 3c96580c Christos Stavrakakis
        # instance.
170 3c96580c Christos Stavrakakis
        msg = "Floating IP '%s' is attached to instance." % floating_ip.id
171 3c96580c Christos Stavrakakis
        raise faults.Conflict(msg)
172 3c96580c Christos Stavrakakis
173 3c96580c Christos Stavrakakis
    # Return the address of the floating IP back to pool
174 3c96580c Christos Stavrakakis
    floating_ip.release_address()
175 3c96580c Christos Stavrakakis
    # And mark the floating IP as deleted
176 3c96580c Christos Stavrakakis
    floating_ip.deleted = True
177 3c96580c Christos Stavrakakis
    floating_ip.save()
178 3c96580c Christos Stavrakakis
    # Release quota for floating IP
179 3c96580c Christos Stavrakakis
    quotas.issue_and_accept_commission(floating_ip, delete=True)
180 3c96580c Christos Stavrakakis
    transaction.commit()
181 3c96580c Christos Stavrakakis
    # Delete the floating IP from DB
182 3c96580c Christos Stavrakakis
    log.info("Deleted floating IP '%s' of user '%s", floating_ip,
183 3c96580c Christos Stavrakakis
             floating_ip.userid)
184 3c96580c Christos Stavrakakis
    floating_ip.delete()