Allow TenantWithContainer to use either containers-in-vm or containers-on-bare-metal
diff --git a/xos/core/models/service.py b/xos/core/models/service.py
index 950ce02..c263bba 100644
--- a/xos/core/models/service.py
+++ b/xos/core/models/service.py
@@ -353,6 +353,9 @@
         super(TenantWithContainer, self).__init__(*args, **kwargs)
         self.cached_instance=None
         self.orig_instance_id = self.get_initial_attribute("instance_id")
+        self.cached_container=None
+        self.orig_container_id = self.get_initial_attribute("container_id")
+
 
     @property
     def instance(self):
@@ -379,6 +382,30 @@
         self.set_attribute("instance_id", value)
 
     @property
+    def container(self):
+        from core.models import Container
+        if getattr(self, "cached_container", None):
+            return self.cached_container
+        container_id=self.get_attribute("container_id")
+        if not container_id:
+            return None
+        containers=Container.objects.filter(id=container_id)
+        if not containers:
+            return None
+        container=containers[0]
+        container.caller = self.creator
+        self.cached_container = container
+        return container
+
+    @container.setter
+    def container(self, value):
+        if value:
+            value = value.id
+        if (value != self.get_attribute("container_id", None)):
+            self.cached_container=None
+        self.set_attribute("container_id", value)
+
+    @property
     def creator(self):
         from core.models import User
         if getattr(self, "cached_creator", None):
@@ -413,7 +440,23 @@
 
         raise XOSProgrammingError("No VPCE image (looked for %s)" % str(self.LOOK_FOR_IMAGES))
 
-    def pick_node(self):
+    @property
+    def use_cobm(self):
+        return self.get_attribute("use_cobm", False)
+
+    @use_cobm.setter
+    def use_cobm(self, v):
+        self.set_attribute("use_cobm", v)
+
+    @creator.setter
+    def creator(self, value):
+        if value:
+            value = value.id
+        if (value != self.get_attribute("creator_id", None)):
+            self.cached_creator=None
+        self.set_attribute("creator_id", value)
+
+    def pick_node_for_instance(self):
         from core.models import Node
         nodes = list(Node.objects.all())
         # TODO: logic to filter nodes by which nodes are up, and which
@@ -421,7 +464,15 @@
         nodes = sorted(nodes, key=lambda node: node.instances.all().count())
         return nodes[0]
 
-    def manage_container(self):
+    def pick_node_for_container_on_metal(self):
+        from core.models import Node
+        nodes = list(Node.objects.all())
+        # TODO: logic to filter nodes by which nodes are up, and which
+        #   nodes the slice can instantiate on.
+        nodes = sorted(nodes, key=lambda node: node.containers.all().count())
+        return nodes[0]
+
+    def manage_container_in_instance(self):
         from core.models import Instance, Flavor
 
         if self.deleted:
@@ -439,7 +490,7 @@
             if not flavors:
                 raise XOSConfigurationError("No m1.small flavor")
 
-            node =self.pick_node()
+            node =self.pick_node_for_instance()
             instance = Instance(slice = self.provider_service.slices.all()[0],
                             node = node,
                             image = self.image,
@@ -455,11 +506,83 @@
                 instance.delete()
                 raise
 
+    def manage_container_on_metal(self):
+        from core.models import Container, Instance, Flavor, Port
+
+        if self.deleted:
+            return
+
+        if (self.container is not None):
+            self.container.delete()
+            self.container = None
+
+        if self.container is None:
+            if not self.provider_service.slices.count():
+                raise XOSConfigurationError("The VCPE service has no slices")
+
+            slice = self.provider_service.slices.all()[0]
+            node = self.pick_node_for_container_on_metal()
+
+            # Our current docker network strategy requires that there be some
+            # instance on the server that connects to the networks, so that
+            # the containers can piggyback off of that configuration.
+            instances = Instance.objects.filter(slice=slice, node=node)
+            if not instances:
+                flavors = Flavor.objects.filter(name="m1.small")
+                if not flavors:
+                    raise XOSConfigurationError("No m1.small flavor")
+
+                node =self.pick_node_for_instance()
+                instance = Instance(slice = self.provider_service.slices.all()[0],
+                                node = node,
+                                image = self.image,
+                                creator = self.creator,
+                                deployment = node.site_deployment.deployment,
+                                flavor = flavors[0])
+                instance.save()
+
+            # Now make the container...
+            container = Container(slice = slice,
+                            node = node,
+                            docker_image = "andybavier/docker-vcpe",
+                            creator = self.creator,
+                            no_sync=True)
+            container.save()
+
+            # ... and add the ports for the container
+            # XXX probably should be done in model_policy
+            for network in slice.networks.all():
+                if (network.name.endswith("-nat")):
+                    continue
+                port = Port(network = network,
+                            container = container)
+                port.save()
+
+            container.no_sync = False
+            container.save()
+
+            try:
+                self.container = container
+                super(TenantWithContainer, self).save()
+            except:
+                container.delete()
+                raise
+
+    def manage_container(self):
+        if self.use_cobm:
+            self.manage_container_on_metal()
+        else:
+            self.manage_container_in_instance()
+
     def cleanup_container(self):
         if self.instance:
             # print "XXX cleanup instance", self.instance
             self.instance.delete()
             self.instance = None
+        if self.container:
+            # print "XXX cleanup container", self.container
+            self.container.delete()
+            self.container = None
 
 class CoarseTenant(Tenant):
     """ TODO: rename "CoarseTenant" --> "StaticTenant" """