~ubuntu-branches/ubuntu/wily/heat/wily-proposed

« back to all changes in this revision

Viewing changes to heat/engine/resources/neutron/floatingip.py

  • Committer: Package Import Robot
  • Author(s): James Page, Corey Bryant, James Page
  • Date: 2015-03-30 11:11:18 UTC
  • mfrom: (1.1.23)
  • Revision ID: package-import@ubuntu.com-20150330111118-2qpycylx6swu4yhj
Tags: 2015.1~b3-0ubuntu1
[ Corey Bryant ]
* New upstream milestone release for OpenStack kilo:
  - d/control: Align with upstream dependencies.
  - d/p/sudoers_patch.patch: Rebased.
  - d/p/fix-requirements.patch: Rebased.

[ James Page ]
* d/p/fixup-assert-regex.patch: Tweak test to use assertRegexpMatches.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#
2
 
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
3
 
#    not use this file except in compliance with the License. You may obtain
4
 
#    a copy of the License at
5
 
#
6
 
#         http://www.apache.org/licenses/LICENSE-2.0
7
 
#
8
 
#    Unless required by applicable law or agreed to in writing, software
9
 
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
10
 
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
11
 
#    License for the specific language governing permissions and limitations
12
 
#    under the License.
13
 
import six
14
 
 
15
 
from heat.common.i18n import _
16
 
from heat.engine import attributes
17
 
from heat.engine import properties
18
 
from heat.engine.resources.neutron import neutron
19
 
from heat.engine.resources.neutron import port
20
 
from heat.engine.resources.neutron import router
21
 
from heat.engine import support
22
 
 
23
 
 
24
 
class FloatingIP(neutron.NeutronResource):
25
 
    PROPERTIES = (
26
 
        FLOATING_NETWORK_ID, FLOATING_NETWORK,
27
 
        VALUE_SPECS, PORT_ID, FIXED_IP_ADDRESS,
28
 
    ) = (
29
 
        'floating_network_id', 'floating_network',
30
 
        'value_specs', 'port_id', 'fixed_ip_address',
31
 
    )
32
 
 
33
 
    ATTRIBUTES = (
34
 
        ROUTER_ID, TENANT_ID, FLOATING_NETWORK_ID_ATTR, FIXED_IP_ADDRESS_ATTR,
35
 
        FLOATING_IP_ADDRESS_ATTR, PORT_ID_ATTR, SHOW,
36
 
    ) = (
37
 
        'router_id', 'tenant_id', 'floating_network_id', 'fixed_ip_address',
38
 
        'floating_ip_address', 'port_id', 'show',
39
 
    )
40
 
 
41
 
    properties_schema = {
42
 
        FLOATING_NETWORK_ID: properties.Schema(
43
 
            properties.Schema.STRING,
44
 
            support_status=support.SupportStatus(
45
 
                support.DEPRECATED,
46
 
                _('Use property %s.') % FLOATING_NETWORK),
47
 
            required=False
48
 
        ),
49
 
        FLOATING_NETWORK: properties.Schema(
50
 
            properties.Schema.STRING,
51
 
            _('Network to allocate floating IP from.'),
52
 
            required=False,
53
 
            support_status=support.SupportStatus(version='2014.2')
54
 
        ),
55
 
        VALUE_SPECS: properties.Schema(
56
 
            properties.Schema.MAP,
57
 
            _('Extra parameters to include in the "floatingip" object in the '
58
 
              'creation request. Parameters are often specific to installed '
59
 
              'hardware or extensions.'),
60
 
            default={}
61
 
        ),
62
 
        PORT_ID: properties.Schema(
63
 
            properties.Schema.STRING,
64
 
            _('ID of an existing port with at least one IP address to '
65
 
              'associate with this floating IP.'),
66
 
            update_allowed=True
67
 
        ),
68
 
        FIXED_IP_ADDRESS: properties.Schema(
69
 
            properties.Schema.STRING,
70
 
            _('IP address to use if the port has multiple addresses.'),
71
 
            update_allowed=True
72
 
        ),
73
 
    }
74
 
 
75
 
    attributes_schema = {
76
 
        ROUTER_ID: attributes.Schema(
77
 
            _('ID of the router used as gateway, set when associated with a '
78
 
              'port.')
79
 
        ),
80
 
        TENANT_ID: attributes.Schema(
81
 
            _('The tenant owning this floating IP.')
82
 
        ),
83
 
        FLOATING_NETWORK_ID_ATTR: attributes.Schema(
84
 
            _('ID of the network in which this IP is allocated.')
85
 
        ),
86
 
        FIXED_IP_ADDRESS_ATTR: attributes.Schema(
87
 
            _('IP address of the associated port, if specified.')
88
 
        ),
89
 
        FLOATING_IP_ADDRESS_ATTR: attributes.Schema(
90
 
            _('The allocated address of this IP.')
91
 
        ),
92
 
        PORT_ID_ATTR: attributes.Schema(
93
 
            _('ID of the port associated with this IP.')
94
 
        ),
95
 
        SHOW: attributes.Schema(
96
 
            _('All attributes.')
97
 
        ),
98
 
    }
