commit 7cc3c7d94d48761ed12bb675b541602b78d38248
Author: Giorgos Verigakis <verigak@gmail.com>
Date:   Mon Oct 3 17:11:25 2011 +0300

    Change Update Metadata to create non-existing keys
    
    Update Metadata methods for servers and images
    used to ignore keys that did not exist. This patch
    will create them instead.
    
    Refs #1403
    Refs #1399

diff --git a/admin/views.py b/admin/views.py
index b500277..17d2dbf 100644
--- a/admin/views.py
+++ b/admin/views.py
@@ -136,7 +136,7 @@ def images_info(request, image_id):
     if not image.format:
         formats = [''] + formats
     
-    metadata = image.imagemetadata_set.order_by('meta_key')
+    metadata = image.metadata.order_by('meta_key')
     html = render('images_info.html', 'images',
                     image=image,
                     states=states,
@@ -162,10 +162,10 @@ def images_modify(request, image_id):
     keys = request.POST.getlist('key')
     vals = request.POST.getlist('value')
     meta = dict(zip(keys, vals))
-    image.imagemetadata_set.all().delete()
+    image.metadata.all().delete()
     for key, val in meta.items():
         if key:
-            image.imagemetadata_set.create(meta_key=key, meta_value=val)
+            image.metadata.create(meta_key=key, meta_value=val)
     
     _log.info('User %s modified Image %s', request.user.name, image.name)
 
diff --git a/api/images.py b/api/images.py
index a0dd180..d236e99 100644
--- a/api/images.py
+++ b/api/images.py
@@ -105,10 +105,6 @@ def image_to_dict(image, detail=True):
 
     return d
 
-def metadata_to_dict(image):
-    image_meta = image.imagemetadata_set.all()
-    return dict((meta.meta_key, meta.meta_value) for meta in image_meta)
-
 
 @util.api_method('GET')
 def list_images(request, detail=False):
@@ -220,7 +216,7 @@ def list_metadata(request, image_id):
     #                       overLimit (413)
 
     image = util.get_image(image_id, request.user)
-    metadata = metadata_to_dict(image)
+    metadata = dict((m.meta_key, m.meta_value) for m in image.metadata.all())
     return util.render_metadata(request, metadata, use_values=True, status=200)
 
 @util.api_method('POST')
@@ -241,22 +237,15 @@ def update_metadata(request, image_id):
         assert isinstance(metadata, dict)
     except (KeyError, AssertionError):
         raise BadRequest('Malformed request.')
-
-    updated = {}
-
-    for key, val in metadata.items():
-        try:
-            meta = ImageMetadata.objects.get(meta_key=key, image=image)
-            meta.meta_value = val
-            meta.save()
-            updated[key] = val
-        except ImageMetadata.DoesNotExist:
-            pass    # Ignore non-existent metadata
     
-    if updated:
-        image.save()
+    for key, val in metadata.items():
+        meta, created = image.metadata.get_or_create(meta_key=key)
+        meta.meta_value = val
+        meta.save()
     
-    return util.render_metadata(request, updated, status=201)
+    image.save()
+    image_meta = dict((m.meta_key, m.meta_value) for m in image.metadata.all())
+    return util.render_metadata(request, image_meta, status=201)
 
 @util.api_method('GET')
 def get_metadata_item(request, image_id, key):
diff --git a/api/servers.py b/api/servers.py
index 3a8cb37..b405e7f 100644
--- a/api/servers.py
+++ b/api/servers.py
@@ -118,11 +118,6 @@ def nic_to_dict(nic):
     return d
 
 
-def metadata_to_dict(vm):
-    vm_meta = vm.virtualmachinemetadata_set.all()
-    return dict((meta.meta_key, meta.meta_value) for meta in vm_meta)
-
-
 def vm_to_dict(vm, detail=False):
     d = dict(id=vm.id, name=vm.name)
     if detail:
@@ -134,8 +129,8 @@ def vm_to_dict(vm, detail=False):
         d['created'] = util.isoformat(vm.created)
         d['flavorRef'] = vm.flavor.id
         d['imageRef'] = vm.sourceimage.id
-
-        metadata = metadata_to_dict(vm)
+        
+        metadata = dict((m.meta_key, m.meta_value) for m in vm.metadata.all())
         if metadata:
             d['metadata'] = {'values': metadata}
 
@@ -395,7 +390,7 @@ def list_metadata(request, server_id):
     #                       overLimit (413)
 
     vm = util.get_vm(server_id, request.user)
-    metadata = metadata_to_dict(vm)
+    metadata = dict((m.meta_key, m.meta_value) for m in vm.metadata.all())
     return util.render_metadata(request, metadata, use_values=True, status=200)
 
 
@@ -417,22 +412,15 @@ def update_metadata(request, server_id):
         assert isinstance(metadata, dict)
     except (KeyError, AssertionError):
         raise faults.BadRequest("Malformed request")
-
-    updated = {}
-
-    for key, val in metadata.items():
-        try:
-            meta = VirtualMachineMetadata.objects.get(meta_key=key, vm=vm)
-            meta.meta_value = val
-            meta.save()
-            updated[key] = val
-        except VirtualMachineMetadata.DoesNotExist:
-            pass    # Ignore non-existent metadata
     
-    if updated:
-        vm.save()
+    for key, val in metadata.items():
+        meta, created = vm.metadata.get_or_create(meta_key=key)
+        meta.meta_value = val
+        meta.save()
     
-    return util.render_metadata(request, updated, status=201)
+    vm.save()
+    vm_meta = dict((m.meta_key, m.meta_value) for m in vm.metadata.all())
+    return util.render_metadata(request, vm_meta, status=201)
 
 
 @util.api_method('GET')
diff --git a/api/tests.py b/api/tests.py
index 17850a0..d68e97d 100644
--- a/api/tests.py
+++ b/api/tests.py
@@ -625,18 +625,12 @@ class UpdateServerMetadata(BaseTestCase):
         new_metadata = {}
         for key in sample(metadata[server_id].keys(), 3):
             new_metadata[key] = 'New %s value' % key
-        response_metadata = self.update_server_metadata(server_id, new_metadata)
-        self.assertEqual(response_metadata, new_metadata)
+        response_metadata = self.update_server_metadata(server_id,
+                                                        new_metadata)
         metadata[server_id].update(new_metadata)
+        self.assertEqual(response_metadata, metadata[server_id])
         self.assertEqual(metadata, self.get_all_server_metadata())
-
-    def test_does_not_create(self):
-        with AssertInvariant(self.get_all_server_metadata) as metadata:
-            server_id = choice(metadata.keys())
-            new_metadata = {'Foo': 'Bar'}
-            response_metadata = self.update_server_metadata(server_id, new_metadata)
-            self.assertEqual(response_metadata, {})
-
+    
     def test_invalid_data(self):
         with AssertInvariant(self.get_all_server_metadata) as metadata:
             server_id = choice(metadata.keys())
@@ -773,17 +767,10 @@ class UpdateImageMetadata(BaseTestCase):
         for key in sample(metadata[image_id].keys(), 3):
             new_metadata[key] = 'New %s value' % key
         response_metadata = self.update_image_metadata(image_id, new_metadata)
-        self.assertEqual(response_metadata, new_metadata)
         metadata[image_id].update(new_metadata)
+        self.assertEqual(response_metadata, metadata[image_id])
         self.assertEqual(metadata, self.get_all_image_metadata())
-
-    def test_does_not_create(self):
-        with AssertInvariant(self.get_all_image_metadata) as metadata:
-            image_id = choice(metadata.keys())
-            new_metadata = {'Foo': 'Bar'}
-            response_metadata = self.update_image_metadata(image_id, new_metadata)
-            self.assertEqual(response_metadata, {})
-
+    
     def test_invalid_data(self):
         with AssertInvariant(self.get_all_image_metadata) as metadata:
             image_id = choice(metadata.keys())
diff --git a/db/models.py b/db/models.py
index 459915f..559d9b2 100644
--- a/db/models.py
+++ b/db/models.py
@@ -140,7 +140,7 @@ class Image(models.Model):
 class ImageMetadata(models.Model):
     meta_key = models.CharField('Image metadata key name', max_length=50)
     meta_value = models.CharField('Image metadata value', max_length=500)
-    image = models.ForeignKey(Image)
+    image = models.ForeignKey(Image, related_name='metadata')
     
     class Meta:
         unique_together = (('meta_key', 'image'),)
@@ -408,7 +408,7 @@ class VirtualMachineGroup(models.Model):
 class VirtualMachineMetadata(models.Model):
     meta_key = models.CharField(max_length=50)
     meta_value = models.CharField(max_length=500)
-    vm = models.ForeignKey(VirtualMachine)
+    vm = models.ForeignKey(VirtualMachine, related_name='metadata')
     
     class Meta:
         unique_together = (('meta_key', 'vm'),)
diff --git a/snf-tools/snf-admin b/snf-tools/snf-admin
index 3e02c7a..2dbffa9 100755
--- a/snf-tools/snf-admin
+++ b/snf-tools/snf-admin
@@ -431,13 +431,13 @@ class ModifyImageMeta(Command):
         
         if not key:
             metadata = {}
-            for meta in image.imagemetadata_set.order_by('meta_key'):
+            for meta in image.metadata.order_by('meta_key'):
                 metadata[meta.meta_key] = meta.meta_value
             print_dict(metadata)
             return
         
         try:
-            meta = image.imagemetadata_set.get(meta_key=key)
+            meta = image.metadata.get(meta_key=key)
         except models.ImageMetadata.DoesNotExist:
             meta = None
         
@@ -448,7 +448,7 @@ class ModifyImageMeta(Command):
         
         if val:
             if not meta:
-                meta = image.imagemetadata_set.create(meta_key=key)
+                meta = image.metadata.create(meta_key=key)
             meta.meta_value = val
             meta.save()
         else:
