From 5bbaa23b56772545221bf59e632d74c8ab1ca617 Mon Sep 17 00:00:00 2001 From: Scott Baker Date: Thu, 14 Aug 2014 17:23:15 -0700 Subject: [PATCH] punch through portfwd; fix not all ports used in sync_network_slivers --- planetstack/core/models/network.py | 48 +++++++++++++++- .../steps/sync_network_slivers.py | 55 ++++++++++++++++++- 2 files changed, 100 insertions(+), 3 deletions(-) diff --git a/planetstack/core/models/network.py b/planetstack/core/models/network.py index f08b9b4..e0e4975 100644 --- a/planetstack/core/models/network.py +++ b/planetstack/core/models/network.py @@ -57,6 +57,52 @@ class Network(PlCoreBase): def can_update(self, user): return self.owner.can_update(user) + @property + def nat_list(self): + """ Support a list of ports in the format "protocol:port, protocol:port, ..." + examples: + tcp 123 + tcp 123:133 + tcp 123, tcp 124, tcp 125, udp 201, udp 202 + + User can put either a "/" or a " " between protocol and ports + Port ranges can be specified with "-" or ":" + """ + nats = [] + if self.ports: + parts = self.ports.split(",") + for part in parts: + part = part.strip() + if "/" in part: + (protocol, ports) = part.split("/",1) + elif " " in part: + (protocol, ports) = part.split(None,1) + else: + raise TypeError('malformed port specifier %s, format example: "tcp 123, tcp 201:206, udp 333"' % part) + + protocol = protocol.strip() + ports = ports.strip() + + if not (protocol in ["udp", "tcp"]): + raise TypeError('unknown protocol %s' % protocol) + + if "-" in ports: + (first, last) = ports.split("-") + first = int(first.strip()) + last = int(last.strip()) + portStr = "%d:%d" % (first, last) + elif ":" in ports: + (first, last) = ports.split(":") + first = int(first.strip()) + last = int(last.strip()) + portStr = "%d:%d" % (first, last) + else: + portStr = "%d" % int(ports) + + nats.append( {"l4_protocol": protocol, "l4_port": portStr} ) + + return nats + @staticmethod def select_by_user(user): if user.is_admin: @@ -69,7 +115,7 @@ class Network(PlCoreBase): class NetworkDeployments(PlCoreBase): # Stores the openstack ids at various deployments - network = models.ForeignKey(Network) + network = models.ForeignKey(Network) deployment = models.ForeignKey(Deployment) net_id = models.CharField(null=True, blank=True, max_length=256, help_text="Quantum network") router_id = models.CharField(null=True, blank=True, max_length=256, help_text="Quantum router id") diff --git a/planetstack/openstack_observer/steps/sync_network_slivers.py b/planetstack/openstack_observer/steps/sync_network_slivers.py index c6e4b7c..37b6d9d 100644 --- a/planetstack/openstack_observer/steps/sync_network_slivers.py +++ b/planetstack/openstack_observer/steps/sync_network_slivers.py @@ -39,8 +39,23 @@ class SyncNetworkSlivers(OpenStackSyncStep): for sliver in slivers: slivers_by_instance_id[sliver.instance_id] = sliver - driver = self.driver.client_driver(caller=sliver.creator, tenant=sliver.slice.name, deployment=sliver.node.deployment.name) - ports = driver.shell.quantum.list_ports()["ports"] + # Get all ports in all deployments + + ports_by_id = {} + for deployment in Deployment.objects.all(): + if not deployment.admin_tenant: + logger.info("deployment %s has no admin_tenant" % deployment.name) + continue + try: + driver = self.driver.admin_driver(deployment=deployment.name) + ports = driver.shell.quantum.list_ports()["ports"] + except: + logger.log_exc("failed to get ports from deployment %s" % deployment.name) + continue + + for port in ports: + ports_by_id[port["id"]] = port + for port in ports: #logger.info("port %s" % str(port)) if port["id"] in networkSlivers_by_port: @@ -95,6 +110,42 @@ class SyncNetworkSlivers(OpenStackSyncStep): port_id=port["id"]) ns.save() + # Now, handle port forwarding + # We get the list of NetworkSlivers again, since we might have just + # added a few. Then, for each one of them we find it's quantum port and + # make sure quantum's nat:forward_ports argument is the same. + + for networkSliver in NetworkSliver.objects.all(): + try: + nat_list = networkSliver.network.nat_list + except (TypeError, ValueError), e: + logger.info("Failed to decode nat_list: %s" % str(e)) + continue + + if not networkSliver.port_id: + continue + + neutron_port = ports_by_id.get(networkSliver.port_id, None) + if not neutron_port: + continue + + neutron_nat_list = neutron_port.get("nat:forward_ports", None) + if not neutron_nat_list: + # make sure that None and the empty set are treated identically + neutron_nat_list = [] + + if (neutron_nat_list != nat_list): + logger.info("Setting nat:forward_ports for port %s network %s sliver %s to %s" % (str(networkSliver.port_id), str(networkSliver.network.id), str(networkSliver.sliver), str(nat_list))) + try: + driver = self.driver.client_driver(caller=networkSliver.sliver.creator, tenant=networkSliver.sliver.slice.name, deployment=networkSliver.sliver.node.deployment.name) + driver.shell.quantum.update_port(networkSliver.port_id, {"port": {"nat:forward_ports": nat_list}}) + except: + logger.log_exc("failed to update port with nat_list %s" % str(nat_list)) + continue + else: + #logger.info("port %s network %s sliver %s nat %s is already set" % (str(networkSliver.port_id), str(networkSliver.network.id), str(networkSliver.sliver), str(nat_list))) + pass + def delete_record(self, network_sliver): # Nothing to do, this is an OpenCloud object pass -- 2.43.0