CORD-1540 Eliminate ManyToMany from Flavor and Image to Deployment

Change-Id: I786e66a8c49af322098136d18fb87bebe199c899
diff --git a/xos/core/admin.py b/xos/core/admin.py
index ee79a8f..9cc03d6 100644
--- a/xos/core/admin.py
+++ b/xos/core/admin.py
@@ -730,26 +730,8 @@
 
 
 class DeploymentAdminForm(forms.ModelForm):
-    images = forms.ModelMultipleChoiceField(
-        queryset=Image.objects.all(),
-        required=False,
-        help_text="Select which images should be deployed on this deployment",
-        widget=FilteredSelectMultiple(
-            verbose_name=('Images'), is_stacked=False
-        )
-    )
-    flavors = forms.ModelMultipleChoiceField(
-        queryset=Flavor.objects.all(),
-        required=False,
-        help_text="Select which flavors should be usable on this deployment",
-        widget=FilteredSelectMultiple(
-            verbose_name=('Flavors'), is_stacked=False
-        )
-    )
-
     class Meta:
         model = Deployment
-        many_to_many = ["flavors", ]
         fields = '__all__'
 
     def __init__(self, *args, **kwargs):
@@ -759,76 +741,6 @@
         self.fields['accessControl'].initial = "allow site " + \
             request.user.site.name
 
-        if self.instance and self.instance.pk:
-            self.fields['images'].initial = [
-                x.image for x in self.instance.imagedeployments.all()]
-            self.fields['flavors'].initial = self.instance.flavors.all()
-
-    def manipulate_m2m_objs(self, this_obj, selected_objs, all_relations, relation_class, local_attrname, foreign_attrname):
-        """ helper function for handling m2m relations from the MultipleChoiceField
-
-            this_obj: the source object we want to link from
-
-            selected_objs: a list of destination objects we want to link to
-
-            all_relations: the full set of relations involving this_obj, including ones we don't want
-
-            relation_class: the class that implements the relation from source to dest
-
-            local_attrname: field name representing this_obj in relation_class
-
-            foreign_attrname: field name representing selected_objs in relation_class
-
-            This function will remove all newobjclass relations from this_obj
-            that are not contained in selected_objs, and add any relations that
-            are in selected_objs but don't exist in the data model yet.
-        """
-
-        existing_dest_objs = []
-        for relation in list(all_relations):
-            if getattr(relation, foreign_attrname) not in selected_objs:
-                # print "deleting site", sdp.site
-                relation.delete()
-            else:
-                existing_dest_objs.append(getattr(relation, foreign_attrname))
-
-        for dest_obj in selected_objs:
-            if dest_obj not in existing_dest_objs:
-                # print "adding site", site
-                kwargs = {foreign_attrname: dest_obj, local_attrname: this_obj}
-                relation = relation_class(**kwargs)
-                relation.save()
-
-    def save(self, commit=True):
-        deployment = super(DeploymentAdminForm, self).save(commit=False)
-
-        if commit:
-            deployment.save()
-            # this has to be done after save() if/when a deployment is first
-            # created
-            deployment.flavors = self.cleaned_data['flavors']
-
-        if deployment.pk:
-            # save_m2m() doesn't seem to work with 'through' relations. So we
-            #    create/destroy the through models ourselves. There has to be
-            #    a better way...
-
-            self.manipulate_m2m_objs(deployment, self.cleaned_data[
-                                     'images'], deployment.imagedeployments.all(), ImageDeployments, "deployment", "image")
-            # manipulate_m2m_objs doesn't work for Flavor/Deployment relationship
-            # so well handle that manually here
-            for flavor in deployment.flavors.all():
-                if getattr(flavor, 'name') not in self.cleaned_data['flavors']:
-                    deployment.flavors.remove(flavor)
-            for flavor in self.cleaned_data['flavors']:
-                if flavor not in deployment.flavors.all():
-                    flavor.deployments.add(deployment)
-
-        self.save_m2m()
-
-        return deployment
-
-
 class DeploymentAdminROForm(DeploymentAdminForm):
 
     def save(self, commit=True):
@@ -843,8 +755,7 @@
 
 class DeploymentAdmin(XOSBaseAdmin):
     model = Deployment
-    fieldList = ['backend_status_text', 'name',
-                 'images', 'flavors', 'accessControl']
+    fieldList = ['backend_status_text', 'name', 'accessControl']
     fieldsets = [
         (None, {'fields': fieldList, 'classes': ['suit-tab suit-tab-general']})]
     # node no longer directly connected to deployment
@@ -1320,17 +1231,17 @@
             deployment_nodes.append(
                 (node.site_deployment.deployment.id, node.id, node.name))
 
+        # Limiting flavors/images by deployment is no longer supported, so assume every deployment supports
+        # everything.
         deployment_flavors = []
-        for flavor in Flavor.objects.all():
-            for deployment in flavor.deployments.all():
+        deployment_images = []
+        for deployment in Deployment.objects.all():
+            for flavor in Flavor.objects.all():
                 deployment_flavors.append(
                     (deployment.id, flavor.id, flavor.name))
