Commit 5b8b9cae by Arnau Comas Codina

Port Forwarding

parent 841e3e1f
Pipeline #1098 failed with stage
in 56 seconds
from openstack.exceptions import ResourceNotFound
from openstack.exceptions import BadRequestException
from interface.network.port_forwarding import PortForwardingInterface
from interface.network.resources import Port, FloatingIP, PortForwarding
from implementation.utils.connection import OpenStackConnection
from implementation.utils.decorators import OpenStackError
import logging
import random
# for limiting the ones that can be allocated over floating ips
RESERVED_PORT_NUMBERS = [22, 80, 9696]
class OSPortForwardingManager(PortForwardingInterface, OpenStackConnection):
......@@ -27,10 +34,14 @@ class OSPortForwardingManager(PortForwardingInterface, OpenStackConnection):
# PortForwarding(item) for item in self.openstack.network.port_forwardings(self.floating_ips[0].id)]
@OpenStackError
def create_port_forwarding(self, instance_id, internal_port_number, protocol):
"""DUBTE hem de gestionar condicions com ara que no estigui creat ja
un port forwarding igual, que la floating_ip no estigui activa, que no
estigui associat a un router, etc.?
Les floating ips estan separades de la ip on hi ha les apis dels serveis
d'openstack? Perquè en devstack no, i no es pot habilitar un port extern
que ja es faci servir (s'ha de restringir)?
"""
project_id = self.openstack.auth['project_id']
......@@ -40,50 +51,33 @@ class OSPortForwardingManager(PortForwardingInterface, OpenStackConnection):
internal_port_id = internal_port_object.id
internal_ip_address = internal_port_object.ip_address
# recorrer cada floating ip i cridar una funció que ens torni un port lliure o None, sinó crear nova ip
# TODO: recorrer cada floating ip i cridar una funció que ens torni un port lliure o None, sinó crear nova ip
floating_ip_id = self.floating_ips[0].id
external_port = "8000" #get_free_port() from list of ports
# floating_ip_id = "3179d648-9bb0-4871-854c-efffceb74fb0" #get_floating_ip_id
floating_ip_address = self.floating_ips[0].address
self.openstack.network.create_port_forwarding(
external_port = self.__obtain_free_port_by_floating_ip_id(floating_ip_id)
print(f"PORT {external_port}")
return PortForwarding(self.openstack.network.create_port_forwarding(
floatingip_id=floating_ip_id,
internal_port_id=internal_port_id,
internal_ip_address=internal_ip_address,
internal_port=internal_port_number,
internal_port=int(internal_port_number),
external_port=external_port,
protocol=protocol,
description='')
port_forwardings = [
PortForwarding(item) for item in self.openstack.network.port_forwardings(
self.floating_ips[0].id)]
# DUBTE: l'instància de la connection sempre s'ha d'inicialitzar amb l'objecte auth.
# no es podria compartir? Perquè aquí necessito accedir a funcions del port manager
# (internal_port_id no coincideix amb la instance_id)
# sinó s'haurà de fer a un nivell superior? de cercar-lo i passar-lo per paràmetre aquí
# on ha d'estar aquesta lògica doncs?
payload = {
"port_forwarding": {
"project_id": f"{project_id}",
"protocol": f"{protocol}",
"internal_ip_address": f"{instance_id}",
"internal_port": f"{internal_port_number}",
"internal_port_id": f"{internal_port_id}",
"external_port": f"{external_port}"
}
}
# create a ks client and get token or do a post directly with client
#ks = self.obtain_keystone_client()
#print(ks)
description=''), floating_ip_address)
# more handcrafted alternatives
#res = self.openstack.network.post(
# f"/floatingips/{floating_ip_id}/port_forwardings", json=payload)
#r = requests.post("http://vm.niif.cloud.bme.hu:18686/v2.0/floatingips" \
# f"/{floating_ip_id}/port_forwardings", data = payload)
#r.json()
@OpenStackError
def delete_port_forwarding(self, instance_id, internal_port_number):
""" Removes port forwarding rule
"""
......@@ -97,8 +91,8 @@ class OSPortForwardingManager(PortForwardingInterface, OpenStackConnection):
floating_ip_id = None
for floating_ip in self.openstack.list_floating_ips():
for port_forwarding in floating_ip.port_forwardings:
if (port_forwarding.internal_ip_address == internal_ip_address)
and (port_forwarding.internal_port == internal_port_number):
if ((port_forwarding.internal_ip_address == internal_ip_address)
and (port_forwarding.internal_port == internal_port_number)):
# found
floating_ip_id = floating_ip.id
break
......@@ -107,15 +101,16 @@ class OSPortForwardingManager(PortForwardingInterface, OpenStackConnection):
# loop again to fetch port forwarding id
# because is not contained in objects from the above results
port_forwarding_id = None
for port_forwarding in self.openstack.network.floating_ip_port_forwardings(floating_ip_id)
if (port_forwarding.internal_ip_address == internal_ip_address)
and (port_forwarding.internal_port == internal_port_number):
for port_forwarding in self.openstack.network.floating_ip_port_forwardings(floating_ip_id):
if ((port_forwarding.internal_ip_address == internal_ip_address)
and (port_forwarding.internal_port == internal_port_number)):
port_forwarding_id = port_forwarding.id
self.openstack.network.delete_port_forwarding(
port_forwarding_id, floating_ip_id)
@OpenStackError
def list_instance_port_forwardings(self, instance_id):
""" Lists all port forwarding rules defined from a vm instance
"""
......@@ -147,3 +142,32 @@ class OSPortForwardingManager(PortForwardingInterface, OpenStackConnection):
internal_port_object = results.pop()
return internal_port_object
def __obtain_free_port_by_floating_ip_id(self, floating_ip_id):
""" Pot una vm tenir port forwardings en diferents floating ips?
"""
# initialize list with the full range of ports
port_numbers = list(range(1, 2**16))
# remove reserved ones
for reserved in RESERVED_PORT_NUMBERS:
if reserved in port_numbers:
port_numbers.remove(reserved)
# query all current port forwardings from the floating ip
already_allocated_port_numbers = []
for item in self.openstack.network.port_forwardings(floating_ip_id):
already_allocated_port_numbers.append(PortForwarding(item).external_port)
# remove already allocated ports from range list
for allocated in already_allocated_port_numbers:
if allocated in port_numbers:
port_numbers.remove(allocated)
free_port_number = None
if len(port_numbers):
free_port_number = random.choice(port_numbers)
return free_port_number
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment