Beispiel #1
0
def vm_define_backup_list_all(request, data=None):
    """
    List (:http:get:`GET </vm/define/backup>`) all backup definitions for all VMs.

    .. http:get:: /vm/define/backup

        :DC-bound?:
            * |dc-yes|
        :Permissions:
            * |VmOwner|
        :Asynchronous?:
            * |async-no|
        :arg data.full: Return list of objects with all backup definition details (default: false)
        :type data.full: boolean
        :arg data.extended: Include total number of backups for each backup definition (default: false)
        :type data.extended: boolean
        :arg data.order_by: :ref:`Available fields for sorting <order_by>`: ``name``, ``disk_id``, ``hostname``, \
``created`` (default: ``hostname,-created``)
        :type data.order_by: string
        :status 200: SUCCESS
        :status 403: Forbidden
    """
    extra = output_extended_backup_count(request, data)
    # TODO: check indexes
    bkp_define = BackupDefine.objects.select_related('vm', 'vm__dc', 'node', 'zpool', 'periodic_task',
                                                     'periodic_task__crontab')\
                                     .filter(vm__in=get_vms(request)).order_by(*BackupDefineView.get_order_by(data))

    if extra:
        bkp_define = bkp_define.extra(extra)

    return BackupDefineView(request, data=data).get(None,
                                                    bkp_define,
                                                    many=True,
                                                    extended=bool(extra))
Beispiel #2
0
def vm_define_backup_list(request, hostname_or_uuid, data=None):
    """
    List (:http:get:`GET </vm/(hostname_or_uuid)/define/backup>`) all VM backup definitions.

    .. http:get:: /vm/(hostname_or_uuid)/define/backup

        :DC-bound?:
            * |dc-yes|
        :Permissions:
            * |VmOwner|
        :Asynchronous?:
            * |async-no|
        :arg hostname_or_uuid: **required** - Server hostname or uuid
        :type hostname_or_uuid: string
        :arg data.full: Return list of objects with all backup definition details (default: false)
        :type data.full: boolean
        :arg data.disk_id: Filter by disk number/ID
        :type data.disk_id: integer
        :arg data.extended: Include total number of backups for each backup definition (default: false)
        :type data.extended: boolean
        :arg data.order_by: :ref:`Available fields for sorting <order_by>`: ``name``, ``disk_id``, ``created`` \
(default: ``-created``)
        :type data.order_by: string
        :status 200: SUCCESS
        :status 403: Forbidden
        :status 404: VM not found
        :status 412: Invalid disk_id
    """
    vm = get_vm(request,
                hostname_or_uuid,
                exists_ok=True,
                noexists_fail=True,
                sr=('node', 'owner'))

    query_filter = {'vm': vm}
    query_filter = filter_disk_id(vm, query_filter, data)

    extra = output_extended_backup_count(request, data)
    # TODO: check indexes
    bkp_define = BackupDefine.objects.select_related('vm', 'vm__dc', 'node', 'zpool', 'periodic_task',
                                                     'periodic_task__crontab')\
                                     .filter(**query_filter).order_by(*BackupDefineView.get_order_by(data))

    if extra:
        bkp_define = bkp_define.extra(extra)

    return BackupDefineView(request, data=data).get(vm,
                                                    bkp_define,
                                                    many=True,
                                                    extended=bool(extra))
