예제 #1
0
 def test_storeImageUpload(self):
     image = "ubuntu-trusty"
     provider = "rax"
     bnum = self.zk.storeBuild(image, zk.ImageBuild())
     up1 = self.zk.storeImageUpload(image, bnum, provider, zk.ImageUpload())
     up2 = self.zk.storeImageUpload(image, bnum, provider, zk.ImageUpload())
     self.assertLess(int(up1), int(up2))
예제 #2
0
    def _deleteUpload(self, upload):
        deleted = False

        if upload.state != zk.DELETING:
            if not self._inProgressUpload(upload):
                data = zk.ImageUpload()
                data.state = zk.DELETING
                self._zk.storeImageUpload(upload.image_name, upload.build_id,
                                          upload.provider_name, data,
                                          upload.id)
                deleted = True

        if upload.state == zk.DELETING or deleted:
            manager = self._config.provider_managers[upload.provider_name]
            try:
                # It is possible we got this far, but don't actually have an
                # external_name. This could mean that zookeeper and cloud
                # provider are some how out of sync.
                if upload.external_name:
                    base = "-".join([upload.image_name, upload.build_id])
                    self.log.info("Deleting image build %s from %s" %
                                  (base, upload.provider_name))
                    manager.deleteImage(upload.external_name)
            except Exception:
                self.log.exception(
                    "Unable to delete image %s from %s:",
                    upload.external_name, upload.provider_name)
            else:
                self.log.debug("Deleting image upload: %s", upload)
                self._zk.deleteUpload(upload.image_name, upload.build_id,
                                      upload.provider_name, upload.id)
예제 #3
0
    def test_store_and_get_image_upload(self):
        image = "ubuntu-trusty"
        provider = "rax"
        orig_data = zk.ImageUpload()
        orig_data.external_id = "deadbeef"
        orig_data.state = zk.READY
        orig_data.format = "qcow2"

        build_number = self.zk.storeBuild(image, zk.ImageBuild())
        upload_id = self.zk.storeImageUpload(image, build_number, provider,
                                             orig_data)
        data = self.zk.getImageUpload(image, build_number, provider, upload_id)

        self.assertEqual(upload_id, data.id)
        self.assertEqual(orig_data.external_id, data.external_id)
        self.assertEqual(orig_data.state, data.state)
        self.assertEqual(orig_data.state_time, data.state_time)
        self.assertEqual(orig_data.format, data.format)
        self.assertEqual(self.zk.getBuildProviders("ubuntu-trusty",
                                                   build_number),
                         [provider])
        self.assertEqual(self.zk.getImageUploadNumbers("ubuntu-trusty",
                                                       build_number,
                                                       provider),
                         [upload_id])
예제 #4
0
    def test_getUploads_any(self):
        path = self.zk._imageUploadPath("trusty", "000", "rax")
        v1 = zk.ImageUpload()
        v1.state = zk.READY
        v2 = zk.ImageUpload()
        v2.state = zk.UPLOADING
        v3 = zk.ImageUpload()
        v3.state = zk.FAILED
        v4 = zk.ImageUpload()
        v4.state = zk.DELETING
        self.zk.client.create(path + "/1", value=v1.serialize(), makepath=True)
        self.zk.client.create(path + "/2", value=v2.serialize(), makepath=True)
        self.zk.client.create(path + "/3", value=v3.serialize(), makepath=True)
        self.zk.client.create(path + "/4", value=v4.serialize(), makepath=True)
        self.zk.client.create(path + "/lock", makepath=True)

        matches = self.zk.getUploads("trusty", "000", "rax", None)
        self.assertEqual(4, len(matches))
예제 #5
0
    def test_storeImageUpload_invalid_build(self):
        image = "ubuntu-trusty"
        build_number = "0000000001"
        provider = "rax"
        orig_data = zk.ImageUpload()

        with testtools.ExpectedException(npe.ZKException,
                                         "Cannot find build .*"):
            self.zk.storeImageUpload(image, build_number, provider, orig_data)
예제 #6
0
    def test_ImageUpload_toDict(self):
        o = zk.ImageUpload('0001', '0003')
        o.external_id = 'DEADBEEF'
        o.external_name = 'trusty'

        d = o.toDict()
        self.assertNotIn('id', d)
        self.assertNotIn('build_id', d)
        self.assertNotIn('provider_name', d)
        self.assertNotIn('image_name', d)
        self.assertEqual(o.external_id, d['external_id'])
        self.assertEqual(o.external_name, d['external_name'])
