Example #1
0
    def batch_loads(self, request):
        if request.method == 'GET':
            files = scan_task_event_resource()
            return response.Response({'files': files})
        elif request.method == 'POST':
            UPLOADTOKEN = 'uploadToken'
            filenames = request.data.getlist('filenames', [])
            attachment_file = request.FILES.get('attachment', None)
            upload_token = request.query_params.get(UPLOADTOKEN, None)

            if attachment_file:
                destination = open(
                    os.path.join(resource_api_setting.LOAD_TMP_DIR,
                                 attachment_file.name), 'wb+')
                for chunk in attachment_file.chunks():  # 分块写入文件
                    destination.write(chunk)
                destination.close()
                filenames = [attachment_file.name]
            if not filenames:
                return response.Response(status=status.HTTP_201_CREATED)

            delay_task.new_task(
                self._batch_loads, 2,
                (filenames, upload_token, attachment_file.name))

            return response.Response(status=status.HTTP_201_CREATED)
Example #2
0
    def sub_perform_create(self, serializer):
        serializer.save()
        instance = serializer.instance
        file_path = instance.encrypt_file.path

        try:
            extract_to_path = self.unzip(file_path, serializer)
            new_task(self._do_update, 0, (extract_to_path, ))
        except Exception as e:
            logger.error("update error msg[%s]", str(e))
            raise exceptions.ValidationError(error.WRONG_UPDATE_ZIP)

        return True
Example #3
0
    def create(self,
               image_name,
               vm_id=None,
               container_id=None,
               image_file=None,
               ftp_file_name=None,
               meta_data=None,
               created=None,
               failed=None,
               timeout_callback=None):
        check_type = 'Image'
        if vm_id:
            image_id = self.operator.create_snapshot(vm_id, image_name)
            image = self.get(image_id)
            # # snapshot
            # bdm = getattr(image, 'block_device_mapping', None)
            # if bdm:
            #     try:
            #         block_snap_id = json.loads(bdm)[0].get("snapshot_id")
            #         self.operator.check_volume_snapshot_status(block_snap_id)
            #     except Exception:
            #         pass
            # else:
            #     image = self.operator.check_image_status(image_id)
            check_type = 'Snapshot'
        elif container_id:
            image = self.operator.save_image(container_id, image_name)
        elif image_file:
            params = {
                'name': image_name,
                'image_file': image_file,
            }
            if meta_data:
                params.update(meta_data)
            image = self.operator.create_image(**params)
        elif ftp_file_name:
            params = {
                'name': image_name,
                'file_name': ftp_file_name,
            }
            if meta_data:
                params.update(meta_data)
            image = self.operator.create_image_by_ftp(**params)
        else:
            raise Exception('param error: no resource for creating image')

        if created or failed:
            new_task(self.operator.check_image_status, 0,
                     (image.id, check_type, created, failed, timeout_callback))

        return image
Example #4
0
def clear_unexcept_standard_device_tmp_vm():
    from common_env.models import StandardDeviceEditServer
    from common_env.utils.standard_device import delete_tmp_vm
    # 每隔半小时清除半小时内还没完成的机器
    tmp_vms = StandardDeviceEditServer.objects.filter(
        create_time__lt=(timezone.now() - datetime.timedelta(minutes=30)),
        status__in=(StandardDeviceEditServer.Status.CREATING,
                    StandardDeviceEditServer.Status.STARTING),
    )
    for tmp_vm in tmp_vms:
        delete_tmp_vm(tmp_vm)

    # 半小时执行一次
    from common_framework.utils import delay_task
    delay_task.new_task(clear_unexcept_standard_device_tmp_vm, 60 * 30, ())
