~raxnetworking/nova/bare_bones_melange

« back to all changes in this revision

Viewing changes to nova/network/quantum/melange_ipam_lib.py

  • Committer: Rajaram Mallya
  • Date: 2011-09-12 10:03:21 UTC
  • mfrom: (1265.2.287 nova)
  • Revision ID: rajarammallya@gmail.com-20110912100321-8zw8575a206dc026
Merged from nova trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# vim: tabstop=4 shiftwidth=4 softtabstop=4
 
2
 
 
3
# Copyright 2011 Nicira Networks, Inc
 
4
# All Rights Reserved.
 
5
#
 
6
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
 
7
#    not use this file except in compliance with the License. You may obtain
 
8
#    a copy of the License at
 
9
#
 
10
#         http://www.apache.org/licenses/LICENSE-2.0
 
11
#
 
12
#    Unless required by applicable law or agreed to in writing, software
 
13
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 
14
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 
15
#    License for the specific language governing permissions and limitations
 
16
#    under the License.
 
17
 
 
18
from netaddr import IPNetwork
 
19
 
 
20
from nova import db
 
21
from nova import exception
 
22
from nova import flags
 
23
from nova import log as logging
 
24
from nova.network.quantum import melange_connection
 
25
 
 
26
 
 
27
LOG = logging.getLogger("nova.network.quantum.melange_ipam_lib")
 
28
 
 
29
FLAGS = flags.FLAGS
 
30
 
 
31
 
 
32
def get_ipam_lib(net_man):
 
33
    return QuantumMelangeIPAMLib()
 
34
 
 
35
 
 
36
class QuantumMelangeIPAMLib(object):
 
37
    """Implements Quantum IP Address Management (IPAM) interface
 
38
       using the Melange service, which is access using the Melange
 
39
       web services API.
 
40
    """
 
41
 
 
42
    def __init__(self):
 
43
        """Initialize class used to connect to Melange server"""
 
44
        self.m_conn = melange_connection.MelangeConnection()
 
45
 
 
46
    def create_subnet(self, context, label, project_id,
 
47
                      quantum_net_id, priority, cidr=None,
 
48
                      gateway_v6=None, cidr_v6=None,
 
49
                      dns1=None, dns2=None):
 
50
        """Contact Melange and create a subnet for any non-NULL
 
51
           IPv4 or IPv6 subnets.
 
52
 
 
53
           Also create a entry in the Nova networks DB, but only
 
54
           to store values not represented in Melange or to
 
55
           temporarily provide compatibility with Nova code that
 
56
           accesses IPAM data directly via the DB (e.g., nova-api)
 
57
        """
 
58
        tenant_id = project_id or FLAGS.quantum_default_tenant_id
 
59
        if cidr:
 
60
            self.m_conn.create_block(quantum_net_id, cidr,
 
61
                                     project_id=tenant_id,
 
62
                                     dns1=dns1, dns2=dns2)
 
63
        if cidr_v6:
 
64
            self.m_conn.create_block(quantum_net_id, cidr_v6,
 
65
                                     project_id=tenant_id,
 
66
                                     dns1=dns1, dns2=dns2)
 
67
 
 
68
        net = {"uuid": quantum_net_id,
 
69
               "project_id": project_id,
 
70
               "priority": priority,
 
71
               "label": label}
 
72
        admin_context = context.elevated()
 
73
        network = db.network_create_safe(admin_context, net)
 
74
 
 
75
    def allocate_fixed_ip(self, context, project_id, quantum_net_id, vif_ref):
 
76
        """Pass call to allocate fixed IP on to Melange"""
 
77
        tenant_id = project_id or FLAGS.quantum_default_tenant_id
 
78
        self.m_conn.allocate_ip(quantum_net_id,
 
79
                                vif_ref['uuid'], project_id=tenant_id,
 
80
                                mac_address=vif_ref['address'])
 
81
 
 
82
    def get_network_id_by_cidr(self, context, cidr, project_id):
 
83
        """Find the Quantum UUID associated with a IPv4 CIDR
 
84
           address for the specified tenant.
 
85
        """
 
86
        tenant_id = project_id or FLAGS.quantum_default_tenant_id
 
87
        all_blocks = self.m_conn.get_blocks(tenant_id)
 
88
        for b in all_blocks['ip_blocks']:
 
89
            if b['cidr'] == cidr:
 
90
                return b['network_id']
 
91
        raise exception.NotFound(_("No network found for cidr %s" % cidr))
 
92
 
 
93
    def delete_subnets_by_net_id(self, context, net_id, project_id):
 
94
        """Find Melange block associated with the Quantum UUID,
 
95
           then tell Melange to delete that block.
 
96
        """
 
97
        admin_context = context.elevated()
 
98
        tenant_id = project_id or FLAGS.quantum_default_tenant_id
 
99
        all_blocks = self.m_conn.get_blocks(tenant_id)
 
100
        for b in all_blocks['ip_blocks']:
 
101
            if b['network_id'] == net_id:
 
102
                self.m_conn.delete_block(b['id'], tenant_id)
 
