display ssh command in sliver detail view
[plstackapi.git] / planetstack / core / xoslib / objects / sliceplus.py
index 7e9836c..6bbbfa2 100644 (file)
@@ -1,6 +1,7 @@
 from core.models import Slice, SlicePrivilege, SliceRole, Sliver, Site, Node, User
 from plus import PlusObjectMixin
 from operator import itemgetter, attrgetter
+from rest_framework.exceptions import APIException
 
 class SlicePlus(Slice, PlusObjectMixin):
     class Meta:
@@ -13,12 +14,16 @@ class SlicePlus(Slice, PlusObjectMixin):
         self.getSliceInfo()
         self._site_allocation = self._sliceInfo["sitesUsed"]
         self._initial_site_allocation = self._site_allocation
+        self._network_ports = self._sliceInfo["networkPorts"]
+        self._initial_network_ports = self._network_ports
 
     def getSliceInfo(self, user=None):
         if not self._sliceInfo:
             used_sites = {}
+            ready_sites = {}
             used_deployments = {}
             sliverCount = 0
+            sshCommands = []
             for sliver in self.slivers.all():
                 site = sliver.node.site_deployment.site
                 deployment = sliver.node.site_deployment.deployment
@@ -26,18 +31,38 @@ class SlicePlus(Slice, PlusObjectMixin):
                 used_deployments[deployment.name] = used_deployments.get(deployment.name, 0) + 1
                 sliverCount = sliverCount + 1
 
+                sshCommand = sliver.get_ssh_command()
+                if sshCommand:
+                    sshCommands.append(sshCommand)
+
+                    ready_sites[site.name] = ready_sites.get(site.name, 0) + 1
+
             users = {}
             for priv in SlicePrivilege.objects.filter(slice=self):
                 if not (priv.user.id in users.keys()):
                     users[priv.user.id] = {"name": priv.user.email, "id": priv.user.id, "roles": []}
                 users[priv.user.id]["roles"].append(priv.role.role)
 
+            # XXX this assumes there is only one network that can have ports bound
+            # to it for a given slice. This is intended for the tenant view, which
+            # will obey this field.
+            networkPorts = ""
+            for networkSlice in self.networkslices.all():
+                network = networkSlice.network
+                if (network.owner.id != self.id):
+                    continue
+                if network.ports:
+                    networkPorts = network.ports
+
             self._sliceInfo= {"sitesUsed": used_sites,
+                    "sitesReady": ready_sites,
                     "deploymentsUsed": used_deployments,
                     "sliverCount": sliverCount,
                     "siteCount": len(used_sites.keys()),
                     "users": users,
-                    "roles": []}
+                    "roles": [],
+                    "sshCommands": sshCommands,
+                    "networkPorts": networkPorts}
 
         if user:
             auser = self._sliceInfo["users"].get(user.id, None)
@@ -46,6 +71,14 @@ class SlicePlus(Slice, PlusObjectMixin):
 
         return self._sliceInfo
 
+    @property
+    def site_ready(self):
+        return self.getSliceInfo()["sitesReady"]
+
+    @site_ready.setter
+    def site_ready(self, value):
+        pass
+
     @property
     def site_allocation(self):
         return self._site_allocation
@@ -73,20 +106,12 @@ class SlicePlus(Slice, PlusObjectMixin):
 
     @property
     def network_ports(self):
-        # XXX this assumes there is only one network that can have ports bound
-        # to it for a given slice. This is intended for the tenant view, which
-        # will obey this field.
-        networkPorts = ""
-        for networkSlice in self.networkslices.all():
-            network = networkSlice.network
-            if network.ports:
-                networkPorts = network.ports
-
-        return networkPorts
+        return self._network_ports
 
     @network_ports.setter
     def network_ports(self, value):
-        print "XXX set networkPorts to", value
+        self._network_ports = value
+        #print "XXX set networkPorts to", value
 
     @staticmethod
     def select_by_user(user):
@@ -115,6 +140,8 @@ class SlicePlus(Slice, PlusObjectMixin):
 
         super(SlicePlus, self).save(*args, **kwargs)
 
+        # try things out first
+
         updated_sites = (self._site_allocation != self._initial_site_allocation) or updated_image or updated_flavor
         if updated_sites:
             self.save_site_allocation(noAct=True, reset=(updated_image or updated_flavor))
@@ -122,12 +149,20 @@ class SlicePlus(Slice, PlusObjectMixin):
         if self._update_users:
             self.save_users(noAct=True)
 
+        if (self._network_ports != self._initial_network_ports):
+            self.save_network_ports(noAct=True)
+
+        # now actually save them
+
         if updated_sites:
             self.save_site_allocation(reset=(updated_image or updated_flavor))
 
         if self._update_users:
             self.save_users()
 
+        if (self._network_ports != self._initial_network_ports):
+            self.save_network_ports()
+
     def save_site_allocation(self, noAct = False, reset=False):
         print "save_site_allocation, reset=",reset
 
@@ -161,7 +196,7 @@ class SlicePlus(Slice, PlusObjectMixin):
                 nodes = self.get_node_allocation([site])
 
                 if (not nodes):
-                    raise ValueError("no nodes in site %s" % site_name)
+                    raise APIException(detail="no nodes in site %s" % site_name)
 
                 while (len(slivers) < desired_allocation):
                     # pick the least allocated node
@@ -211,6 +246,36 @@ class SlicePlus(Slice, PlusObjectMixin):
 
                  print "deleted user id", user_id
 
+    def save_network_ports(self, noAct=False):
+        # First search for any network that already has a filled in 'ports'
+        # field. We'll assume there can only be one, so it must be the right
+        # one.
+        for networkSlice in self.networkslices.all():
+            network = networkSlice.network
+            if (network.owner.id != self.id):
+                continue
+            if network.ports:
+                network.ports = self._network_ports
+                if (not noAct):
+                    network.save()
+                return
+
+        # Now try a network that is a "NAT", since setting ports on a non-NAT
+        # network doesn't make much sense.
+        for networkSlice in self.networkslices.all():
+            network = networkSlice.network
+            if (network.owner.id != self.id):
+                continue
+            if network.template.translation=="NAT":
+                network.ports = self._network_ports
+                if (not noAct):
+                    network.save()
+                return
+
+        # uh oh, we didn't find a network
+
+        raise APIException(detail="No network was found that ports could be set on")
+