Example #5
0
    def update_online(self, request):
        zip_url = self.shift_data.get('url')
        file_path = "/tmp/%s.zip" % str(uuid.uuid4())

        import requests
        r = requests.get(zip_url, stream=True)
        with open(file_path, "wb") as zip:
            for chunk in r.iter_content(chunk_size=1024):
                if chunk:
                    zip.write(chunk)

        extract_to_path = self.unzip(file_path)

        new_task(self._do_update, 0, (extract_to_path, ))
        return response.Response({'status': 'ok'})
Example #6
0
def callback(**kwargs):
    from common_framework.utils import delay_task

    if not settings.DEBUG:
        delay_task.new_task(clear_not_use_resources, 0, ())

    def normal_callback():
        clear_expired_env()
        clear_unexcept_envs()
        clear_unexcept_standard_device_tmp_vm()

    delay_task.new_task(normal_callback, 0, ())

    clear_uncontrol_standard_device_tmp_vm()

    from common_remote.managers import check_setting
    check_setting()
Example #7
0
def clear_unexcept_envs():
    from common_env.models import Env, EnvTerminal
    from common_env.handlers.manager import admin_delete_env
    unexcept_envs = Env.objects.exclude(
        envterminal__status=EnvTerminal.Status.DELETED, ).filter(
            status__in=Env.Status.DELETED, )
    for env in unexcept_envs:
        try:
            admin_delete_env(env)
            logger.info('clear unexcept env[env_id=%s] ok', env.id)
        except Exception as e:
            logger.error('clear unexcept env[env_id=%s] error: %s', env.id,
                         str(e))

    # 半小时执行一次
    from common_framework.utils import delay_task
    delay_task.new_task(clear_unexcept_envs, 60 * 30, ())
Example #8
0
def recording_convert(request):
    host_ip = request.data.get('host_ip')
    convert_key = request.data.get('convert_key')
    convert_params = json.loads(request.data.get('convert_params', '{}'))
    recording_name = request.data.get('recording_name')
    screen_size = request.data.get('screen_size') or '1366x768'
    if not convert_key or not recording_name or not isinstance(
            convert_params, dict):
        raise PermissionDenied()

    convert_func = api_settings.RECORDING_CONVERT_CALLBACK.get(convert_key)
    if not convert_func:
        raise PermissionDenied()

    def tmp_task():
        remote_manager = RemoteManager(host=host_ip)
        callback_script = ''
        if host_ip and host_ip != api_settings.OJ_SERVER['host_ip']:
            executor = {
                'func': delay_convert_callback,
                'params': {
                    'recording_name': recording_name,
                    'screen_size': screen_size,
                    'convert_func': convert_func,
                    'convert_params': convert_params,
                }
            }
            condition = RecordingConvertTask.dump_executor(executor)
            task = RecordingConvertTask.objects.filter(**condition).first()
            if not task:
                task = RecordingConvertTask.objects.create(extra=executor.get(
                    'extra', ''),
                                                           **condition)
            callback_url = settings.SERVER_HOST + reverse(
                'common_remote:recording_convert_over', (task.id, ))
            callback_script = 'curl {callback_url}'.format(
                callback_url=callback_url)
        video_names = remote_manager.convert_recording(
            recording_name,
            screen_size=screen_size,
            callback_script=callback_script)
        convert_func(video_names, screen_size, **convert_params)

    new_task(tmp_task, 0, ())

    return Response({})
Example #9
0
    def _destroy_env_related(cls, env):
        def tmp_task():
            logger.info('delete env[%s] related start', env.pk)
            # 删除关联测试场景
            test_env_map = env_models.TestEnvMap.objects.filter(
                template_env=env).first()
            if test_env_map:
                try:
                    admin_delete_env(test_env_map.test_env)
                except Exception as e:
                    logger.error('delete env[%s] related test env error: %s',
                                 env.pk, e)
            # 删除关联快照场景
            snapshot_env_map = env_models.SnapshotEnvMap.objects.filter(
                template_env=env).first()
            if snapshot_env_map:
                try:
                    admin_delete_env(snapshot_env_map.tmp_env)
                except Exception as e:
                    logger.error(
                        'delete env[%s] related snapshot env error: %s',
                        env.pk, e)
            # 删除快照
            image_ids = [
                envterminal.image_id
                for envterminal in env.envterminal_set.all()
            ]
            image_ids = filter(lambda x: x, image_ids)
            for image_id in image_ids:
                try:
                    scene.image.delete(image_id)
                except Exception as e:
                    logger.error('delete env[%s] related snapshot error: %s',
                                 env.pk, e)
            logger.info('delete env[%s] related end', env.pk)

        new_task(tmp_task, 0, ())