예제 #7
0
    def test_deleteBuild_with_uploads(self):
        image = 'trusty'
        provider = 'rax'

        build = zk.ImageBuild()
        build.state = zk.READY
        bnum = self.zk.storeBuild(image, build)

        upload = zk.ImageUpload()
        upload.state = zk.READY
        self.zk.storeImageUpload(image, bnum, provider, upload)

        self.assertFalse(self.zk.deleteBuild(image, bnum))
예제 #8
0
    def test_getMostRecentImageUpload(self):
        image = "ubuntu-trusty"
        provider = "rax"

        build1 = zk.ImageBuild()
        build1.state = zk.READY
        build2 = zk.ImageBuild()
        build2.state = zk.READY
        build2.state_time = build1.state_time + 10

        bnum1 = self.zk.storeBuild(image, build1)
        bnum2 = self.zk.storeBuild(image, build2)

        upload1 = zk.ImageUpload()
        upload1.state = zk.READY
        upload2 = zk.ImageUpload()
        upload2.state = zk.READY
        upload2.state_time = upload1.state_time + 10

        self.zk.storeImageUpload(image, bnum1, provider, upload1)
        self.zk.storeImageUpload(image, bnum2, provider, upload2)

        d = self.zk.getMostRecentImageUpload(image, provider, zk.READY)
        self.assertEqual(upload2.state_time, d.state_time)
예제 #9
0
    def test_getMostRecentBuildImageUploads_any_state(self):
        image = "ubuntu-trusty"
        provider = "rax"
        build = {'state': zk.READY, 'state_time': int(time.time())}
        up1 = zk.ImageUpload()
        up1.state = zk.READY
        up2 = zk.ImageUpload()
        up2.state = zk.READY
        up2.state_time = up1.state_time + 10
        up3 = zk.ImageUpload()
        up3.state = zk.UPLOADING
        up3.state_time = up2.state_time + 10

        bnum = self.zk.storeBuild(image, zk.ImageBuild.fromDict(build))
        self.zk.storeImageUpload(image, bnum, provider, up1)
        self.zk.storeImageUpload(image, bnum, provider, up2)
        up3_id = self.zk.storeImageUpload(image, bnum, provider, up3)

        # up3 should be the most recent upload, regardless of state
        data = self.zk.getMostRecentBuildImageUploads(1, image, bnum, provider,
                                                      None)
        self.assertNotEqual([], data)
        self.assertEqual(1, len(data))
        self.assertEqual(data[0].id, up3_id)
예제 #10
0
    def test_getMostRecentBuildImageUploads_with_state(self):
        image = "ubuntu-trusty"
        provider = "rax"
        build = {'state': zk.READY, 'state_time': int(time.time())}
        up1 = zk.ImageUpload()
        up1.state = zk.READY
        up2 = zk.ImageUpload()
        up2.state = zk.READY
        up2.state_time = up1.state_time + 10
        up3 = zk.ImageUpload()
        up3.state = zk.DELETING
        up3.state_time = up2.state_time + 10

        bnum = self.zk.storeBuild(image, zk.ImageBuild.fromDict(build))
        self.zk.storeImageUpload(image, bnum, provider, up1)
        up2_id = self.zk.storeImageUpload(image, bnum, provider, up2)
        self.zk.storeImageUpload(image, bnum, provider, up3)

        # up2 should be the most recent 'ready' upload
        data = self.zk.getMostRecentBuildImageUploads(1, image, bnum, provider,
                                                      zk.READY)
        self.assertNotEqual([], data)
        self.assertEqual(1, len(data))
        self.assertEqual(data[0].id, up2_id)
예제 #11
0
    def test_ImageUpload_toDict(self):
        o = zk.ImageUpload('0001', '0003')
        o.state = zk.UPLOADING
        o.external_id = 'DEADBEEF'
        o.external_name = 'trusty'
        o.format = 'qcow2'

        d = o.toDict()
        self.assertNotIn('id', d)
        self.assertNotIn('build_id', d)
        self.assertNotIn('provider_name', d)
        self.assertNotIn('image_name', d)
        self.assertEqual(o.state, d['state'])
        self.assertEqual(o.state_time, d['state_time'])
        self.assertEqual(o.external_id, d['external_id'])
        self.assertEqual(o.external_name, d['external_name'])
        self.assertEqual(o.format, d['format'])