99
 
 
100
 
    def add_dependencies(self, deps):
101
 
        super(FloatingIP, self).add_dependencies(deps)
102
 
 
103
 
        for resource in self.stack.itervalues():
104
 
            # depend on any RouterGateway in this template with the same
105
 
            # network_id as this floating_network_id
106
 
            if resource.has_interface('OS::Neutron::RouterGateway'):
107
 
                gateway_network = resource.properties.get(
108
 
                    router.RouterGateway.NETWORK) or resource.properties.get(
109
 
                        router.RouterGateway.NETWORK_ID)
110
 
                floating_network = self.properties.get(
111
 
                    self.FLOATING_NETWORK) or self.properties.get(
112
 
                        self.FLOATING_NETWORK_ID)
113
 
                if gateway_network == floating_network:
114
 
                    deps += (self, resource)
115
 
 
116
 
            # depend on any RouterInterface in this template which interfaces
117
 
            # with the same subnet that this floating IP's port is assigned
118
 
            # to
119
 
            elif resource.has_interface('OS::Neutron::RouterInterface'):
120
 
 
121
 
                def port_on_subnet(resource, subnet):
122
 
                    if not resource.has_interface('OS::Neutron::Port'):
123
 
                        return False
124
 
                    for fixed_ip in resource.properties.get(
125
 
                            port.Port.FIXED_IPS):
126
 
 
127
 
                        port_subnet = (
128
 
                            fixed_ip.get(port.Port.FIXED_IP_SUBNET)
129
 
                            or fixed_ip.get(port.Port.FIXED_IP_SUBNET_ID))
130
 
                        return subnet == port_subnet
131
 
                    return False
132
 
 
133
 
                interface_subnet = (
134
 
                    resource.properties.get(router.RouterInterface.SUBNET) or
135
 
                    resource.properties.get(router.RouterInterface.SUBNET_ID))
136
 
                for d in deps.graph()[self]:
137
 
                    if port_on_subnet(d, interface_subnet):
138
 
                        deps += (self, resource)
139
 
                        break
140
 
            # depend on Router with EXTERNAL_GATEWAY_NETWORK property
141
 
            # this template with the same network_id as this
142
 
            # floating_network_id
143
 
            elif resource.has_interface('OS::Neutron::Router'):
144
 
                gateway = resource.properties.get(
145
 
                    router.Router.EXTERNAL_GATEWAY)
146
 
                if gateway:
147
 
                    gateway_network = gateway.get(
148
 
                        router.Router.EXTERNAL_GATEWAY_NETWORK)
149
 
                    floating_network = self.properties.get(
150
 
                        self.FLOATING_NETWORK) or self.properties.get(
151
 
                            self.FLOATING_NETWORK_ID)
152
 
                    if gateway_network == floating_network:
153
 
                        deps += (self, resource)
154
 
 
155
 
    def validate(self):
156
 
        super(FloatingIP, self).validate()
157
 
        self._validate_depr_property_required(
158
 
            self.properties, self.FLOATING_NETWORK, self.FLOATING_NETWORK_ID)
159
 
 
160
 
    def handle_create(self):
161
 
        props = self.prepare_properties(
162
 
            self.properties,
163
 
            self.physical_resource_name())
164
 
        self.client_plugin().resolve_network(props, self.FLOATING_NETWORK,
165
 
                                             'floating_network_id')
166
 
        fip = self.neutron().create_floatingip({
167
 
            'floatingip': props})['floatingip']
168
 
        self.resource_id_set(fip['id'])
169
 
 
170
 
    def _show_resource(self):
171
 
        return self.neutron().show_floatingip(self.resource_id)['floatingip']
172
 
 
173
 
    def handle_delete(self):
174
 
        client = self.neutron()
175
 
        try:
176
 
            client.delete_floatingip(self.resource_id)
177
 
        except Exception as ex:
178
 
            self.client_plugin().ignore_not_found(ex)
179
 
 
180
 
    def handle_update(self, json_snippet, tmpl_diff, prop_diff):
181
 
        if prop_diff:
182
 
            neutron_client = self.neutron()
183
 
 
184
 
            port_id = prop_diff.get(self.PORT_ID,
185
 
                                    self.properties.get(self.PORT_ID))
186
 
 
187
 
            fixed_ip_address = prop_diff.get(
188
 
                self.FIXED_IP_ADDRESS,
189
 
                self.properties.get(self.FIXED_IP_ADDRESS))
190
 
 
191
 
            request_body = {
192
 
                'floatingip': {
193
 
                    'port_id': port_id,
194
 
                    'fixed_ip_address': fixed_ip_address}}
195
 
 
196
 
            neutron_client.update_floatingip(self.resource_id, request_body)
197
 
 
198
 
 
199
 