Example #10
0
def clear_expired_env():
    try:
        from common_env.handlers.manager import admin_delete_env
        from common_env.models import Env, TestEnvMap

        from course.models import LessonEnv
        from practice.base_models import TaskEnv

        now_time = timezone.now()

        # 题目环境
        expired_task_envs = TaskEnv.objects.exclude(env=None).filter(
            env__status__in=(Env.Status.CREATING, Env.Status.USING),
            destroy_time__lte=timezone.now())

        for task_env in expired_task_envs:
            try:
                admin_delete_env(task_env.env)
                logger.info(
                    'clear expired task env[task_env_id=%s, env_id=%s] ok' %
                    (task_env.id, task_env.env.id))
            except Exception as e:
                logger.error(
                    'clear expired task env[task_env_id=%s, env_id=%s] error: %s'
                    % (task_env.id, task_env.env.id, str(e)))

        # 实验环境
        expired_lesson_envs = LessonEnv.objects.exclude(env=None).filter(
            env__status__in=(Env.Status.CREATING, Env.Status.USING),
            destroy_time__lte=timezone.now())
        for lesson_env in expired_lesson_envs:
            try:
                admin_delete_env(lesson_env.env)
                logger.info(
                    'clear expired lesson env[lesson_env_id=%s, env_id=%s] ok'
                    % (lesson_env.id, lesson_env.env.id))
            except Exception as e:
                logger.error(
                    'clear expired lesson env[lesson_env_id=%s, env_id=%s] error: %s'
                    % (lesson_env.id, lesson_env.env.id, str(e)))

        # 场景测试环境
        prev_time = now_time - datetime.timedelta(hours=2)
        test_env_maps = TestEnvMap.objects.exclude(test_env=None).filter(
            test_env__status__in=Env.ActiveStatusList,
            test_env__create_time__lte=prev_time,
        )

        for test_env_map in test_env_maps:
            try:
                admin_delete_env(test_env_map.test_env)
                logger.info(
                    'clear expired test env[test_env_map_id=%s, env_id=%s] ok'
                    % (test_env_map.id, test_env_map.test_env.id))
            except Exception as e:
                logger.error(
                    'clear expired test env[test_env_map_id=%s, env_id=%s] error: %s'
                    % (test_env_map.id, test_env_map.test_env.id, str(e)))

        connection.close()
    except Exception as e:
        logger.error('clear expired task env error: %s' % str(e))

    from common_framework.utils import delay_task
    delay_task.new_task(clear_expired_env, 60 * 2, ())