예제 #12
0
    def _uploadImage(self, build_id, upload_id, image_name, images, provider,
                     username):
        '''
        Upload a local DIB image build to a provider.

        :param str build_id: Unique ID of the image build to upload.
        :param str upload_id: Unique ID of the upload.
        :param str image_name: Name of the diskimage.
        :param list images: A list of DibImageFile objects from this build
            that available for uploading.
        :param provider: The provider from the parsed config file.
        :param username:
        '''
        start_time = time.time()
        timestamp = int(start_time)

        image = None
        for i in images:
            if provider.image_type == i.extension:
                image = i
                break

        if not image:
            raise exceptions.BuilderInvalidCommandError(
                "Unable to find image file of type %s for id %s to upload" %
                (provider.image_type, build_id)
            )

        self.log.debug("Found image file of type %s for image id: %s" %
                       (image.extension, image.image_id))

        filename = image.to_path(self._config.imagesdir, with_extension=True)

        ext_image_name = provider.image_name_format.format(
            image_name=image_name, timestamp=str(timestamp)
        )

        self.log.info("Uploading DIB image build %s from %s to %s" %
                      (build_id, filename, provider.name))

        manager = self._config.provider_managers[provider.name]
        provider_image = provider.diskimages.get(image_name)
        if provider_image is None:
            raise exceptions.BuilderInvalidCommandError(
                "Could not find matching provider image for %s" % image_name
            )

        meta = provider_image.meta.copy()
        meta['nodepool_build_id'] = build_id
        meta['nodepool_upload_id'] = upload_id

        try:
            external_id = manager.uploadImage(
                ext_image_name, filename,
                image_type=image.extension,
                meta=meta,
                md5=image.md5,
                sha256=image.sha256,
            )
        except Exception:
            self.log.exception("Failed to upload image %s to provider %s" %
                               (image_name, provider.name))
            data = zk.ImageUpload()
            data.state = zk.FAILED
            return data

        if self._statsd:
            dt = int((time.time() - start_time) * 1000)
            key = 'nodepool.image_update.%s.%s' % (image_name,
                                                   provider.name)
            self._statsd.timing(key, dt)
            self._statsd.incr(key)

        base = "-".join([image_name, build_id])
        self.log.info("Image build %s in %s is ready" %
                      (base, provider.name))

        data = zk.ImageUpload()
        data.state = zk.READY
        data.external_id = external_id
        data.external_name = ext_image_name
        data.format = image.extension
        data.username = username

        return data
예제 #13
0
    def _checkProviderImageUpload(self, provider, image):
        '''
        The main body of _checkForProviderUploads.  This encapsulates
        checking whether an image for a provider should be uploaded
        and performing the upload.  It is a separate function so that
        exception handling can treat all provider-image uploads
        indepedently.

        :returns: True if an upload was attempted, False otherwise.
        '''
        # Check if image uploads are paused.
        if provider.diskimages.get(image.name).pause:
            return False

        # Search for the most recent 'ready' image build
        builds = self._zk.getMostRecentBuilds(1, image.name,
                                              zk.READY)
        if not builds:
            return False

        build = builds[0]

        # Search for locally built images. The image name and build
        # sequence ID is used to name the image.
        local_images = DibImageFile.from_image_id(
            self._config.imagesdir, "-".join([image.name, build.id]))
        if not local_images:
            return False

        # See if this image has already been uploaded
        upload = self._zk.getMostRecentBuildImageUploads(
            1, image.name, build.id, provider.name, zk.READY)
        if upload:
            return False

        # See if this provider supports the available image formats
        if provider.image_type not in build.formats:
            return False

        try:
            with self._zk.imageUploadLock(
                image.name, build.id, provider.name,
                blocking=False
            ):
                # Verify once more that it hasn't been uploaded since the
                # last check.
                upload = self._zk.getMostRecentBuildImageUploads(
                    1, image.name, build.id, provider.name, zk.READY)
                if upload:
                    return False

                # NOTE: Due to the configuration file disagreement issue
                # (the copy we have may not be current), we try to verify
                # that another thread isn't trying to delete this build just
                # before we upload.
                b = self._zk.getBuild(image.name, build.id)
                if b.state == zk.DELETING:
                    return False

                # New upload number with initial state 'uploading'
                data = zk.ImageUpload()
                data.state = zk.UPLOADING
                data.username = build.username

                upnum = self._zk.storeImageUpload(
                    image.name, build.id, provider.name, data)

                data = self._uploadImage(build.id, upnum, image.name,
                                         local_images, provider,
                                         build.username)

                # Set final state
                self._zk.storeImageUpload(image.name, build.id,
                                          provider.name, data, upnum)
                return True
        except exceptions.ZKLockException:
            # Lock is already held. Skip it.
            return False