← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~jtv/maas/commissioning-tarball into lp:maas

 

Jeroen T. Vermeulen has proposed merging lp:~jtv/maas/commissioning-tarball into lp:maas.

Commit message:
Model method: create tar archive of all commissioning scripts.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~jtv/maas/commissioning-tarball/+merge/137045

This was discussed with several people.  What you see here is just the model part: "give me a tar archive containing all commissioning scripts."  In all likelihood this will be a very small and simple tar file, but if it turns out to be large or expensive to produce, we can then worry about caching it (and where) and maybe compressing it (and where).  We should be able to manage those pretty transparently; there are no design warts to accommodate optimization.

The next step will be to provide this tarball on the metadata API.  If we ever want to specialize the tarballs for different kinds of nodes, the model method can sprout filtering parameters but the API won't change — the requesting node's identity is already an implicit part of every metadata request.


Jeroen
-- 
https://code.launchpad.net/~jtv/maas/commissioning-tarball/+merge/137045
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~jtv/maas/commissioning-tarball into lp:maas.
=== modified file 'src/metadataserver/models/commissioningscript.py'
--- src/metadataserver/models/commissioningscript.py	2012-11-22 11:53:01 +0000
+++ src/metadataserver/models/commissioningscript.py	2012-11-29 20:52:44 +0000
@@ -15,14 +15,42 @@
     'CommissioningScript',
     ]
 
+from io import BytesIO
+import os.path
+import tarfile
 
 from django.db.models import (
     CharField,
+    Manager,
     Model,
     )
 from metadataserver import DefaultMeta
 from metadataserver.fields import BinaryField
 
+# Path prefix for commissioning scripts.  Commissioning scripts will be
+# extracted into this directory.
+ARCHIVE_PREFIX = "commissioning.d"
+
+
+class CommissioningScriptManager(Manager):
+    """Utility for the collection of `CommissioningScript`s."""
+
+    def get_archive(self):
+        """Produce a tar archive of all commissioning scripts.
+
+        Each of the scripts will be in the `ARCHIVE_PREFIX` directory.
+        """
+        binary = BytesIO()
+        tarball = tarfile.open(mode='w', fileobj=binary)
+        for script in self.all().order_by('name'):
+            path = os.path.join(ARCHIVE_PREFIX, script.name)
+            tarinfo = tarfile.TarInfo(name=path)
+            tarinfo.size = len(script.content)
+            tarball.addfile(tarinfo, BytesIO(script.content))
+        tarball.close()
+        binary.seek(0)
+        return binary.read()
+
 
 class CommissioningScript(Model):
     """User-provided commissioning script.
@@ -34,5 +62,7 @@
     class Meta(DefaultMeta):
         """Needed for South to recognize this model."""
 
+    objects = CommissioningScriptManager()
+
     name = CharField(max_length=255, null=False, editable=False, unique=True)
     content = BinaryField(null=False)

=== modified file 'src/metadataserver/tests/test_commissioningscript.py'
--- src/metadataserver/tests/test_commissioningscript.py	2012-11-23 11:40:16 +0000
+++ src/metadataserver/tests/test_commissioningscript.py	2012-11-29 20:52:44 +0000
@@ -12,13 +12,22 @@
 __metaclass__ = type
 __all__ = []
 
+from io import BytesIO
+import os.path
 from random import randint
+import tarfile
 
 from maasserver.testing.factory import factory
 from maasserver.testing.testcase import TestCase
 from maastesting.utils import sample_binary_data
 from metadataserver.fields import Bin
 from metadataserver.models import CommissioningScript
+from metadataserver.models.commissioningscript import ARCHIVE_PREFIX
+
+
+def open_tarfile(content):
+    """Open tar file from raw binary data."""
+    return tarfile.open(fileobj=BytesIO(content))
 
 
 def make_script_name(base_name=None, number=None):
@@ -31,6 +40,36 @@
         '%0.2d-%s' % (number, factory.make_name(base_name)))
 
 
+class TestCommissioningScriptManager(TestCase):
+
+    def test_get_archive_wraps_scripts_in_tar(self):
+        script = factory.make_commissioning_script()
+        archive = open_tarfile(CommissioningScript.objects.get_archive())
+        archived_script = archive.next()
+        self.assertTrue(archived_script.isfile())
+        self.assertEqual(
+            os.path.join(ARCHIVE_PREFIX, script.name),
+            archived_script.name)
+        self.assertEqual(
+            script.content,
+            archive.extractfile(archived_script).read())
+
+    def test_get_archive_wraps_all_scripts(self):
+        scripts = {factory.make_commissioning_script() for counter in range(3)}
+        archive = open_tarfile(CommissioningScript.objects.get_archive())
+        self.assertItemsEqual(
+            {os.path.join(ARCHIVE_PREFIX, script.name) for script in scripts},
+            archive.getnames())
+
+    def test_get_archive_supports_binary_scripts(self):
+        script = factory.make_commissioning_script(content=sample_binary_data)
+        archive = open_tarfile(CommissioningScript.objects.get_archive())
+        archived_script = archive.next()
+        self.assertEqual(
+            script.content,
+            archive.extractfile(archived_script).read())
+
+
 class TestCommissioningScript(TestCase):
 
     def test_scripts_may_be_binary(self):


Follow ups