Example #11
0
def clear_not_use_resources():
    logger.info('clear not use resources start')
    # 清除场景相关的资源
    try:
        from common_env.handlers.local_lib import scene
        from common_env.models import Env, EnvTerminal, EnvNet, EnvGateway, StandardDeviceEditServer
        from common_env.setting import api_settings as common_env_settings
        from common_scene.setting import api_settings as common_scene_settings
        from common_scene.complex.views import BaseScene
        from common_scene.clients.neutron_client import Client as NeutronClient

        operator = BaseScene()

        using_status = Env.ActiveStatusList

        vms = operator.list_server(prefix=common_env_settings.BASE_GROUP_NAME)
        dockers = operator.list_container(
            prefix=common_env_settings.BASE_GROUP_NAME)
        routers = operator.list_router(
            prefix=common_env_settings.BASE_GROUP_NAME)
        firewalls = operator.list_firewall(
            prefix=common_env_settings.BASE_GROUP_NAME)
        networks = operator.list_network(
            prefix=common_env_settings.BASE_GROUP_NAME)

        _clear_resources([vm.id for vm in vms], scene.vm.delete, [
            (EnvTerminal.objects.filter(
                env__status__in=using_status,
                image_type=EnvTerminal.ImageType.VM), 'vm_id'),
            (StandardDeviceEditServer.objects.exclude(
                status=StandardDeviceEditServer.Status.DELETED), 'tmp_vm_id')
        ], 'clear not use env resources: not_use_vm_ids - %s')
        _clear_resources(
            [docker.id for docker in dockers], scene.docker.delete,
            [(EnvTerminal.objects.filter(
                env__status__in=using_status,
                image_type=EnvTerminal.ImageType.DOCKER), 'vm_id'),
             (StandardDeviceEditServer.objects.exclude(
                 status=StandardDeviceEditServer.Status.DELETED),
              'tmp_docker_id')],
            'clear not use env resources: not_use_docker_ids - %s')
        _clear_resources(
            [router['id'] for router in routers], scene.router.delete,
            [(EnvGateway.objects.filter(env__status__in=using_status),
              'router_id'),
             (StandardDeviceEditServer.objects.exclude(
                 status=StandardDeviceEditServer.Status.DELETED),
              'tmp_router_id')],
            'clear not use env resources: not_use_router_ids - %s')
        _clear_resources(
            [firewall['id'] for firewall in firewalls], scene.firewall.delete,
            [
                (EnvGateway.objects.filter(env__status__in=using_status),
                 'firewall_id'),
            ], 'clear not use env resources: not_use_firewall_ids - %s')
        _clear_resources(
            [network['id'] for network in networks], scene.network.delete,
            [(EnvNet.objects.filter(env__status__in=using_status), 'net_id'),
             (StandardDeviceEditServer.objects.exclude(
                 status=StandardDeviceEditServer.Status.DELETED),
              'tmp_network_id')],
            'clear not use env resources: not_use_network_ids - %s')

        operator.clear_unused_port()

        logger.info('clear not use env resources ok')
    except Exception as e:
        logger.error('clear not use env resources error: %s' % str(e))

    # 清除攻防赛相关的资源, 攻防赛机器使用的是场景的, 只需清理路由和网络
    try:
        from event_attack_defense.models import AttackDefenseEvent
        from event_attack_defense.setting import api_settings as event_ad_settings

        routers = operator.list_router(
            prefix=event_ad_settings.BASE_GROUP_NAME)
        networks = operator.list_network(
            prefix=event_ad_settings.BASE_GROUP_NAME)

        _clear_resources(
            [router['id'] for router in routers], scene.router.delete, [
                (AttackDefenseEvent.objects.all(), 'global_router'),
            ], 'clear not use ad event resources: not_use_router_ids - %s')

        _clear_resources(
            [network['id'] for network in networks], scene.network.delete, [
                (AttackDefenseEvent.objects.all(), 'global_network'),
            ], 'clear not use ad event resources: not_use_network_ids - %s')

        logger.info('clear not use ad event resources ok')

    except Exception as e:
        logger.error('clear not use ad event resources error: %s' % str(e))

    # 清除错误资源
    try:
        error_vms = operator.list_server(
            prefix=common_env_settings.BASE_GROUP_NAME,
            search_opts={'status': 'ERROR'})
        error_vm_ids = [error_vm.id for error_vm in error_vms]
        if error_vm_ids:
            logger.info('clear error resources: error_vm_ids - %s',
                        error_vm_ids)
            for vm_id in error_vm_ids:
                scene.vm.delete(vm_id)

        dockers = operator.list_container(
            prefix=common_env_settings.BASE_GROUP_NAME)
        error_docker_ids = [
            docker.id for docker in dockers if docker.status.lower() == 'error'
        ]
        if error_docker_ids:
            logger.info('clear error resources: error_docker_ids - %s',
                        error_docker_ids)
            for docker_id in error_docker_ids:
                scene.docker.delete(docker_id)
    except Exception as e:
        logger.error('clear error resources error: %s' % str(e))

    logger.info('clear not use resources end')

    # 一天执行一次
    from common_framework.utils import delay_task
    delay_task.new_task(clear_not_use_resources, 60 * 60 * 24, ())