Beispiel #3
0
def node_vm_define_backup_list(request, hostname, data=None):
    """
    List (:http:get:`GET </node/(hostname)/define/backup>`) all backup definitions targeted onto a specific backup node.

    .. http:get:: /node/(hostname)/define/backup

        :DC-bound?:
            * |dc-no|
        :Permissions:
            * |Superadmin|
        :Asynchronous?:
            * |async-no|
        :arg hostname: **required** - Node hostname
        :type hostname: string
        :arg data.full: Return list of objects with all backup definition details (default: false)
        :type data.full: boolean
        :arg data.extended: Include total number of backups for each backup definition (default: false)
        :type data.extended: boolean
        :arg data.order_by: :ref:`Available fields for sorting <order_by>`: ``name``, ``disk_id``, ``hostname``, \
``created`` (default: ``hostname,-created``)
        :type data.order_by: string
        :status 200: SUCCESS
        :status 403: Forbidden
    """
    node = get_node(request, hostname, exists_ok=True, noexists_fail=True)
    extra = output_extended_backup_count(request, data)
    # TODO: check indexes
    bkp_define = BackupDefine.objects.select_related('vm', 'vm__dc', 'node', 'zpool', 'periodic_task',
                                                     'periodic_task__crontab')\
                                     .filter(node=node).order_by(*BackupDefineView.get_order_by(data))

    if extra:
        bkp_define = bkp_define.extra(extra)

    return BackupDefineView(request, data=data).get(None,
                                                    bkp_define,
                                                    many=True,
                                                    extended=bool(extra))
Beispiel #4
0
def vm_define_backup(request, hostname_or_uuid, bkpdef, data=None):
    """
    Show (:http:get:`GET </vm/(hostname_or_uuid)/define/backup/(bkpdef)>`),
    create (:http:post:`POST </vm/(hostname_or_uuid)/define/backup/(bkpdef)>`),
    remove (:http:delete:`DELETE </vm/(hostname_or_uuid)/define/backup/(bkpdef)>`) or
    update (:http:put:`PUT </vm/(hostname_or_uuid)/define/backup/(bkpdef)>`)
    a VM backup definition and schedule.

    .. http:get:: /vm/(hostname_or_uuid)/define/backup/(bkpdef)

        :DC-bound?:
            * |dc-yes|
        :Permissions:
            * |VmOwner|
        :Asynchronous?:
            * |async-no|
        :arg hostname_or_uuid: **required** - Server hostname or uuid
        :type hostname_or_uuid: string
        :arg bkpdef: **required** - Backup definition name
        :type bkpdef: string
        :arg data.disk_id: **required** - Disk number/ID (default: 1)
        :type data.disk_id: integer
        :arg data.extended: Include total number of backups (default: false)
        :type data.extended: boolean
        :status 200: SUCCESS
        :status 403: Forbidden
        :status 404: VM not found / Backup definition not found
        :status 412: Invalid disk_id

    .. http:post:: /vm/(hostname_or_uuid)/define/backup/(bkpdef)

        :DC-bound?:
            * |dc-yes|
        :Permissions:
            * |Admin|
        :Asynchronous?:
            * |async-no|
        :arg hostname_or_uuid: **required** - Server hostname or uuid
        :type hostname_or_uuid: string
        :arg bkpdef: **required** - Backup definition name (predefined: hourly, daily, weekly, monthly)
        :type bkpdef: string
        :arg data.disk_id: **required** - Disk number/ID (default: 1)
        :type data.disk_id: integer
        :arg data.type: **required** - Backup type (1 - dataset, 2 - file) (default: 1)
        :type: data.type: integer
        :arg data.node: **required** - Name of the backup node
        :type data.node: string
        :arg data.zpool: **required** - The zpool used on the backup node (default: zones)
        :type data.zpool: string
        :arg data.schedule: **required** - Schedule in UTC CRON format (e.g. 30 4 * * 6)
        :type data.schedule: string
        :arg data.retention: **required** - Maximum number of backups to keep
        :type data.retention: integer
        :arg data.active: Enable or disable backup schedule (default: true)
        :type data.active: boolean
        :arg data.compression: Backup file compression algorithm (0 - none, 1 - gzip, 2 - bzip2) (default: 0)
        :type data.compression: integer
        :arg data.bwlimit: Transfer rate limit in bytes (default: null => no limit)
        :type data.bwlimit: integer
        :arg data.desc: Backup definition description
        :type data.desc: string
        :arg data.fsfreeze: Whether to send filesystem freeze command to QEMU agent socket before \
creating backup snapshot (requires QEMU Guest Agent) (default: false)
        :type data.fsfreeze: boolean
        :status 200: SUCCESS
        :status 400: FAILURE
        :status 403: Forbidden
        :status 404: VM not found
        :status 406: Backup definition already exists
        :status 412: Invalid disk_id
        :status 423: Node is not operational / VM is not operational

    .. http:put:: /vm/(hostname_or_uuid)/define/backup/(bkpdef)

        :DC-bound?:
            * |dc-yes|
        :Permissions:
            * |Admin|
        :Asynchronous?:
            * |async-no|
        :arg hostname_or_uuid: **required** - Server hostname or uuid
        :type hostname_or_uuid: string
        :arg bkpdef: **required** - Backup definition name
        :type bkpdef: string
        :arg data.disk_id: **required** - Disk number/ID (default: 1)
        :type data.disk_id: integer
        :arg data.schedule: Schedule in UTC CRON format (e.g. 30 4 * * 6)
        :type data.schedule: string
        :arg data.retention: Maximum number of backups to keep
        :type data.retention: integer
        :arg data.active: Enable or disable backup schedule
        :type data.active: boolean
        :arg data.compression: Backup file compression algorithm (0 - none, 1 - gzip, 2 - bzip2)
        :type data.compression: integer
        :arg data.bwlimit: Transfer rate limit in bytes
        :type data.bwlimit: integer
        :arg data.desc: Backup definition description
        :type data.desc: string
        :status 200: SUCCESS
        :status 400: FAILURE
        :status 403: Forbidden
        :status 404: VM not found / Backup definition not found
        :status 412: Invalid disk_id
        :status 423: Node is not operational / VM is not operational

    .. http:delete:: /vm/(hostname_or_uuid)/define/backup/(bkpdef)

        :DC-bound?:
            * |dc-yes|
        :Permissions:
            * |Admin|
        :Asynchronous?:
            * |async-no|
        :arg hostname_or_uuid: **required** - Server hostname or uuid
        :type hostname_or_uuid: string
        :arg bkpdef: **required** - Backup definition name
        :type bkpdef: string
        :arg data.disk_id: **required** - Disk number/ID (default: 1)
        :type data.disk_id: integer
        :status 200: SUCCESS
        :status 400: FAILURE
        :status 403: Forbidden
        :status 404: VM not found / Backup definition not found
        :status 412: Invalid disk_id
        :status 423: Node is not operational / VM is not operational

    """
    vm = get_vm(request, hostname_or_uuid, exists_ok=True, noexists_fail=True)

    disk_id, real_disk_id, zfs_filesystem = get_disk_id(request, vm, data)

    extra = output_extended_backup_count(request, data)

    define = get_object(request,
                        BackupDefine, {
                            'name': bkpdef,
                            'vm': vm,
                            'disk_id': real_disk_id
                        },
                        sr=('vm', 'vm__dc', 'node', 'periodic_task',
                            'periodic_task__crontab'),
                        extra={'select': extra})

    return BackupDefineView(request, data=data).response(vm,
                                                         define,
                                                         extended=bool(extra))