-
-        deployment_images = []
-        for image in Image.objects.all():
-            for deployment_image in image.imagedeployments.all():
+            for image in Image.objects.all():
                 deployment_images.append(
-                    (deployment_image.deployment.id, image.id, image.name))
+                    (deployment.id, image.id, image.name))
 
         site_login_bases = []
         for site in Site.objects.all():
@@ -1596,22 +1507,21 @@
 
     def render_change_form(self, request, context, add=False, change=False, form_url='', obj=None):
         deployment_nodes = []
-#        for node in Node.objects.all():
         for node in Node.objects.order_by("name"):
             deployment_nodes.append(
                 (node.site_deployment.deployment.id, node.id, node.name))
 
+        # Limiting flavors/images by deployment is no longer supported, so assume every deployment supports
+        # everything.
         deployment_flavors = []
-        for flavor in Flavor.objects.all():
-            for deployment in flavor.deployments.all():
+        deployment_images = []
+        for deployment in Deployment.objects.all():
+            for flavor in Flavor.objects.all():
                 deployment_flavors.append(
                     (deployment.id, flavor.id, flavor.name))
-
-        deployment_images = []
-        for image in Image.objects.all():
-            for deployment_image in image.imagedeployments.all():
+            for image in Image.objects.all():
                 deployment_images.append(
-                    (deployment_image.deployment.id, image.id, image.name))
+                    (deployment.id, image.id, image.name))
 
         site_login_bases = []
         for site in Site.objects.all():
diff --git a/xos/core/models/core.xproto b/xos/core/models/core.xproto
index 8e6fe8b..587769d 100644
--- a/xos/core/models/core.xproto
+++ b/xos/core/models/core.xproto
@@ -191,7 +191,6 @@
      required string name = 1 [max_length = 32, content_type = "stripped", blank = False, help_text = "name of this flavor, as displayed to users", null = False, db_index = False];
      optional string description = 2 [db_index = False, max_length = 1024, null = True, content_type = "stripped", blank = True];
      required string flavor = 3 [max_length = 32, content_type = "stripped", blank = False, help_text = "flavor string used to configure deployments", null = False, db_index = False];
-     required manytomany deployments->Deployment/DashboardView_deployments:flavors = 6 [db_index = False, null = False, blank = True];
 }
 
 
@@ -202,7 +201,6 @@
      required string container_format = 4 [db_index = False, max_length = 256, null = False, content_type = "stripped", blank = False];
      optional string path = 5 [max_length = 256, content_type = "stripped", blank = True, help_text = "Path to image on local disk", null = True, db_index = False];
      optional string tag = 6 [max_length = 256, content_type = "stripped", blank = True, help_text = "For Docker Images, tag of image", null = True, db_index = False];
-     required manytomany deployments->Deployment/ImageDeployments:images = 7 [help_text = "Select which images should be instantiated on this deployment", null = False, db_index = False, blank = True];
 }
 
 
diff --git a/xos/tosca/resources/deployment.py b/xos/tosca/resources/deployment.py
index dc2a79f..ec53849 100644
--- a/xos/tosca/resources/deployment.py
+++ b/xos/tosca/resources/deployment.py
@@ -12,37 +12,7 @@
         return args
 
     def postprocess(self, obj):
-        for imageName in self.get_requirements("tosca.relationships.SupportsImage"):
-            image = self.get_xos_object(Image, name=imageName)
-            imageDeps = ImageDeployments.objects.filter(deployment=obj, image=image)
-            if not imageDeps:
-                self.info("Attached Image %s to Deployment %s" % (image, obj))
-                imageDep = ImageDeployments(deployment=obj, image=image)
-                imageDep.save()
-
-        # DEPRECATED - should switch to using a requirement, so tosca can do
-        # the topsort properly
-
-        flavors = self.get_property("flavors")
-        if flavors:
-            flavors = flavors.split(",")
-            flavors = [x.strip() for x in flavors]
-
-            for flavor in flavors:
-                flavor = self.get_xos_object(Flavor, name=flavor)
-                if not flavor.deployments.filter(id=obj.id).exists():
-                    self.info("Attached flavor %s to deployment %s" % (flavor, obj))
-                    flavor.deployments.add(obj)
-                    flavor.save()
-
-        # The new, right way
-        for flavor in self.get_requirements("tosca.relationships.SupportsFlavor"):
-            flavor = self.get_xos_object(Flavor, name=flavor)
-            if not flavor.deployments.filter(id=obj.id).exists():
-                self.info("Attached flavor %s to deployment %s" % (flavor, obj))
-                flavor.deployments.add(obj)
-                flavor.save()
-
+        # Note: support for Flavors and Images is dropped
 
         rolemap = ( ("tosca.relationships.AdminPrivilege", "admin"), )
         self.postprocess_privileges(DeploymentRole, DeploymentPrivilege, rolemap, obj, "deployment")