7d3111f941
This moves the client creation code out of Clients._neutron() into its own client plugin. Neutron is an integrated project, and python-neutronclient is a dependency, so the import is now mandatory. Also any conditional code which skipped if the neutron client was missing has been removed, since the presense or absense of an installed neutronclient has no bearing on whether neutron is installed on a given cloud. Change-Id: Id9fdc50e80efe78731e21934ed9f2704cc3eb408
224 lines
8.2 KiB
Python
224 lines
8.2 KiB
Python
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
from heat.engine import attributes
|
|
from heat.engine import properties
|
|
from heat.engine.resources.neutron import neutron
|
|
from heat.engine.resources.neutron import neutron_utils
|
|
from heat.engine.resources.neutron import router
|
|
from heat.engine import support
|
|
|
|
from neutronclient.common.exceptions import NeutronClientException
|
|
|
|
|
|
class FloatingIP(neutron.NeutronResource):
|
|
PROPERTIES = (
|
|
FLOATING_NETWORK_ID, FLOATING_NETWORK,
|
|
VALUE_SPECS, PORT_ID, FIXED_IP_ADDRESS,
|
|
) = (
|
|
'floating_network_id', 'floating_network',
|
|
'value_specs', 'port_id', 'fixed_ip_address',
|
|
)
|
|
|
|
ATTRIBUTES = (
|
|
ROUTER_ID, TENANT_ID, FLOATING_NETWORK_ID_ATTR, FIXED_IP_ADDRESS_ATTR,
|
|
FLOATING_IP_ADDRESS_ATTR, PORT_ID_ATTR, SHOW,
|
|
) = (
|
|
'router_id', 'tenant_id', 'floating_network_id', 'fixed_ip_address',
|
|
'floating_ip_address', 'port_id', 'show',
|
|
)
|
|
|
|
properties_schema = {
|
|
FLOATING_NETWORK_ID: properties.Schema(
|
|
properties.Schema.STRING,
|
|
support_status=support.SupportStatus(
|
|
support.DEPRECATED,
|
|
_('Use property %s.') % FLOATING_NETWORK),
|
|
required=False
|
|
),
|
|
FLOATING_NETWORK: properties.Schema(
|
|
properties.Schema.STRING,
|
|
_('Network to allocate floating IP from.'),
|
|
required=False
|
|
),
|
|
VALUE_SPECS: properties.Schema(
|
|
properties.Schema.MAP,
|
|
_('Extra parameters to include in the "floatingip" object in the '
|
|
'creation request. Parameters are often specific to installed '
|
|
'hardware or extensions.'),
|
|
default={}
|
|
),
|
|
PORT_ID: properties.Schema(
|
|
properties.Schema.STRING,
|
|
_('ID of an existing port with at least one IP address to '
|
|
'associate with this floating IP.')
|
|
),
|
|
FIXED_IP_ADDRESS: properties.Schema(
|
|
properties.Schema.STRING,
|
|
_('IP address to use if the port has multiple addresses.')
|
|
),
|
|
}
|
|
|
|
attributes_schema = {
|
|
ROUTER_ID: attributes.Schema(
|
|
_('ID of the router used as gateway, set when associated with a '
|
|
'port.')
|
|
),
|
|
TENANT_ID: attributes.Schema(
|
|
_('The tenant owning this floating IP.')
|
|
),
|
|
FLOATING_NETWORK_ID_ATTR: attributes.Schema(
|
|
_('ID of the network in which this IP is allocated.')
|
|
),
|
|
FIXED_IP_ADDRESS_ATTR: attributes.Schema(
|
|
_('IP address of the associated port, if specified.')
|
|
),
|
|
FLOATING_IP_ADDRESS_ATTR: attributes.Schema(
|
|
_('The allocated address of this IP.')
|
|
),
|
|
PORT_ID_ATTR: attributes.Schema(
|
|
_('ID of the port associated with this IP.')
|
|
),
|
|
SHOW: attributes.Schema(
|
|
_('All attributes.')
|
|
),
|
|
}
|
|
|
|
def add_dependencies(self, deps):
|
|
super(FloatingIP, self).add_dependencies(deps)
|
|
# depend on any RouterGateway in this template with the same
|
|
# network_id as this floating_network_id
|
|
for resource in self.stack.itervalues():
|
|
if resource.has_interface('OS::Neutron::RouterGateway'):
|
|
gateway_network = resource.properties.get(
|
|
router.RouterGateway.NETWORK) or resource.properties.get(
|
|
router.RouterGateway.NETWORK_ID)
|
|
floating_network = self.properties.get(
|
|
self.FLOATING_NETWORK) or self.properties.get(
|
|
self.FLOATING_NETWORK_ID)
|
|
if gateway_network == floating_network:
|
|
deps += (self, resource)
|
|
|
|
def validate(self):
|
|
super(FloatingIP, self).validate()
|
|
self._validate_depr_property_required(
|
|
self.properties, self.FLOATING_NETWORK, self.FLOATING_NETWORK_ID)
|
|
|
|
def handle_create(self):
|
|
props = self.prepare_properties(
|
|
self.properties,
|
|
self.physical_resource_name())
|
|
neutron_utils.resolve_network(
|
|
self.neutron(), props, self.FLOATING_NETWORK,
|
|
'floating_network_id')
|
|
fip = self.neutron().create_floatingip({
|
|
'floatingip': props})['floatingip']
|
|
self.resource_id_set(fip['id'])
|
|
|
|
def _show_resource(self):
|
|
return self.neutron().show_floatingip(self.resource_id)['floatingip']
|
|
|
|
def handle_delete(self):
|
|
client = self.neutron()
|
|
try:
|
|
client.delete_floatingip(self.resource_id)
|
|
except NeutronClientException as ex:
|
|
self._handle_not_found_exception(ex)
|
|
|
|
|
|
class FloatingIPAssociation(neutron.NeutronResource):
|
|
PROPERTIES = (
|
|
FLOATINGIP_ID, PORT_ID, FIXED_IP_ADDRESS,
|
|
) = (
|
|
'floatingip_id', 'port_id', 'fixed_ip_address',
|
|
)
|
|
|
|
properties_schema = {
|
|
FLOATINGIP_ID: properties.Schema(
|
|
properties.Schema.STRING,
|
|
_('ID of the floating IP to associate.'),
|
|
required=True,
|
|
update_allowed=True
|
|
),
|
|
PORT_ID: properties.Schema(
|
|
properties.Schema.STRING,
|
|
_('ID of an existing port with at least one IP address to '
|
|
'associate with this floating IP.'),
|
|
required=True,
|
|
update_allowed=True
|
|
),
|
|
FIXED_IP_ADDRESS: properties.Schema(
|
|
properties.Schema.STRING,
|
|
_('IP address to use if the port has multiple addresses.'),
|
|
update_allowed=True
|
|
),
|
|
}
|
|
|
|
def handle_create(self):
|
|
props = self.prepare_properties(self.properties, self.name)
|
|
|
|
floatingip_id = props.pop(self.FLOATINGIP_ID)
|
|
|
|
self.neutron().update_floatingip(floatingip_id, {
|
|
'floatingip': props})['floatingip']
|
|
self.resource_id_set('%s:%s' % (floatingip_id, props[self.PORT_ID]))
|
|
|
|
def handle_delete(self):
|
|
if not self.resource_id:
|
|
return
|
|
client = self.neutron()
|
|
(floatingip_id, port_id) = self.resource_id.split(':')
|
|
try:
|
|
client.update_floatingip(
|
|
floatingip_id,
|
|
{'floatingip': {'port_id': None}})
|
|
except NeutronClientException as ex:
|
|
self._handle_not_found_exception(ex)
|
|
|
|
def handle_update(self, json_snippet, tmpl_diff, prop_diff):
|
|
if prop_diff:
|
|
(floatingip_id, port_id) = self.resource_id.split(':')
|
|
neutron_client = self.neutron()
|
|
# if the floatingip_id is changed, disassociate the port which
|
|
# associated with the old floatingip_id
|
|
if self.FLOATINGIP_ID in prop_diff:
|
|
try:
|
|
neutron_client.update_floatingip(
|
|
floatingip_id,
|
|
{'floatingip': {'port_id': None}})
|
|
except NeutronClientException as ex:
|
|
self._handle_not_found_exception(ex)
|
|
|
|
# associate the floatingip with the new port
|
|
floatingip_id = (prop_diff.get(self.FLOATINGIP_ID) or
|
|
floatingip_id)
|
|
port_id = prop_diff.get(self.PORT_ID) or port_id
|
|
|
|
fixed_ip_address = (prop_diff.get(self.FIXED_IP_ADDRESS) or
|
|
self.properties.get(self.FIXED_IP_ADDRESS))
|
|
|
|
request_body = {
|
|
'floatingip': {
|
|
'port_id': port_id,
|
|
'fixed_ip_address': fixed_ip_address}}
|
|
|
|
neutron_client.update_floatingip(floatingip_id, request_body)
|
|
self.resource_id_set('%s:%s' % (floatingip_id, port_id))
|
|
|
|
|
|
def resource_mapping():
|
|
return {
|
|
'OS::Neutron::FloatingIP': FloatingIP,
|
|
'OS::Neutron::FloatingIPAssociation': FloatingIPAssociation,
|
|
}
|