Example #12
0
    def image(self, request, pk=None):
        if request.method == 'POST':
            device = self.get_object()
            if not device.tmp_vm or (not device.tmp_vm.tmp_vm_id
                                     and not device.tmp_vm.tmp_docker_id):
                raise exceptions.ValidationError(error.NO_TMP_ENV)

            if device.image_status == env_models.StandardDevice.ImageStatus.CREATING:
                raise exceptions.ValidationError(error.IMAGE_SAVING)

            device.image_status = env_models.StandardDevice.ImageStatus.CREATING
            device.save()
            self.clear_cache()

            def _create_image():
                image_name = device.name
                # # snapshot
                # image_name = '{}__$__{}'.format(image_name, str(uuid.uuid4()))
                # 删除旧的镜像
                try:
                    old_image_id = scene.image.get(image_name=image_name).id
                except:
                    old_image_id = None

                def created(image):
                    logger.info('device[%s] image created', device.pk)
                    device.image_status = env_models.StandardDevice.ImageStatus.CREATED
                    try:
                        device.save()
                        # # snapshot
                        # env_models.StandardDeviceSnapshot.objects.create(
                        #     standard_device=device,
                        #     name=image_name,
                        # )
                    except Exception as e:
                        logger.error('save standard device[%s] error: %s',
                                     device.pk, e)

                    # # snapshot
                    # if device.tmp_vm.tmp_vm_id:
                    #     try:
                    #         delete_tmp_vm(device.tmp_vm)
                    #     except Exception as e:
                    #         logger.error('delete standard device[%s] tmp vm error: %s', device.pk, e)
                    self.clear_cache()
                    # 删除旧的镜像
                    if old_image_id:
                        scene.image.delete(image_id=old_image_id)

                def failed(error):
                    logger.info('device[%s] image failed', device.pk)
                    device.image_status = env_models.StandardDevice.ImageStatus.ERROR
                    try:
                        device.save()
                    except Exception as e:
                        logger.error('save standard device[%s] error: %s',
                                     device.pk, e)
                    self.clear_cache()

                    # # snapshot
                    # if device.tmp_vm.tmp_vm_id:
                    #     scene.vm.start(device.tmp_vm.tmp_vm_id)

                try:
                    if device.tmp_vm.tmp_vm_id:
                        # # snapshot
                        # scene.vm.shutdown(device.tmp_vm.tmp_vm_id)
                        scene.image.create(image_name,
                                           vm_id=device.tmp_vm.tmp_vm_id,
                                           created=created,
                                           failed=failed,
                                           timeout_callback=created)
                    elif device.tmp_vm.tmp_docker_id:
                        scene.image.create(
                            image_name,
                            container_id=device.tmp_vm.tmp_docker_id,
                            created=created,
                            failed=failed,
                            timeout_callback=created)
                    else:
                        raise exceptions.ValidationError(error.NO_TMP_ENV)
                except Exception as e:
                    logger.error('device[%s] save image error: %s', device.pk,
                                 e)
                    device.error = e.message
                    device.image_status = env_models.StandardDevice.ImageStatus.ERROR
                    device.save()
                    self.clear_cache()

            new_task(_create_image, 0, ())
            return Response({})