Beispiel #5
0
def vm_create_cb(result, task_id, vm_uuid=None):
    """
    A callback function for api.vm.base.views.vm_manage.
    """
    vm = Vm.objects.select_related('dc').get(uuid=vm_uuid)
    msg = result.get('message', '')

    if result['returncode'] == 0 and msg.find('Successfully created') >= 0:
        json = result.pop('json', None)

        try:  # save json from smartos
            json_active = vm.json.load(json)
            vm.json_active = json_active
            vm.json = json_active
            if result['meta']['apiview']['recreate']:
                Snapshot.objects.filter(vm=vm).delete()
                SnapshotDefine.objects.filter(vm=vm).delete()
                BackupDefine.objects.filter(vm=vm).delete()
                vm.save_metadata('installed', False, save=False)

        except Exception as e:
            logger.error(
                'Could not parse json output from POST vm_manage(%s). Error: %s',
                vm_uuid, e)
            _vm_error(task_id, vm)
            logger.exception(e)
            raise TaskException(result, 'Could not parse json output')

        else:
            # save all
            vm.save(update_node_resources=True, update_storage_resources=True)
            vm_update_ipaddress_usage(vm)
            # vm_json_active_changed.send(task_id, vm=vm)  # Signal! -> not needed because vm_deployed is called below
            vm_created.send(task_id, vm=vm)  # Signal!

            if msg.find('Successfully started'
                        ) < 0:  # VM was created, but could not be started
                logger.error(
                    'VM %s was created, but could not be started! Error: %s',
                    vm_uuid, msg)
                _vm_error(task_id, vm)
                raise TaskException(result, 'Initial start failed (%s)' % msg)

            sendmail(vm.owner,
                     'vm/base/vm_create_subject.txt',
                     'vm/base/vm_create_email.txt',
                     extra_context={'vm': vm},
                     user_i18n=True,
                     dc=vm.dc,
                     fail_silently=True)

    else:
        logger.error(
            'Found nonzero returncode in result from POST vm_manage(%s). Error: %s',
            vm_uuid, msg)
        # Revert status and inform user
        _vm_create_cb_failed(result, task_id, vm)

        if result['meta']['apiview']['recreate'] and msg.find(
                'Successfully deleted') >= 0:
            _vm_error(task_id, vm)  # Something went terribly wrong

        # and FAIL this task
        raise TaskException(
            result, 'Got bad return code (%s). Error: %s' %
            (result['returncode'], msg))

    # So far so good. Now wait for deploy_over in vm_status_event_cb
    logger.info('VM %s is waiting for deploy_over...', vm_uuid)
    timer = 0
    repeat = 0

    while not vm.has_deploy_finished():
        if timer > VMS_VM_DEPLOY_TOOLONG:  # 10 minutes is too long
            if repeat == VMS_VM_DEPLOY_TOOLONG_MAX_CYCLES:  # 20 minutes is really too long
                logger.error('VM %s deploy process has timed out!', vm_uuid)
                _vm_error(task_id, vm)
                result['message'] = 'VM %s deploy has timed out' % vm.hostname
                task_log_cb_error(result, task_id, vm=vm, **result['meta'])
                return result

            repeat += 1
            timer = 0
            logger.error(
                'VM %s takes too long to deploy. Sending force stop/start',
                vm_uuid)
            # noinspection PyUnusedLocal
            tid, err = vm_reset(vm)

        sleep(3.0)
        timer += 3

    logger.info('VM %s is completely deployed!', vm_uuid)
    internal_metadata = vm.json.get(
        'internal_metadata', {}).copy()  # save internal_metadata for email
    vm = Vm.objects.select_related('dc', 'template').get(pk=vm.pk)  # Reload vm
    vm_deployed.send(task_id, vm=vm)  # Signal!
    sendmail(vm.owner,
             'vm/base/vm_deploy_subject.txt',
             'vm/base/vm_deploy_email.txt',
             fail_silently=True,
             extra_context={
                 'vm': vm,
                 'internal_metadata': internal_metadata
             },
             user_i18n=True,
             dc=vm.dc)

    try:
        result['message'] = '\n'.join(result['message'].strip().split('\n')
                                      [:-1])  # Remove "started" stuff
    except Exception as e:
        logger.exception(e)

    task_log_cb_success(result, task_id, vm=vm, **result['meta'])

    try:
        if vm.template:  # Try to create snapshot/backup definitions defined by template
            vm_define_snapshot, vm_define_backup = vm.template.vm_define_snapshot, vm.template.vm_define_backup

            if vm_define_snapshot or vm_define_backup:
                user = User.objects.get(id=user_id_from_task_id(task_id))
                request = get_dummy_request(vm.dc, method='POST', user=user)
                SnapshotDefineView.create_from_template(request,
                                                        vm,
                                                        vm_define_snapshot,
                                                        log=logger)
                BackupDefineView.create_from_template(request,
                                                      vm,
                                                      vm_define_backup,
                                                      log=logger)
    except Exception as e:
        logger.exception(e)

    return result