Exemple #1
0
    def create(self, vm, snap):
        """Create [POST] image from VM snapshot (ImageAdmin).

        This is always a DC bound task, but the task_id has a DC_UNBOUND task group flag,
        because socket.io will inform any admin regardless of the current admin DC.
        The callback is responsible for attaching the image into current DC.
        """
        img, data, request = self.img, self.data, self.request

        assert request.dc == vm.dc

        if vm.uuid in settings.VMS_INTERNAL:  # Bug #chili-792
            raise PreconditionRequired('Internal VM can\'t be used for creating images')

        data.pop('dc_bound', None)  # Default DC binding cannot be changed when creating Image for the first time
        img.dc_bound = vm.dc        # Default DC binding set to VM DC (cannot be changed, ^^^)
        img.ostype = vm.ostype      # Default ostype inherited from VM (cannot be changed)
        img.size = snap.disk_size   # Default disk size inherited from VM (cannot be changed)
        img.owner = request.user    # Default user (can be changed)
        img.alias = img.name        # Default alias (can be changed)
        img.status = Image.OK       # Set status for preliminary checks
        # Validate data (manifest info)
        ser = ImageSerializer(request, img, data)

        if not ser.is_valid():
            return FailureTaskResponse(request, ser.errors, dc_bound=self.dc_bound)

        # Preliminary checks
        self._run_checks(img_server_must_exist=True)  # This sets self.img_server to ImageVm()

        if vm.status not in (vm.RUNNING, vm.STOPPED, vm.STOPPING, vm.FROZEN):
            raise VmIsNotOperational

        if snap.status != snap.OK:
            raise ExpectationFailed('VM snapshot status is not OK')

        # Build manifest and set PENDING status
        # noinspection PyUnusedLocal
        data = ser.data
        img.manifest = img.build_manifest()
        img.status = Image.PENDING
        img.src_vm = vm
        img.src_snap = snap
        img.save()
        # Set snapshot status to PENDING
        snap.save_status(snap.PENDING)
        # Build command
        cmd_add = ' ; e=$?; cat %s/%s/manifest 2>&1; exit $e' % (self.img_server.datasets_dir, img.uuid)
        cmd = 'esimg create -s %s@%s' % (snap.zfs_filesystem, snap.zfs_name)

        if self.img_server.node != vm.node:
            cmd += ' -H %s' % vm.node.address

        return self._run_execute(LOG_IMAGE_CREATE, cmd, stdin=img.manifest.dump(), delete_on_error=True, vm=vm,
                                 snap=snap, error_fun=lambda: snap.save_status(snap.OK), detail_dict=ser.detail_dict(),
                                 cmd_add=cmd_add)
Exemple #2
0
    def put(self):
        """Update [PUT] image manifest in DB and on image server if needed.

        The task group is always DC unbound, but the current DC depends on the dc_bound flag:
            - dc_bound=False:   task DC is default DC
            - dc_bound=[DC]:    task DC is dc_bound DC
        The callback is responsible for restoring the active manifest if something goes wrong.
        """
        img = self.img
        ser = ImageSerializer(self.request, img, self.data, partial=True)
        img_backup = ser.create_img_backup()

        if not ser.is_valid():
            return FailureTaskResponse(self.request,
                                       ser.errors,
                                       dc_bound=self.dc_bound)

        # Preliminary checks
        self._run_checks()  # This sets self.img_server to ImageVm()
        ser_data = ser.data

        if ser.update_manifest:
            # Rebuild manifest
            img.manifest = img.build_manifest()

        if self.img_server and ser.update_manifest:
            img.status = Image.PENDING
            img.backup = img_backup
            img.save()

            return self._run_execute(LOG_IMAGE_UPDATE,
                                     'esimg update',
                                     stdin=img.manifest.dump(),
                                     recover_on_error=img_backup,
                                     detail_dict=ser.detail_dict())
        else:
            # Just save new data
            img.manifest_active = img.manifest
            img.save()

            return SuccessTaskResponse(self.request,
                                       ser_data,
                                       obj=img,
                                       msg=LOG_IMAGE_UPDATE,
                                       detail_dict=ser.detail_dict(),
                                       dc_bound=self.dc_bound)
Exemple #3
0
    def post(self):
        """Import [POST] image from URL.

        This is always a DC bound task, but the task_id has a DC_UNBOUND task group flag,
        because socket.io will inform any admin regardless of the current admin DC.
        The callback is responsible for attaching the image into current DC if the image is dc_bound.
        """
        img, data, request = self.img, self.data, self.request

        # ImageImportAdmin permission is required
        if not request.user.has_permission(request,
                                           ImageImportAdminPermission.name):
            raise PermissionDenied

        # Validate URL and file URL
        ser_import = ImportImageSerializer(img, data=data)

        if not ser_import.is_valid():
            return FailureTaskResponse(request,
                                       ser_import.errors,
                                       dc_bound=self.dc_bound)

        if not request.user.is_staff:
            self.data.pop(
                'dc_bound', None
            )  # default DC binding cannot be changed when creating object

        img.manifest = ser_import.manifest  # Load imported manifest
        img.owner = request.user  # Default user (can be changed)
        img.alias = img.name  # Default alias (can be changed)
        img.status = Image.OK  # Set status for preliminary checks

        # More default fields retrieved from the downloaded image manifest
        for img_field in ('version', 'desc', 'resize', 'deploy', 'tags'):
            if img_field not in data:
                def_value = getattr(img, img_field, None)
                if def_value:
                    data[img_field] = def_value

        # Validate data for overriding manifest info
        ser = ImageSerializer(request, img, data)

        if not ser.is_valid():
            return FailureTaskResponse(request,
                                       ser.errors,
                                       dc_bound=self.dc_bound)

        # Preliminary checks
        self._run_checks()
        # Build new manifest
        img.manifest = img.build_manifest()
        # Add URL into detail dict
        ser_data = ser.data
        dd = ser.detail_dict()
        dd.update(ser_import.detail_dict())

        if self.img_server:
            img.status = Image.PENDING
            img.save()

            if ser_import.img_file_url.startswith(self.img_server.repo_url):
                logger.info(
                    'Importing image from local image server - assuming that image exists on server'
                )
                cmd = 'esimg update -c'
            else:
                cmd = 'esimg import -f %s' % ser_import.img_file_url

            return self._run_execute(LOG_IMAGE_IMPORT,
                                     cmd,
                                     stdin=img.manifest.dump(),
                                     delete_on_error=True,
                                     detail_dict=dd)
        else:
            img.status = Image.OK
            img.manifest_active = img.manifest
            img.save()

            return SuccessTaskResponse(self.request,
                                       ser_data,
                                       obj=img,
                                       msg=LOG_IMAGE_IMPORT,
                                       detail_dict=dd,
                                       dc_bound=self.dc_bound)