class FloatingIPAssociation(neutron.NeutronResource):
200
 
    PROPERTIES = (
201
 
        FLOATINGIP_ID, PORT_ID, FIXED_IP_ADDRESS,
202
 
    ) = (
203
 
        'floatingip_id', 'port_id', 'fixed_ip_address',
204
 
    )
205
 
 
206
 
    properties_schema = {
207
 
        FLOATINGIP_ID: properties.Schema(
208
 
            properties.Schema.STRING,
209
 
            _('ID of the floating IP to associate.'),
210
 
            required=True,
211
 
            update_allowed=True
212
 
        ),
213
 
        PORT_ID: properties.Schema(
214
 
            properties.Schema.STRING,
215
 
            _('ID of an existing port with at least one IP address to '
216
 
              'associate with this floating IP.'),
217
 
            required=True,
218
 
            update_allowed=True
219
 
        ),
220
 
        FIXED_IP_ADDRESS: properties.Schema(
221
 
            properties.Schema.STRING,
222
 
            _('IP address to use if the port has multiple addresses.'),
223
 
            update_allowed=True
224
 
        ),
225
 
    }
226
 
 
227
 
    def add_dependencies(self, deps):
228
 
        super(FloatingIPAssociation, self).add_dependencies(deps)
229
 
 
230
 
        for resource in six.itervalues(self.stack):
231
 
            if resource.has_interface('OS::Neutron::RouterInterface'):
232
 
 
233
 
                def port_on_subnet(resource, subnet):
234
 
                    if not resource.has_interface('OS::Neutron::Port'):
235
 
                        return False
236
 
                    for fixed_ip in resource.properties.get(
237
 
                            port.Port.FIXED_IPS):
238
 
 
239
 
                        port_subnet = (
240
 
                            fixed_ip.get(port.Port.FIXED_IP_SUBNET)
241
 
                            or fixed_ip.get(port.Port.FIXED_IP_SUBNET_ID))
242
 
                        return subnet == port_subnet
243
 
                    return False
244
 
 
245
 
                interface_subnet = (
246
 
                    resource.properties.get(router.RouterInterface.SUBNET) or
247
 
                    resource.properties.get(router.RouterInterface.SUBNET_ID))
248
 
                for d in deps.graph()[self]:
249
 
                    if port_on_subnet(d, interface_subnet):
250
 
                        deps += (self, resource)
251
 
                        break
252
 
 
253
 
    def handle_create(self):
254
 
        props = self.prepare_properties(self.properties, self.name)
255
 
 
256
 
        floatingip_id = props.pop(self.FLOATINGIP_ID)
257
 
 
258
 
        self.neutron().update_floatingip(floatingip_id, {
259
 
            'floatingip': props})['floatingip']
260
 
        self.resource_id_set('%s:%s' % (floatingip_id, props[self.PORT_ID]))
261
 
 
262
 
    def handle_delete(self):
263
 
        if not self.resource_id:
264
 
            return
265
 
        client = self.neutron()
266
 
        (floatingip_id, port_id) = self.resource_id.split(':')
267
 
        try:
268
 
            client.update_floatingip(
269
 
                floatingip_id,
270
 
                {'floatingip': {'port_id': None}})
271
 
        except Exception as ex:
272
 
            self.client_plugin().ignore_not_found(ex)
273
 
 
274
 
    def handle_update(self, json_snippet, tmpl_diff, prop_diff):
275
 
        if prop_diff:
276
 
            (floatingip_id, port_id) = self.resource_id.split(':')
277
 
            neutron_client = self.neutron()
278
 
            # if the floatingip_id is changed, disassociate the port which
279
 
            # associated with the old floatingip_id
280
 
            if self.FLOATINGIP_ID in prop_diff:
281
 
                try:
282
 
                    neutron_client.update_floatingip(
283
 
                        floatingip_id,
284
 
                        {'floatingip': {'port_id': None}})
285
 
                except Exception as ex:
286
 
                    self.client_plugin().ignore_not_found(ex)
287
 
 
288
 
            # associate the floatingip with the new port
289
 
            floatingip_id = (prop_diff.get(self.FLOATINGIP_ID) or
290
 
                             floatingip_id)
291
 
            port_id = prop_diff.get(self.PORT_ID) or port_id
292
 
 
293
 
            fixed_ip_address = (prop_diff.get(self.FIXED_IP_ADDRESS) or
294
 
                                self.properties.get(self.FIXED_IP_ADDRESS))
295
 
 
296
 
            request_body = {
297
 
                'floatingip': {
298
 
                    'port_id': port_id,
299
 
                    'fixed_ip_address': fixed_ip_address}}
300
 
 
301
 
            neutron_client.update_floatingip(floatingip_id, request_body)
302
 
            self.resource_id_set('%s:%s' % (floatingip_id, port_id))
303
 
 
304
 
 
305
 
def resource_mapping():
306
 
    return {
307
 
        'OS::Neutron::FloatingIP': FloatingIP,
308
 
        'OS::Neutron::FloatingIPAssociation': FloatingIPAssociation,
309
 
    }