Example #13
0
            def _create_vm():
                if device.error:
                    env_models.StandardDevice.objects.filter(
                        pk=device.pk).update(error='')

                # 建机器
                try:
                    creater = StandardDeviceTmpVmCreater(image_name, device)
                    ret = creater.create_resource()
                except Exception as e:
                    env_models.StandardDevice.objects.filter(
                        pk=device.pk).update(error=e.message)
                    device.tmp_vm.delete()
                    self.clear_cache()
                    return

                logger.info(
                    'create template vm for device[%s] by image[%s] return[%s]: waiting for update'
                    % (device.pk, image_name, ret))
                float_ip = ret['float_ip']
                port = device.access_port or env_models.EnvTerminal.AccessModeDefaultPort.get(
                    device.access_mode)
                update_params = {}

                if device.access_mode in (
                        env_models.EnvTerminal.AccessMode.SSH,
                        env_models.EnvTerminal.AccessMode.RDP):
                    # 建连接
                    remote_manager = RemoteManager(request.user)
                    connection_name = '%s:%s:%s:%s' % (
                        request.user.id, float_ip, port,
                        hashlib.md5(str(uuid.uuid4())).hexdigest())
                    params = {
                        'username': ret['username'],
                        'password': ret['password'],
                    }
                    try:
                        if device.access_mode == env_models.EnvTerminal.AccessMode.SSH:
                            connection_id = remote_manager.create_ssh_connection(
                                connection_name, float_ip,
                                **params).connection_id
                        elif device.access_mode == env_models.EnvTerminal.AccessMode.RDP:
                            params[
                                'security'] = device.access_connection_mode or 'rdp'
                            if device.system_type == env_models.StandardDevice.SystemType.LINUX:
                                params['enable-sftp'] = 'true'
                            connection_id = remote_manager.create_rdp_connection(
                                connection_name, float_ip,
                                **params).connection_id
                        update_params['connection_id'] = connection_id
                    except Exception as e:
                        logger.error('create guacamole connection error: %s',
                                     e)

                # 建代理
                if port and proxy.PROXY_SWITCH:
                    try:
                        proxy_ports = proxy.create_proxy(float_ip, [port])
                    except Exception as e:
                        logger.error('create tmp_vm[%s] proxy error: %s' %
                                     (device.tmp_vm.id, e))
                        env_models.StandardDevice.objects.filter(
                            pk=device.pk).update(error=e.message)
                        creater.rollback_resource()
                        device.tmp_vm.delete()
                        self.clear_cache()
                        raise e
                    logger.info(
                        'create template vm for device[%s] by image[%s]: create proxy %s:%s --> %s'
                        % (device.pk, image_name, float_ip, port, proxy_ports))
                    if len(proxy_ports) > 0:
                        update_params['proxy_port'] = proxy_ports[0]
                        proxy.restart_proxy()

                tmp_vm = device.tmp_vm
                # 获取最新的数据
                lastest_tmp_vm = env_models.StandardDeviceEditServer.objects.get(
                    pk=tmp_vm.pk)
                if lastest_tmp_vm.status == env_models.StandardDeviceEditServer.Status.RUNNING:
                    tmp_vm_status = env_models.StandardDeviceEditServer.Status.RUNNING
                else:
                    tmp_vm_status = env_models.StandardDeviceEditServer.Status.STARTING

                update_params.update({
                    'tmp_network_ids':
                    json.dumps(ret['network_ids']),
                    'tmp_router_ids':
                    json.dumps(ret['router_ids']),
                    'tmp_docker_id':
                    ret['docker_id'],
                    'tmp_vm_id':
                    ret['vm_id'],
                    'tmp_net_ports':
                    json.dumps(ret['net_ports']),
                    'protocol':
                    device.access_mode,
                    'float_ip':
                    float_ip,
                    'host_ip':
                    ret['host_ip'],
                    'host_name':
                    ret['host_name'],
                    'port':
                    port,
                    'username':
                    ret['username'],
                    'password':
                    ret['password'],
                    'status':
                    tmp_vm_status,
                })

                try:
                    env_models.StandardDeviceEditServer.objects.filter(
                        pk=tmp_vm.pk).update(**update_params)
                except Exception as e:
                    logger.error('update tmp_vm[%s] error: %s' %
                                 (tmp_vm.id, e))
                    delete_tmp_vm(tmp_vm, destroy=False)
                    raise e
                self.clear_cache()
                new_task(self._check_tmp_vm_status, 0, (tmp_vm.id, device))
