summaryrefslogtreecommitdiff
path: root/heat/engine/resources/openstack/neutron/floatingip.py
diff options
context:
space:
mode:
Diffstat (limited to 'heat/engine/resources/openstack/neutron/floatingip.py')
-rw-r--r--heat/engine/resources/openstack/neutron/floatingip.py156
1 files changed, 156 insertions, 0 deletions
diff --git a/heat/engine/resources/openstack/neutron/floatingip.py b/heat/engine/resources/openstack/neutron/floatingip.py
index a56a0163d..1b1aa1d77 100644
--- a/heat/engine/resources/openstack/neutron/floatingip.py
+++ b/heat/engine/resources/openstack/neutron/floatingip.py
@@ -455,8 +455,164 @@ class FloatingIPAssociation(neutron.NeutronResource):
self.resource_id_set(self.id)
+class FloatingIPPortForward(neutron.NeutronResource):
+ """A resource for creating port forwarding for floating IPs.
+
+ This resource creates port forwarding for floating IPs.
+ These are sub-resource of exsisting Floating ips, which requires the
+ service_plugin and extension port_forwarding enabled and that the floating
+ ip is not associated with a neutron port.
+ """
+
+ default_client_name = 'openstack'
+
+ required_service_extension = 'floating-ip-port-forwarding'
+
+ support_status = support.SupportStatus(
+ status=support.SUPPORTED,
+ version='19.0.0',
+ )
+
+ PROPERTIES = (
+ INTERNAL_IP_ADDRESS, INTERNAL_PORT_NUMBER, EXTERNAL_PORT,
+ INTERNAL_PORT, PROTOCOL, FLOATINGIP
+ ) = (
+ 'internal_ip_address', 'internal_port_number',
+ 'external_port', 'internal_port', 'protocol', 'floating_ip'
+ )
+
+ properties_schema = {
+ INTERNAL_IP_ADDRESS: properties.Schema(
+ properties.Schema.STRING,
+ _('Internal IP address to port forwarded to.'),
+ required=True,
+ update_allowed=True,
+ constraints=[
+ constraints.CustomConstraint('ip_addr')
+ ]
+ ),
+ INTERNAL_PORT_NUMBER: properties.Schema(
+ properties.Schema.INTEGER,
+ _('Internal port number to port forward to.'),
+ update_allowed=True,
+ constraints=[
+ constraints.Range(min=1, max=65535)
+ ]
+ ),
+ EXTERNAL_PORT: properties.Schema(
+ properties.Schema.INTEGER,
+ _('External port address to port forward from.'),
+ required=True,
+ update_allowed=True,
+ constraints=[
+ constraints.Range(min=1, max=65535)
+ ]
+ ),
+ INTERNAL_PORT: properties.Schema(
+ properties.Schema.STRING,
+ _('Name or ID of the internal_ip_address port.'),
+ required=True,
+ update_allowed=True,
+ constraints=[
+ constraints.CustomConstraint('neutron.port')
+ ]
+ ),
+ PROTOCOL: properties.Schema(
+ properties.Schema.STRING,
+ _('Port protocol to forward.'),
+ required=True,
+ update_allowed=True,
+ constraints=[
+ constraints.AllowedValues([
+ 'tcp', 'udp', 'icmp', 'icmp6', 'sctp', 'dccp'])
+ ]
+ ),
+ FLOATINGIP: properties.Schema(
+ properties.Schema.STRING,
+ _('Name or ID of the floating IP create port forwarding on.'),
+ required=True,
+ ),
+ }
+
+ def translation_rules(self, props):
+ client_plugin = self.client_plugin()
+ return [
+ translation.TranslationRule(
+ props,
+ translation.TranslationRule.RESOLVE,
+ [self.FLOATINGIP],
+ client_plugin=client_plugin,
+ finder='find_network_ip'
+ ),
+ translation.TranslationRule(
+ props,
+ translation.TranslationRule.RESOLVE,
+ [self.INTERNAL_PORT],
+ client_plugin=client_plugin,
+ finder='find_network_port'
+ )
+ ]
+
+ def add_dependencies(self, deps):
+ super(FloatingIPPortForward, self).add_dependencies(deps)
+
+ for resource in self.stack.values():
+ if resource.has_interface('OS::Neutron::RouterInterface'):
+
+ def port_on_subnet(resource, subnet):
+ if not resource.has_interface('OS::Neutron::Port'):
+ return False
+ fixed_ips = resource.properties.get(
+ port.Port.FIXED_IPS) or []
+ for fixed_ip in fixed_ips:
+ port_subnet = (
+ fixed_ip.get(port.Port.FIXED_IP_SUBNET)
+ or fixed_ip.get(port.Port.FIXED_IP_SUBNET_ID))
+ return subnet == port_subnet
+ return False
+
+ interface_subnet = (
+ resource.properties.get(router.RouterInterface.SUBNET) or
+ resource.properties.get(router.RouterInterface.SUBNET_ID))
+ for d in deps.graph()[self]:
+ if port_on_subnet(d, interface_subnet):
+ deps += (self, resource)
+ break
+
+ def handle_create(self):
+ props = self.prepare_properties(self.properties, self.name)
+ fp = self.client().network.create_floating_ip_port_forwarding(
+ props.pop(self.FLOATINGIP),
+ **props)
+ self.resource_id_set(fp.id)
+
+ def handle_delete(self):
+ if not self.resource_id:
+ return
+
+ self.client().network.delete_floating_ip_port_forwarding(
+ self.properties[self.FLOATINGIP],
+ self.resource_id,
+ ignore_missing=True
+ )
+
+ def handle_check(self):
+ self.client().network.get_port_forwarding(
+ self.resource_id,
+ self.properties[self.FLOATINGIP]
+ )
+
+ def handle_update(self, prop_diff):
+ if prop_diff:
+ self.client().network.update_floating_ip_port_forwarding(
+ self.properties[self.FLOATINGIP],
+ self.resource_id,
+ **prop_diff)
+
+
def resource_mapping():
return {
'OS::Neutron::FloatingIP': FloatingIP,
'OS::Neutron::FloatingIPAssociation': FloatingIPAssociation,
+ 'OS::Neutron::FloatingIPPortForward': FloatingIPPortForward,
}