103
 
 
104
        network = db.network_get_by_uuid(admin_context, net_id)
 
105
        db.network_delete_safe(context, network['id'])
 
106
 
 
107
    def get_project_and_global_net_ids(self, context, project_id):
 
108
        """Fetches all networks associated with this project, or
 
109
           that are "global" (i.e., have no project set).
 
110
           Returns list sorted by 'priority' (lowest integer value
 
111
           is highest priority).
 
112
        """
 
113
        if project_id is None:
 
114
            raise Exception(_("get_project_and_global_net_ids must be called"
 
115
                              " with a non-null project_id"))
 
116
 
 
117
        admin_context = context.elevated()
 
118
 
 
119
        # Decorate with priority
 
120
        priority_nets = []
 
121
        for tenant_id in (project_id, FLAGS.quantum_default_tenant_id):
 
122
            blocks = self.m_conn.get_blocks(tenant_id)
 
123
            for ip_block in blocks['ip_blocks']:
 
124
                network_id = ip_block['network_id']
 
125
                network = db.network_get_by_uuid(admin_context, network_id)
 
126
                if network:
 
127
                    priority = network['priority']
 
128
                    priority_nets.append((priority, network_id, tenant_id))
 
129
 
 
130
        # Sort by priority
 
131
        priority_nets.sort()
 
132
 
 
133
        # Undecorate
 
134
        return [(network_id, tenant_id)
 
135
                for priority, network_id, tenant_id in priority_nets]
 
136
 
 
137
    def get_subnets_by_net_id(self, context, project_id, net_id):
 
138
        """Returns information about the IPv4 and IPv6 subnets
 
139
           associated with a Quantum Network UUID.
 
140
        """
 
141
 
 
142
        # FIXME(danwent):  Melange actually returns the subnet info
 
143
        # when we query for a particular interface.  We may want to
 
144
        # rework the ipam_manager python API to let us take advantage of
 
145
        # this, as right now we have to get all blocks and cycle through
 
146
        # them.
 
147
        subnet_v4 = None
 
148
        subnet_v6 = None
 
149
        tenant_id = project_id or FLAGS.quantum_default_tenant_id
 
150
        all_blocks = self.m_conn.get_blocks(tenant_id)
 
151
        for b in all_blocks['ip_blocks']:
 
152
            if b['network_id'] == net_id:
 
153
                subnet = {'network_id': b['network_id'],
 
154
                          'cidr': b['cidr'],
 
155
                          'gateway': b['gateway'],
 
156
                          'broadcast': b['broadcast'],
 
157
                          'netmask': b['netmask'],
 
158
                          'dns1': b['dns1'],
 
159
                          'dns2': b['dns2']}
 
160
 
 
161
                if IPNetwork(b['cidr']).version == 6:
 
162
                    subnet_v6 = subnet
 
163
                else:
 
164
                    subnet_v4 = subnet
 
165
        return (subnet_v4, subnet_v6)
 
166
 
 
167
    def get_v4_ips_by_interface(self, context, net_id, vif_id, project_id):
 
168
        """Returns a list of IPv4 address strings associated with
 
169
           the specified virtual interface.
 
170
        """
 
171
        return self._get_ips_by_interface(context, net_id, vif_id,
 
172
                                                        project_id, 4)
 
173
 
 
174
    def get_v6_ips_by_interface(self, context, net_id, vif_id, project_id):
 
175
        """Returns a list of IPv6 address strings associated with
 
176
           the specified virtual interface.
 
177
        """
 
178
        return self._get_ips_by_interface(context, net_id, vif_id,
 
179
                                                        project_id, 6)
 
180
 
 
181
    def _get_ips_by_interface(self, context, net_id, vif_id, project_id,
 
182
                                                               ip_version):
 
183
        """Helper method to fetch v4 or v6 addresses for a particular
 
184
           virtual interface.
 
185
        """
 
186
        tenant_id = project_id or FLAGS.quantum_default_tenant_id
 
187
        ip_list = self.m_conn.get_allocated_ips(net_id, vif_id, tenant_id)
 
188
        return [ip['address'] for ip in ip_list
 
189
                if IPNetwork(ip['address']).version == ip_version]
 
190
 
 
191
    def verify_subnet_exists(self, context, project_id, quantum_net_id):
 
192
        """Confirms that a subnet exists that is associated with the
 
193
           specified Quantum Network UUID.
 
194
        """
 
195
        tenant_id = project_id or FLAGS.quantum_default_tenant_id
 
196
        v4_subnet, v6_subnet = self.get_subnets_by_net_id(context, tenant_id,
 
197
                                    quantum_net_id)
 
198
        return v4_subnet is not None
 
199
 
 
200
    def deallocate_ips_by_vif(self, context, project_id, net_id, vif_ref):
 
201
        """Deallocate all fixed IPs associated with the specified
 
202
           virtual interface.
 
203
        """
 
204
        tenant_id = project_id or FLAGS.quantum_default_tenant_id
 
205
        self.m_conn.deallocate_ips(net_id, vif_ref['uuid'], tenant_id)