Example #14
0
    def tmp_vm(self, request, pk=None):
        if request.method == 'GET':
            device = self.get_object()
            if device.tmp_vm:
                data = mserializers.StandardDeviceEditServerSerializer(
                    device.tmp_vm).data
            else:
                data = None
            return Response(data)
        elif request.method == 'POST':
            device = self.get_object()
            if device.access_mode not in (
                    env_models.EnvTerminal.AccessMode.SSH,
                    env_models.EnvTerminal.AccessMode.RDP,
                    env_models.EnvTerminal.AccessMode.CONSOLE,
                    env_models.EnvTerminal.AccessMode.TELNET,
            ):
                raise exceptions.ValidationError(
                    error.STANDARD_DEVICE_ACCESSMODE_ERROR)

            # # snapshot
            # image_name = get_lastest_image_name(device.name, device)
            # if device.image_type == env_models.StandardDevice.ImageType.VM:
            #     try:
            #         image = scene.volume.get(snapshot_name=image_name)
            #     except Exception:
            #         image = None
            #
            # if not image:
            #     try:
            #         image = scene.image.get(image_name=image_name)
            #     except:
            #         image = None
            #
            # if not image:
            #     if image_name != device.name:
            #         raise exceptions.ValidationError(error.IMAGE_NOT_FOUND)
            #
            #     # 没有镜像则从基础镜像创建
            #     image_name = device.source_image_name

            image_name = device.name
            try:
                image = scene.image.get(image_name=image_name)
            except:
                image = None
            # 没有镜像则从基础镜像创建
            if not image:
                image_name = device.source_image_name
            if not image_name:
                raise exceptions.ValidationError(error.NO_BASE_IMAGE)

            if device.tmp_vm:
                edit_server = device.tmp_vm
                if edit_server.status != env_models.StandardDeviceEditServer.Status.DELETED:
                    raise exceptions.ValidationError(error.TMP_ENV_CONFLICT)
                delete_tmp_vm(edit_server, destroy=False)
                edit_server.status = env_models.StandardDeviceEditServer.Status.CREATING
                edit_server.save()
            else:
                edit_server = env_models.StandardDeviceEditServer.objects.create(
                    create_user=request.user)
                device.tmp_vm = edit_server
                device.save()
            self.clear_cache()

            def _create_vm():
                if device.error:
                    env_models.StandardDevice.objects.filter(
                        pk=device.pk).update(error='')

                # 建机器
                try:
                    creater = StandardDeviceTmpVmCreater(image_name, device)
                    ret = creater.create_resource()
                except Exception as e:
                    env_models.StandardDevice.objects.filter(
                        pk=device.pk).update(error=e.message)
                    device.tmp_vm.delete()
                    self.clear_cache()
                    return

                logger.info(
                    'create template vm for device[%s] by image[%s] return[%s]: waiting for update'
                    % (device.pk, image_name, ret))
                float_ip = ret['float_ip']
                port = device.access_port or env_models.EnvTerminal.AccessModeDefaultPort.get(
                    device.access_mode)
                update_params = {}

                if device.access_mode in (
                        env_models.EnvTerminal.AccessMode.SSH,
                        env_models.EnvTerminal.AccessMode.RDP):
                    # 建连接
                    remote_manager = RemoteManager(request.user)
                    connection_name = '%s:%s:%s:%s' % (
                        request.user.id, float_ip, port,
                        hashlib.md5(str(uuid.uuid4())).hexdigest())
                    params = {
                        'username': ret['username'],
                        'password': ret['password'],
                    }
                    try:
                        if device.access_mode == env_models.EnvTerminal.AccessMode.SSH:
                            connection_id = remote_manager.create_ssh_connection(
                                connection_name, float_ip,
                                **params).connection_id
                        elif device.access_mode == env_models.EnvTerminal.AccessMode.RDP:
                            params[
                                'security'] = device.access_connection_mode or 'rdp'
                            if device.system_type == env_models.StandardDevice.SystemType.LINUX:
                                params['enable-sftp'] = 'true'
                            connection_id = remote_manager.create_rdp_connection(
                                connection_name, float_ip,
                                **params).connection_id
                        update_params['connection_id'] = connection_id
                    except Exception as e:
                        logger.error('create guacamole connection error: %s',
                                     e)

                # 建代理
                if port and proxy.PROXY_SWITCH:
                    try:
                        proxy_ports = proxy.create_proxy(float_ip, [port])
                    except Exception as e:
                        logger.error('create tmp_vm[%s] proxy error: %s' %
                                     (device.tmp_vm.id, e))
                        env_models.StandardDevice.objects.filter(
                            pk=device.pk).update(error=e.message)
                        creater.rollback_resource()
                        device.tmp_vm.delete()
                        self.clear_cache()
                        raise e
                    logger.info(
                        'create template vm for device[%s] by image[%s]: create proxy %s:%s --> %s'
                        % (device.pk, image_name, float_ip, port, proxy_ports))
                    if len(proxy_ports) > 0:
                        update_params['proxy_port'] = proxy_ports[0]
                        proxy.restart_proxy()

                tmp_vm = device.tmp_vm
                # 获取最新的数据
                lastest_tmp_vm = env_models.StandardDeviceEditServer.objects.get(
                    pk=tmp_vm.pk)
                if lastest_tmp_vm.status == env_models.StandardDeviceEditServer.Status.RUNNING:
                    tmp_vm_status = env_models.StandardDeviceEditServer.Status.RUNNING
                else:
                    tmp_vm_status = env_models.StandardDeviceEditServer.Status.STARTING

                update_params.update({
                    'tmp_network_ids':
                    json.dumps(ret['network_ids']),
                    'tmp_router_ids':
                    json.dumps(ret['router_ids']),
                    'tmp_docker_id':
                    ret['docker_id'],
                    'tmp_vm_id':
                    ret['vm_id'],
                    'tmp_net_ports':
                    json.dumps(ret['net_ports']),
                    'protocol':
                    device.access_mode,
                    'float_ip':
                    float_ip,
                    'host_ip':
                    ret['host_ip'],
                    'host_name':
                    ret['host_name'],
                    'port':
                    port,
                    'username':
                    ret['username'],
                    'password':
                    ret['password'],
                    'status':
                    tmp_vm_status,
                })

                try:
                    env_models.StandardDeviceEditServer.objects.filter(
                        pk=tmp_vm.pk).update(**update_params)
                except Exception as e:
                    logger.error('update tmp_vm[%s] error: %s' %
                                 (tmp_vm.id, e))
                    delete_tmp_vm(tmp_vm, destroy=False)
                    raise e
                self.clear_cache()
                new_task(self._check_tmp_vm_status, 0, (tmp_vm.id, device))

            new_task(_create_vm, 0, ())
            return Response(
                mserializers.StandardDeviceEditServerSerializer(
                    edit_server).data)
        elif request.method == 'DELETE':
            device = self.get_object()
            if device.tmp_vm:
                delete_tmp_vm(device.tmp_vm)
            self.clear_cache()
            return Response(status=status.HTTP_204_NO_CONTENT)