Przeglądaj źródła

完成去除启动作业的轻重构

James Iter 8 lat temu
rodzic
commit
a00ff67856

+ 0 - 145
api/boot_job.py

@@ -1,145 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-
-from flask import Blueprint
-from flask import request, g
-import jimit as ji
-import json
-
-from api.base import Base
-from models import Rules
-from models import Utils
-from models.boot_job import BootJob, OperateRule
-
-
-__author__ = 'James Iter'
-__date__ = '2017/6/19'
-__contact__ = 'james.iter.cn@gmail.com'
-__copyright__ = '(c) 2017 by James Iter.'
-
-
-blueprint = Blueprint(
-    'api_boot_job',
-    __name__,
-    url_prefix='/api/boot_job'
-)
-
-blueprints = Blueprint(
-    'api_boot_jobs',
-    __name__,
-    url_prefix='/api/boot_jobs'
-)
-
-
-boot_job_base = Base(the_class=BootJob, the_blueprint=blueprint, the_blueprints=blueprints)
-
-
-@Utils.dumps2response
-def r_create():
-
-    boot_job = BootJob()
-
-    args_rules = [
-        Rules.NAME.value,
-        Rules.USE_FOR.value,
-        Rules.REMARK.value
-    ]
-
-    boot_job.name = request.json.get('name')
-    boot_job.use_for = request.json.get('use_for')
-    boot_job.remark = request.json.get('remark')
-
-    try:
-        ji.Check.previewing(args_rules, boot_job.__dict__)
-
-        ret = dict()
-        ret['state'] = ji.Common.exchange_state(20000)
-
-        if boot_job.exist_by('name'):
-            ret['state'] = ji.Common.exchange_state(40901)
-            ret['state']['sub']['zh-cn'] = ''.join([ret['state']['sub']['zh-cn'], ': ', boot_job.name])
-            return ret
-
-        boot_job.create()
-        boot_job.get_by('name')
-        ret['data'] = boot_job.__dict__
-        return ret
-    except ji.PreviewingError, e:
-        return json.loads(e.message)
-
-
-@Utils.dumps2response
-def r_update(_id):
-
-    boot_job = BootJob()
-
-    args_rules = [
-        Rules.ID.value
-    ]
-
-    if 'name' in request.json:
-        args_rules.append(
-            Rules.NAME.value,
-        )
-
-    if 'use_for' in request.json:
-        args_rules.append(
-            Rules.USE_FOR.value,
-        )
-
-    if 'remark' in request.json:
-        args_rules.append(
-            Rules.REMARK.value,
-        )
-
-    if args_rules.__len__() < 2:
-        ret = dict()
-        ret['state'] = ji.Common.exchange_state(20000)
-        return ret
-
-    request.json['id'] = _id
-
-    try:
-        ji.Check.previewing(args_rules, request.json)
-        boot_job.id = request.json.get('id')
-        boot_job.get()
-        boot_job.name = request.json.get('name', boot_job.name)
-        boot_job.use_for = request.json.get('use_for', boot_job.use_for)
-        boot_job.remark = request.json.get('remark', boot_job.remark)
-
-        boot_job.update()
-        g.config = None
-
-        boot_job.get()
-
-        ret = dict()
-        ret['state'] = ji.Common.exchange_state(20000)
-        ret['data'] = boot_job.__dict__
-        return ret
-    except ji.PreviewingError, e:
-        return json.loads(e.message)
-
-
-@Utils.dumps2response
-def r_delete(ids):
-    operate_rule_base = Base(the_class=OperateRule)
-    operate_rule_base.delete(ids=ids, ids_rule=Rules.IDS.value, by_field='boot_job_id')
-
-    return boot_job_base.delete(ids=ids, ids_rule=Rules.IDS.value, by_field='id')
-
-
-@Utils.dumps2response
-def r_get(ids):
-    return boot_job_base.get(ids=ids, ids_rule=Rules.IDS.value, by_field='id')
-
-
-@Utils.dumps2response
-def r_get_by_filter():
-    return boot_job_base.get_by_filter()
-
-
-@Utils.dumps2response
-def r_content_search():
-    return boot_job_base.content_search()
-

+ 32 - 179
api/guest.py

@@ -11,7 +11,6 @@ import jimit as ji
 
 
 from api.base import Base
 from api.base import Base
 from models import DiskState, Host
 from models import DiskState, Host
-from models import OperateRule
 from models.initialize import app, dev_table
 from models.initialize import app, dev_table
 from models import Database as db
 from models import Database as db
 from models import Config
 from models import Config
@@ -19,7 +18,9 @@ from models import Disk
 from models import Rules
 from models import Rules
 from models import Utils
 from models import Utils
 from models import Guest
 from models import Guest
-from models import OSTemplate
+from models import OSTemplateImage
+from models import OSTemplateProfile
+from models import OSTemplateInitializeOperate
 from models import GuestXML
 from models import GuestXML
 from models import status
 from models import status
 
 
@@ -52,7 +53,7 @@ def r_create():
     args_rules = [
     args_rules = [
         Rules.CPU.value,
         Rules.CPU.value,
         Rules.MEMORY.value,
         Rules.MEMORY.value,
-        Rules.OS_TEMPLATE_ID.value,
+        Rules.OS_TEMPLATE_IMAGE_ID.value,
         Rules.QUANTITY.value,
         Rules.QUANTITY.value,
         Rules.REMARK.value,
         Rules.REMARK.value,
         Rules.PASSWORD.value,
         Rules.PASSWORD.value,
@@ -74,20 +75,23 @@ def r_create():
         config.id = 1
         config.id = 1
         config.get()
         config.get()
 
 
-        os_template = OSTemplate()
-        os_template.id = request.json.get('os_template_id')
-        if not os_template.exist():
+        os_template_image = OSTemplateImage()
+        os_template_profile = OSTemplateProfile()
+
+        os_template_image.id = request.json.get('os_template_image_id')
+        if not os_template_image.exist():
             ret['state'] = ji.Common.exchange_state(40450)
             ret['state'] = ji.Common.exchange_state(40450)
-            ret['state']['sub']['zh-cn'] = ''.join([ret['state']['sub']['zh-cn'], ': ', os_template.id.__str__()])
+            ret['state']['sub']['zh-cn'] = ''.join([ret['state']['sub']['zh-cn'], ': ', os_template_image.id.__str__()])
             return ret
             return ret
 
 
-        os_template.get()
-        # 重置密码的 boot job id 固定为 1
-        boot_jobs_id = [1, os_template.boot_job_id]
+        os_template_image.get()
+        os_template_profile.id = os_template_image.os_template_profile_id
+        os_template_profile.get()
 
 
-        boot_jobs, boot_jobs_count = OperateRule.get_by_filter(
-            filter_str='boot_job_id:in:' +
-                       ','.join(['{0}'.format(boot_job_id) for boot_job_id in boot_jobs_id]).__str__())
+        os_template_initialize_operates, os_template_initialize_operates_count = \
+            OSTemplateInitializeOperate.get_by_filter(
+                filter_str='os_template_initialize_operate_set_id:eq:' +
+                           os_template_profile.os_template_initialize_operate_set_id.__str__())
 
 
         if db.r.scard(app.config['ip_available_set']) < 1:
         if db.r.scard(app.config['ip_available_set']) < 1:
             ret['state'] = ji.Common.exchange_state(50350)
             ret['state'] = ji.Common.exchange_state(50350)
@@ -119,7 +123,7 @@ def r_create():
             guest.cpu = request.json.get('cpu')
             guest.cpu = request.json.get('cpu')
             # 虚拟机内存单位,模板生成方法中已置其为GiB
             # 虚拟机内存单位,模板生成方法中已置其为GiB
             guest.memory = request.json.get('memory')
             guest.memory = request.json.get('memory')
-            guest.os_template_id = request.json.get('os_template_id')
+            guest.os_template_image_id = request.json.get('os_template_image_id')
             guest.label = ji.Common.generate_random_code(length=8)
             guest.label = ji.Common.generate_random_code(length=8)
             guest.remark = request.json.get('remark', '')
             guest.remark = request.json.get('remark', '')
 
 
@@ -151,7 +155,7 @@ def r_create():
             disk.quota(config=config)
             disk.quota(config=config)
             disk.create()
             disk.create()
 
 
-            guest_xml = GuestXML(guest=guest, disk=disk, config=config, os_type=os_template.os_type)
+            guest_xml = GuestXML(guest=guest, disk=disk, config=config, os_type=os_template_profile.os_type)
             guest.xml = guest_xml.get_domain()
             guest.xml = guest_xml.get_domain()
 
 
             # 在可用计算节点中平均分配任务
             # 在可用计算节点中平均分配任务
@@ -165,9 +169,9 @@ def r_create():
             guest.create()
             guest.create()
 
 
             # 替换占位符为有效内容
             # 替换占位符为有效内容
-            _boot_jobs = copy.deepcopy(boot_jobs)
-            for k, v in enumerate(_boot_jobs):
-                _boot_jobs[k]['content'] = v['content'].replace('{IP}', guest.ip).\
+            _os_template_initialize_operates = copy.deepcopy(os_template_initialize_operates)
+            for k, v in enumerate(_os_template_initialize_operates):
+                _os_template_initialize_operates[k]['content'] = v['content'].replace('{IP}', guest.ip).\
                     replace('{HOSTNAME}', guest.label). \
                     replace('{HOSTNAME}', guest.label). \
                     replace('{PASSWORD}', guest.password). \
                     replace('{PASSWORD}', guest.password). \
                     replace('{NETMASK}', config.netmask).\
                     replace('{NETMASK}', config.netmask).\
@@ -175,7 +179,7 @@ def r_create():
                     replace('{DNS1}', config.dns1).\
                     replace('{DNS1}', config.dns1).\
                     replace('{DNS2}', config.dns2)
                     replace('{DNS2}', config.dns2)
 
 
-                _boot_jobs[k]['command'] = v['command'].replace('{IP}', guest.ip). \
+                _os_template_initialize_operates[k]['command'] = v['command'].replace('{IP}', guest.ip). \
                     replace('{HOSTNAME}', guest.label). \
                     replace('{HOSTNAME}', guest.label). \
                     replace('{PASSWORD}', guest.password). \
                     replace('{PASSWORD}', guest.password). \
                     replace('{NETMASK}', config.netmask). \
                     replace('{NETMASK}', config.netmask). \
@@ -191,14 +195,12 @@ def r_create():
                 'dfs_volume': config.dfs_volume,
                 'dfs_volume': config.dfs_volume,
                 'node_id': guest.node_id,
                 'node_id': guest.node_id,
                 'name': guest.label,
                 'name': guest.label,
-                'template_path': os_template.path,
-                'os_type': os_template.os_type,
-                'disk': disk.__dict__,
-                # disk 将被废弃,由 disks 代替,暂时保留它的目的,是为了保持与 JimV-N 的兼容性
+                'template_path': os_template_image.path,
+                'os_type': os_template_profile.os_type,
                 'disks': [disk.__dict__],
                 'disks': [disk.__dict__],
                 'xml': guest_xml.get_domain(),
                 'xml': guest_xml.get_domain(),
-                'boot_jobs': _boot_jobs,
-                'passback_parameters': {'boot_jobs_id': boot_jobs_id}
+                'os_template_initialize_operates': _os_template_initialize_operates,
+                'passback_parameters': {}
             }
             }
 
 
             Utils.emit_instruction(message=json.dumps(message, ensure_ascii=False))
             Utils.emit_instruction(message=json.dumps(message, ensure_ascii=False))
@@ -379,40 +381,14 @@ def r_boot(uuids):
             guest.uuid = uuid
             guest.uuid = uuid
             guest.get_by('uuid')
             guest.get_by('uuid')
 
 
-            _, boot_jobs_id = guest.get_boot_jobs()
-
-            boot_jobs = list()
-
-            if boot_jobs_id.__len__() > 0:
-                boot_jobs, count = OperateRule.get_by_filter(filter_str='boot_job_id:in:' + ','.join(boot_jobs_id))
-
-            # 替换占位符为有效内容
-            for k, v in enumerate(boot_jobs):
-                boot_jobs[k]['content'] = v['content'].replace('{IP}', guest.ip). \
-                    replace('{HOSTNAME}', guest.label). \
-                    replace('{PASSWORD}', guest.password). \
-                    replace('{NETMASK}', config.netmask). \
-                    replace('{GATEWAY}', config.gateway). \
-                    replace('{DNS1}', config.dns1). \
-                    replace('{DNS2}', config.dns2)
-
-                boot_jobs[k]['command'] = v['command'].replace('{IP}', guest.ip). \
-                    replace('{HOSTNAME}', guest.label). \
-                    replace('{PASSWORD}', guest.password). \
-                    replace('{NETMASK}', config.netmask). \
-                    replace('{GATEWAY}', config.gateway). \
-                    replace('{DNS1}', config.dns1). \
-                    replace('{DNS2}', config.dns2)
-
             disks, _ = Disk.get_by_filter(filter_str=':'.join(['guest_uuid', 'eq', guest.uuid]))
             disks, _ = Disk.get_by_filter(filter_str=':'.join(['guest_uuid', 'eq', guest.uuid]))
 
 
             message = {
             message = {
                 '_object': 'guest',
                 '_object': 'guest',
                 'action': 'boot',
                 'action': 'boot',
                 'uuid': uuid,
                 'uuid': uuid,
-                'boot_jobs': boot_jobs,
                 'node_id': guest.node_id,
                 'node_id': guest.node_id,
-                'passback_parameters': {'boot_jobs_id': boot_jobs_id},
+                'passback_parameters': {},
                 'disks': disks
                 'disks': disks
             }
             }
 
 
@@ -757,7 +733,7 @@ def r_distribute_count():
     ret['state'] = ji.Common.exchange_state(20000)
     ret['state'] = ji.Common.exchange_state(20000)
 
 
     ret['data'] = {
     ret['data'] = {
-        'os_template_id': dict(),
+        'os_template_image_id': dict(),
         'status': dict(),
         'status': dict(),
         'node_id': dict(),
         'node_id': dict(),
         'cpu_memory': dict(),
         'cpu_memory': dict(),
@@ -767,8 +743,8 @@ def r_distribute_count():
     }
     }
 
 
     for guest in rows:
     for guest in rows:
-        if guest['os_template_id'] not in ret['data']['os_template_id']:
-            ret['data']['os_template_id'][guest['os_template_id']] = 0
+        if guest['os_template_image_id'] not in ret['data']['os_template_image_id']:
+            ret['data']['os_template_image_id'][guest['os_template_image_id']] = 0
 
 
         if guest['status'] not in ret['data']['status']:
         if guest['status'] not in ret['data']['status']:
             ret['data']['status'][guest['status']] = 0
             ret['data']['status'][guest['status']] = 0
@@ -780,7 +756,7 @@ def r_distribute_count():
         if cpu_memory not in ret['data']['cpu_memory']:
         if cpu_memory not in ret['data']['cpu_memory']:
             ret['data']['cpu_memory'][cpu_memory] = 0
             ret['data']['cpu_memory'][cpu_memory] = 0
 
 
-        ret['data']['os_template_id'][guest['os_template_id']] += 1
+        ret['data']['os_template_image_id'][guest['os_template_image_id']] += 1
         ret['data']['status'][guest['status']] += 1
         ret['data']['status'][guest['status']] += 1
         ret['data']['node_id'][guest['node_id']] += 1
         ret['data']['node_id'][guest['node_id']] += 1
         ret['data']['cpu_memory'][cpu_memory] += 1
         ret['data']['cpu_memory'][cpu_memory] += 1
@@ -829,127 +805,6 @@ def r_update(uuid):
         return json.loads(e.message)
         return json.loads(e.message)
 
 
 
 
-@Utils.dumps2response
-def r_add_boot_jobs(uuids, boot_jobs_id):
-
-    args_rules = [
-        Rules.UUIDS.value,
-        Rules.BOOT_JOBS_ID.value
-    ]
-
-    try:
-        ji.Check.previewing(args_rules, {'uuids': uuids, 'boot_jobs_id': boot_jobs_id})
-
-        guest = Guest()
-        for uuid in uuids.split(','):
-            guest.uuid = uuid
-            guest.get_by('uuid')
-
-        for uuid in uuids.split(','):
-            guest.uuid = uuid
-            guest.add_boot_jobs(boot_jobs_id=boot_jobs_id.split(','))
-
-        ret = dict()
-        ret['state'] = ji.Common.exchange_state(20000)
-
-        if uuids.split(',').__len__() > 1:
-            ret['data'] = dict()
-            for uuid in uuids.split(','):
-                guest.uuid = uuid
-                boot_jobs = dict()
-                boot_jobs['ttl'], boot_jobs['boot_jobs'] = guest.get_boot_jobs()
-                ret['data'][uuid] = boot_jobs
-
-        else:
-            guest.uuid = uuids
-            ret['data'] = dict()
-            ret['data']['ttl'], ret['data']['boot_jobs'] = guest.get_boot_jobs()
-
-        return ret
-
-    except ji.PreviewingError, e:
-        return json.loads(e.message)
-
-
-@Utils.dumps2response
-def r_get_boot_jobs(uuids):
-
-    args_rules = [
-        Rules.UUIDS.value
-    ]
-
-    try:
-        ji.Check.previewing(args_rules, {'uuids': uuids})
-
-        guest = Guest()
-
-        for uuid in uuids.split(','):
-            guest.uuid = uuid
-            guest.get_by('uuid')
-
-        ret = dict()
-        ret['state'] = ji.Common.exchange_state(20000)
-
-        if uuids.split(',').__len__() > 1:
-            ret['data'] = dict()
-            for uuid in uuids.split(','):
-                guest.uuid = uuid
-                boot_jobs = dict()
-                boot_jobs['ttl'], boot_jobs['boot_jobs'] = guest.get_boot_jobs()
-                ret['data'][uuid] = boot_jobs
-
-        else:
-            guest.uuid = uuids
-            ret['data'] = dict()
-            ret['data']['ttl'], ret['data']['boot_jobs'] = guest.get_boot_jobs()
-
-        return ret
-
-    except ji.PreviewingError, e:
-        return json.loads(e.message)
-
-
-@Utils.dumps2response
-def r_delete_boot_jobs(uuids, boot_jobs_id):
-
-    args_rules = [
-        Rules.UUIDS.value,
-        Rules.BOOT_JOBS_ID.value
-    ]
-
-    try:
-        ji.Check.previewing(args_rules, {'uuids': uuids, 'boot_jobs_id': boot_jobs_id})
-
-        guest = Guest()
-        # 检测所指定的 UUDIs 实例都存在
-        for uuid in uuids.split(','):
-            guest.uuid = uuid
-            guest.get_by('uuid')
-
-        for uuid in uuids.split(','):
-            guest.uuid = uuid
-            guest.delete_boot_jobs(boot_jobs_id=boot_jobs_id.split(','))
-
-        ret = dict()
-        ret['state'] = ji.Common.exchange_state(20000)
-        return ret
-
-    except ji.PreviewingError, e:
-        return json.loads(e.message)
-
-
-@Utils.dumps2response
-def r_get_uuids_of_all_had_boot_job():
-    guest = Guest()
-    try:
-        ret = dict()
-        ret['state'] = ji.Common.exchange_state(20000)
-        ret['data'] = guest.get_uuids_of_all_had_boot_job()
-        return ret
-    except ji.PreviewingError, e:
-        return json.loads(e.message)
-
-
 @Utils.dumps2response
 @Utils.dumps2response
 def r_reset_password(uuids, password):
 def r_reset_password(uuids, password):
 
 
@@ -974,8 +829,6 @@ def r_reset_password(uuids, password):
             guest.password = password
             guest.password = password
             guest.update()
             guest.update()
 
 
-            guest.add_boot_jobs(boot_jobs_id=['1'])
-
         ret = dict()
         ret = dict()
         ret['state'] = ji.Common.exchange_state(20000)
         ret['state'] = ji.Common.exchange_state(20000)
         return ret
         return ret

+ 0 - 200
api/operate_rule.py

@@ -1,200 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-
-from flask import Blueprint
-from flask import request
-import jimit as ji
-import json
-
-from api.base import Base
-from models import Rules
-from models import Utils
-from models.boot_job import OperateRule, BootJob
-from models.status import OperateRuleKind
-
-__author__ = 'James Iter'
-__date__ = '2017/6/19'
-__contact__ = 'james.iter.cn@gmail.com'
-__copyright__ = '(c) 2017 by James Iter.'
-
-
-blueprint = Blueprint(
-    'api_operate_rule',
-    __name__,
-    url_prefix='/api/operate_rule'
-)
-
-blueprints = Blueprint(
-    'api_operate_rules',
-    __name__,
-    url_prefix='/api/operate_rules'
-)
-
-
-operate_rule_base = Base(the_class=OperateRule, the_blueprint=blueprint, the_blueprints=blueprints)
-
-
-@Utils.dumps2response
-def r_create():
-
-    boot_job = BootJob()
-    operate_rule = OperateRule()
-
-    args_rules = [
-        Rules.BOOT_JOB_ID_EXT.value,
-        Rules.OPERATE_RULE_KIND.value,
-        Rules.OPERATE_RULE_SEQUENCE.value
-    ]
-
-    operate_rule.boot_job_id = request.json.get('boot_job_id')
-    operate_rule.kind = request.json.get('kind')
-    operate_rule.path = request.json.get('path', '')
-    operate_rule.sequence = request.json.get('sequence', 0)
-    operate_rule.content = request.json.get('content', '')
-    operate_rule.command = request.json.get('command', '')
-
-    if operate_rule.kind == OperateRuleKind.cmd.value:
-        args_rules.append(
-            Rules.OPERATE_RULE_COMMAND.value
-        )
-
-    else:
-        args_rules.extend([
-            Rules.OPERATE_RULE_PATH.value,
-            Rules.OPERATE_RULE_CONTENT.value
-        ])
-
-    try:
-        ji.Check.previewing(args_rules, operate_rule.__dict__)
-
-        ret = dict()
-        ret['state'] = ji.Common.exchange_state(20000)
-
-        boot_job.id = operate_rule.boot_job_id
-        if not boot_job.exist():
-            ret['state'] = ji.Common.exchange_state(40401)
-            ret['state']['sub']['zh-cn'] = ''.join([ret['state']['sub']['zh-cn'], ': ', boot_job.id.__str__()])
-            return ret
-
-        if operate_rule.kind == OperateRuleKind.cmd.value:
-            data, total = operate_rule.get_by_filter(
-                filter_str=':'.join(['boot_job_id', 'eq', operate_rule.boot_job_id.__str__()]) + ';' +
-                           ':'.join(['command', 'eq', operate_rule.command]))
-
-        else:
-            data, total = operate_rule.get_by_filter(
-                filter_str=':'.join(['boot_job_id', 'eq', operate_rule.boot_job_id.__str__()]) + ';' +
-                           ':'.join(['path', 'eq', operate_rule.path]))
-
-        if data.__len__() > 0:
-            ret['state'] = ji.Common.exchange_state(40901)
-
-            if operate_rule.kind == OperateRuleKind.cmd.value:
-                ret['state']['sub']['zh-cn'] = ''.join([ret['state']['sub']['zh-cn'],
-                                                        ', command: ', operate_rule.command,
-                                                        ', boot_job_id: ', operate_rule.boot_job_id.__str__()])
-
-            else:
-                ret['state']['sub']['zh-cn'] = ''.join([ret['state']['sub']['zh-cn'], ', path: ', operate_rule.path,
-                                                        ', boot_job_id: ', operate_rule.boot_job_id.__str__()])
-            return ret
-
-        operate_rule.create()
-        data, total = operate_rule.get_by_filter(
-            filter_str=':'.join(['boot_job_id', 'eq', operate_rule.boot_job_id.__str__()]) + ';' +
-                       ':'.join(['path', 'eq', operate_rule.path]))
-        ret['data'] = data[0]
-        return ret
-
-    except ji.PreviewingError, e:
-        return json.loads(e.message)
-
-
-@Utils.dumps2response
-def r_update(_id):
-
-    operate_rule = OperateRule()
-
-    args_rules = [
-        Rules.ID.value
-    ]
-
-    if 'boot_job_id' in request.json:
-        args_rules.append(
-            Rules.BOOT_JOB_ID_EXT.value,
-        )
-
-    if 'kind' in request.json:
-        args_rules.append(
-            Rules.OPERATE_RULE_KIND.value,
-        )
-
-    if 'sequence' in request.json:
-        args_rules.append(
-            Rules.OPERATE_RULE_SEQUENCE.value,
-        )
-
-    if 'path' in request.json:
-        args_rules.append(
-            Rules.OPERATE_RULE_PATH.value,
-        )
-
-    if 'content' in request.json:
-        args_rules.append(
-            Rules.OPERATE_RULE_CONTENT.value,
-        )
-
-    if 'command' in request.json:
-        args_rules.append(
-            Rules.OPERATE_RULE_COMMAND.value,
-        )
-
-    if args_rules.__len__() < 2:
-        ret = dict()
-        ret['state'] = ji.Common.exchange_state(20000)
-        return ret
-
-    request.json['id'] = _id
-
-    try:
-        ji.Check.previewing(args_rules, request.json)
-        operate_rule.id = request.json.get('id')
-        operate_rule.get()
-        operate_rule.boot_job_id = request.json.get('boot_job_id', operate_rule.boot_job_id)
-        operate_rule.kind = request.json.get('kind', operate_rule.kind)
-        operate_rule.sequence = request.json.get('sequence', operate_rule.sequence)
-        operate_rule.path = request.json.get('path', operate_rule.path)
-        operate_rule.content = request.json.get('content', operate_rule.content)
-        operate_rule.command = request.json.get('command', operate_rule.command)
-
-        operate_rule.update()
-        operate_rule.get()
-
-        ret = dict()
-        ret['state'] = ji.Common.exchange_state(20000)
-        ret['data'] = operate_rule.__dict__
-        return ret
-    except ji.PreviewingError, e:
-        return json.loads(e.message)
-
-
-@Utils.dumps2response
-def r_delete(ids):
-    return operate_rule_base.delete(ids=ids, ids_rule=Rules.IDS.value, by_field='id')
-
-
-@Utils.dumps2response
-def r_get(ids):
-    return operate_rule_base.get(ids=ids, ids_rule=Rules.IDS.value, by_field='id')
-
-
-@Utils.dumps2response
-def r_get_by_filter():
-    return operate_rule_base.get_by_filter()
-
-
-@Utils.dumps2response
-def r_content_search():
-    return operate_rule_base.content_search()
-

+ 0 - 165
api/os_template.py

@@ -1,165 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-
-from flask import Blueprint
-from flask import request
-import jimit as ji
-import json
-
-from api.base import Base
-from models import OSTemplate
-from models import Rules
-from models import Utils
-
-
-__author__ = 'James Iter'
-__date__ = '2017/3/30'
-__contact__ = 'james.iter.cn@gmail.com'
-__copyright__ = '(c) 2017 by James Iter.'
-
-
-blueprint = Blueprint(
-    'api_os_template',
-    __name__,
-    url_prefix='/api/os_template'
-)
-
-blueprints = Blueprint(
-    'api_os_templates',
-    __name__,
-    url_prefix='/api/os_templates'
-)
-
-
-os_template_base = Base(the_class=OSTemplate, the_blueprint=blueprint, the_blueprints=blueprints)
-
-
-@Utils.dumps2response
-def r_create():
-
-    os_template = OSTemplate()
-
-    args_rules = [
-        Rules.LABEL.value,
-        Rules.PATH.value,
-        Rules.ACTIVE.value,
-        Rules.OS_TYPE.value,
-        Rules.ICON.value,
-        Rules.BOOT_JOB_ID_EXT.value
-    ]
-
-    os_template.label = request.json.get('label')
-    os_template.path = request.json.get('path')
-    os_template.os_type = request.json.get('os_type')
-    os_template.active = request.json.get('active')
-    os_template.icon = request.json.get('icon')
-    os_template.boot_job_id = request.json.get('boot_job_id', 0)
-
-    try:
-        ji.Check.previewing(args_rules, os_template.__dict__)
-
-        ret = dict()
-        ret['state'] = ji.Common.exchange_state(20000)
-
-        if os_template.exist_by('path'):
-            ret['state'] = ji.Common.exchange_state(40901)
-            ret['state']['sub']['zh-cn'] = ''.join([ret['state']['sub']['zh-cn'], ': ', os_template.path])
-            return ret
-
-        os_template.create()
-        os_template.get_by('path')
-        ret['data'] = os_template.__dict__
-        return ret
-    except ji.PreviewingError, e:
-        return json.loads(e.message)
-
-
-@Utils.dumps2response
-def r_update(_id):
-
-    os_template = OSTemplate()
-
-    args_rules = [
-        Rules.ID.value
-    ]
-
-    if 'label' in request.json:
-        args_rules.append(
-            Rules.LABEL.value,
-        )
-
-    if 'path' in request.json:
-        args_rules.append(
-            Rules.PATH.value,
-        )
-
-    if 'os_type' in request.json:
-        args_rules.append(
-            Rules.OS_TYPE.value,
-        )
-
-    if 'active' in request.json:
-        args_rules.append(
-            Rules.ACTIVE.value,
-        )
-
-    if 'icon' in request.json:
-        args_rules.append(
-            Rules.ICON.value,
-        )
-
-    if 'boot_job_id' in request.json:
-        args_rules.append(
-            Rules.BOOT_JOB_ID_EXT.value,
-        )
-
-    if args_rules.__len__() < 2:
-        ret = dict()
-        ret['state'] = ji.Common.exchange_state(20000)
-        return ret
-
-    request.json['id'] = _id
-
-    try:
-        ji.Check.previewing(args_rules, request.json)
-        os_template.id = request.json.get('id')
-
-        os_template.get()
-        os_template.label = request.json.get('label', os_template.label)
-        os_template.path = request.json.get('path', os_template.path)
-        os_template.os_type = request.json.get('os_type', os_template.os_type)
-        os_template.active = request.json.get('active', os_template.active)
-        os_template.icon = request.json.get('icon', os_template.icon)
-        os_template.boot_job_id = request.json.get('boot_job_id', os_template.boot_job_id)
-
-        os_template.update()
-        os_template.get()
-
-        ret = dict()
-        ret['state'] = ji.Common.exchange_state(20000)
-        ret['data'] = os_template.__dict__
-        return ret
-    except ji.PreviewingError, e:
-        return json.loads(e.message)
-
-
-@Utils.dumps2response
-def r_delete(ids):
-    return os_template_base.delete(ids=ids, ids_rule=Rules.IDS.value, by_field='id')
-
-
-@Utils.dumps2response
-def r_get(ids):
-    return os_template_base.get(ids=ids, ids_rule=Rules.IDS.value, by_field='id')
-
-
-@Utils.dumps2response
-def r_get_by_filter():
-    return os_template_base.get_by_filter()
-
-
-@Utils.dumps2response
-def r_content_search():
-    return os_template_base.content_search()
-

+ 0 - 26
api_route_table.py

@@ -7,9 +7,6 @@ from api import config
 from api import user
 from api import user
 from api import guest
 from api import guest
 from api import disk
 from api import disk
-from api import boot_job
-from api import operate_rule
-from api import os_template
 from api import os_template_image
 from api import os_template_image
 from api import os_template_profile
 from api import os_template_profile
 from api import os_template_initialize_operate_set
 from api import os_template_initialize_operate_set
@@ -41,29 +38,6 @@ add_rule_api(user.blueprint, '/_reset_password/<token>', api_func='user.r_reset_
 add_rule_api(user.blueprint, '/_send_reset_password_email/<login_name>', api_func='user.r_send_reset_password_email',
 add_rule_api(user.blueprint, '/_send_reset_password_email/<login_name>', api_func='user.r_send_reset_password_email',
              methods=['PUT'])
              methods=['PUT'])
 
 
-# 系统启动作业配置操作
-add_rule_api(boot_job.blueprint, '', api_func='boot_job.r_create', methods=['POST'])
-add_rule_api(boot_job.blueprint, '/<_id>', api_func='boot_job.r_update', methods=['PATCH'])
-add_rule_api(boot_job.blueprints, '/<ids>', api_func='boot_job.r_delete', methods=['DELETE'])
-add_rule_api(boot_job.blueprints, '/<ids>', api_func='boot_job.r_get', methods=['GET'])
-add_rule_api(boot_job.blueprints, '', api_func='boot_job.r_get_by_filter', methods=['GET'])
-add_rule_api(boot_job.blueprints, '/_search', api_func='boot_job.r_content_search', methods=['GET'])
-
-add_rule_api(operate_rule.blueprint, '', api_func='operate_rule.r_create', methods=['POST'])
-add_rule_api(operate_rule.blueprint, '/<_id>', api_func='operate_rule.r_update', methods=['PATCH'])
-add_rule_api(operate_rule.blueprints, '/<ids>', api_func='operate_rule.r_delete', methods=['DELETE'])
-add_rule_api(operate_rule.blueprints, '/<ids>', api_func='operate_rule.r_get', methods=['GET'])
-add_rule_api(operate_rule.blueprints, '', api_func='operate_rule.r_get_by_filter', methods=['GET'])
-add_rule_api(operate_rule.blueprints, '/_search', api_func='operate_rule.r_content_search', methods=['GET'])
-
-# 系统模板操作
-add_rule_api(os_template.blueprint, '', api_func='os_template.r_create', methods=['POST'])
-add_rule_api(os_template.blueprint, '/<_id>', api_func='os_template.r_update', methods=['PATCH'])
-add_rule_api(os_template.blueprints, '/<ids>', api_func='os_template.r_delete', methods=['DELETE'])
-add_rule_api(os_template.blueprints, '/<ids>', api_func='os_template.r_get', methods=['GET'])
-add_rule_api(os_template.blueprints, '', api_func='os_template.r_get_by_filter', methods=['GET'])
-add_rule_api(os_template.blueprints, '/_search', api_func='os_template.r_content_search', methods=['GET'])
-
 # 系统模板镜像操作
 # 系统模板镜像操作
 add_rule_api(os_template_image.blueprint, '', api_func='os_template_image.r_create', methods=['POST'])
 add_rule_api(os_template_image.blueprint, '', api_func='os_template_image.r_create', methods=['POST'])
 add_rule_api(os_template_image.blueprint, '/<_id>', api_func='os_template_image.r_update', methods=['PATCH'])
 add_rule_api(os_template_image.blueprint, '/<_id>', api_func='os_template_image.r_update', methods=['PATCH'])

+ 0 - 28
main.py

@@ -26,13 +26,6 @@ from models import Config
 from models import User
 from models import User
 from api.user import blueprint as user_blueprint
 from api.user import blueprint as user_blueprint
 
 
-from api.boot_job import blueprint as boot_job_blueprint
-from api.boot_job import blueprints as boot_job_blueprints
-from api.operate_rule import blueprint as operate_rule_blueprint
-from api.operate_rule import blueprints as operate_rule_blueprints
-from api.os_template import blueprint as os_template_blueprint
-from api.os_template import blueprints as os_template_blueprints
-
 from api.os_template_image import blueprint as os_template_image_blueprint
 from api.os_template_image import blueprint as os_template_image_blueprint
 from api.os_template_image import blueprints as os_template_image_blueprints
 from api.os_template_image import blueprints as os_template_image_blueprints
 from api.os_template_initialize_operate_set import blueprint as os_template_initialize_operate_set_blueprint
 from api.os_template_initialize_operate_set import blueprint as os_template_initialize_operate_set_blueprint
@@ -68,13 +61,6 @@ from views.log import blueprints as view_log_blueprints
 from views.os_template_image import blueprint as view_os_template_image_blueprint
 from views.os_template_image import blueprint as view_os_template_image_blueprint
 from views.os_template_image import blueprints as view_os_template_image_blueprints
 from views.os_template_image import blueprints as view_os_template_image_blueprints
 
 
-from views.os_template import blueprint as view_os_template_blueprint
-from views.os_template import blueprints as view_os_template_blueprints
-from views.boot_job import blueprint as view_boot_job_blueprint
-from views.boot_job import blueprints as view_boot_job_blueprints
-from views.operate_rule import blueprint as view_operate_rule_blueprint
-from views.operate_rule import blueprints as view_operate_rule_blueprints
-
 from views.host import blueprint as view_host_blueprint
 from views.host import blueprint as view_host_blueprint
 from views.host import blueprints as view_host_blueprints
 from views.host import blueprints as view_host_blueprints
 
 
@@ -226,13 +212,6 @@ try:
 
 
     app.register_blueprint(user_blueprint)
     app.register_blueprint(user_blueprint)
 
 
-    app.register_blueprint(boot_job_blueprint)
-    app.register_blueprint(boot_job_blueprints)
-    app.register_blueprint(operate_rule_blueprint)
-    app.register_blueprint(operate_rule_blueprints)
-    app.register_blueprint(os_template_blueprint)
-    app.register_blueprint(os_template_blueprints)
-
     app.register_blueprint(os_template_image_blueprint)
     app.register_blueprint(os_template_image_blueprint)
     app.register_blueprint(os_template_image_blueprints)
     app.register_blueprint(os_template_image_blueprints)
     app.register_blueprint(os_template_initialize_operate_set_blueprint)
     app.register_blueprint(os_template_initialize_operate_set_blueprint)
@@ -267,13 +246,6 @@ try:
     app.register_blueprint(view_os_template_image_blueprint)
     app.register_blueprint(view_os_template_image_blueprint)
     app.register_blueprint(view_os_template_image_blueprints)
     app.register_blueprint(view_os_template_image_blueprints)
 
 
-    app.register_blueprint(view_os_template_blueprint)
-    app.register_blueprint(view_os_template_blueprints)
-    app.register_blueprint(view_boot_job_blueprint)
-    app.register_blueprint(view_boot_job_blueprints)
-    app.register_blueprint(view_operate_rule_blueprint)
-    app.register_blueprint(view_operate_rule_blueprints)
-
     app.register_blueprint(view_host_blueprint)
     app.register_blueprint(view_host_blueprint)
     app.register_blueprint(view_host_blueprints)
     app.register_blueprint(view_host_blueprints)
 
 

+ 1 - 1
misc/init.sql

@@ -32,7 +32,7 @@ CREATE TABLE IF NOT EXISTS guest(
     label VARCHAR(64) NOT NULL UNIQUE,
     label VARCHAR(64) NOT NULL UNIQUE,
     password VARCHAR(255) NOT NULL,
     password VARCHAR(255) NOT NULL,
     remark VARCHAR(255) NOT NULL DEFAULT '',
     remark VARCHAR(255) NOT NULL DEFAULT '',
-    os_template_id BIGINT UNSIGNED NOT NULL,
+    os_template_image_id BIGINT UNSIGNED NOT NULL,
     create_time BIGINT UNSIGNED NOT NULL,
     create_time BIGINT UNSIGNED NOT NULL,
     -- 运行时的状态用 status;
     -- 运行时的状态用 status;
     status TINYINT UNSIGNED NOT NULL DEFAULT 0,
     status TINYINT UNSIGNED NOT NULL DEFAULT 0,

+ 3 - 12
models/__init__.py

@@ -39,14 +39,6 @@ from guest import (
     Guest, Disk
     Guest, Disk
 )
 )
 
 
-from boot_job import (
-    BootJob, OperateRule
-)
-
-from os_template import (
-    OSTemplate
-)
-
 from os_template_image import (
 from os_template_image import (
     OSTemplateImage
     OSTemplateImage
 )
 )
@@ -68,8 +60,7 @@ from status import (
     GuestState,
     GuestState,
     ResponseState,
     ResponseState,
     DiskState,
     DiskState,
-    LogLevel,
-    OSType
+    LogLevel
 )
 )
 
 
 from guest_xml import (
 from guest_xml import (
@@ -108,8 +99,8 @@ __copyright__ = '(c) 2017 by James Iter.'
 
 
 
 
 __all__ = [
 __all__ = [
-    'Rules', 'Utils', 'Init', 'Database', 'FilterFieldType', 'Filter', 'EmitKind', 'GuestState', 'DiskState', 'OSType',
-    'LogLevel', 'ORM', 'User', 'Config', 'Guest', 'Disk', 'BootJob', 'OperateRule', 'OSTemplate', 'GuestXML', 'Log',
+    'Rules', 'Utils', 'Init', 'Database', 'FilterFieldType', 'Filter', 'EmitKind', 'GuestState', 'DiskState',
+    'LogLevel', 'ORM', 'User', 'Config', 'Guest', 'Disk', 'GuestXML', 'Log',
     'OSTemplateImage', 'OSTemplateProfile', 'OSTemplateInitializeOperateSet', 'OSTemplateInitializeOperate',
     'OSTemplateImage', 'OSTemplateProfile', 'OSTemplateInitializeOperateSet', 'OSTemplateInitializeOperate',
     'EventProcessor', 'ResponseState', 'GuestCPUMemory', 'GuestTraffic', 'GuestDiskIO', 'HostCPUMemory', 'HostTraffic',
     'EventProcessor', 'ResponseState', 'GuestCPUMemory', 'GuestTraffic', 'GuestDiskIO', 'HostCPUMemory', 'HostTraffic',
     'HostDiskUsageIO', 'Host'
     'HostDiskUsageIO', 'Host'

+ 0 - 79
models/boot_job.py

@@ -1,79 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-
-from models import FilterFieldType
-from models import ORM
-
-
-__author__ = 'James Iter'
-__date__ = '2017/6/19'
-__contact__ = 'james.iter.cn@gmail.com'
-__copyright__ = '(c) 2017 by James Iter.'
-
-
-class BootJob(ORM):
-
-    _table_name = 'boot_job'
-    _primary_key = 'id'
-
-    def __init__(self):
-        super(BootJob, self).__init__()
-        self.id = 0
-        self.name = None
-        self.use_for = None
-        self.remark = ''
-
-    @staticmethod
-    def get_filter_keywords():
-        return {
-            'id': FilterFieldType.INT.value,
-            'name': FilterFieldType.STR.value,
-            'use_for': FilterFieldType.INT.value,
-            'remark': FilterFieldType.STR.value
-        }
-
-    @staticmethod
-    def get_allow_update_keywords():
-        return ['use_for']
-
-    @staticmethod
-    def get_allow_content_search_keywords():
-        return ['name', 'remark']
-
-
-class OperateRule(ORM):
-
-    _table_name = 'operate_rule'
-    _primary_key = 'id'
-
-    def __init__(self):
-        super(OperateRule, self).__init__()
-        self.id = 0
-        self.boot_job_id = None
-        self.kind = ''
-        self.sequence = 0
-        self.command = ''
-        self.path = ''
-        self.content = ''
-
-    @staticmethod
-    def get_filter_keywords():
-        return {
-            'id': FilterFieldType.INT.value,
-            'boot_job_id': FilterFieldType.INT.value,
-            'sequence': FilterFieldType.INT.value,
-            'command': FilterFieldType.STR.value,
-            'path': FilterFieldType.STR.value,
-            'content': FilterFieldType.STR.value,
-        }
-
-    @staticmethod
-    def get_allow_update_keywords():
-        return ['boot_job_id', 'sequence']
-
-    @staticmethod
-    def get_allow_content_search_keywords():
-        return ['command', 'path', 'content']
-
-

+ 1 - 5
models/event_processor.py

@@ -205,13 +205,9 @@ class EventProcessor(object):
                     cls.disk.update()
                     cls.disk.update()
 
 
             elif action == 'boot':
             elif action == 'boot':
-                boot_jobs_id = cls.message['message']['passback_parameters']['boot_jobs_id']
 
 
                 if state == ResponseState.success.value:
                 if state == ResponseState.success.value:
-                    cls.guest.uuid = uuid
-
-                    if boot_jobs_id.__len__() > 0:
-                        cls.guest.delete_boot_jobs(boot_jobs_id=boot_jobs_id)
+                    pass
 
 
         elif _object == 'disk':
         elif _object == 'disk':
             if action == 'create':
             if action == 'create':

+ 1 - 37
models/guest.py

@@ -7,8 +7,6 @@ import jimit as ji
 from filter import FilterFieldType
 from filter import FilterFieldType
 from orm import ORM
 from orm import ORM
 from status import GuestState, DiskState
 from status import GuestState, DiskState
-from database import Database as db
-from initialize import app
 
 
 
 
 __author__ = 'James Iter'
 __author__ = 'James Iter'
@@ -29,7 +27,7 @@ class Guest(ORM):
         self.label = None
         self.label = None
         self.password = None
         self.password = None
         self.remark = ''
         self.remark = ''
-        self.os_template_id = None
+        self.os_template_image_id = None
         self.create_time = ji.Common.tus()
         self.create_time = ji.Common.tus()
         self.status = GuestState.no_state.value
         self.status = GuestState.no_state.value
         self.progress = 0
         self.progress = 0
@@ -63,40 +61,6 @@ class Guest(ORM):
     def get_allow_content_search_keywords():
     def get_allow_content_search_keywords():
         return ['label', 'remark', 'node_id', 'ip']
         return ['label', 'remark', 'node_id', 'ip']
 
 
-    def get_boot_jobs_key(self):
-        return ':'.join([app.config['guest_boot_jobs'], self.uuid])
-
-    def add_boot_jobs(self, boot_jobs_id):
-        if not isinstance(boot_jobs_id, list):
-            raise ValueError('The boot_jobs_id must be a list.')
-
-        key = self.get_boot_jobs_key()
-        db.r.sadd(key, *boot_jobs_id)
-        db.r.expire(key, app.config['guest_boot_jobs_wait_time'])
-
-    def get_boot_jobs(self):
-        return db.r.ttl(self.get_boot_jobs_key()), list(db.r.smembers(self.get_boot_jobs_key()))
-
-    def delete_boot_jobs(self, boot_jobs_id):
-        if not isinstance(boot_jobs_id, list):
-            raise ValueError('The boot_jobs_id must be a list.')
-
-        key = self.get_boot_jobs_key()
-        db.r.srem(key, *boot_jobs_id)
-
-        # 如果集合下还有值,则更新启动作业有效时间
-        if db.r.exists(key):
-            db.r.expire(key, app.config['guest_boot_jobs_wait_time'])
-
-    @staticmethod
-    def get_uuids_of_all_had_boot_job():
-        boot_job_keys = db.r.keys(pattern=app.config['guest_boot_jobs'] + '*')
-        uuids = list()
-        for boot_job_key in boot_job_keys:
-            uuids.append(boot_job_key.split(':')[-1])
-
-        return uuids
-
 
 
 class Disk(ORM):
 class Disk(ORM):
 
 

+ 2 - 2
models/guest_xml.py

@@ -2,7 +2,7 @@
 # -*- coding: utf-8 -*-
 # -*- coding: utf-8 -*-
 
 
 
 
-from models import Config, Disk, OSTemplate, OSType
+from models import Config, Disk
 from models import Guest
 from models import Guest
 from models import status
 from models import status
 
 
@@ -59,7 +59,7 @@ class GuestXML(object):
         # Windows Guest 设为 localtime,非 Windows Guest 都设为 utc
         # Windows Guest 设为 localtime,非 Windows Guest 都设为 utc
         offset = 'utc'
         offset = 'utc'
 
 
-        if self.os_type == OSType.windows.value:
+        if str(self.os_type).lower().find('windows') >= 0:
             offset = 'localtime'
             offset = 'localtime'
 
 
         return """<clock offset='{0}'/>""".format(offset)
         return """<clock offset='{0}'/>""".format(offset)

+ 0 - 48
models/os_template.py

@@ -1,48 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-
-from models import FilterFieldType
-from models import ORM
-
-
-__author__ = 'James Iter'
-__date__ = '2017/3/23'
-__contact__ = 'james.iter.cn@gmail.com'
-__copyright__ = '(c) 2017 by James Iter.'
-
-
-class OSTemplate(ORM):
-
-    _table_name = 'os_template'
-    _primary_key = 'id'
-
-    def __init__(self):
-        super(OSTemplate, self).__init__()
-        self.id = 0
-        self.label = None
-        self.path = None
-        self.os_type = None
-        self.active = None
-        self.icon = None
-        self.boot_job_id = None
-
-    @staticmethod
-    def get_filter_keywords():
-        return {
-            'id': FilterFieldType.INT.value,
-            'label': FilterFieldType.STR.value,
-            'path': FilterFieldType.STR.value,
-            'os_type': FilterFieldType.INT.value,
-            'active': FilterFieldType.BOOL.value,
-            'boot_job_id': FilterFieldType.INT.value
-        }
-
-    @staticmethod
-    def get_allow_update_keywords():
-        return ['active', 'boot_job_id', 'os_type']
-
-    @staticmethod
-    def get_allow_content_search_keywords():
-        return ['label', 'path', 'os_type']
-

+ 1 - 1
models/rules.py

@@ -64,7 +64,7 @@ class Rules(Enum):
     UUIDS = (REG_UUIDS, 'uuids')
     UUIDS = (REG_UUIDS, 'uuids')
     CPU = (int, 'cpu')
     CPU = (int, 'cpu')
     MEMORY = (int, 'memory')
     MEMORY = (int, 'memory')
-    OS_TEMPLATE_ID = (int, 'os_template_id')
+    OS_TEMPLATE_IMAGE_ID = (int, 'os_template_image_id')
     QUANTITY = (int, 'quantity')
     QUANTITY = (int, 'quantity')
     NAME = (basestring, 'name')
     NAME = (basestring, 'name')
     PATH = (basestring, 'path')
     PATH = (basestring, 'path')

+ 0 - 15
models/status.py

@@ -85,12 +85,6 @@ class BootJobUseFor(IntEnum):
     user = 2
     user = 2
 
 
 
 
-class OperateRuleKind(IntEnum):
-    cmd = 0
-    write_file = 1
-    append_file = 2
-
-
 class OSTemplateInitializeOperateKind(IntEnum):
 class OSTemplateInitializeOperateKind(IntEnum):
     cmd = 0
     cmd = 0
     write_file = 1
     write_file = 1
@@ -108,12 +102,3 @@ class HostCollectionPerformanceDataKind(IntEnum):
     traffic = 1
     traffic = 1
     disk_usage_io = 2
     disk_usage_io = 2
 
 
-
-class OSType(IntEnum):
-    linux = 0
-    windows = 1
-    bsd = 2
-    aix = 3
-    hp_unix = 4
-    unknown = 255
-

+ 0 - 523
templates/boot_jobs_show.html

@@ -1,523 +0,0 @@
-{% extends "layout.html" %}
-{% block head %}
-    {{ super() }}
-    <style type="text/css">
-
-        @media (min-width: 768px) {
-            .form-horizontal .control-label {
-                text-align: left;
-            }
-        }
-
-        label>span {
-            color: deepskyblue;
-        }
-
-        .table {
-            font-size: 12px;
-            border-width: 1px;
-            line-height: 20px;
-        }
-        .table > thead > tr > th,
-        .table > tfoot > tr > th {
-            color: #999999;
-            font-weight: normal;
-            border-bottom: 0 solid #e1e6eb;
-            background-color: #F5F6FA;
-        }
-        
-        .table > tbody > tr > td {
-            color: #424547;
-        }
-
-        .table-bordered > tbody > tr {
-            padding-top: 10px;
-            padding-bottom: 10px;
-        }
-
-        .table-bordered > thead > tr > th,
-        .table-bordered > tbody > tr > th,
-        .table-bordered > tfoot > tr > th,
-        .table-bordered > thead > tr > td,
-        .table-bordered > tbody > tr > td,
-        .table-bordered > tfoot > tr > td {
-            border-style: solid;
-            border-width: 1px 0 0 0;
-        }
-
-        .btn,
-        .form-control,
-        .modal-content {
-            border-radius: 0 !important;
-        }
-    </style>
-
-{% endblock head %}
-{% block content %}
-
-<script type="text/javascript">
-    var page = 1;
-    var page_size = 10;
-    var keyword = '';
-    var resource_path = window.location.pathname;
-    var cur_url = resource_path;
-
-    $(document).ready(function() {
-        page_size = $('#page_size').val();
-        cur_url = resource_path + '?page=' + page + '&page_size=' + page_size;
-
-        var last_ready = null;
-        $('#content_search').keydown(function() {
-            if (last_ready !== null) {
-                clearTimeout(last_ready);
-            }
-            last_ready = setTimeout(function () {
-                keyword = $('#content_search').val();
-                cur_url = resource_path + '?page=' + page + '&page_size=' + page_size;
-                if (keyword.length > 0) {
-                    cur_url = resource_path + '?page=' + page + '&page_size=' + page_size + '&keyword=' + keyword;
-                }
-                window.location.href=cur_url;
-            }, 1000);
-        });
-
-        $('#page_size').change(function () {
-            keyword = $('#content_search').val();
-            page_size = $('#page_size').val();
-            cur_url = resource_path + '?page=' + page + '&page_size=' + page_size;
-            if (keyword.length > 0) {
-                cur_url = resource_path + '?page=' + page + '&page_size=' + page_size + '&keyword=' + keyword;
-            }
-            window.location.href=cur_url;
-        });
-
-        $('#edit_name_modal').on('show.bs.modal', function (me) {
-            $('#boot_job_id').val($(me.relatedTarget).parent().parent().prev().text());
-            $('#edit_name').val($(me.relatedTarget).prev().text());
-        });
-
-        $('#edit_remark_modal').on('show.bs.modal', function (me) {
-            $('#boot_job_id').val($(me.relatedTarget).parent().parent().prev().prev().prev().text());
-            $('#edit_remark').val($(me.relatedTarget).prev().text());
-        });
-
-        $('#add_boot_job_modal').on('show.bs.modal', function (me) {
-        });
-
-        $('#update_use_for_modal').on('show.bs.modal', function (me) {
-            $('#boot_job_id').val($(me.relatedTarget).parent().prev().prev().text());
-            $('#update_use_for_instance_desc').text($(me.relatedTarget).parent().prev().text());
-        });
-
-        $('#add_boot_job_form').formValidation({
-            framework: 'bootstrap4',
-            icon: {
-                valid: 'fa fa-check',
-                invalid: 'fa fa-times',
-                validating: 'fa fa-refresh'
-            },
-            // Since the Bootstrap Button hides the radio and checkbox
-            // We exclude the disabled elements only
-            excluded: ':disabled',
-            locale: 'zh_CN',
-            fields: {
-                name: {
-                    validators: {
-                        notEmpty: {
-                        },
-                        stringLength: {
-                            min: 1,
-                            max: 255
-                        }
-                    }
-                },
-                use_for: {
-                    validators: {
-                        notEmpty: {
-                        }
-                    }
-                },
-                remark: {
-                    validators: {
-                        stringLength: {
-                            max: 255
-                        }
-                    }
-                }
-            }
-        })
-        .on('success.field.fv', function(e, data) {
-            if (data.fv.getInvalidFields().length > 0) {    // There is invalid field
-                data.fv.disableSubmitButtons(true);
-            }
-        });
-    });
-
-    function refresh() {
-        keyword = $('#content_search').val();
-        page = $('#pagination li.active a').text();
-        page_size = $('#page_size').val();
-        cur_url = resource_path + '?page=' + page + '&page_size=' + page_size;
-        if (keyword.length > 0) {
-            cur_url = resource_path + '?page=' + page + '&page_size=' + page_size + '&keyword=' + keyword;
-        }
-        window.location.href=cur_url;
-    }
-
-    function row_onmouseover(me) {
-        $(me).find(".edit_name_trigger, .edit_remark_trigger").css('display','inline-flex');
-    }
-
-    function row_onmouseout(me) {
-        $(me).find(".edit_name_trigger, .edit_remark_trigger").css('display','none');
-    }
-
-    function name_update(me) {
-        var boot_job_id = $('#boot_job_id').val();
-        var name = $('#edit_name').val();
-        $('#edit_name_modal').modal('hide');
-        $.ajax({
-            url : '/api/boot_job/' + boot_job_id,
-            type : 'PATCH',
-            contentType: "application/json; charset=utf-8",
-            data : JSON.stringify({
-                name: name
-            }),
-            error : function() {
-                alter_danger('启动作业名称更新失败!');
-            },
-            success : function() {
-                alter_success('启动作业名称更新成功!');
-                refresh()
-            }
-        });
-    }
-
-    function remark_update(me) {
-        var boot_job_id = $('#boot_job_id').val();
-        var remark = $('#edit_remark').val();
-        $('#edit_remark_modal').modal('hide');
-        $.ajax({
-            url : '/api/boot_job/' + boot_job_id,
-            type : 'PATCH',
-            contentType: "application/json; charset=utf-8",
-            data : JSON.stringify({
-                remark: remark
-            }),
-            error : function() {
-                alter_danger('启动作业备注更新失败!');
-            },
-            success : function() {
-                alter_success('启动作业备注路径更新成功!');
-                refresh()
-            }
-        });
-    }
-
-    function update_use_for(id) {
-        $.ajax({
-            url : '/api/boot_job/' + id,
-            type : 'PATCH',
-            contentType: "application/json; charset=utf-8",
-            data : JSON.stringify({
-                use_for: parseInt($('#update_use_for').val())
-            }),
-            error : function() {
-                alter_danger('变更启动作业作用域指令发送失败!');
-            },
-            success : function() {
-                alter_success('变更启动作业作用域指令发送成功!');
-                refresh();
-            }
-        });
-    }
-
-    function remove(id) {
-        $.ajax({
-            url : '/api/boot_jobs/' + id,
-            type : 'DELETE',
-            contentType: "application/json; charset=utf-8",
-            error : function() {
-                alter_danger('启动作业删除指令发送失败!');
-            },
-            success : function() {
-                alter_success('启动作业删除指令发送成功!');
-                refresh();
-            }
-        });
-    }
-
-    function delete_at(me) {
-        var id = $('#boot_job_id').val();
-        remove(id);
-        $('#delete_modal').modal('hide');
-    }
-
-    function update_use_for_at(me) {
-        var id = $('#boot_job_id').val();
-        update_use_for(id);
-        $('#update_use_for_modal').modal('hide');
-    }
-</script>
-<div class="panel">
-    <div class="panel-body">
-        <h3 class="title-hero" style="font-size: 24px;">
-            启动作业
-        </h3>
-        <div>
-            <div id="datatable-row-highlight_wrapper" class="dataTables_wrapper form-inline">
-                <div class="row" style="padding: 10px 10px 10px 0; width: 100%;">
-                    <div class="col-sm-12" style="padding-right: 0;">
-                        <div id="datatable-row-highlight_filter" class="dataTables_filter" style="display: inline-block;">
-                            <input id="content_search" type="search" class="form-control" placeholder="模糊搜索..." value="{%- if keyword -%} {{ keyword }} {%- endif -%}" style="margin-left: 0; border-radius: 0;">
-                        </div>
-                        <div class="pull-right">
-                            <button class="btn btn-default" onclick="refresh()" style="border-radius: 0;"><span class="glyph-icon icon-elusive-arrows-cw"></span></button>
-                            <a class="btn btn-info" href="javascript:;" data-toggle="modal" data-target="#add_boot_job_modal" style="border-radius: 0; padding-left: 40px; padding-right: 40px;">添加启动作业</a>
-                        </div>
-                    </div>
-                </div>
-                <table id="boot_job_list" class="table table-bordered table-hover" cellspacing="0" width="100%" role="grid"
-                       style="width: 100%; margin-bottom: 0; border-bottom-width: 0;">
-                <thead>
-                <tr role="row">
-                    <th style="display: none;">ID</th>
-                    <th width="280px;">名称</th>
-                    <th>作用域</th>
-                    <th width="600px;">备注</th>
-                    <th>操作</th>
-                </tr>
-                </thead>
-                <tbody>
-                {% for item in boot_jobs_ret.data %}
-                <tr role="row" class="odd" onmouseover="row_onmouseover(this);" onmouseout="row_onmouseout(this);">
-                    <td style="display: none;">{{ item.id }}</td>
-                    <td>
-                        <div>
-                            <a href="/operate_rules?boot_job_id={{ item.id }}"><p style="display: inline-block;">{{ item.name }}</p></a>
-                            <a href="javascript:;" class="edit_name_trigger" data-toggle="modal" data-target="#edit_name_modal" style="display: none; float: right;">
-                                <span class="glyph-icon icon-elusive-pencil" style="width: 20px; height: 20px; margin-left: 10px; border-radius: 0; border: 1px solid rgb(220, 233, 255); background-color: #ffffff;"></span>
-                            </a>
-                        </div>
-                    </td>
-                    <td>
-                        <a href="javascript:;" data-toggle="modal" data-target="#update_use_for_modal">
-                            {% if item.use_for == 0 %}
-                                <span style="color: #8800FF;">模板</span>
-                            {% elif item.use_for == 1 %}
-                                <span style="color: #3333FF;">系统</span>
-                            {% elif item.use_for == 2 %}
-                                <span style="color: #00BB00;">用户</span>
-                            {% else %}
-                                <span style="color: #990000;">未知</span>
-                            {% endif %}
-                        </a>
-                    </td>
-                    <td>
-                        <div>
-                            <p style="display: inline-block;">{{ item.remark }}</p>
-                            <a href="javascript:;" class="edit_remark_trigger" data-toggle="modal" data-target="#edit_remark_modal" style="display: none; float: right;">
-                                <span class="glyph-icon icon-elusive-pencil" style="width: 20px; height: 20px; margin-left: 10px; border-radius: 0; border: 1px solid rgb(220, 233, 255); background-color: #ffffff;"></span>
-                            </a>
-                        </div>
-                    </td>
-                    <td>
-                        <div class="dropdown inline-block">
-                            <a href="javascript:;" class="dropdown-toggle" data-toggle="dropdown">
-                                更多
-                            </a>
-                            <ul class="dropdown-menu">
-                                <li>
-                                    <a href="javascript:;" data-toggle="modal" data-target="#delete_modal"
-                                       onclick="$('#boot_job_id').val($(this).parent().parent().parent().parent().parent().children()[0].textContent);
-                                       $('#delete_instance_desc').text($(this).parent().parent().parent().parent().parent().children()[1].textContent)">
-                                        删除
-                                    </a>
-                                </li>
-                            </ul>
-                        </div>
-                    </td>
-                </tr>
-                {% endfor %}
-                </tbody>
-                </table>
-
-                <table class="table table-bordered" style="border-top-width: 0; z-index: 99; position: sticky; bottom: 0;">
-                    <tfoot>
-                    <tr style="height: 70px;">
-                        <th>
-                            <div class="row">
-                                <div class="col-sm-6">
-                                </div>
-                                <div class="col-sm-3" style="font-size: 12px; padding-top: 5px; text-align: right;">
-                                    共有{{ boot_jobs_ret.paging.total }}条,每页显示:
-                                    <select id="page_size" name="datatable-row-highlight_length" title="page_size" class="form-control" style="height: 22px; vertical-align: baseline;">
-                                        <option value="10" {% if page_size == 10 %} selected {% endif %}>10</option>
-                                        <option value="20" {% if page_size == 20 %} selected {% endif %}>20</option>
-                                        <option value="50" {% if page_size == 50  %} selected {% endif %}>50</option>
-                                    </select>&nbsp;&nbsp;条
-                                </div>
-                                <div class="col-sm-3" style="text-align: left;">
-                                    <div class="dataTables_paginate paging_bootstrap" id="datatable-row-highlight_paginate">
-                                        <ul id="pagination" class="pagination">
-                                            <li class="{% if page == 1 %} disabled {% endif %}">
-                                                <a href="{{ resource_path }}?page={{ page - 1 }}&page_size={{ page_size }}{% if keyword %}&keyword={{ keyword }}{% endif %}{% if order_by %}&order_by={{ order_by }}{% endif %}{% if order %}&order={{ order }}{% endif %}">«</a>
-                                            </li>
-                                            {% for item in pages %}
-                                            <li class="{% if item == page %} active {% endif %}">
-                                                <a href="{{ resource_path }}?page={{ item }}&page_size={{ page_size }}{% if keyword %}&keyword={{ keyword }}{% endif %}{% if order_by %}&order_by={{ order_by }}{% endif %}{% if order %}&order={{ order }}{% endif %}">{{ item }}</a>
-                                            </li>
-                                            {% endfor %}
-                                            <li class="{% if page == last_page %} disabled {% endif %}">
-                                                <a href="{{ resource_path }}?page={{ page + 1 }}&page_size={{ page_size }}{% if keyword %}&keyword={{ keyword }}{% endif %}{% if order_by %}&order_by={{ order_by }}{% endif %}{% if order %}&order={{ order }}{% endif %}">»</a>
-                                            </li>
-                                        </ul>
-                                    </div>
-                                </div>
-                            </div>
-                        </th>
-                    </tr>
-                    </tfoot>
-                </table>
-            </div>
-        </div>
-    </div>
-</div>
-
-<input id="boot_job_id" title="启动作业 ID" class="form-control" name="boot_job_id" hidden>
-
-<div class="modal" id="edit_name_modal" tabindex="-1" role="dialog" style="margin-top: 100px;">
-    <div class="modal-dialog modal-sm">
-        <div class="modal-content">
-            <div class="modal-header">
-                <h4 class="modal-title">编辑启动作业名称:</h4>
-            </div>
-            <div class="modal-body">
-                <input id="edit_name" title="启动作业名称" class="form-control" name="boot_job_name">
-            </div>
-            <div class="modal-footer">
-                <button type="button" class="btn btn-sm btn-primary" onclick="name_update();">确定</button>
-                <button type="button" class="btn btn-sm btn-default" data-dismiss="modal">取消</button>
-            </div>
-        </div>
-    </div>
-</div>
-
-<div class="modal" id="edit_remark_modal" tabindex="-1" role="dialog" style="margin-top: 100px;">
-    <div class="modal-dialog">
-        <div class="modal-content">
-            <div class="modal-header">
-                <h4 class="modal-title">编辑模板路径:</h4>
-            </div>
-            <div class="modal-body">
-                <input id="edit_remark" title="启动作业备注" class="form-control" name="boot_job_remark">
-            </div>
-            <div class="modal-footer">
-                <button type="button" class="btn btn-sm btn-primary" onclick="remark_update();">确定</button>
-                <button type="button" class="btn btn-sm btn-default" data-dismiss="modal">取消</button>
-            </div>
-        </div>
-    </div>
-</div>
-
-<div class="modal" id="delete_modal" tabindex="-1" role="dialog" style="margin-top: 100px;">
-    <div class="modal-dialog">
-        <div class="modal-content">
-            <div class="modal-header">
-                <h4 class="modal-title">删除启动作业:</h4>
-            </div>
-            <div class="modal-body">
-                <p>你确定要删除该启动作业吗?</p>
-                <h3 style="color: orangered;" id="delete_instance_desc"></h3>
-            </div>
-            <div class="modal-footer">
-                <button type="button" class="btn btn-sm btn-primary" onclick="delete_at();">确定</button>
-                <button type="button" class="btn btn-sm btn-default" data-dismiss="modal">取消</button>
-            </div>
-        </div>
-    </div>
-</div>
-
-<div class="modal" id="add_boot_job_modal" tabindex="-1" role="dialog" style="margin-top: 100px;">
-    <div class="modal-dialog modal-lg">
-        <div class="modal-content">
-            <div class="modal-header">
-                <h4 class="modal-title">添加启动作业:</h4>
-            </div>
-            <div class="modal-body" style="padding-top: 0; padding-bottom: 0;">
-                <div class="example-box-wrapper">
-                    <form id="add_boot_job_form" class="form-horizontal bordered-row" action="/boot_job" method="post">
-                        <div class="form-group">
-                            <div class="col-sm-2"></div>
-                            <label class="col-sm-2 control-label"><span class="glyph-icon icon-elusive-compass-circled"></span>&nbsp;&nbsp;启动作业名称</label>
-                            <div class="col-sm-6">
-                                <input id="name" name="name" type="text" title="启动作业名称" class="form-control">
-                            </div>
-                        </div>
-                        <div class="form-group">
-                            <div class="col-sm-2"></div>
-                            <label class="col-sm-2 control-label"><span class="glyph-icon icon-pie-chart"></span>&nbsp;&nbsp;作用域</label>
-                            <div class="col-sm-6">
-                                <select id="use_for" name="use_for" title="作用域" class="selectpicker">
-                                    <option value="2" data-subtext="通过重启系统,批量执行用户预定的操作" selected>用户</option>
-                                    <option value="0" data-subtext="从模板克隆的虚拟机,首次启动时初始化系统使用">模板</option>
-                                    <!--<option value="1" data-subtext="JimV系统平台内置的功能,如重置系统密码,更换IP等操作">系统</option>-->
-                                </select>
-                            </div>
-                        </div>
-                        <div class="form-group">
-                            <div class="col-sm-2"></div>
-                            <label class="col-sm-2 control-label"><span class="glyph-icon icon-newspaper-o"></span>&nbsp;&nbsp;备注</label>
-                            <div class="col-sm-6">
-                                <input id="remark" name="remark" type="text" title="备注" class="form-control">
-                            </div>
-                        </div>
-                        <div class="form-group">
-                            <div class="col-sm-4"></div>
-                            <div class="col-sm-6 pull-right">
-                                <button type="submit" class="btn btn-blue-alt" style="width: 180px; height: 40px; font-size: 16px;" disabled>创建</button>
-                                <button class="btn btn-default" style="width: 64px; height: 40px; font-size: 16px;" data-dismiss="modal">取消</button>
-                            </div>
-                        </div>
-                    </form>
-                </div>
-            </div>
-        </div>
-    </div>
-</div>
-
-<div class="modal" id="update_use_for_modal" tabindex="-1" role="dialog" style="margin-top: 100px;">
-    <div class="modal-dialog">
-        <div class="modal-content">
-            <div class="modal-header">
-                <h4 class="modal-title">变更作用域:</h4>
-            </div>
-            <div class="modal-body" style="padding-top: 0;">
-                <form class="form-horizontal bordered-row">
-                    <div class="form-group">
-                        <div class="col-sm-1"></div>
-                        <label class="col-sm-3 control-label"><span class="glyph-icon icon-elusive-compass-circled"></span>&nbsp;&nbsp;启动作业名称</label>
-                        <div class="col-sm-8">
-                            <h3 style="color: orangered;" id="update_use_for_instance_desc"></h3>
-                        </div>
-                    </div>
-                    <div class="form-group">
-                        <div class="col-sm-1"></div>
-                        <label class="col-sm-3 control-label"><span class="glyph-icon icon-pie-chart"></span>&nbsp;&nbsp;作用域</label>
-                        <div class="col-sm-8">
-                            <select id="update_use_for" name="use_for" title="作用域" class="selectpicker">
-                                <option value="2" data-subtext="通过重启系统,批量执行用户预定的操作" selected>用户</option>
-                                <option value="0" data-subtext="从模板克隆的虚拟机,首次启动时初始化系统使用">模板</option>
-                            </select>
-                        </div>
-                    </div>
-                </form>
-            </div>
-            <div class="modal-footer">
-                <button type="button" class="btn btn-sm btn-primary" onclick="update_use_for_at();">确定</button>
-                <button type="button" class="btn btn-sm btn-default" data-dismiss="modal">取消</button>
-            </div>
-        </div>
-    </div>
-</div>
-{% endblock content %}

+ 0 - 307
templates/guest_boot_jobs.html

@@ -1,307 +0,0 @@
-{% extends "layout.html" %}
-{% block head %}
-    {{ super() }}
-    <style type="text/css">
-
-        @media (min-width: 768px) {
-            .form-horizontal .control-label {
-                text-align: left;
-            }
-        }
-
-        label>span {
-            color: deepskyblue;
-        }
-
-        .table {
-            font-size: 12px;
-            border-width: 1px;
-            line-height: 20px;
-        }
-        .table > thead > tr > th,
-        .table > tfoot > tr > th {
-            color: #999999;
-            font-weight: normal;
-            border-bottom: 0 solid #e1e6eb;
-            background-color: #F5F6FA;
-        }
-        
-        .table > tbody > tr > td {
-            color: #424547;
-        }
-
-        .table-bordered > tbody > tr {
-            padding-top: 10px;
-            padding-bottom: 10px;
-        }
-
-        .table-bordered > thead > tr > th,
-        .table-bordered > tbody > tr > th,
-        .table-bordered > tfoot > tr > th,
-        .table-bordered > thead > tr > td,
-        .table-bordered > tbody > tr > td,
-        .table-bordered > tfoot > tr > td {
-            border-style: solid;
-            border-width: 1px 0 0 0;
-        }
-
-        .btn,
-        .form-control,
-        .modal-content {
-            border-radius: 0 !important;
-        }
-    </style>
-
-{% endblock head %}
-{% block content %}
-
-<script type="text/javascript">
-    var resource_path = window.location.pathname;
-    var cur_url = resource_path;
-
-    $(document).ready(function() {
-        $('#add_boot_job_modal').on('show.bs.modal', function (me) {
-            refresh_boot_job_selectpicker($('#boot_job_selector'));
-        });
-        $('#add_guest_boot_job_form').formValidation({
-            framework: 'bootstrap4',
-            icon: {
-                valid: 'fa fa-check',
-                invalid: 'fa fa-times',
-                validating: 'fa fa-refresh'
-            },
-            // Since the Bootstrap Button hides the radio and checkbox
-            // We exclude the disabled elements only
-            excluded: ':disabled',
-            locale: 'zh_CN',
-            fields: {
-                boot_job_selector: {
-                    validators: {
-                        notEmpty: {}
-                    }
-                }
-            }
-        })
-        .on('success.field.fv', function(e, data) {
-            if (data.fv.getInvalidFields().length > 0) {    // There is invalid field
-                data.fv.disableSubmitButtons(true);
-            }
-        });
-    });
-
-    function refresh() {
-        cur_url = resource_path;
-        window.location.href=cur_url;
-    }
-
-    function refresh_boot_job_selectpicker(selectpicker) {
-        $.ajax({
-            url : '/api/boot_jobs?filter=use_for:eq:2',
-            type : 'GET',
-            contentType: "application/json; charset=utf-8",
-            dataType: 'json',
-            error : function() {
-            },
-            success : function(data, textStatus, xhr) {
-                selectpicker.empty();
-                $.each(data.data, function(k, v) {
-                    selectpicker.append(
-                        $('<option>', {value: v['id'], text: v['name'], 'data-subtext': v['remark']})
-                    );
-                });
-                selectpicker.selectpicker('refresh');
-            }
-        });
-    }
-
-    function add_boot_job(id) {
-        $.ajax({
-            url : '/api/guests/_boot_jobs/{{ uuid }}/' + id,
-            type : 'PUT',
-            contentType: "application/json; charset=utf-8",
-            error : function() {
-                alter_danger('启动作业添加指令发送失败!');
-            },
-            success : function() {
-                alter_success('启动作业添加指令发送成功!');
-                refresh();
-            }
-        });
-    }
-
-    function remove(id) {
-        $.ajax({
-            url : '/api/guests/_boot_jobs/{{ uuid }}/' + id,
-            type : 'DELETE',
-            contentType: "application/json; charset=utf-8",
-            error : function() {
-                alter_danger('启动作业删除指令发送失败!');
-            },
-            success : function() {
-                alter_success('启动作业删除指令发送成功!');
-                refresh();
-            }
-        });
-    }
-
-    function delete_at(me) {
-        var id = $('#boot_job_id').val();
-        remove(id);
-        $('#delete_modal').modal('hide');
-    }
-
-    function add_boot_job_at(me) {
-        var id = $('#boot_job_selector').val();
-        add_boot_job(id);
-        $('#add_boot_job_modal').modal('hide');
-    }
-</script>
-<div class="panel">
-    <div class="panel-body">
-        <h3 class="title-hero" style="font-size: 24px;">
-            启动作业(<a href="/guest/detail/{{ guest_ret.data.uuid }}" style="color: #0275d8;">{{ guest_ret.data.label }}/{{ guest_ret.data.remark }}</a>)
-        </h3>
-        <div>
-            <div id="datatable-row-highlight_wrapper" class="dataTables_wrapper form-inline">
-                <div class="row" style="padding: 10px 10px 10px 0; width: 100%;">
-                    <div class="col-sm-12" style="padding-right: 0;">
-                        <h4 style="color: orange; {% if guest_boot_jobs_ret.data.ttl < 1 %}display: none;{% endif %}">下列启动作业将在
-                            <span style="color: #b94a48; {% if guest_boot_jobs_ret.data.ttl // 60 == 0 %}display: none;{% endif %}">{{ guest_boot_jobs_ret.data.ttl // 60 }}分</span>
-                            <span style="color: #b94a48; {% if guest_boot_jobs_ret.data.ttl % 60 == 0 %}display: none;{% endif %}">{{ guest_boot_jobs_ret.data.ttl % 60 }}秒</span>
-                            <span>后失效</span>
-                        </h4>
-                        <div class="pull-right">
-                            <button class="btn btn-default" onclick="refresh()" style="border-radius: 0;"><span class="glyph-icon icon-elusive-arrows-cw"></span></button>
-                            <a class="btn btn-info" href="javascript:;" data-toggle="modal" data-target="#add_boot_job_modal" style="border-radius: 0; padding-left: 40px; padding-right: 40px;">添加启动作业</a>
-                        </div>
-                    </div>
-                </div>
-                <table id="boot_job_list" class="table table-bordered table-hover" cellspacing="0" width="100%" role="grid"
-                       style="width: 100%; margin-bottom: 0; border-bottom-width: 0;">
-                <thead>
-                <tr role="row">
-                    <th style="display: none;">ID</th>
-                    <th width="280px;">名称</th>
-                    <th>作用域</th>
-                    <th width="600px;">备注</th>
-                    <th>操作</th>
-                </tr>
-                </thead>
-                <tbody>
-                {% for item in guest_boot_jobs_ret.data.boot_jobs %}
-                <tr role="row" class="odd">
-                    <td style="display: none;">{{ item }}</td>
-                    <td>
-                        <div>
-                            <a href="/operate_rules?boot_job_id={{ item }}"><p style="display: inline-block;">{{ boot_jobs_mapping_by_id[item | int].name }}</p></a>
-                        </div>
-                    </td>
-                    <td>
-                        {% if boot_jobs_mapping_by_id[item | int].use_for == 0 %}
-                            <span style="color: #8800FF;">模板</span>
-                        {% elif boot_jobs_mapping_by_id[item | int].use_for == 1 %}
-                            <span style="color: #3333FF;">系统</span>
-                        {% elif boot_jobs_mapping_by_id[item | int].use_for == 2 %}
-                            <span style="color: #00BB00;">用户</span>
-                        {% else %}
-                            <span style="color: #990000;">未知</span>
-                        {% endif %}
-                    </td>
-                    <td>
-                        <div>
-                            <p style="display: inline-block;">{{ boot_jobs_mapping_by_id[item | int].remark }}</p>
-                        </div>
-                    </td>
-                    <td>
-                        <div class="dropdown inline-block">
-                            <a href="javascript:;" class="dropdown-toggle" data-toggle="dropdown">
-                                更多
-                            </a>
-                            <ul class="dropdown-menu">
-                                <li>
-                                    <a href="javascript:;" data-toggle="modal" data-target="#delete_modal"
-                                       onclick="$('#boot_job_id').val($(this).parent().parent().parent().parent().parent().children()[0].textContent);
-                                       $('#delete_instance_desc').text($(this).parent().parent().parent().parent().parent().children()[1].textContent)">
-                                        删除
-                                    </a>
-                                </li>
-                            </ul>
-                        </div>
-                    </td>
-                </tr>
-                {% endfor %}
-                </tbody>
-                </table>
-
-                <table class="table table-bordered" style="border-top-width: 0; z-index: 99; position: sticky; bottom: 0;">
-                    <tfoot>
-                    <tr style="height: 70px;">
-                        <th>
-                            <div class="row">
-                                <div class="col-sm-6">
-                                </div>
-                                <div class="col-sm-3" style="font-size: 12px; padding-top: 5px; text-align: right;">
-                                </div>
-                                <div class="col-sm-3" style="text-align: left;">
-                                </div>
-                            </div>
-                        </th>
-                    </tr>
-                    </tfoot>
-                </table>
-            </div>
-        </div>
-    </div>
-</div>
-
-<input id="boot_job_id" title="启动作业 ID" class="form-control" name="boot_job_id" hidden>
-
-<div class="modal" id="delete_modal" tabindex="-1" role="dialog" style="margin-top: 100px;">
-    <div class="modal-dialog">
-        <div class="modal-content">
-            <div class="modal-header">
-                <h4 class="modal-title">删除启动作业:</h4>
-            </div>
-            <div class="modal-body">
-                <p>你确定要删除该启动作业吗?</p>
-                <h3 style="color: orangered;" id="delete_instance_desc"></h3>
-            </div>
-            <div class="modal-footer">
-                <button type="button" class="btn btn-sm btn-primary" onclick="delete_at();">确定</button>
-                <button type="button" class="btn btn-sm btn-default" data-dismiss="modal">取消</button>
-            </div>
-        </div>
-    </div>
-</div>
-
-<div class="modal" id="add_boot_job_modal" tabindex="-1" role="dialog" style="margin-top: 100px;">
-    <div class="modal-dialog modal-lg">
-        <div class="modal-content">
-            <div class="modal-header">
-                <h4 class="modal-title">添加启动作业:</h4>
-            </div>
-            <div class="modal-body" style="padding-top: 0; padding-bottom: 0;">
-                <div class="example-box-wrapper">
-                    <form id="add_guest_boot_job_form" class="form-horizontal bordered-row">
-                        <div class="form-group">
-                            <div class="col-sm-2"></div>
-                            <label class="col-sm-2 control-label"><span class="glyph-icon icon-list-alt"></span>&nbsp;&nbsp;启动作业</label>
-                            <div class="col-sm-6">
-                                <select id="boot_job_selector" name="boot_job_selector" title="启动作业" class="selectpicker">
-                                </select>
-                            </div>
-                        </div>
-                        <div class="form-group">
-                            <div class="col-sm-4"></div>
-                            <div class="col-sm-6 pull-right">
-                                <button type="submit" class="btn btn-blue-alt" style="width: 180px; height: 40px; font-size: 16px;" onclick="add_boot_job_at();" disabled>添加</button>
-                                <button class="btn btn-default" style="width: 64px; height: 40px; font-size: 16px;" data-dismiss="modal">取消</button>
-                            </div>
-                        </div>
-                    </form>
-                </div>
-            </div>
-        </div>
-    </div>
-</div>
-{% endblock content %}

+ 50 - 5
templates/guest_create.html

@@ -60,7 +60,7 @@
                         }
                         }
                     }
                     }
                 },
                 },
-                os_template_id: {
+                os_template_image_id: {
                     validators: {
                     validators: {
                         notEmpty: {
                         notEmpty: {
                         }
                         }
@@ -105,8 +105,56 @@
                 data.fv.disableSubmitButtons(true);
                 data.fv.disableSubmitButtons(true);
             }
             }
         });
         });
+
+        refresh_os_template_image_id_selectpicker($('#os_template_image_id'));
     });
     });
 
 
+    function get_os_templates_profile_mapping_by_id() {
+        var os_templates_profile_mapping_by_id = {};
+
+        $.ajax({
+            url : '/api/os_templates_profile',
+            type : 'GET',
+            contentType: "application/json; charset=utf-8",
+            dataType: 'json',
+            async: false,
+            error : function() {
+            },
+            success : function(data, textStatus, xhr) {
+                $.each(data.data, function(k, v) {
+                    os_templates_profile_mapping_by_id[v['id']] = v;
+                });
+            }
+        });
+
+        return os_templates_profile_mapping_by_id;
+    }
+
+    function refresh_os_template_image_id_selectpicker(selectpicker) {
+        $.ajax({
+            url : '/api/os_templates_image',
+            type : 'GET',
+            contentType: "application/json; charset=utf-8",
+            dataType: 'json',
+            async: false,
+            error : function() {
+            },
+            success : function(data, textStatus, xhr) {
+                var os_templates_profile_mapping_by_id = get_os_templates_profile_mapping_by_id();
+                selectpicker.empty();
+                $.each(data.data, function(k, v) {
+                    if (v['logo'] === "") {
+                        v['logo'] = os_templates_profile_mapping_by_id[v['os_template_profile_id']].icon;
+                    }
+                    selectpicker.append(
+                        $('<option>', {value: v['id'], text: '\xa0\xa0' + v['label'], 'data-icon': v['logo']})
+                    );
+                });
+                selectpicker.selectpicker('refresh');
+            }
+        });
+    }
+
     $(function() { "use strict";
     $(function() { "use strict";
         $("#quantity").TouchSpin({
         $("#quantity").TouchSpin({
             max: 20,
             max: 20,
@@ -201,10 +249,7 @@
                     <div class="form-group">
                     <div class="form-group">
                         <label class="col-sm-2 control-label"><span class="glyph-icon icon-elusive-inbox-alt"></span>&nbsp;&nbsp;系统模板</label>
                         <label class="col-sm-2 control-label"><span class="glyph-icon icon-elusive-inbox-alt"></span>&nbsp;&nbsp;系统模板</label>
                         <div class="col-sm-6">
                         <div class="col-sm-6">
-                            <select id="os_template" name="os_template_id" title="请选择系统模板..." class="selectpicker" data-width="100%">
-                                {% for item in os_template_ret.data %}
-                                    <option value="{{ item.id }}" data-icon="{{ item.icon }}">&nbsp;&nbsp;{{ item.label }}</option>
-                                {% endfor %}
+                            <select id="os_template_image_id" name="os_template_image_id" title="请选择系统模板..." class="selectpicker" data-width="100%">
                             </select>
                             </select>
                         </div>
                         </div>
                     </div>
                     </div>

+ 7 - 2
templates/guest_detail.html

@@ -1107,9 +1107,14 @@
                             <td>
                             <td>
                                 <span class="guest-label">操作系统:&nbsp;&nbsp;&nbsp;&nbsp;</span>
                                 <span class="guest-label">操作系统:&nbsp;&nbsp;&nbsp;&nbsp;</span>
                                 <span class="guest-desc">
                                 <span class="guest-desc">
-                                {{ os_template_ret.data.label }}
+                                {{ os_template_image_ret.data.label }}
                                 </span>&nbsp;&nbsp;&nbsp;&nbsp;
                                 </span>&nbsp;&nbsp;&nbsp;&nbsp;
-                                <span class="{{ os_template_ret.data.icon }}"></span>
+
+                                {% if os_template_image_ret.data.logo == "" %}
+                                    <span class="{{ os_templates_profile_mapping_by_id[os_template_image_ret.data.os_template_profile_id].icon }}"></span>
+                                {% else %}
+                                    <span class="{{ os_template_image_ret.data.logo }}"></span>
+                                {% endif %}
                             </td>
                             </td>
                         </tr>
                         </tr>
                         <tr>
                         <tr>

+ 0 - 406
templates/guests_boot_jobs.html

@@ -1,406 +0,0 @@
-{% extends "layout.html" %}
-{% block head %}
-    {{ super() }}
-    <style type="text/css">
-        .table {
-            font-size: 12px;
-            border-width: 1px;
-            line-height: 20px;
-        }
-        .table > thead > tr > th,
-        .table > tfoot > tr > th {
-            color: #999999;
-            font-weight: normal;
-            border-bottom: 0 solid #e1e6eb;
-            background-color: #F5F6FA;
-        }
-        
-        .table > tbody > tr > td {
-            color: #424547;
-        }
-
-        .table-bordered > tbody > tr {
-            padding-top: 10px;
-            padding-bottom: 10px;
-        }
-
-        .table-bordered > thead > tr > th,
-        .table-bordered > tbody > tr > th,
-        .table-bordered > tfoot > tr > th,
-        .table-bordered > thead > tr > td,
-        .table-bordered > tbody > tr > td,
-        .table-bordered > tfoot > tr > td {
-            border-style: solid;
-            border-width: 1px 0 0 0;
-        }
-
-        .btn,
-        .form-control,
-        .modal-content {
-            border-radius: 0 !important;
-        }
-
-        .tr-selected td,
-        .tr-selected {
-            color: #000 !important;
-            background: #fafaff !important;
-        }
-    </style>
-
-{% endblock head %}
-{% block content %}
-
-<script type="text/javascript">
-    var page = 1;
-    var page_size = 10;
-    var keyword = '';
-    var resource_path = window.location.pathname;
-    var cur_url = resource_path;
-
-    $(document).ready(function() {
-        page_size = $('#page_size').val();
-        cur_url = resource_path + '?page=' + page + '&page_size=' + page_size;
-
-        var last_ready = null;
-        $('#content_search').keydown(function() {
-            if (last_ready !== null) {
-                clearTimeout(last_ready);
-            }
-            last_ready = setTimeout(function () {
-                keyword = $('#content_search').val();
-                cur_url = resource_path + '?page=' + page + '&page_size=' + page_size;
-                if (keyword.length > 0) {
-                    cur_url = resource_path + '?page=' + page + '&page_size=' + page_size + '&keyword=' + keyword;
-                }
-                window.location.href=cur_url;
-            }, 1000);
-        });
-
-        $('#page_size').change(function () {
-            keyword = $('#content_search').val();
-            page_size = $('#page_size').val();
-            cur_url = resource_path + '?page=' + page + '&page_size=' + page_size;
-            if (keyword.length > 0) {
-                cur_url = resource_path + '?page=' + page + '&page_size=' + page_size + '&keyword=' + keyword;
-            }
-            window.location.href=cur_url;
-        });
-
-        $("thead").on('click', ".all_selector", function() {
-            if ($("thead .all_selector").is(':checked')) {
-                $("tbody tr").find('td input[type="checkbox"]:eq(0)').prop('checked', true);
-                $(".all_selector").prop('checked', true);
-            } else {
-                $("tbody tr").find('td input[type="checkbox"]:eq(0)').prop('checked', false);
-                $(".all_selector").prop('checked', false);
-            }
-
-            select_item_action();
-        });
-
-        $("tfoot").on('click', ".all_selector", function() {
-            if ($("tfoot .all_selector").is(':checked')) {
-                $("tbody tr").find('td input[type="checkbox"]:eq(0)').prop('checked', true);
-                $(".all_selector").prop('checked', true);
-            } else {
-                $("tbody tr").find('td input[type="checkbox"]:eq(0)').prop('checked', false);
-                $(".all_selector").prop('checked', false);
-            }
-
-            select_item_action();
-        });
-
-        $("tbody tr").on('click', "input[type='checkbox']", function() {
-            select_item_action();
-        });
-
-        $('body').addClass('add-transition');
-        $('.add-page-transition').on('click', function(){
-            var transAttr = $(this).attr('data-transition');
-            $('.add-transition').attr('class', 'add-transition');
-            $('.add-transition').addClass(transAttr);
-        });
-    });
-
-    function get_selected_element(checked) {
-        if (checked === null) {
-            checked = true;
-        }
-
-        if (checked) {
-            return $('tbody :checked');
-        } else {
-
-            return $('tbody input:not(:checked)');
-        }
-    }
-
-    function highlight_selected_element() {
-        var selected_element = get_selected_element(true);
-        var no_selected_element = get_selected_element(false);
-
-        selected_element.each(function(i, e) {
-            $(e).parent().parent().toggleClass('tr-selected', true);
-        });
-
-        no_selected_element.each(function(i, e) {
-            $(e).parent().parent().toggleClass('tr-selected', false);
-        });
-    }
-
-    function shortcut_bar_enable() {
-        var selected_element = get_selected_element(true);
-
-        if (selected_element.length > 0) {
-            $('.btn-shortcut').toggleClass('disabled', false);
-        } else {
-            $('.btn-shortcut').toggleClass('disabled', true);
-        }
-    }
-
-    function select_item_action() {
-        highlight_selected_element();
-        shortcut_bar_enable();
-    }
-
-    function refresh() {
-        page = $('#pagination li.active a').text();
-        page_size = $('#page_size').val();
-        cur_url = resource_path + '?page=' + page + '&page_size=' + page_size;
-        window.location.href=cur_url;
-    }
-
-    function remove(uuid, boot_job_id, do_refresh) {
-        $.ajax({
-            url : '/api/guests/_boot_jobs/' + uuid + '/' + boot_job_id,
-            type : 'DELETE',
-            contentType: "application/json; charset=utf-8",
-            error : function() {
-                alter_danger('启动作业删除指令发送失败!');
-            },
-            success : function() {
-                // 未指定值的参数为 undefined
-                if (do_refresh) {
-                    alter_success('启动作业删除指令发送成功!');
-                    refresh();
-                }
-            }
-        });
-    }
-
-    function delete_at(me) {
-        var uuid = $('#instance_uuid').val();
-        var boot_job_id = $('#instance_boot_job_id').val();
-        remove(uuid, boot_job_id, true);
-        $('#delete_modal').modal('hide');
-    }
-
-    function get_selected_uuids_and_boot_jobs_id() {
-        var selected_element = get_selected_element(true);
-        var uuids = [];
-        var boot_jobs_id = [];
-
-        selected_element.each(function(i, e) {
-            var uuid = $(e).parent().prev().prev().text();
-            var boot_job_id = $(e).parent().prev().text();
-            uuids.push(uuid);
-            boot_jobs_id.push(boot_job_id);
-        });
-
-        return {'uuids': uuids, 'boot_jobs_id': boot_jobs_id};
-    }
-
-    function get_checked_uuids_and_boot_jobs_id() {
-        var uuids_and_boot_jobs_id = get_selected_uuids_and_boot_jobs_id();
-
-        if (uuids_and_boot_jobs_id['uuids'].length < 1) {
-            alter_warning('未选择任何可操作的实例!');
-            return false;
-        }
-
-        return uuids_and_boot_jobs_id;
-    }
-
-    function batch_delete() {
-        var uuids_and_boot_jobs_id = get_checked_uuids_and_boot_jobs_id();
-        if (uuids_and_boot_jobs_id['uuids'] && uuids_and_boot_jobs_id['boot_jobs_id']) {
-            for (var i=0; i<uuids_and_boot_jobs_id['uuids'].length; i++) {
-                if (i === uuids_and_boot_jobs_id['uuids'].length  - 1) {
-                    remove(uuids_and_boot_jobs_id['uuids'][i], uuids_and_boot_jobs_id['boot_jobs_id'][i], true);
-                } else {
-                    remove(uuids_and_boot_jobs_id['uuids'][i], uuids_and_boot_jobs_id['boot_jobs_id'][i], false);
-                }
-            }
-        }
-        $('#batch_delete_modal').modal('hide');
-    }
-</script>
-<div class="panel">
-    <div class="panel-body">
-        <h3 class="title-hero" style="font-size: 24px;">
-            虚拟机启动作业
-        </h3>
-        <div>
-            <div id="datatable-row-highlight_wrapper" class="dataTables_wrapper form-inline">
-                <div class="row" style="padding: 10px 10px 10px 0; width: 100%;">
-                    <div class="col-sm-12" style="padding-right: 0;">
-                        <div class="pull-right">
-                            <button class="btn btn-default" onclick="refresh()" style="border-radius: 0;"><span class="glyph-icon icon-elusive-arrows-cw"></span></button>
-                        </div>
-                    </div>
-                </div>
-                <table id="guests_boot_jobs_list" class="table table-bordered table-hover" cellspacing="0" width="100%" role="grid"
-                       style="width: 100%; margin-bottom: 0; border-bottom-width: 0;">
-                <thead>
-                <tr role="row">
-                    <th style="display: none;">UUID</th>
-                    <th style="display: none;">启动作业 ID</th>
-                    <th><input class="all_selector" title="选取所有" type="checkbox"></th>
-                    <th width="180px;">有效时间</th>
-                    <th width="180px;">启动作业</th>
-                    <th width="180px;">名称</th>
-                    <th></th>
-                    <th>状态</th>
-                    <th>IP</th>
-                    <th>操作</th>
-                </tr>
-                </thead>
-                <tbody>
-                {% for uuid, boot_jobs in guests_boot_jobs_ret.data.iteritems() %}
-                    {% for boot_job_id in boot_jobs.boot_jobs %}
-                    <tr role="row" class="odd">
-                        <td style="display: none;">{{ uuid }}</td>
-                        <td style="display: none;">{{ boot_job_id }}</td>
-                        <td><input title="选中" type="checkbox"></td>
-                        <td>
-                            <span style="color: #b94a48; {% if boot_jobs.ttl // 60 == 0 %}display: none;{% endif %}">{{ boot_jobs.ttl // 60 }}分</span>
-                            <span style="color: #b94a48; {% if boot_jobs.ttl % 60 == 0 %}display: none;{% endif %}">{{ boot_jobs.ttl % 60 }}秒</span>
-                        </td>
-                        <td>
-                            <div>
-                                <a href="/operate_rules?boot_job_id={{ boot_job_id }}">
-                                    <p style="display: inline-block;">{{ boot_jobs_mapping_by_id[boot_job_id | int].name }}</p>
-                                </a>
-                            </div>
-                        </td>
-                        <td>
-                            <div>
-                                <a href="/guest/detail/{{ uuid }}">
-                                    <p style="display: inline-block;">
-                                        {{ guests_mapping_by_uuid[uuid].label }}
-                                    </p>
-                                </a>
-                                <div>
-                                    <p style="display: inline-block;">{{ guests_mapping_by_uuid[uuid].remark }}</p>
-                                </div>
-                            </div>
-                        </td>
-                        <td><span class="{{ os_templates_mapping_by_id[guests_mapping_by_uuid[uuid].os_template_id].icon }}"></span></td>
-                        <td>{{ format_guest_status(guests_mapping_by_uuid[uuid].status, guests_mapping_by_uuid[uuid].progress)|safe }}</td>
-                        <td>{{ guests_mapping_by_uuid[uuid].ip }}</td>
-                        <td>
-                            <div class="dropdown inline-block">
-                                <a href="javascript:;" class="dropdown-toggle" data-toggle="dropdown">
-                                    更多
-                                </a>
-                                <ul class="dropdown-menu">
-                                    <li>
-                                        <a href="javascript:;" data-toggle="modal" data-target="#delete_modal"
-                                            onclick="$('#instance_uuid').val($(this).parent().parent().parent().parent().parent().children()[0].textContent);
-                                                $('#instance_boot_job_id').val($(this).parent().parent().parent().parent().parent().children()[1].textContent);
-                                                $('#delete_instance_desc').text($($(this).parent().parent().parent().parent().parent().children()[5]).find('div a')[0].text);
-                                                $('#delete_instance_desc').append('/' + $($(this).parent().parent().parent().parent().parent().children()[4]).find('div a')[0].text)">
-                                            删除
-                                        </a>
-                                    </li>
-                                </ul>
-                            </div>
-                        </td>
-                    </tr>
-                    {% endfor %}
-                {% endfor %}
-                </tbody>
-                </table>
-
-                <table class="table table-bordered" style="border-top-width: 0; z-index: 99; position: sticky; bottom: 0;">
-                    <tfoot>
-                    <tr style="height: 70px;">
-                        <th><input type="checkbox" title="选取所有" class="all_selector"></th>
-                        <th>
-                            <div class="row">
-                                <div class="col-sm-6">
-                                    <button class="btn btn-default btn-shortcut disabled" data-toggle="modal" data-target="#batch_delete_modal">删除</button>
-                                </div>
-                                <div class="col-sm-3" style="font-size: 12px; padding-top: 5px; text-align: right;">
-                                    共有{{ paging_total }}个,每页显示:
-                                    <select id="page_size" name="datatable-row-highlight_length" title="page_size" class="form-control" style="height: 22px; vertical-align: baseline;">
-                                        <option value="10" {% if page_size == 10 %} selected {% endif %}>10</option>
-                                        <option value="20" {% if page_size == 20 %} selected {% endif %}>20</option>
-                                        <option value="50" {% if page_size == 50  %} selected {% endif %}>50</option>
-                                    </select>&nbsp;&nbsp;个
-                                </div>
-                                <div class="col-sm-3" style="text-align: left;">
-                                    <div class="dataTables_paginate paging_bootstrap" id="datatable-row-highlight_paginate">
-                                        <ul id="pagination" class="pagination">
-                                            <li class="{% if page == 1 %} disabled {% endif %}">
-                                                <a href="{{ resource_path }}?page={{ page - 1 }}&page_size={{ page_size }}{% if keyword %}&keyword={{ keyword }}{% endif %}">«</a>
-                                            </li>
-                                            {% for item in pages %}
-                                                <li class="{% if item == page %} active {% endif %}">
-                                                    <a href="{{ resource_path }}?page={{ item }}&page_size={{ page_size }}{% if keyword %}&keyword={{ keyword }}{% endif %}">{{ item }}</a>
-                                                </li>
-                                            {% endfor %}
-                                            <li class="{% if page == last_page %} disabled {% endif %}">
-                                                <a href="{{ resource_path }}?page={{ page + 1 }}&page_size={{ page_size }}{% if keyword %}&keyword={{ keyword }}{% endif %}">»</a>
-                                            </li>
-                                        </ul>
-                                    </div>
-                                </div>
-                            </div>
-                        </th>
-                    </tr>
-                    </tfoot>
-                </table>
-            </div>
-        </div>
-    </div>
-</div>
-
-<input id="instance_uuid" title="实例 UUID" class="form-control" name="uuid" hidden>
-<input id="instance_boot_job_id" title="实例启动作业 ID" class="form-control" name="boot_job_id" hidden>
-
-<div class="modal" id="delete_modal" tabindex="-1" role="dialog" style="margin-top: 100px;">
-    <div class="modal-dialog">
-        <div class="modal-content">
-            <div class="modal-header">
-                <h4 class="modal-title">删除启动作业:</h4>
-            </div>
-            <div class="modal-body">
-                <p>你确定要删除该启动作业吗?</p>
-                <h3 style="color: orangered;" id="delete_instance_desc"></h3>
-            </div>
-            <div class="modal-footer">
-                <button type="button" class="btn btn-sm btn-primary" onclick="delete_at();">确定</button>
-                <button type="button" class="btn btn-sm btn-default" data-dismiss="modal">取消</button>
-            </div>
-        </div>
-    </div>
-</div>
-
-<div class="modal" id="batch_delete_modal" tabindex="-1" role="dialog" style="margin-top: 100px;">
-    <div class="modal-dialog">
-        <div class="modal-content">
-            <div class="modal-header">
-                <h4 class="modal-title">批量删除启动作业:</h4>
-            </div>
-            <div class="modal-body">
-                <p>您确定要执行批量删除选择的启动作业吗?</p>
-            </div>
-            <div class="modal-footer">
-                <button type="button" class="btn btn-sm btn-primary" onclick="batch_delete();">确定</button>
-                <button type="button" class="btn btn-sm btn-default" data-dismiss="modal">取消</button>
-            </div>
-        </div>
-    </div>
-</div>
-{% endblock content %}

+ 7 - 95
templates/guests_show.html

@@ -170,10 +170,6 @@
             $('#reset_password_instance_uuid').val(
             $('#reset_password_instance_uuid').val(
                 $(me.relatedTarget).parent().parent().parent().parent().parent().children()[0].textContent);
                 $(me.relatedTarget).parent().parent().parent().parent().parent().children()[0].textContent);
         });
         });
-
-        $('#add_boot_job_modal').on('show.bs.modal', function (me) {
-            refresh_boot_job_selectpicker($('#boot_job_selector'));
-        });
     });
     });
 
 
     function refresh() {
     function refresh() {
@@ -187,26 +183,6 @@
         window.location.href=cur_url;
         window.location.href=cur_url;
     }
     }
 
 
-    function refresh_boot_job_selectpicker(selectpicker) {
-        $.ajax({
-            url : '/api/boot_jobs?filter=use_for:eq:2',
-            type : 'GET',
-            contentType: "application/json; charset=utf-8",
-            dataType: 'json',
-            error : function() {
-            },
-            success : function(data, textStatus, xhr) {
-                selectpicker.empty();
-                $.each(data.data, function(k, v) {
-                    selectpicker.append(
-                        $('<option>', {value: v['id'], text: v['name'], 'data-subtext': v['remark']})
-                    );
-                });
-                selectpicker.selectpicker('refresh');
-            }
-        });
-    }
-
     function row_onmouseover(me) {
     function row_onmouseover(me) {
         $(me).find(".edit_remark_trigger").css('display','inline-flex');
         $(me).find(".edit_remark_trigger").css('display','inline-flex');
     }
     }
@@ -417,22 +393,6 @@
         });
         });
     }
     }
 
 
-    function add_boot_job(uuids, boot_job_id) {
-        $.ajax({
-            url : '/api/guests/_boot_jobs/' + uuids.join(',') + '/' + boot_job_id,
-            type : 'PUT',
-            contentType: "application/json; charset=utf-8",
-            error : function() {
-                alter_danger('启动作业添加指令发送失败!');
-            },
-            success : function() {
-                alter_success('启动作业添加指令发送成功!');
-                window.location.href='/guests/boot_jobs_list';
-                // refresh();
-            }
-        });
-    }
-
     function boot_at(me) {
     function boot_at(me) {
         var uuid = $('#instance_uuid').val();
         var uuid = $('#instance_uuid').val();
         boot([uuid]);
         boot([uuid]);
@@ -594,15 +554,6 @@
         $('#batch_delete_modal').modal('hide');
         $('#batch_delete_modal').modal('hide');
     }
     }
 
 
-    function batch_add_boot_job() {
-        var uuids = get_checked_uuids();
-        var boot_job_id = $('#boot_job_selector').val();
-        if (uuids) {
-            add_boot_job(uuids, boot_job_id);
-        }
-        $('#add_boot_job_modal').modal('hide');
-    }
-
     var show_real_password = false;
     var show_real_password = false;
     function change_display_password(me) {
     function change_display_password(me) {
         if (show_real_password) {
         if (show_real_password) {
@@ -669,7 +620,13 @@
                             </a>
                             </a>
                         </div>
                         </div>
                     </td>
                     </td>
-                    <td><span class="{{ os_templates_mapping_by_id[item.os_template_id].icon }}" title="{{ os_templates_mapping_by_id[item.os_template_id].label }}"></span></td>
+                    <td>
+                        {% if os_templates_image_mapping_by_id[item.os_template_image_id].logo == "" %}
+                            <span class="{{ os_templates_profile_mapping_by_id[os_templates_image_mapping_by_id[item.os_template_image_id].os_template_profile_id].icon }}" title="{{ os_templates_image_mapping_by_id[item.os_template_image_id].label }}"></span>
+                        {% else %}
+                            <span class="{{ os_templates_image_mapping_by_id[item.os_template_image_id].logo }}" title="{{ os_templates_image_mapping_by_id[item.os_template_image_id].label }}"></span>
+                        {% endif %}
+                    </td>
                     <td>{{ format_guest_status(item.status, item.progress)|safe }}</td>
                     <td>{{ format_guest_status(item.status, item.progress)|safe }}</td>
                     <td>{{ hosts_mapping_by_node_id[item.node_id].hostname }}</td>
                     <td>{{ hosts_mapping_by_node_id[item.node_id].hostname }}</td>
                     <td>CPU :&nbsp;&nbsp;{{ item.cpu }}&nbsp;核<br />内存 :&nbsp;&nbsp;{{ item.memory }}&nbsp;GB</td>
                     <td>CPU :&nbsp;&nbsp;{{ item.cpu }}&nbsp;核<br />内存 :&nbsp;&nbsp;{{ item.memory }}&nbsp;GB</td>
@@ -681,7 +638,6 @@
                             <a href="javascript:;" class="dropdown-toggle" data-toggle="dropdown">
                             <a href="javascript:;" class="dropdown-toggle" data-toggle="dropdown">
                                 更多
                                 更多
                             </a>
                             </a>
-                            <div class="small-badge bg-red" style="display: {% if guests_boot_jobs_ret.data[item.uuid].boot_jobs|length < 1 %} none {% else %} inline-flex{% endif %};"></div>
                             <ul class="dropdown-menu">
                             <ul class="dropdown-menu">
                                 <li class="{% if item.status not in [4, 5, 6] %} disabled {% endif %}">
                                 <li class="{% if item.status not in [4, 5, 6] %} disabled {% endif %}">
                                     <a href="javascript:;" data-toggle="modal" data-target="#boot_modal"
                                     <a href="javascript:;" data-toggle="modal" data-target="#boot_modal"
@@ -744,13 +700,6 @@
                                     <a href="/guest/vnc/{{ item.uuid }}" target="_blank">远程连接</a>
                                     <a href="/guest/vnc/{{ item.uuid }}" target="_blank">远程连接</a>
                                 </li>
                                 </li>
                                 <li class="divider"></li>
                                 <li class="divider"></li>
-                                <li class="">
-                                    <a href="/guest/boot_jobs/{{ item.uuid }}" target="_blank">
-                                        启动作业&nbsp;&nbsp;
-                                        <span class="bs-badge badge-info" style="display: {% if guests_boot_jobs_ret.data[item.uuid].boot_jobs|length < 1 %} none {% endif %};">{{ guests_boot_jobs_ret.data[item.uuid].boot_jobs|length }}</span>
-                                    </a>
-                                </li>
-                                <li class="divider"></li>
                                 <li class="">
                                 <li class="">
                                     <a href="javascript:;" data-toggle="modal" data-target="#reset_password_modal"
                                     <a href="javascript:;" data-toggle="modal" data-target="#reset_password_modal"
                                        onclick="$('#reset_password_type').val('single')">
                                        onclick="$('#reset_password_type').val('single')">
@@ -813,12 +762,6 @@
                                                 </a>
                                                 </a>
                                             </li>
                                             </li>
                                             <li class="divider"></li>
                                             <li class="divider"></li>
-                                            <li>
-                                                <a href="javascript:;" data-toggle="modal" data-target="#add_boot_job_modal">
-                                                    启动作业
-                                                </a>
-                                            </li>
-                                            <li class="divider"></li>
                                             <li>
                                             <li>
                                                 <a href="javascript:;" data-toggle="modal" data-target="#batch_force_shutdown_modal">强制停止</a>
                                                 <a href="javascript:;" data-toggle="modal" data-target="#batch_force_shutdown_modal">强制停止</a>
                                             </li>
                                             </li>
@@ -922,37 +865,6 @@
     </div>
     </div>
 </div>
 </div>
 
 
-<div class="modal" id="add_boot_job_modal" tabindex="-1" role="dialog" style="margin-top: 100px;">
-    <div class="modal-dialog modal-lg">
-        <div class="modal-content">
-            <div class="modal-header">
-                <h4 class="modal-title">添加启动作业:</h4>
-            </div>
-            <div class="modal-body" style="padding-top: 0; padding-bottom: 0;">
-                <div class="example-box-wrapper">
-                    <form class="form-horizontal bordered-row">
-                        <div class="form-group">
-                            <div class="col-sm-2"></div>
-                            <label class="col-sm-2 control-label"><span class="glyph-icon icon-list-alt"></span>&nbsp;&nbsp;启动作业</label>
-                            <div class="col-sm-6">
-                                <select id="boot_job_selector" name="boot_job_selector" title="启动作业" class="selectpicker">
-                                </select>
-                            </div>
-                        </div>
-                        <div class="form-group">
-                            <div class="col-sm-4"></div>
-                            <div class="col-sm-6 pull-right">
-                                <button class="btn btn-blue-alt" style="width: 180px; height: 40px; font-size: 16px;" onclick="batch_add_boot_job();">添加</button>
-                                <button class="btn btn-default" style="width: 64px; height: 40px; font-size: 16px;" data-dismiss="modal">取消</button>
-                            </div>
-                        </div>
-                    </form>
-                </div>
-            </div>
-        </div>
-    </div>
-</div>
-
 <input id="instance_uuid" title="实例 UUID" class="form-control" name="uuid" hidden>
 <input id="instance_uuid" title="实例 UUID" class="form-control" name="uuid" hidden>
 
 
 <div class="modal" id="delete_modal" tabindex="-1" role="dialog" style="margin-top: 100px;">
 <div class="modal" id="delete_modal" tabindex="-1" role="dialog" style="margin-top: 100px;">

+ 2 - 26
templates/layout.html

@@ -338,16 +338,10 @@
                             </a>
                             </a>
                         </li>
                         </li>
                         <li>
                         <li>
-                            <a href="#" title="虚拟机">
+                            <a href="{{ url_for('v_guests.show') }}" title="虚拟机实例">
                                 <i class="glyph-icon icon-linecons-cloud"></i>
                                 <i class="glyph-icon icon-linecons-cloud"></i>
-                                <span>虚拟机</span>
+                                <span>虚拟机实例</span>
                             </a>
                             </a>
-                            <div class="sidebar-submenu">
-                                <ul>
-                                    <li><a href="{{ url_for('v_guests.show') }}" title="虚拟机实例列表"><span>实例</span></a></li>
-                                    <li><a href="{{ url_for('v_guests.show_guests_boot_jobs') }}" title="虚拟机启动作业列表"><span>启动作业</span></a></li>
-                                </ul>
-                            </div><!-- .sidebar-submenu -->
                         </li>
                         </li>
                         <li>
                         <li>
                             <a href="{{ url_for('v_disks.show') }}" title="磁盘实例列表">
                             <a href="{{ url_for('v_disks.show') }}" title="磁盘实例列表">
@@ -373,24 +367,6 @@
                                 <span>虚拟机模板镜像</span>
                                 <span>虚拟机模板镜像</span>
                             </a>
                             </a>
                         </li>
                         </li>
-                        <li>
-                            <a href="{{ url_for('v_os_templates.show') }}" title="虚拟机模板列表">
-                                <i class="glyph-icon icon-linecons-inbox"></i>
-                                <span>虚拟机模板</span>
-                            </a>
-                        </li>
-                        <li>
-                            <a href="#" title="虚拟机启动作业">
-                                <i class="glyph-icon icon-linecons-paper-plane"></i>
-                                <span>启动作业</span>
-                            </a>
-                            <div class="sidebar-submenu">
-                                <ul>
-                                    <li><a href="{{ url_for('v_boot_jobs.show') }}" title="启动作业列表"><span>启动作业</span></a></li>
-                                    <li><a href="{{ url_for('v_operate_rules.show') }}" title="启动作业操作细则"><span>启动作业操作细则</span></a></li>
-                                </ul>
-                            </div><!-- .sidebar-submenu -->
-                        </li>
                         <li>
                         <li>
                             <a href="{{ url_for('v_config.show') }}" title="JimV 虚拟化平台系统配置">
                             <a href="{{ url_for('v_config.show') }}" title="JimV 虚拟化平台系统配置">
                                 <i class="glyph-icon icon-linecons-cog"></i>
                                 <i class="glyph-icon icon-linecons-cog"></i>

+ 0 - 733
templates/operate_rules_show.html

@@ -1,733 +0,0 @@
-{% extends "layout.html" %}
-{% block head %}
-    {{ super() }}
-    <style type="text/css">
-
-        @media (min-width: 768px) {
-            .form-horizontal .control-label {
-                text-align: left;
-            }
-        }
-
-        label>span {
-            color: deepskyblue;
-        }
-
-        .table {
-            font-size: 12px;
-            border-width: 1px;
-            line-height: 20px;
-        }
-        .table > thead > tr > th,
-        .table > tfoot > tr > th {
-            color: #999999;
-            font-weight: normal;
-            border-bottom: 0 solid #e1e6eb;
-            background-color: #F5F6FA;
-        }
-        
-        .table > tbody > tr > td {
-            color: #424547;
-        }
-
-        .table-bordered > tbody > tr {
-            padding-top: 10px;
-            padding-bottom: 10px;
-        }
-
-        .table-bordered > thead > tr > th,
-        .table-bordered > tbody > tr > th,
-        .table-bordered > tfoot > tr > th,
-        .table-bordered > thead > tr > td,
-        .table-bordered > tbody > tr > td,
-        .table-bordered > tfoot > tr > td {
-            border-style: solid;
-            border-width: 1px 0 0 0;
-        }
-
-        .btn,
-        .form-control,
-        .modal-content {
-            border-radius: 0 !important;
-        }
-
-        .path_or_command {
-            white-space: nowrap;
-            overflow: hidden;
-            background-color: #e5eef4;
-            text-overflow: ellipsis;
-            padding-left: 5px;
-            padding-right: 5px;
-        }
-
-        .path_or_command:hover {
-            white-space: inherit;
-            overflow: visible;
-        }
-    </style>
-
-{% endblock head %}
-{% block content %}
-
-<script type="text/javascript">
-    var page = 1;
-    var page_size = 10;
-    var keyword = '';
-    var resource_path = window.location.pathname;
-    var cur_url = resource_path;
-
-    $(document).ready(function() {
-        page_size = $('#page_size').val();
-        cur_url = resource_path + '?page=' + page + '&page_size=' + page_size;
-
-        var last_ready = null;
-        $('#content_search').keydown(function() {
-            if (last_ready !== null) {
-                clearTimeout(last_ready);
-            }
-            last_ready = setTimeout(function () {
-                keyword = $('#content_search').val();
-                cur_url = resource_path + '?page=' + page + '&page_size=' + page_size;
-                if (keyword.length > 0) {
-                    cur_url = resource_path + '?page=' + page + '&page_size=' + page_size + '&keyword=' + keyword;
-                }
-                window.location.href=cur_url;
-            }, 1000);
-        });
-
-        $('#page_size').change(function () {
-            keyword = $('#content_search').val();
-            page_size = $('#page_size').val();
-            cur_url = resource_path + '?page=' + page + '&page_size=' + page_size;
-            if (keyword.length > 0) {
-                cur_url = resource_path + '?page=' + page + '&page_size=' + page_size + '&keyword=' + keyword;
-            }
-            window.location.href=cur_url;
-        });
-
-        $('#edit_path_modal').on('show.bs.modal', function (me) {
-            $(me.relatedTarget).css('display','none');
-            $('#operate_rule_id').val($(me.relatedTarget).parent().parent().prev().prev().prev().prev().text());
-            $('#edit_path').val($(me.relatedTarget).parent()[0].innerText);
-        });
-
-        $('#edit_content_modal').on('show.bs.modal', function (me) {
-            // 下行 display 设为 none 的目的为,第三行取框内文本时,避免了末尾多出来的换行符。
-            $(me.relatedTarget).css('display','none');
-            $('#operate_rule_id').val($(me.relatedTarget).parent().parent().prev().prev().prev().prev().text());
-            $('#edit_content').val($(me.relatedTarget).parent()[0].innerText);
-        });
-
-        $('#edit_command_modal').on('show.bs.modal', function (me) {
-            $(me.relatedTarget).css('display','none');
-            $('#operate_rule_id').val($(me.relatedTarget).parent().parent().prev().prev().prev().prev().text());
-            $('#edit_command').val($(me.relatedTarget).parent()[0].innerText);
-        });
-
-        $('#add_operate_rule_modal').on('show.bs.modal', function (me) {
-            refresh_operate_rule_boot_job_selectpicker($('#boot_job_id'));
-        });
-
-        $('#update_kind_modal').on('show.bs.modal', function (me) {
-            $('#operate_rule_id').val($(me.relatedTarget).parent().prev().prev().text());
-            $('#update_kind_instance_desc').text($(me.relatedTarget).parent().prev()[0].innerText);
-            $('#update_kind_instance_desc_sub').empty();
-            $('#update_kind_instance_desc_sub').append($(me.relatedTarget).parent().next().next().find('div').prop('outerHTML'));
-        });
-
-        $('#update_sequence_modal').on('show.bs.modal', function (me) {
-            $('#operate_rule_id').val($(me.relatedTarget).parent().prev().prev().prev().text());
-            $('#update_sequence').val($(me.relatedTarget)[0].innerText);
-            $('#update_sequence_instance_desc').text($(me.relatedTarget).parent().prev().prev()[0].innerText);
-            $('#update_sequence_instance_desc_sub').empty();
-            $('#update_sequence_instance_desc_sub').append($(me.relatedTarget).parent().next().find('div').prop('outerHTML'));
-        });
-
-        $('#kind').on('changed.bs.select', function (me) {
-            $('#payload_panel').empty();
-            if ($('#kind').val() == '0') {
-                $('#payload_panel').append('\
-                    <div class="form-group">\
-                        <div class="col-sm-2"></div>\
-                        <label class="col-sm-2 control-label"><span class="glyph-icon icon-terminal"></span>&nbsp;&nbsp;命令</label>\
-                        <div class="col-sm-6">\
-                            <input id="command" title="命令" class="form-control" name="command">\
-                        </div>\
-                    </div>'
-                );
-            } else {
-                $('#payload_panel').append('\
-                    <div class="form-group">\
-                        <div class="col-sm-2"></div>\
-                        <label class="col-sm-2 control-label"><span class="glyph-icon icon-elusive-stumbleupon"></span>&nbsp;&nbsp;文件路径</label>\
-                        <div class="col-sm-6">\
-                            <input id="path" title="操作细则文件路径" class="form-control" name="path">\
-                        </div>\
-                    </div>'
-                );
-                $('#payload_panel').append('\
-                    <div class="form-group">\
-                        <div class="col-sm-2"></div>\
-                        <label class="col-sm-2 control-label"><span class="glyph-icon icon-file-text-o"></span>&nbsp;&nbsp;文件内容</label>\
-                        <div class="col-sm-6">\
-                            <textarea id="content" title="操作细则文件内容" class="form-control" rows="6" name="content"></textarea>\
-                        </div>\
-                    </div>'
-                );
-            }
-        });
-
-        $('#add_operate_rule_form').formValidation({
-            framework: 'bootstrap4',
-            icon: {
-                valid: 'fa fa-check',
-                invalid: 'fa fa-times',
-                validating: 'fa fa-refresh'
-            },
-            // Since the Bootstrap Button hides the radio and checkbox
-            // We exclude the disabled elements only
-            excluded: ':disabled',
-            locale: 'zh_CN',
-            fields: {
-                boot_job_id: {
-                    validators: {
-                        notEmpty: {
-                        }
-                    }
-                },
-                kind: {
-                    validators: {
-                        notEmpty: {
-                        }
-                    }
-                },
-                sequence: {
-                    validators: {
-                        between: {
-                            min: 1,
-                            max: 20
-                        }
-                    }
-                }
-            }
-        })
-        .on('success.field.fv', function(e, data) {
-            if (data.fv.getInvalidFields().length > 0) {    // There is invalid field
-                data.fv.disableSubmitButtons(true);
-            }
-        });
-    });
-
-    function refresh() {
-        keyword = $('#content_search').val();
-        page = $('#pagination li.active a').text();
-        page_size = $('#page_size').val();
-        cur_url = resource_path + '?page=' + page + '&page_size=' + page_size;
-        if (keyword.length > 0) {
-            cur_url = resource_path + '?page=' + page + '&page_size=' + page_size + '&keyword=' + keyword;
-        }
-        window.location.href=cur_url;
-    }
-
-    function panel_onmouseover(me) {
-        $(me).find(".edit_trigger").css('display','inline-flex');
-    }
-
-    function panel_onmouseout(me) {
-        $(me).find(".edit_trigger").css('display','none');
-    }
-
-    $(function() { "use strict";
-        $("#update_sequence, #sequence").TouchSpin({
-            max: 20,
-            min: 1,
-            verticalbuttons: true,
-            verticalupclass: 'glyph-icon icon-plus',
-            verticaldownclass: 'glyph-icon icon-minus'
-        });
-    });
-
-    function refresh_operate_rule_boot_job_selectpicker(selectpicker) {
-        $.ajax({
-            url : '/api/boot_jobs?filter=use_for:notin:1',
-            type : 'GET',
-            contentType: "application/json; charset=utf-8",
-            dataType: 'json',
-            error : function() {
-            },
-            success : function(data, textStatus, xhr) {
-                selectpicker.empty();
-                $.each(data.data, function(k, v) {
-                    selectpicker.append(
-                        $('<option>', {value: v['id'], text: v['name'], 'data-subtext': v['remark']})
-                    );
-                });
-                selectpicker.selectpicker('refresh');
-            }
-        });
-    }
-
-    function path_update(me) {
-        var operate_rule_id = $('#operate_rule_id').val();
-        var path = $('#edit_path').val();
-        $('#edit_path_modal').modal('hide');
-        $.ajax({
-            url : '/api/operate_rule/' + operate_rule_id,
-            type : 'PATCH',
-            contentType: "application/json; charset=utf-8",
-            data : JSON.stringify({
-                path: path
-            }),
-            error : function() {
-                alter_danger('操作细则文件路径更新失败!');
-            },
-            success : function() {
-                alter_success('操作细则文件路径更新成功!');
-                refresh()
-            }
-        });
-    }
-
-    function content_update(me) {
-        var operate_rule_id = $('#operate_rule_id').val();
-        var content = $('#edit_content').val();
-        $('#edit_content_modal').modal('hide');
-        $.ajax({
-            url : '/api/operate_rule/' + operate_rule_id,
-            type : 'PATCH',
-            contentType: "application/json; charset=utf-8",
-            data : JSON.stringify({
-                content: content
-            }),
-            error : function() {
-                alter_danger('操作细则文件内容更新失败!');
-            },
-            success : function() {
-                alter_success('操作细则文件内容更新成功!');
-                refresh()
-            }
-        });
-    }
-
-    function command_update(me) {
-        var operate_rule_id = $('#operate_rule_id').val();
-        var command = $('#edit_command').val();
-        $('#edit_command_modal').modal('hide');
-        $.ajax({
-            url : '/api/operate_rule/' + operate_rule_id,
-            type : 'PATCH',
-            contentType: "application/json; charset=utf-8",
-            data : JSON.stringify({
-                command: command
-            }),
-            error : function() {
-                alter_danger('操作细则命令更新失败!');
-            },
-            success : function() {
-                alter_success('操作细则命令更新成功!');
-                refresh()
-            }
-        });
-    }
-
-    function update_kind(id) {
-        $.ajax({
-            url : '/api/operate_rule/' + id,
-            type : 'PATCH',
-            contentType: "application/json; charset=utf-8",
-            data : JSON.stringify({
-                kind: parseInt($('#update_kind').val())
-            }),
-            error : function() {
-                alter_danger('变更操作细则类型指令发送失败!');
-            },
-            success : function() {
-                alter_success('变更操作细则类型指令发送成功!');
-                refresh();
-            }
-        });
-    }
-
-    function update_sequence(id) {
-        $.ajax({
-            url : '/api/operate_rule/' + id,
-            type : 'PATCH',
-            contentType: "application/json; charset=utf-8",
-            data : JSON.stringify({
-                sequence: parseInt($('#update_sequence').val())
-            }),
-            error : function() {
-                alter_danger('变更操作细则执行序列指令发送失败!');
-            },
-            success : function() {
-                alter_success('变更操作细则执行序列指令发送成功!');
-                refresh();
-            }
-        });
-    }
-
-    function remove(id) {
-        $.ajax({
-            url : '/api/operate_rules/' + id,
-            type : 'DELETE',
-            contentType: "application/json; charset=utf-8",
-            error : function() {
-                alter_danger('操作细则删除指令发送失败!');
-            },
-            success : function() {
-                alter_success('操作细则删除指令发送成功!');
-                refresh();
-            }
-        });
-    }
-
-    function delete_at(me) {
-        var id = $('#operate_rule_id').val();
-        remove(id);
-        $('#delete_modal').modal('hide');
-    }
-
-    function update_kind_at(me) {
-        var id = $('#operate_rule_id').val();
-        update_kind(id);
-        $('#update_kind_modal').modal('hide');
-    }
-
-    function update_sequence_at(me) {
-        var id = $('#operate_rule_id').val();
-        update_sequence(id);
-        $('#update_sequence_modal').modal('hide');
-    }
-</script>
-<div class="panel">
-    <div class="panel-body">
-        <h3 class="title-hero" style="font-size: 24px;">
-            启动作业操作细则
-        </h3>
-        <div>
-            <div id="datatable-row-highlight_wrapper" class="dataTables_wrapper form-inline">
-                <div class="row" style="padding: 10px 10px 10px 0; width: 100%;">
-                    <div class="col-sm-12" style="padding-right: 0;">
-                        <div id="datatable-row-highlight_filter" class="dataTables_filter" style="display: inline-block;">
-                            <input id="content_search" type="search" class="form-control" placeholder="模糊搜索..." value="{%- if keyword -%} {{ keyword }} {%- endif -%}" style="margin-left: 0; border-radius: 0;">
-                        </div>
-                        <div class="pull-right">
-                            <button class="btn btn-default" onclick="refresh()" style="border-radius: 0;"><span class="glyph-icon icon-elusive-arrows-cw"></span></button>
-                            <a class="btn btn-info" href="javascript:;" data-toggle="modal" data-target="#add_operate_rule_modal" style="border-radius: 0; padding-left: 40px; padding-right: 40px;">添加操作细则</a>
-                        </div>
-                    </div>
-                </div>
-                <table id="operate_rule_list" class="table table-bordered table-hover" cellspacing="0" width="100%" role="grid"
-                       style="width: 100%; margin-bottom: 0; border-bottom-width: 0;">
-                <thead>
-                <tr role="row">
-                    <th style="display: none;">ID</th>
-                    <th>启动作业</th>
-                    <th width="80px;">类型</th>
-                    <th>执行序列</th>
-                    <th width="600px;">[路径/内容 | 命令]</th>
-                    <th>操作</th>
-                </tr>
-                </thead>
-                <tbody>
-                {% for item in operate_rules_ret.data %}
-                <tr role="row" class="odd">
-                    <td style="display: none;">{{ item.id }}</td>
-                    <td>
-                        <a href="/boot_jobs?boot_job_id={{ item.boot_job_id }}">
-                            {{ boot_jobs_mapping_by_id[item.boot_job_id].name }}
-                        </a>
-                    </td>
-                    <td>
-                        <a href="javascript:;" data-toggle="modal" data-target="#update_kind_modal">
-                            {% if item.kind == 0 %}
-                                <span style="color: #8800FF;">命令</span>
-                            {% elif item.kind == 1 %}
-                                <span style="color: #3333FF;">覆写文件</span>
-                            {% elif item.kind == 2 %}
-                                <span style="color: #00BB00;">追加内容</span>
-                            {% else %}
-                                <span style="color: #990000;">未知</span>
-                            {% endif %}
-                        </a>
-                    </td>
-                    <td>
-                        <a href="javascript:;" data-toggle="modal" data-target="#update_sequence_modal">
-                            {{ item.sequence }}
-                        </a>
-                    </td>
-                    <td onmouseover="panel_onmouseover(this);" onmouseout="panel_onmouseout(this);">
-                        {% if item.kind in [1, 2]%}
-                            <div class="path_or_command">{{ item.path }}<a href="javascript:;" class="edit_trigger" data-toggle="modal" data-target="#edit_path_modal" style="display: none; float: right;">
-                                    <span class="glyph-icon icon-elusive-pencil" style="width: 20px; height: 20px; margin-left: 10px; border-radius: 0; border: 1px solid rgb(220, 233, 255); background-color: #ffffff;"></span>
-                                </a>
-                            </div>
-                            <pre style="border-radius: 0; padding-right: 5px;">{{ item.content }}<a href="javascript:;" class="edit_trigger" data-toggle="modal" data-target="#edit_content_modal" style="display: none; float: right;">
-                                <span class="glyph-icon icon-elusive-pencil" style="width: 20px; height: 18px; margin-left: 10px; border-radius: 0; border: 1px solid rgb(220, 233, 255); background-color: #ffffff;"></span>
-                            </a></pre>
-                        {% elif item.kind == 0 %}
-                            <div class="path_or_command" style="background-color: #f9f2f4">{{ item.command }}<a href="javascript:;" class="edit_trigger" data-toggle="modal" data-target="#edit_command_modal" style="display: none; float: right;">
-                                    <span class="glyph-icon icon-elusive-pencil" style="width: 20px; height: 20px; margin-left: 10px; border-radius: 0; border: 1px solid rgb(220, 233, 255); background-color: #ffffff;"></span>
-                                </a>
-                            </div>
-                        {% endif %}
-                    </td>
-                    <td>
-                        <div class="dropdown inline-block">
-                            <a href="javascript:;" class="dropdown-toggle" data-toggle="dropdown">
-                                更多
-                            </a>
-                            <ul class="dropdown-menu">
-                                <li>
-                                    <a href="javascript:;" data-toggle="modal" data-target="#delete_modal"
-                                        onclick="$('#operate_rule_id').val($(this).parent().parent().parent().parent().parent().children()[0].textContent);
-                                        $('#delete_instance_desc_sub').empty();
-                                        $('#delete_instance_desc_sub').append($(this).parent().parent().parent().parent().prev().find('div').prop('outerHTML'));
-                                        $('#delete_instance_desc').text($(this).parent().parent().parent().parent().parent().children()[1].textContent)">
-                                        删除
-                                    </a>
-                                </li>
-                            </ul>
-                        </div>
-                    </td>
-                </tr>
-                {% endfor %}
-                </tbody>
-                </table>
-
-                <table class="table table-bordered" style="border-top-width: 0; z-index: 99; position: sticky; bottom: 0;">
-                    <tfoot>
-                    <tr style="height: 70px;">
-                        <th>
-                            <div class="row">
-                                <div class="col-sm-6">
-                                </div>
-                                <div class="col-sm-3" style="font-size: 12px; padding-top: 5px; text-align: right;">
-                                    共有{{ operate_rules_ret.paging.total }}条,每页显示:
-                                    <select id="page_size" name="datatable-row-highlight_length" title="page_size" class="form-control" style="height: 22px; vertical-align: baseline;">
-                                        <option value="10" {% if page_size == 10 %} selected {% endif %}>10</option>
-                                        <option value="20" {% if page_size == 20 %} selected {% endif %}>20</option>
-                                        <option value="50" {% if page_size == 50  %} selected {% endif %}>50</option>
-                                    </select>&nbsp;&nbsp;条
-                                </div>
-                                <div class="col-sm-3" style="text-align: left;">
-                                    <div class="dataTables_paginate paging_bootstrap" id="datatable-row-highlight_paginate">
-                                        <ul id="pagination" class="pagination">
-                                            <li class="{% if page == 1 %} disabled {% endif %}">
-                                                <a href="{{ resource_path }}?page={{ page - 1 }}&page_size={{ page_size }}{% if keyword %}&keyword={{ keyword }}{% endif %}{% if order_by %}&order_by={{ order_by }}{% endif %}{% if order %}&order={{ order }}{% endif %}">«</a>
-                                            </li>
-                                            {% for item in pages %}
-                                            <li class="{% if item == page %} active {% endif %}">
-                                                <a href="{{ resource_path }}?page={{ item }}&page_size={{ page_size }}{% if keyword %}&keyword={{ keyword }}{% endif %}{% if order_by %}&order_by={{ order_by }}{% endif %}{% if order %}&order={{ order }}{% endif %}">{{ item }}</a>
-                                            </li>
-                                            {% endfor %}
-                                            <li class="{% if page == last_page %} disabled {% endif %}">
-                                                <a href="{{ resource_path }}?page={{ page + 1 }}&page_size={{ page_size }}{% if keyword %}&keyword={{ keyword }}{% endif %}{% if order_by %}&order_by={{ order_by }}{% endif %}{% if order %}&order={{ order }}{% endif %}">»</a>
-                                            </li>
-                                        </ul>
-                                    </div>
-                                </div>
-                            </div>
-                        </th>
-                    </tr>
-                    </tfoot>
-                </table>
-            </div>
-        </div>
-    </div>
-</div>
-
-<input id="operate_rule_id" title="操作细则 ID" class="form-control" name="operate_rule_id" hidden>
-
-<div class="modal" id="edit_path_modal" tabindex="-1" role="dialog" style="margin-top: 100px;">
-    <div class="modal-dialog">
-        <div class="modal-content">
-            <div class="modal-header">
-                <h4 class="modal-title">编辑操作细则文件路径:</h4>
-            </div>
-            <div class="modal-body">
-                <input id="edit_path" title="操作细则文件路径" class="form-control" name="operate_rule_path">
-            </div>
-            <div class="modal-footer">
-                <button type="button" class="btn btn-sm btn-primary" onclick="path_update();">确定</button>
-                <button type="button" class="btn btn-sm btn-default" data-dismiss="modal">取消</button>
-            </div>
-        </div>
-    </div>
-</div>
-
-<div class="modal" id="edit_content_modal" tabindex="-1" role="dialog" style="margin-top: 100px;">
-    <div class="modal-dialog">
-        <div class="modal-content">
-            <div class="modal-header">
-                <h4 class="modal-title">编辑操作细则文件内容:</h4>
-            </div>
-            <div class="modal-body">
-                <textarea id="edit_content" title="操作细则文件内容" class="form-control" rows="6"
-                          name="operate_rule_content"></textarea>
-            </div>
-            <div class="modal-footer">
-                <button type="button" class="btn btn-sm btn-primary" onclick="content_update();">确定</button>
-                <button type="button" class="btn btn-sm btn-default" data-dismiss="modal">取消</button>
-            </div>
-        </div>
-    </div>
-</div>
-
-<div class="modal" id="edit_command_modal" tabindex="-1" role="dialog" style="margin-top: 100px;">
-    <div class="modal-dialog">
-        <div class="modal-content">
-            <div class="modal-header">
-                <h4 class="modal-title">编辑操作细则命令:</h4>
-            </div>
-            <div class="modal-body">
-                <input id="edit_command" title="操作细则命令" class="form-control" name="operate_rule_command">
-            </div>
-            <div class="modal-footer">
-                <button type="button" class="btn btn-sm btn-primary" onclick="command_update();">确定</button>
-                <button type="button" class="btn btn-sm btn-default" data-dismiss="modal">取消</button>
-            </div>
-        </div>
-    </div>
-</div>
-
-<div class="modal" id="delete_modal" tabindex="-1" role="dialog" style="margin-top: 100px;">
-    <div class="modal-dialog">
-        <div class="modal-content">
-            <div class="modal-header">
-                <h4 class="modal-title">删除操作细则:</h4>
-            </div>
-            <div class="modal-body">
-                <p>你确定要删除该操作细则吗?</p>
-                <h3 style="color: orangered;" id="delete_instance_desc"></h3>
-                <h6 id="delete_instance_desc_sub"></h6>
-            </div>
-            <div class="modal-footer">
-                <button type="button" class="btn btn-sm btn-primary" onclick="delete_at();">确定</button>
-                <button type="button" class="btn btn-sm btn-default" data-dismiss="modal">取消</button>
-            </div>
-        </div>
-    </div>
-</div>
-
-<div class="modal" id="add_operate_rule_modal" tabindex="-1" role="dialog" style="margin-top: 100px;">
-    <div class="modal-dialog modal-lg">
-        <div class="modal-content">
-            <div class="modal-header">
-                <h4 class="modal-title">添加操作细则:</h4>
-            </div>
-            <div class="modal-body" style="padding-top: 0; padding-bottom: 0;">
-                <div class="example-box-wrapper">
-                    <form id="add_operate_rule_form" class="form-horizontal bordered-row" action="/operate_rule" method="post">
-                        <div class="form-group">
-                            <div class="col-sm-2"></div>
-                            <label class="col-sm-2 control-label"><span class="glyph-icon icon-elusive-compass-circled"></span>&nbsp;&nbsp;启动作业</label>
-                            <div class="col-sm-6">
-                                <select id="boot_job_id" name="boot_job_id" title="启动作业" class="selectpicker">
-                                </select>
-                            </div>
-                        </div>
-                        <div class="form-group">
-                            <div class="col-sm-2"></div>
-                            <label class="col-sm-2 control-label"><span class="glyph-icon icon-th-list"></span>&nbsp;&nbsp;类型</label>
-                            <div class="col-sm-6">
-                                <select id="kind" name="kind" title="请选择" class="selectpicker">
-                                    <option value="0" data-subtext="系统启动前,通过 guestfish 所执行的命令">命令</option>
-                                    <option value="1" data-subtext="系统启动前,通过 guestfish 替换目标文件中的内容">覆写文件</option>
-                                    <option value="2" data-subtext="系统启动前,通过 guestfish 向目标文件追加内容">追加内容</option>
-                                </select>
-                            </div>
-                        </div>
-                        <div class="form-group">
-                            <div class="col-sm-2"></div>
-                            <label class="col-sm-2 control-label"><span class="glyph-icon icon-sort-numeric-asc"></span>&nbsp;&nbsp;执行序列</label>
-                            <div class="col-sm-6">
-                                <input id="sequence" title="执行序列" class="form-control" type="text" value="1" name="sequence">
-                            </div>
-                        </div>
-                        <div id="payload_panel" class="form-group">
-                        </div>
-                        <div class="form-group">
-                            <div class="col-sm-4"></div>
-                            <div class="col-sm-6 pull-right">
-                                <button type="submit" class="btn btn-blue-alt" style="width: 180px; height: 40px; font-size: 16px;" disabled>创建</button>
-                                <button class="btn btn-default" style="width: 64px; height: 40px; font-size: 16px;" data-dismiss="modal">取消</button>
-                            </div>
-                        </div>
-                    </form>
-                </div>
-            </div>
-        </div>
-    </div>
-</div>
-
-<div class="modal" id="update_kind_modal" tabindex="-1" role="dialog" style="margin-top: 100px;">
-    <div class="modal-dialog">
-        <div class="modal-content">
-            <div class="modal-header">
-                <h4 class="modal-title">变更操作类型:</h4>
-            </div>
-            <div class="modal-body" style="padding-top: 0;">
-                <form class="form-horizontal bordered-row">
-                    <div class="form-group">
-                        <div class="col-sm-1"></div>
-                        <label class="col-sm-3 control-label"><span class="glyph-icon icon-elusive-compass-circled"></span>&nbsp;&nbsp;标识</label>
-                        <div class="col-sm-8">
-                            <h3 style="color: orangered;" id="update_kind_instance_desc"></h3>
-                            <h6 id="update_kind_instance_desc_sub"></h6>
-                        </div>
-                    </div>
-                    <div class="form-group">
-                        <div class="col-sm-1"></div>
-                        <label class="col-sm-3 control-label"><span class="glyph-icon icon-th-list"></span>&nbsp;&nbsp;操作细则类型</label>
-                        <div class="col-sm-8">
-                            <select id="update_kind" name="use_for" title="操作类型" class="selectpicker">
-                                <option value="0" data-subtext="系统启动前,通过 guestfish 所执行的命令" selected>命令</option>
-                                <option value="1" data-subtext="系统启动前,通过 guestfish 替换目标文件中的内容">覆写文件</option>
-                                <option value="2" data-subtext="系统启动前,通过 guestfish 向目标文件追加内容">追加内容</option>
-                            </select>
-                        </div>
-                    </div>
-                </form>
-            </div>
-            <div class="modal-footer">
-                <button type="button" class="btn btn-sm btn-primary" onclick="update_kind_at();">确定</button>
-                <button type="button" class="btn btn-sm btn-default" data-dismiss="modal">取消</button>
-            </div>
-        </div>
-    </div>
-</div>
-
-<div class="modal" id="update_sequence_modal" tabindex="-1" role="dialog" style="margin-top: 100px;">
-    <div class="modal-dialog">
-        <div class="modal-content">
-            <div class="modal-header">
-                <h4 class="modal-title">变更操作细则执行序列:</h4>
-            </div>
-            <div class="modal-body" style="padding-top: 0;">
-                <form class="form-horizontal bordered-row">
-                    <div class="form-group">
-                        <div class="col-sm-1"></div>
-                        <label class="col-sm-3 control-label"><span class="glyph-icon icon-elusive-compass-circled"></span>&nbsp;&nbsp;标识</label>
-                        <div class="col-sm-8">
-                            <h3 style="color: orangered;" id="update_sequence_instance_desc"></h3>
-                            <h6 id="update_sequence_instance_desc_sub"></h6>
-                        </div>
-                    </div>
-                    <div class="form-group">
-                        <div class="col-sm-1"></div>
-                        <label class="col-sm-3 control-label"><span class="glyph-icon icon-sort-numeric-asc"></span>&nbsp;&nbsp;执行序列</label>
-                        <div class="col-sm-8">
-                            <input id="update_sequence" title="执行序列" class="form-control" type="text" value="1" name="update_sequence">
-                        </div>
-                    </div>
-                </form>
-            </div>
-            <div class="modal-footer">
-                <button type="button" class="btn btn-sm btn-primary" onclick="update_sequence_at();">确定</button>
-                <button type="button" class="btn btn-sm btn-default" data-dismiss="modal">取消</button>
-            </div>
-        </div>
-    </div>
-</div>
-{% endblock content %}

+ 0 - 880
templates/os_templates_show.html

@@ -1,880 +0,0 @@
-{% extends "layout.html" %}
-{% block head %}
-    {{ super() }}
-    <style type="text/css">
-
-        @media (min-width: 768px) {
-            .form-horizontal .control-label {
-                text-align: left;
-            }
-        }
-
-        label>span {
-            color: deepskyblue;
-        }
-
-        .table {
-            font-size: 12px;
-            border-width: 1px;
-            line-height: 20px;
-        }
-        .table > thead > tr > th,
-        .table > tfoot > tr > th {
-            color: #999999;
-            font-weight: normal;
-            border-bottom: 0 solid #e1e6eb;
-            background-color: #F5F6FA;
-        }
-        
-        .table > tbody > tr > td {
-            color: #424547;
-        }
-
-        .table-bordered > tbody > tr {
-            padding-top: 10px;
-            padding-bottom: 10px;
-        }
-
-        .table-bordered > thead > tr > th,
-        .table-bordered > tbody > tr > th,
-        .table-bordered > tfoot > tr > th,
-        .table-bordered > thead > tr > td,
-        .table-bordered > tbody > tr > td,
-        .table-bordered > tfoot > tr > td {
-            border-style: solid;
-            border-width: 1px 0 0 0;
-        }
-
-        .btn,
-        .form-control,
-        .modal-content {
-            border-radius: 0 !important;
-        }
-
-        .btn-shortcut {
-            font-size: 12px !important;
-            padding: 0 26px;
-        }
-
-        .show {
-            display: inline-block !important;
-        }
-
-        .tr-selected td,
-        .tr-selected {
-            color: #000 !important;
-            background: #fafaff !important;
-        }
-    </style>
-
-{% endblock head %}
-{% block content %}
-
-<script type="text/javascript">
-    var page = 1;
-    var page_size = 10;
-    var keyword = '';
-    var resource_path = window.location.pathname;
-    var cur_url = resource_path;
-
-    $(document).ready(function() {
-        page_size = $('#page_size').val();
-        cur_url = resource_path + '?page=' + page + '&page_size=' + page_size;
-
-        var last_ready = null;
-        $('#content_search').keydown(function() {
-            if (last_ready !== null) {
-                clearTimeout(last_ready);
-            }
-            last_ready = setTimeout(function () {
-                keyword = $('#content_search').val();
-                cur_url = resource_path + '?page=' + page + '&page_size=' + page_size;
-                if (keyword.length > 0) {
-                    cur_url = resource_path + '?page=' + page + '&page_size=' + page_size + '&keyword=' + keyword;
-                }
-                window.location.href=cur_url;
-            }, 1000);
-        });
-
-        $('#page_size').change(function () {
-            keyword = $('#content_search').val();
-            page_size = $('#page_size').val();
-            cur_url = resource_path + '?page=' + page + '&page_size=' + page_size;
-            if (keyword.length > 0) {
-                cur_url = resource_path + '?page=' + page + '&page_size=' + page_size + '&keyword=' + keyword;
-            }
-            window.location.href=cur_url;
-        });
-
-        $("thead").on('click', ".all_selector", function() {
-            if ($("thead .all_selector").is(':checked')) {
-                $("tbody tr").find('td input[type="checkbox"]:eq(0)').prop('checked', true);
-                $(".all_selector").prop('checked', true);
-            } else {
-                $("tbody tr").find('td input[type="checkbox"]:eq(0)').prop('checked', false);
-                $(".all_selector").prop('checked', false);
-            }
-
-            select_item_action();
-        });
-
-        $("tfoot").on('click', ".all_selector", function() {
-            if ($("tfoot .all_selector").is(':checked')) {
-                $("tbody tr").find('td input[type="checkbox"]:eq(0)').prop('checked', true);
-                $(".all_selector").prop('checked', true);
-            } else {
-                $("tbody tr").find('td input[type="checkbox"]:eq(0)').prop('checked', false);
-                $(".all_selector").prop('checked', false);
-            }
-
-            select_item_action();
-        });
-
-        $("tbody tr").on('click', "input[type='checkbox']", function() {
-            select_item_action();
-        });
-
-        $('#edit_label_modal').on('show.bs.modal', function (me) {
-            $('#os_template_id').val($(me.relatedTarget).parent().parent().prev().prev().text());
-            $('#edit_label').val($(me.relatedTarget).prev().text());
-        });
-
-        $('#edit_path_modal').on('show.bs.modal', function (me) {
-            $('#os_template_id').val($(me.relatedTarget).parent().parent().prev().prev().prev().prev().text());
-            $('#edit_path').val($(me.relatedTarget).prev().text());
-        });
-
-        $('#add_os_template_modal').on('show.bs.modal', function (me) {
-            refresh_os_template_boot_job_selectpicker($('#boot_job_id'));
-        });
-
-        $('#update_boot_job_modal').on('show.bs.modal', function (me) {
-            refresh_os_template_boot_job_selectpicker($('#update_boot_job_id'));
-        });
-
-        $('#update_os_type_modal').on('show.bs.modal', function (me) {
-            $('#os_template_id').val($(me.relatedTarget).parent().prev().prev().prev().prev().prev().text());
-            $('#update_os_type_instance_desc').text($(me.relatedTarget).parent().prev().prev().prev().text());
-        });
-
-        $('#update_icon_modal').on('show.bs.modal', function (me) {
-            $('#os_template_id').val($(me.relatedTarget).parent().prev().prev().prev().prev().prev().prev().text());
-            $('#update_icon_instance_desc').text($(me.relatedTarget).parent().prev().prev().prev().prev().text());
-        });
-
-        $('#add_os_template_form').formValidation({
-            framework: 'bootstrap4',
-            icon: {
-                valid: 'fa fa-check',
-                invalid: 'fa fa-times',
-                validating: 'fa fa-refresh'
-            },
-            // Since the Bootstrap Button hides the radio and checkbox
-            // We exclude the disabled elements only
-            excluded: ':disabled',
-            locale: 'zh_CN',
-            fields: {
-                label: {
-                    validators: {
-                        notEmpty: {},
-                        stringLength: {
-                            min: 2,
-                            max: 255
-                        }
-                    }
-                },
-                icon: {
-                    validators: {
-                        notEmpty: {
-                        }
-                    }
-                },
-                path: {
-                    validators: {
-                        notEmpty: {},
-                        stringLength: {
-                            min: 2,
-                            max: 255
-                        }
-                    }
-                },
-                os_type: {
-                    validators: {
-                        notEmpty: {
-                        }
-                    }
-                },
-                boot_job_id: {
-                    validators: {
-                        notEmpty: {
-                        }
-                    }
-                }
-            }
-        })
-        .on('success.field.fv', function(e, data) {
-            if (data.fv.getInvalidFields().length > 0) {    // There is invalid field
-                data.fv.disableSubmitButtons(true);
-            }
-        })
-    });
-
-    function refresh() {
-        keyword = $('#content_search').val();
-        page = $('#pagination li.active a').text();
-        page_size = $('#page_size').val();
-        cur_url = resource_path + '?page=' + page + '&page_size=' + page_size;
-        if (keyword.length > 0) {
-            cur_url = resource_path + '?page=' + page + '&page_size=' + page_size + '&keyword=' + keyword;
-        }
-        window.location.href=cur_url;
-    }
-
-    function row_onmouseover(me) {
-        $(me).find(".edit_label_trigger, .edit_path_trigger").css('display','inline-flex');
-    }
-
-    function row_onmouseout(me) {
-        $(me).find(".edit_label_trigger, .edit_path_trigger").css('display','none');
-    }
-
-    function refresh_os_template_boot_job_selectpicker(selectpicker) {
-        $.ajax({
-            url : '/api/boot_jobs?filter=use_for:eq:0',
-            type : 'GET',
-            contentType: "application/json; charset=utf-8",
-            dataType: 'json',
-            error : function() {
-            },
-            success : function(data, textStatus, xhr) {
-                selectpicker.empty();
-                $.each(data.data, function(k, v) {
-                    selectpicker.append(
-                        $('<option>', {value: v['id'], text: v['name'], 'data-subtext': v['remark']})
-                    );
-                });
-                selectpicker.selectpicker('refresh');
-            }
-        });
-    }
-
-    function label_update(me) {
-        var os_template_id = $('#os_template_id').val();
-        var label = $('#edit_label').val();
-        $('#edit_label_modal').modal('hide');
-        $.ajax({
-            url : '/api/os_template/' + os_template_id,
-            type : 'PATCH',
-            contentType: "application/json; charset=utf-8",
-            data : JSON.stringify({
-                label: label
-            }),
-            error : function() {
-                alter_danger('模板名称更新失败!');
-            },
-            success : function() {
-                alter_success('模板名称更新成功!');
-                refresh()
-            }
-        });
-    }
-
-    function path_update(me) {
-        var os_template_id = $('#os_template_id').val();
-        var path = $('#edit_path').val();
-        $('#edit_path_modal').modal('hide');
-        $.ajax({
-            url : '/api/os_template/' + os_template_id,
-            type : 'PATCH',
-            contentType: "application/json; charset=utf-8",
-            data : JSON.stringify({
-                path: path
-            }),
-            error : function() {
-                alter_danger('模板路径更新失败!');
-            },
-            success : function() {
-                alter_success('模板路径更新成功!');
-                refresh()
-            }
-        });
-    }
-
-    function get_selected_element(checked) {
-        if (checked === null) {
-            checked = true;
-        }
-
-        if (checked) {
-            return $('tbody :checked');
-        } else {
-
-            return $('tbody input:not(:checked)');
-        }
-    }
-    
-    function highlight_selected_element() {
-        var selected_element = get_selected_element(true);
-        var no_selected_element = get_selected_element(false);
-
-        selected_element.each(function(i, e) {
-            $(e).parent().parent().toggleClass('tr-selected', true);
-        });
-
-        no_selected_element.each(function(i, e) {
-            $(e).parent().parent().toggleClass('tr-selected', false);
-        });
-    }
-    
-    function shortcut_bar_enable() {
-        var selected_element = get_selected_element(true);
-
-        if (selected_element.length > 0) {
-            $('.btn-shortcut').toggleClass('disabled', false);
-        } else {
-            $('.btn-shortcut').toggleClass('disabled', true);
-        }
-    }
-
-    function select_item_action() {
-        highlight_selected_element();
-        shortcut_bar_enable();
-    }
-
-    function enable(id) {
-        $.ajax({
-            url : '/api/os_template/' + id,
-            type : 'PATCH',
-            contentType: "application/json; charset=utf-8",
-            data : JSON.stringify({
-                active: true
-            }),
-            error : function() {
-                alter_danger('启用指令发送失败!');
-            },
-            success : function() {
-                alter_success('启用指令发送成功!');
-                refresh();
-            }
-        });
-    }
-
-    function disable(id) {
-        $.ajax({
-            url : '/api/os_template/' + id,
-            type : 'PATCH',
-            contentType: "application/json; charset=utf-8",
-            data : JSON.stringify({
-                active: false
-            }),
-            error : function() {
-                alter_danger('禁用指令发送失败!');
-            },
-            success : function() {
-                alter_success('禁用指令发送成功!');
-                refresh();
-            }
-        });
-    }
-
-    function remove(id) {
-        $.ajax({
-            url : '/api/os_templates/' + id,
-            type : 'DELETE',
-            contentType: "application/json; charset=utf-8",
-            error : function() {
-                alter_danger('模板删除指令发送失败!');
-            },
-            success : function() {
-                alter_success('模板删除指令发送成功!');
-                refresh();
-            }
-        });
-    }
-
-    function update_boot_job(id) {
-        $.ajax({
-            url : '/api/os_template/' + id,
-            type : 'PATCH',
-            contentType: "application/json; charset=utf-8",
-            data : JSON.stringify({
-                boot_job_id: parseInt($('#update_boot_job_id').val())
-            }),
-            error : function() {
-                alter_danger('变更初始化作业指令发送失败!');
-            },
-            success : function() {
-                alter_success('变更初始化作业指令发送成功!');
-                refresh();
-            }
-        });
-    }
-
-    function update_os_type(id) {
-        $.ajax({
-            url : '/api/os_template/' + id,
-            type : 'PATCH',
-            contentType: "application/json; charset=utf-8",
-            data : JSON.stringify({
-                os_type: parseInt($('#update_os_type').val())
-            }),
-            error : function() {
-                alter_danger('变更操作系统类型指令发送失败!');
-            },
-            success : function() {
-                alter_success('变更操作系统类型指令发送成功!');
-                refresh();
-            }
-        });
-    }
-
-    function update_icon(id) {
-        $.ajax({
-            url : '/api/os_template/' + id,
-            type : 'PATCH',
-            contentType: "application/json; charset=utf-8",
-            data : JSON.stringify({
-                icon: $('#update_icon').val()
-            }),
-            error : function() {
-                alter_danger('变更 ICON 指令发送失败!');
-            },
-            success : function() {
-                alter_success('变更 ICON 指令发送成功!');
-                refresh();
-            }
-        });
-    }
-
-    function enable_at(me) {
-        var id = $(me).parent().parent().parent().parent().parent().children()[0].textContent;
-        enable(id);
-    }
-
-    function disable_at(me) {
-        var id = $(me).parent().parent().parent().parent().parent().children()[0].textContent;
-        disable(id);
-    }
-
-    function delete_at(me) {
-        var id = $('#os_template_id').val();
-        remove(id);
-        $('#delete_modal').modal('hide');
-    }
-
-    function update_boot_job_at(me) {
-        var id = $('#os_template_id').val();
-        update_boot_job(id);
-        $('#update_boot_job_modal').modal('hide');
-    }
-
-    function update_os_type_at(me) {
-        var id = $('#os_template_id').val();
-        update_os_type(id);
-        $('#update_os_type_modal').modal('hide');
-    }
-
-    function update_icon_at(me) {
-        var id = $('#os_template_id').val();
-        update_icon(id);
-        $('#update_icon_modal').modal('hide');
-    }
-</script>
-<div class="panel">
-    <div class="panel-body">
-        <h3 class="title-hero" style="font-size: 24px;">
-            虚拟机模板
-        </h3>
-        <div>
-            <div id="datatable-row-highlight_wrapper" class="dataTables_wrapper form-inline">
-                <div class="row" style="padding: 10px 10px 10px 0; width: 100%;">
-                    <div class="col-sm-12" style="padding-right: 0;">
-                        <div id="datatable-row-highlight_filter" class="dataTables_filter" style="display: inline-block;">
-                            <input id="content_search" type="search" class="form-control" placeholder="模糊搜索..." value="{%- if keyword -%} {{ keyword }} {%- endif -%}" style="margin-left: 0; border-radius: 0;">
-                        </div>
-                        <div class="pull-right">
-                            <button class="btn btn-default" onclick="refresh()" style="border-radius: 0;"><span class="glyph-icon icon-elusive-arrows-cw"></span></button>
-                            <a class="btn btn-info" href="javascript:;" data-toggle="modal" data-target="#add_os_template_modal" style="border-radius: 0; padding-left: 40px; padding-right: 40px;">添加模板</a>
-                        </div>
-                    </div>
-                </div>
-                <table id="os_template_list" class="table table-bordered table-hover" cellspacing="0" width="100%" role="grid"
-                       style="width: 100%; margin-bottom: 0; border-bottom-width: 0;">
-                <thead>
-                <tr role="row">
-                    <th style="display: none;">ID</th>
-                    <th><input class="all_selector" title="选取所有" type="checkbox"></th>
-                    <th width="180px;">名称</th>
-                    <th>状态</th>
-                    <th width="500px;">路径</th>
-                    <th>操作系统类型</th>
-                    <th>ICON</th>
-                    <th>初始化作业</th>
-                    <th>操作</th>
-                </tr>
-                </thead>
-                <tbody>
-                {% for item in os_templates_ret.data %}
-                <tr role="row" class="odd" onmouseover="row_onmouseover(this);" onmouseout="row_onmouseout(this);">
-                    <td style="display: none;">{{ item.id }}</td>
-                    <td><input title="选中" type="checkbox"></td>
-                    <td>
-                        <div>
-                            <p style="display: inline-block;">{{ item.label }}</p>
-                            <a href="javascript:;" class="edit_label_trigger" data-toggle="modal" data-target="#edit_label_modal" style="display: none; float: right;">
-                                <span class="glyph-icon icon-elusive-pencil" style="width: 20px; height: 20px; margin-left: 10px; border-radius: 0; border: 1px solid rgb(220, 233, 255); background-color: #ffffff;"></span>
-                            </a>
-                        </div>
-                    </td>
-                    <td>{% if item.active == 0 %}
-                        <span style="color: #990000;">未启用</span>
-                        {% else %}
-                        <span style="color: #00BB00;">启用</span>
-                        {% endif %}
-                    </td>
-                    <td>
-                        <div>
-                            <p style="display: inline-block;">{{ item.path }}</p>
-                            <a href="javascript:;" class="edit_path_trigger" data-toggle="modal" data-target="#edit_path_modal" style="display: none; float: right;">
-                                <span class="glyph-icon icon-elusive-pencil" style="width: 20px; height: 20px; margin-left: 10px; border-radius: 0; border: 1px solid rgb(220, 233, 255); background-color: #ffffff;"></span>
-                            </a>
-                        </div>
-                    </td>
-                    <td>
-                        <a href="javascript:;" data-toggle="modal" data-target="#update_os_type_modal">
-                            {{ item.os_type }}
-                        </a>
-                    </td>
-                    <td>
-                        <a href="javascript:;" data-toggle="modal" data-target="#update_icon_modal">
-                            <span class="{{ item.icon }}"></span>
-                        </a>
-                    </td>
-                    <td>
-                        <a href="/boot_jobs?boot_job_id={{ item.boot_job_id }}">
-                            {{ boot_jobs_mapping_by_id[item.boot_job_id].name }}
-                        </a>
-                    </td>
-                    <td>
-                        <div class="dropdown inline-block">
-                            <a href="javascript:;" class="dropdown-toggle" data-toggle="dropdown">
-                                更多
-                            </a>
-                            <ul class="dropdown-menu">
-                                <li class="{% if item.active == true %} disabled {% endif %}" style="{% if item.sequence == 0 %} display: none; {% endif %}">
-                                    <a href="javascript:;" onclick="enable_at(this);">
-                                        启用
-                                    </a>
-                                </li>
-                                <li class="{% if item.active != true %} disabled {% endif %}" style="{% if item.sequence == 0 %} display: none; {% endif %}">
-                                    <a href="javascript:;" onclick="disable_at(this);">
-                                        禁用
-                                    </a>
-                                </li>
-                                <li class="divider" style="{% if item.sequence == 0 %} display: none; {% endif %}"></li>
-                                <li>
-                                    <a href="javascript:;" data-toggle="modal" data-target="#update_boot_job_modal"
-                                        onclick="$('#os_template_id').val($(this).parent().parent().parent().parent().parent().children()[0].textContent);
-                                        $('#update_boot_job_instance_desc').text($(this).parent().parent().parent().parent().parent().children()[2].textContent)">
-                                        变更初始化作业
-                                    </a>
-                                </li>
-                                <li class="divider" style="{% if item.sequence == 0 %} display: none; {% endif %}"></li>
-                                <li>
-                                    <a href="javascript:;" data-toggle="modal" data-target="#delete_modal"
-                                       onclick="$('#os_template_id').val($(this).parent().parent().parent().parent().parent().children()[0].textContent);
-                                       $('#delete_instance_desc').text($(this).parent().parent().parent().parent().parent().children()[2].textContent)">
-                                        删除
-                                    </a>
-                                </li>
-                            </ul>
-                        </div>
-                    </td>
-                </tr>
-                {% endfor %}
-                </tbody>
-                </table>
-
-                <table class="table table-bordered" style="border-top-width: 0; z-index: 99; position: sticky; bottom: 0;">
-                    <tfoot>
-                    <tr style="height: 70px;">
-                        <th><input type="checkbox" title="选取所有" class="all_selector"></th>
-                        <th>
-                            <div class="row">
-                                <div class="col-sm-6">
-                                </div>
-                                <div class="col-sm-3" style="font-size: 12px; padding-top: 5px; text-align: right;">
-                                    共有{{ os_templates_ret.paging.total }}条,每页显示:
-                                    <select id="page_size" name="datatable-row-highlight_length" title="page_size" class="form-control" style="height: 22px; vertical-align: baseline;">
-                                        <option value="10" {% if page_size == 10 %} selected {% endif %}>10</option>
-                                        <option value="20" {% if page_size == 20 %} selected {% endif %}>20</option>
-                                        <option value="50" {% if page_size == 50  %} selected {% endif %}>50</option>
-                                    </select>&nbsp;&nbsp;条
-                                </div>
-                                <div class="col-sm-3" style="text-align: left;">
-                                    <div class="dataTables_paginate paging_bootstrap" id="datatable-row-highlight_paginate">
-                                        <ul id="pagination" class="pagination">
-                                            <li class="{% if page == 1 %} disabled {% endif %}">
-                                                <a href="{{ resource_path }}?page={{ page - 1 }}&page_size={{ page_size }}{% if keyword %}&keyword={{ keyword }}{% endif %}{% if order_by %}&order_by={{ order_by }}{% endif %}{% if order %}&order={{ order }}{% endif %}">«</a>
-                                            </li>
-                                            {% for item in pages %}
-                                            <li class="{% if item == page %} active {% endif %}">
-                                                <a href="{{ resource_path }}?page={{ item }}&page_size={{ page_size }}{% if keyword %}&keyword={{ keyword }}{% endif %}{% if order_by %}&order_by={{ order_by }}{% endif %}{% if order %}&order={{ order }}{% endif %}">{{ item }}</a>
-                                            </li>
-                                            {% endfor %}
-                                            <li class="{% if page == last_page %} disabled {% endif %}">
-                                                <a href="{{ resource_path }}?page={{ page + 1 }}&page_size={{ page_size }}{% if keyword %}&keyword={{ keyword }}{% endif %}{% if order_by %}&order_by={{ order_by }}{% endif %}{% if order %}&order={{ order }}{% endif %}">»</a>
-                                            </li>
-                                        </ul>
-                                    </div>
-                                </div>
-                            </div>
-                        </th>
-                    </tr>
-                    </tfoot>
-                </table>
-            </div>
-        </div>
-    </div>
-</div>
-
-<input id="os_template_id" title="模板 ID" class="form-control" name="os_template_id" hidden>
-
-<div class="modal" id="edit_label_modal" tabindex="-1" role="dialog" style="margin-top: 100px;">
-    <div class="modal-dialog modal-sm">
-        <div class="modal-content">
-            <div class="modal-header">
-                <h4 class="modal-title">编辑模板名称:</h4>
-            </div>
-            <div class="modal-body">
-                <input id="edit_label" title="系统模板名称" class="form-control" name="os_template_label">
-            </div>
-            <div class="modal-footer">
-                <button type="button" class="btn btn-sm btn-primary" onclick="label_update();">确定</button>
-                <button type="button" class="btn btn-sm btn-default" data-dismiss="modal">取消</button>
-            </div>
-        </div>
-    </div>
-</div>
-
-<div class="modal" id="edit_path_modal" tabindex="-1" role="dialog" style="margin-top: 100px;">
-    <div class="modal-dialog">
-        <div class="modal-content">
-            <div class="modal-header">
-                <h4 class="modal-title">编辑模板路径:</h4>
-            </div>
-            <div class="modal-body">
-                <input id="edit_path" title="系统模板路径" class="form-control" name="os_template_path">
-            </div>
-            <div class="modal-footer">
-                <button type="button" class="btn btn-sm btn-primary" onclick="path_update();">确定</button>
-                <button type="button" class="btn btn-sm btn-default" data-dismiss="modal">取消</button>
-            </div>
-        </div>
-    </div>
-</div>
-
-<div class="modal" id="delete_modal" tabindex="-1" role="dialog" style="margin-top: 100px;">
-    <div class="modal-dialog">
-        <div class="modal-content">
-            <div class="modal-header">
-                <h4 class="modal-title">删除模板:</h4>
-            </div>
-            <div class="modal-body">
-                <p>你确定要删除该模板吗?</p>
-                <h3 style="color: orangered;" id="delete_instance_desc"></h3>
-            </div>
-            <div class="modal-footer">
-                <button type="button" class="btn btn-sm btn-primary" onclick="delete_at();">确定</button>
-                <button type="button" class="btn btn-sm btn-default" data-dismiss="modal">取消</button>
-            </div>
-        </div>
-    </div>
-</div>
-
-<div class="modal" id="add_os_template_modal" tabindex="-1" role="dialog" style="margin-top: 100px;">
-    <div class="modal-dialog modal-lg">
-        <div class="modal-content">
-            <div class="modal-header">
-                <h4 class="modal-title">添加模板:</h4>
-            </div>
-            <div class="modal-body" style="padding-top: 0; padding-bottom: 0;">
-                <div class="example-box-wrapper">
-                    <form id="add_os_template_form" class="form-horizontal bordered-row" action="/os_template" method="post">
-                        <div class="form-group">
-                            <div class="col-sm-2"></div>
-                            <label class="col-sm-2 control-label"><span class="glyph-icon icon-elusive-compass-circled"></span>&nbsp;&nbsp;模板名称</label>
-                            <div class="col-sm-6">
-                                <input id="label" name="label" type="text" title="模板名称" class="form-control">
-                            </div>
-                        </div>
-                        <div class="form-group">
-                            <div class="col-sm-2"></div>
-                            <label class="col-sm-2 control-label"><span class="glyph-icon icon-bookmark-o"></span>&nbsp;&nbsp;ICON</label>
-                            <div class="col-sm-6">
-                                <select id="icon" name="icon" title="模板 ICON" class="selectpicker">
-                                    <option value="icon-os icon-os-centos" data-icon="icon-os icon-os-centos" selected>CentOS</option>
-                                    <option value="icon-os icon-os-linux" data-icon="icon-os icon-os-linux">Linux</option>
-                                    <option value="icon-os icon-os-ubuntu" data-icon="icon-os icon-os-ubuntu">Ubuntu</option>
-                                    <option value="icon-os icon-os-suse" data-icon="icon-os icon-os-suse">Suse</option>
-                                    <option value="icon-os icon-os-gentoo" data-icon="icon-os icon-os-gentoo">Gentoo</option>
-                                    <option value="icon-os icon-os-debian" data-icon="icon-os icon-os-debian">Debian</option>
-                                    <option value="icon-os icon-os-redhat" data-icon="icon-os icon-os-redhat">Redhat</option>
-                                    <option value="icon-os icon-os-bsd" data-icon="icon-os icon-os-bsd">BSD</option>
-                                    <option value="icon-os icon-os-windows" data-icon="icon-os icon-os-windows">Windows</option>
-                                </select>
-                            </div>
-                        </div>
-                        <div class="form-group">
-                            <div class="col-sm-2"></div>
-                            <label class="col-sm-2 control-label"><span class="glyph-icon icon-elusive-stumbleupon"></span>&nbsp;&nbsp;模板路径</label>
-                            <div class="col-sm-6">
-                                <input id="path" name="path" type="text" title="模板路径" class="form-control">
-                            </div>
-                        </div>
-                        <div class="form-group">
-                            <div class="col-sm-2"></div>
-                            <label class="col-sm-2 control-label"><span class="glyph-icon icon-bookmark-o"></span>&nbsp;&nbsp;模板系统类型</label>
-                            <div class="col-sm-6">
-                                <select id="os_type" name="os_type" title="请选择模板系统类型" class="selectpicker">
-                                    <option value="0">Linux</option>
-                                    <option value="1">Windows</option>
-                                    <option value="2">BSD</option>
-                                    <option value="3">AIX</option>
-                                    <option value="4">HP-UNIX</option>
-                                </select>
-                            </div>
-                        </div>
-                        <div class="form-group">
-                            <div class="col-sm-2"></div>
-                            <label class="col-sm-2 control-label"><span class="glyph-icon icon-file-code-o"></span>&nbsp;&nbsp;初始化作业</label>
-                            <div class="col-sm-6">
-                                <select id="boot_job_id" name="boot_job_id" title="实例的启动作业" class="selectpicker">
-                                </select>
-                            </div>
-                        </div>
-                        <div class="form-group">
-                            <div class="col-sm-4"></div>
-                            <div class="col-sm-6 pull-right">
-                                <button type="submit" class="btn btn-blue-alt" style="width: 180px; height: 40px; font-size: 16px;" disabled>创建</button>
-                                <button class="btn btn-default" style="width: 64px; height: 40px; font-size: 16px;" data-dismiss="modal">取消</button>
-                            </div>
-                        </div>
-                    </form>
-                </div>
-            </div>
-        </div>
-    </div>
-</div>
-
-<div class="modal" id="update_boot_job_modal" tabindex="-1" role="dialog" style="margin-top: 100px;">
-    <div class="modal-dialog">
-        <div class="modal-content">
-            <div class="modal-header">
-                <h4 class="modal-title">变更初始化作业:</h4>
-            </div>
-            <div class="modal-body" style="padding-top: 0;">
-                <form class="form-horizontal bordered-row">
-                    <div class="form-group">
-                        <div class="col-sm-1"></div>
-                        <label class="col-sm-3 control-label"><span class="glyph-icon icon-elusive-compass-circled"></span>&nbsp;&nbsp;模板名称</label>
-                        <div class="col-sm-8">
-                            <h3 style="color: orangered;" id="update_boot_job_instance_desc"></h3>
-                        </div>
-                    </div>
-                    <div class="form-group">
-                        <div class="col-sm-1"></div>
-                        <label class="col-sm-3 control-label"><span class="glyph-icon icon-file-code-o"></span>&nbsp;&nbsp;初始化作业</label>
-                        <div class="col-sm-8">
-                            <select id="update_boot_job_id" name="boot_job_id" title="实例的启动作业" class="selectpicker">
-                            </select>
-                        </div>
-                    </div>
-                </form>
-            </div>
-            <div class="modal-footer">
-                <button type="button" class="btn btn-sm btn-primary" onclick="update_boot_job_at();">确定</button>
-                <button type="button" class="btn btn-sm btn-default" data-dismiss="modal">取消</button>
-            </div>
-        </div>
-    </div>
-</div>
-
-<div class="modal" id="update_os_type_modal" tabindex="-1" role="dialog" style="margin-top: 100px;">
-    <div class="modal-dialog">
-        <div class="modal-content">
-            <div class="modal-header">
-                <h4 class="modal-title">变更操作系统类型:</h4>
-            </div>
-            <div class="modal-body" style="padding-top: 0;">
-                <form class="form-horizontal bordered-row">
-                    <div class="form-group">
-                        <div class="col-sm-1"></div>
-                        <label class="col-sm-3 control-label"><span class="glyph-icon icon-elusive-compass-circled"></span>&nbsp;&nbsp;操作系统类型</label>
-                        <div class="col-sm-8">
-                            <h3 style="color: orangered;" id="update_os_type_instance_desc"></h3>
-                        </div>
-                    </div>
-                    <div class="form-group">
-                        <div class="col-sm-1"></div>
-                        <div class="col-sm-8">
-                            <select id="update_os_type" name="os_type" title="操作系统类型" class="selectpicker">
-                                <option value="0" selected>Linux</option>
-                                <option value="1">Windows</option>
-                                <option value="2">BSD</option>
-                                <option value="3">AIX</option>
-                                <option value="4">HP-UNIX</option>
-                            </select>
-                        </div>
-                    </div>
-                </form>
-            </div>
-            <div class="modal-footer">
-                <button type="button" class="btn btn-sm btn-primary" onclick="update_os_type_at();">确定</button>
-                <button type="button" class="btn btn-sm btn-default" data-dismiss="modal">取消</button>
-            </div>
-        </div>
-    </div>
-</div>
-
-<div class="modal" id="update_icon_modal" tabindex="-1" role="dialog" style="margin-top: 100px;">
-    <div class="modal-dialog">
-        <div class="modal-content">
-            <div class="modal-header">
-                <h4 class="modal-title">变更 ICON:</h4>
-            </div>
-            <div class="modal-body" style="padding-top: 0;">
-                <form class="form-horizontal bordered-row">
-                    <div class="form-group">
-                        <div class="col-sm-1"></div>
-                        <label class="col-sm-3 control-label"><span class="glyph-icon icon-elusive-compass-circled"></span>&nbsp;&nbsp;模板名称</label>
-                        <div class="col-sm-8">
-                            <h3 style="color: orangered;" id="update_icon_instance_desc"></h3>
-                        </div>
-                    </div>
-                    <div class="form-group">
-                        <div class="col-sm-1"></div>
-                        <div class="col-sm-8">
-                            <select id="update_icon" name="icon" title="模板 ICON" class="selectpicker">
-                                <option value="icon-os icon-os-centos" data-icon="icon-os icon-os-centos" selected>CentOS</option>
-                                <option value="icon-os icon-os-linux" data-icon="icon-os icon-os-linux">Linux</option>
-                                <option value="icon-os icon-os-ubuntu" data-icon="icon-os icon-os-ubuntu">Ubuntu</option>
-                                <option value="icon-os icon-os-suse" data-icon="icon-os icon-os-suse">Suse</option>
-                                <option value="icon-os icon-os-gentoo" data-icon="icon-os icon-os-gentoo">Gentoo</option>
-                                <option value="icon-os icon-os-debian" data-icon="icon-os icon-os-debian">Debian</option>
-                                <option value="icon-os icon-os-redhat" data-icon="icon-os icon-os-redhat">Redhat</option>
-                                <option value="icon-os icon-os-bsd" data-icon="icon-os icon-os-bsd">BSD</option>
-                                <option value="icon-os icon-os-windows" data-icon="icon-os icon-os-windows">Windows</option>
-                            </select>
-                        </div>
-                    </div>
-                </form>
-            </div>
-            <div class="modal-footer">
-                <button type="button" class="btn btn-sm btn-primary" onclick="update_icon_at();">确定</button>
-                <button type="button" class="btn btn-sm btn-default" data-dismiss="modal">取消</button>
-            </div>
-        </div>
-    </div>
-</div>
-{% endblock content %}

+ 1 - 1
tests/test_os_template.py

@@ -16,7 +16,7 @@ __copyright__ = '(c) 2017 by James Iter.'
 class TestOSTemplate(unittest.TestCase):
 class TestOSTemplate(unittest.TestCase):
 
 
     base_url = 'http://127.0.0.1:8008/api'
     base_url = 'http://127.0.0.1:8008/api'
-    os_template_id = 0
+    os_template_image_id = 0
 
 
     def setUp(self):
     def setUp(self):
         pass
         pass

+ 0 - 133
views/boot_job.py

@@ -1,133 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-
-import json
-from flask import Blueprint, render_template, url_for, request, redirect
-import requests
-from math import ceil
-
-from models.status import BootJobUseFor
-
-__author__ = 'James Iter'
-__date__ = '2017/7/15'
-__contact__ = 'james.iter.cn@gmail.com'
-__copyright__ = '(c) 2017 by James Iter.'
-
-
-blueprint = Blueprint(
-    'v_boot_job',
-    __name__,
-    url_prefix='/boot_job'
-)
-
-blueprints = Blueprint(
-    'v_boot_jobs',
-    __name__,
-    url_prefix='/boot_jobs'
-)
-
-
-def show():
-    args = list()
-    page = int(request.args.get('page', 1))
-    page_size = int(request.args.get('page_size', 10))
-    keyword = request.args.get('keyword', None)
-    boot_job_id = request.args.get('boot_job_id', None)
-    order_by = request.args.get('order_by', None)
-    order = request.args.get('order', None)
-    filters = list()
-    resource_path = request.path
-
-    if page is not None:
-        args.append('page=' + page.__str__())
-
-    if page_size is not None:
-        args.append('page_size=' + page_size.__str__())
-
-    if keyword is not None:
-        args.append('keyword=' + keyword.__str__())
-
-    if boot_job_id is not None:
-        filters.append('id:in:' + boot_job_id.__str__())
-
-    if order_by is not None:
-        args.append('order_by=' + order_by)
-
-    if order is not None:
-        args.append('order=' + order)
-
-    if filters.__len__() > 0:
-        args.append('filter=' + ','.join(filters))
-
-    host_url = request.host_url.rstrip('/')
-
-    boot_jobs_url = host_url + url_for('api_boot_jobs.r_get_by_filter')
-    if keyword is not None:
-        boot_jobs_url = host_url + url_for('api_boot_jobs.r_content_search')
-
-    if args.__len__() > 0:
-        boot_jobs_url = boot_jobs_url + '?' + '&'.join(args)
-
-    boot_jobs_ret = requests.get(url=boot_jobs_url, cookies=request.cookies)
-    boot_jobs_ret = json.loads(boot_jobs_ret.content)
-
-    for i, boot_job in enumerate(boot_jobs_ret['data']):
-        # 去除系统级的启动作业。系统级的启动作业不展示给使用者。
-        if boot_job['use_for'] == BootJobUseFor.system.value:
-            del boot_jobs_ret['data'][i]
-
-    last_page = int(ceil(boot_jobs_ret['paging']['total'] / float(page_size)))
-    page_length = 5
-    pages = list()
-    if page < int(ceil(page_length / 2.0)):
-        for i in range(1, page_length + 1):
-            pages.append(i)
-            if i == last_page or last_page == 0:
-                break
-
-    elif last_page - page < page_length / 2:
-        for i in range(last_page - page_length + 1, last_page + 1):
-            if i < 1:
-                continue
-            pages.append(i)
-
-    else:
-        for i in range(page - page_length / 2, page + int(ceil(page_length / 2.0))):
-            pages.append(i)
-            if i == last_page or last_page == 0:
-                break
-
-    return render_template('boot_jobs_show.html', boot_jobs_ret=boot_jobs_ret,
-                           resource_path=resource_path,
-                           page=page, page_size=page_size, keyword=keyword, pages=pages, order_by=order_by, order=order,
-                           last_page=last_page)
-
-
-def create():
-    host_url = request.host_url.rstrip('/')
-
-    if request.method == 'POST':
-        name = request.form.get('name')
-        use_for = request.form.get('use_for')
-        remark = request.form.get('remark')
-
-        payload = {
-            "name": name,
-            "use_for": int(use_for),
-            "remark": remark
-        }
-
-        url = host_url + '/api/boot_job'
-        headers = {'content-type': 'application/json'}
-        r = requests.post(url, data=json.dumps(payload), cookies=request.cookies, headers=headers)
-        j_r = json.loads(r.content)
-        return render_template('success.html', go_back_url='/boot_jobs', timeout=10000, title='提交成功',
-                               message_title='添加启动作业的请求已被接受',
-                               message='您所提交的启动作业已创建。页面将在10秒钟后自动跳转到模板列表页面!')
-
-    else:
-        return redirect(url_for('v_boot_jobs.show'))
-
-
-

+ 7 - 6
views/disk.py

@@ -208,7 +208,7 @@ def detail(uuid):
     disk_ret = json.loads(disk_ret.content)
     disk_ret = json.loads(disk_ret.content)
 
 
     guest_ret = None
     guest_ret = None
-    os_template_ret = None
+    os_template_image_ret = None
 
 
     config_url = host_url + url_for('api_config.r_get')
     config_url = host_url + url_for('api_config.r_get')
     config_ret = requests.get(url=config_url, cookies=request.cookies)
     config_ret = requests.get(url=config_url, cookies=request.cookies)
@@ -220,12 +220,13 @@ def detail(uuid):
         guest_ret = requests.get(url=guest_url, cookies=request.cookies)
         guest_ret = requests.get(url=guest_url, cookies=request.cookies)
         guest_ret = json.loads(guest_ret.content)
         guest_ret = json.loads(guest_ret.content)
 
 
-        os_template_url = host_url + url_for('api_os_templates.r_get', ids=guest_ret['data']['os_template_id'].__str__())
+        os_template_image_url = host_url + url_for('api_os_templates_image.r_get',
+                                                   ids=guest_ret['data']['os_template_image_id'].__str__())
 
 
-        os_template_ret = requests.get(url=os_template_url, cookies=request.cookies)
-        os_template_ret = json.loads(os_template_ret.content)
+        os_template_image_ret = requests.get(url=os_template_image_url, cookies=request.cookies)
+        os_template_image_ret = json.loads(os_template_image_ret.content)
 
 
-    return render_template('disk_detail.html', uuid=uuid, guest_ret=guest_ret, os_template_ret=os_template_ret,
-                           disk_ret=disk_ret, config_ret=config_ret)
+    return render_template('disk_detail.html', uuid=uuid, guest_ret=guest_ret,
+                           os_template_image_ret=os_template_image_ret, disk_ret=disk_ret, config_ret=config_ret)
 
 
 
 

+ 33 - 156
views/guest.py

@@ -56,7 +56,8 @@ def show():
     if keyword is not None:
     if keyword is not None:
         guests_url = host_url + url_for('api_guests.r_content_search')
         guests_url = host_url + url_for('api_guests.r_content_search')
 
 
-    os_templates_url = host_url + url_for('api_os_templates.r_get_by_filter')
+    os_templates_image_url = host_url + url_for('api_os_templates_image.r_get_by_filter')
+    os_templates_profile_url = host_url + url_for('api_os_templates_profile.r_get_by_filter')
 
 
     if args.__len__() > 0:
     if args.__len__() > 0:
         guests_url = guests_url + '?' + '&'.join(args)
         guests_url = guests_url + '?' + '&'.join(args)
@@ -71,30 +72,23 @@ def show():
     guests_ret = requests.get(url=guests_url, cookies=request.cookies)
     guests_ret = requests.get(url=guests_url, cookies=request.cookies)
     guests_ret = json.loads(guests_ret.content)
     guests_ret = json.loads(guests_ret.content)
 
 
-    os_templates_ret = requests.get(url=os_templates_url, cookies=request.cookies)
-    os_templates_ret = json.loads(os_templates_ret.content)
-    os_templates_mapping_by_id = dict()
-    for os_template in os_templates_ret['data']:
-        os_templates_mapping_by_id[os_template['id']] = os_template
+    os_templates_image_ret = requests.get(url=os_templates_image_url, cookies=request.cookies)
+    os_templates_image_ret = json.loads(os_templates_image_ret.content)
+    os_templates_image_mapping_by_id = dict()
+    for os_template_image in os_templates_image_ret['data']:
+        os_templates_image_mapping_by_id[os_template_image['id']] = os_template_image
+
+    os_templates_profile_ret = requests.get(url=os_templates_profile_url, cookies=request.cookies)
+    os_templates_profile_ret = json.loads(os_templates_profile_ret.content)
+    os_templates_profile_mapping_by_id = dict()
+    for os_template_profile in os_templates_profile_ret['data']:
+        os_templates_profile_mapping_by_id[os_template_profile['id']] = os_template_profile
 
 
     guests_uuid = list()
     guests_uuid = list()
 
 
     for guest in guests_ret['data']:
     for guest in guests_ret['data']:
         guests_uuid.append(guest['uuid'])
         guests_uuid.append(guest['uuid'])
 
 
-    guests_boot_jobs_ret = {'data': dict()}
-
-    if guests_uuid.__len__() > 0:
-        # 获取指定 Guest 的启动作业 ID
-        guests_boot_jobs_url = host_url + url_for('api_guests.r_get_boot_jobs', uuids=','.join(guests_uuid))
-        guests_boot_jobs_ret = requests.get(url=guests_boot_jobs_url, cookies=request.cookies)
-
-        guests_boot_jobs_ret = json.loads(guests_boot_jobs_ret.content)
-
-        # 统一单个、多个的返回JSON格式
-        if guests_uuid.__len__() == 1:
-            guests_boot_jobs_ret['data'] = {guests_uuid[0]: guests_boot_jobs_ret['data']}
-
     last_page = int(ceil(guests_ret['paging']['total'] / float(page_size)))
     last_page = int(ceil(guests_ret['paging']['total'] / float(page_size)))
     page_length = 5
     page_length = 5
     pages = list()
     pages = list()
@@ -117,9 +111,9 @@ def show():
                 break
                 break
 
 
     return render_template('guests_show.html', guests_ret=guests_ret, resource_path=resource_path,
     return render_template('guests_show.html', guests_ret=guests_ret, resource_path=resource_path,
-                           os_templates_mapping_by_id=os_templates_mapping_by_id,
-                           hosts_mapping_by_node_id=hosts_mapping_by_node_id,
-                           guests_boot_jobs_ret=guests_boot_jobs_ret, page=page,
+                           os_templates_image_mapping_by_id=os_templates_image_mapping_by_id,
+                           os_templates_profile_mapping_by_id=os_templates_profile_mapping_by_id,
+                           hosts_mapping_by_node_id=hosts_mapping_by_node_id, page=page,
                            page_size=page_size, keyword=keyword, pages=pages, last_page=last_page)
                            page_size=page_size, keyword=keyword, pages=pages, last_page=last_page)
 
 
 
 
@@ -128,7 +122,7 @@ def create():
 
 
     if request.method == 'POST':
     if request.method == 'POST':
         ability = request.form.get('ability')
         ability = request.form.get('ability')
-        os_template_id = request.form.get('os_template_id')
+        os_template_image_id = request.form.get('os_template_image_id')
         quantity = request.form.get('quantity')
         quantity = request.form.get('quantity')
         password = request.form.get('password')
         password = request.form.get('password')
         remark = request.form.get('remark')
         remark = request.form.get('remark')
@@ -148,7 +142,7 @@ def create():
         payload = {
         payload = {
             "cpu": int(cpu),
             "cpu": int(cpu),
             "memory": int(memory),
             "memory": int(memory),
-            "os_template_id": int(os_template_id),
+            "os_template_image_id": int(os_template_image_id),
             "quantity": int(quantity),
             "quantity": int(quantity),
             "remark": remark,
             "remark": remark,
             "password": password,
             "password": password,
@@ -183,16 +177,12 @@ def create():
                                message='您所提交的资源正在创建中。根据所提交资源的大小,需要等待几到十几分钟。页面将在10秒钟后自动跳转到实例列表页面!')
                                message='您所提交的资源正在创建中。根据所提交资源的大小,需要等待几到十几分钟。页面将在10秒钟后自动跳转到实例列表页面!')
 
 
     else:
     else:
-        os_template_url = host_url + url_for('api_os_templates.r_get_by_filter')
         hosts_url = host_url + url_for('api_hosts.r_get_by_filter', alive=True)
         hosts_url = host_url + url_for('api_hosts.r_get_by_filter', alive=True)
 
 
-        os_template_ret = requests.get(url=os_template_url, cookies=request.cookies)
-        os_template_ret = json.loads(os_template_ret.content)
-
         hosts_ret = requests.get(url=hosts_url, cookies=request.cookies)
         hosts_ret = requests.get(url=hosts_url, cookies=request.cookies)
         hosts_ret = json.loads(hosts_ret.content)
         hosts_ret = json.loads(hosts_ret.content)
 
 
-        return render_template('guest_create.html', os_template_ret=os_template_ret, hosts_ret=hosts_ret)
+        return render_template('guest_create.html', hosts_ret=hosts_ret)
 
 
 
 
 def port_is_opened(port):
 def port_is_opened(port):
@@ -251,10 +241,18 @@ def detail(uuid):
     guest_ret = requests.get(url=guest_url, cookies=request.cookies)
     guest_ret = requests.get(url=guest_url, cookies=request.cookies)
     guest_ret = json.loads(guest_ret.content)
     guest_ret = json.loads(guest_ret.content)
 
 
-    os_template_url = host_url + url_for('api_os_templates.r_get', ids=guest_ret['data']['os_template_id'].__str__())
+    os_template_image_url = host_url + url_for('api_os_templates_image.r_get',
+                                               ids=guest_ret['data']['os_template_image_id'].__str__())
+    os_templates_profile_url = host_url + url_for('api_os_templates_profile.r_get_by_filter')
 
 
-    os_template_ret = requests.get(url=os_template_url, cookies=request.cookies)
-    os_template_ret = json.loads(os_template_ret.content)
+    os_template_image_ret = requests.get(url=os_template_image_url, cookies=request.cookies)
+    os_template_image_ret = json.loads(os_template_image_ret.content)
+
+    os_templates_profile_ret = requests.get(url=os_templates_profile_url, cookies=request.cookies)
+    os_templates_profile_ret = json.loads(os_templates_profile_ret.content)
+    os_templates_profile_mapping_by_id = dict()
+    for os_template_profile in os_templates_profile_ret['data']:
+        os_templates_profile_mapping_by_id[os_template_profile['id']] = os_template_profile
 
 
     disks_url = host_url + url_for('api_disks.r_get_by_filter', filter='guest_uuid:in:' + guest_ret['data']['uuid'])
     disks_url = host_url + url_for('api_disks.r_get_by_filter', filter='guest_uuid:in:' + guest_ret['data']['uuid'])
     disks_ret = requests.get(url=disks_url, cookies=request.cookies)
     disks_ret = requests.get(url=disks_url, cookies=request.cookies)
@@ -264,7 +262,9 @@ def detail(uuid):
     config_ret = requests.get(url=url, cookies=request.cookies)
     config_ret = requests.get(url=url, cookies=request.cookies)
     config_ret = json.loads(config_ret.content)
     config_ret = json.loads(config_ret.content)
 
 
-    return render_template('guest_detail.html', uuid=uuid, guest_ret=guest_ret, os_template_ret=os_template_ret,
+    return render_template('guest_detail.html', uuid=uuid, guest_ret=guest_ret,
+                           os_template_image_ret=os_template_image_ret,
+                           os_templates_profile_mapping_by_id=os_templates_profile_mapping_by_id,
                            hosts_mapping_by_node_id=hosts_mapping_by_node_id,
                            hosts_mapping_by_node_id=hosts_mapping_by_node_id,
                            disks_ret=disks_ret, config_ret=config_ret)
                            disks_ret=disks_ret, config_ret=config_ret)
 
 
@@ -275,126 +275,3 @@ def success():
                            message='您所提交的资源正在创建中。根据所提交资源的大小,需要等待几到十几分钟。页面将在10秒钟后自动跳转到实例列表页面!')
                            message='您所提交的资源正在创建中。根据所提交资源的大小,需要等待几到十几分钟。页面将在10秒钟后自动跳转到实例列表页面!')
 
 
 
 
-def show_boot_job(uuid):
-    host_url = request.host_url.rstrip('/')
-
-    guest_url = host_url + url_for('api_guests.r_get', uuids=uuid)
-
-    guest_ret = requests.get(url=guest_url, cookies=request.cookies)
-    guest_ret = json.loads(guest_ret.content)
-
-    guest_boot_jobs_url = host_url + url_for('api_guests.r_get_boot_jobs', uuids=uuid)
-    guest_boot_jobs_ret = requests.get(url=guest_boot_jobs_url, cookies=request.cookies)
-    guest_boot_jobs_ret = json.loads(guest_boot_jobs_ret.content)
-
-    boot_jobs_url = host_url + url_for('api_boot_jobs.r_get_by_filter',
-                                       filter='id:in:' + ','.join(guest_boot_jobs_ret['data']['boot_jobs']))
-
-    boot_jobs_ret = requests.get(url=boot_jobs_url, cookies=request.cookies)
-    boot_jobs_ret = json.loads(boot_jobs_ret.content)
-    boot_jobs_mapping_by_id = dict()
-    for boot_job in boot_jobs_ret['data']:
-        boot_jobs_mapping_by_id[boot_job['id']] = boot_job
-
-    return render_template('guest_boot_jobs.html', uuid=uuid, guest_ret=guest_ret,
-                           guest_boot_jobs_ret=guest_boot_jobs_ret, boot_jobs_mapping_by_id=boot_jobs_mapping_by_id)
-
-
-def show_guests_boot_jobs():
-    page = int(request.args.get('page', 1))
-    page_size = int(request.args.get('page_size', 10))
-
-    host_url = request.host_url.rstrip('/')
-
-    # 获取所有有启动作业的 Guests uuid
-    uuids_of_all_had_boot_job_url = host_url + url_for('api_guests.r_get_uuids_of_all_had_boot_job')
-
-    uuids_of_all_had_boot_job_ret = requests.get(url=uuids_of_all_had_boot_job_url, cookies=request.cookies)
-    uuids_of_all_had_boot_job_ret = json.loads(uuids_of_all_had_boot_job_ret.content)
-    guests_uuid = uuids_of_all_had_boot_job_ret['data']
-
-    guests_boot_jobs_ret = {'data': dict()}
-
-    if guests_uuid.__len__() > 0:
-        # 获取指定 Guest 的启动作业 ID
-        guests_boot_jobs_url = host_url + url_for('api_guests.r_get_boot_jobs',
-                                                  uuids=','.join(guests_uuid[page_size * (page - 1): page_size * page]))
-        guests_boot_jobs_ret = requests.get(url=guests_boot_jobs_url, cookies=request.cookies)
-
-        guests_boot_jobs_ret = json.loads(guests_boot_jobs_ret.content)
-
-        # 统一单个、多个的返回JSON格式
-        if guests_uuid.__len__() == 1:
-            guests_boot_jobs_ret['data'] = {guests_uuid[0]: guests_boot_jobs_ret['data']}
-
-    # 取出 Guests 的启动作业 IDs,并去重
-    guests_boot_jobs_id = list()
-    for uuid, guest_boot_jobs in guests_boot_jobs_ret['data'].items():
-        guests_boot_jobs_id.extend(guest_boot_jobs['boot_jobs'])
-
-    guests_boot_jobs_id = list(set(guests_boot_jobs_id))
-
-    # 获取指定启动作业ID 的启动作业
-    boot_jobs_url = host_url + url_for('api_boot_jobs.r_get_by_filter',
-                                       filter='id:in:' + ','.join(guests_boot_jobs_id))
-
-    boot_jobs_ret = requests.get(url=boot_jobs_url, cookies=request.cookies)
-    boot_jobs_ret = json.loads(boot_jobs_ret.content)
-
-    # 启动作业 ID 与启动作业的映射
-    boot_jobs_mapping_by_id = dict()
-    for boot_job in boot_jobs_ret['data']:
-        boot_jobs_mapping_by_id[boot_job['id']] = boot_job
-
-    guests_url = host_url + url_for('api_guests.r_get_by_filter',
-                                    filter='uuid:in:' + ','.join(guests_uuid[page_size * (page - 1): page_size * page]))
-
-    guests_ret = requests.get(url=guests_url, cookies=request.cookies)
-    guests_ret = json.loads(guests_ret.content)
-
-    # Guest uuid 与 Guest 的映射
-    guests_mapping_by_uuid = dict()
-    for guest in guests_ret['data']:
-        guests_mapping_by_uuid[guest['uuid']] = guest
-
-    os_templates_url = host_url + url_for('api_os_templates.r_get_by_filter')
-    os_templates_ret = requests.get(url=os_templates_url, cookies=request.cookies)
-    os_templates_ret = json.loads(os_templates_ret.content)
-
-    # 模板与模板 ID 的映射
-    os_templates_mapping_by_id = dict()
-    for os_template in os_templates_ret['data']:
-        os_templates_mapping_by_id[os_template['id']] = os_template
-
-    paging_total = guests_uuid.__len__()
-
-    last_page = int(ceil(paging_total / float(page_size)))
-    if last_page == 0:
-        last_page = 1
-
-    page_length = 5
-    pages = list()
-    if page < int(ceil(page_length / 2.0)):
-        for i in range(1, page_length + 1):
-            pages.append(i)
-            if i == last_page:
-                break
-
-    elif last_page - page < page_length / 2:
-        for i in range(last_page - page_length + 1, last_page + 1):
-            if i < 1:
-                continue
-            pages.append(i)
-
-    else:
-        for i in range(page - page_length / 2, page + int(ceil(page_length / 2.0))):
-            pages.append(i)
-            if i == last_page:
-                break
-
-    return render_template('guests_boot_jobs.html', guests_boot_jobs_ret=guests_boot_jobs_ret,
-                           boot_jobs_mapping_by_id=boot_jobs_mapping_by_id,
-                           guests_mapping_by_uuid=guests_mapping_by_uuid,
-                           os_templates_mapping_by_id=os_templates_mapping_by_id, page=page, page_size=page_size,
-                           pages=pages, last_page=last_page, paging_total=paging_total)
-

+ 0 - 152
views/operate_rule.py

@@ -1,152 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-
-import json
-from flask import Blueprint, render_template, url_for, request, redirect
-import requests
-from math import ceil
-
-from models.status import OperateRuleKind, BootJobUseFor
-
-__author__ = 'James Iter'
-__date__ = '2017/7/17'
-__contact__ = 'james.iter.cn@gmail.com'
-__copyright__ = '(c) 2017 by James Iter.'
-
-
-blueprint = Blueprint(
-    'v_operate_rule',
-    __name__,
-    url_prefix='/operate_rule'
-)
-
-blueprints = Blueprint(
-    'v_operate_rules',
-    __name__,
-    url_prefix='/operate_rules'
-)
-
-
-def show():
-    args = list()
-    page = int(request.args.get('page', 1))
-    page_size = int(request.args.get('page_size', 10))
-    keyword = request.args.get('keyword', None)
-    boot_job_id = request.args.get('boot_job_id', None)
-    order_by = request.args.get('order_by', None)
-    order = request.args.get('order', None)
-    filters = list()
-    resource_path = request.path
-
-    if page is not None:
-        args.append('page=' + page.__str__())
-
-    if page_size is not None:
-        args.append('page_size=' + page_size.__str__())
-
-    if keyword is not None:
-        args.append('keyword=' + keyword.__str__())
-
-    if boot_job_id is not None:
-        filters.append('boot_job_id:in:' + boot_job_id.__str__())
-
-    if order_by is not None:
-        args.append('order_by=' + order_by)
-
-    if order is not None:
-        args.append('order=' + order)
-
-    if filters.__len__() > 0:
-        args.append('filter=' + ','.join(filters))
-
-    host_url = request.host_url.rstrip('/')
-
-    operate_rules_url = host_url + url_for('api_operate_rules.r_get_by_filter')
-    if keyword is not None:
-        operate_rules_url = host_url + url_for('api_operate_rules.r_content_search')
-
-    boot_jobs_url = host_url + url_for('api_boot_jobs.r_get_by_filter')
-
-    if args.__len__() > 0:
-        operate_rules_url = operate_rules_url + '?' + '&'.join(args)
-
-    operate_rules_ret = requests.get(url=operate_rules_url, cookies=request.cookies)
-    operate_rules_ret = json.loads(operate_rules_ret.content)
-
-    system_level_ids = list()
-
-    boot_jobs_ret = requests.get(url=boot_jobs_url, cookies=request.cookies)
-    boot_jobs_ret = json.loads(boot_jobs_ret.content)
-    boot_jobs_mapping_by_id = dict()
-    for boot_job in boot_jobs_ret['data']:
-        boot_jobs_mapping_by_id[boot_job['id']] = boot_job
-
-        if boot_job['use_for'] == BootJobUseFor.system.value:
-            system_level_ids.append(boot_job['id'])
-
-    for i, operate_rule in enumerate(operate_rules_ret['data']):
-        # 去除系统级的启动作业。系统级的启动作业不展示给使用者。
-        if operate_rule['boot_job_id'] in system_level_ids:
-            del operate_rules_ret['data'][i]
-
-    last_page = int(ceil(operate_rules_ret['paging']['total'] / float(page_size)))
-    page_length = 5
-    pages = list()
-    if page < int(ceil(page_length / 2.0)):
-        for i in range(1, page_length + 1):
-            pages.append(i)
-            if i == last_page or last_page == 0:
-                break
-
-    elif last_page - page < page_length / 2:
-        for i in range(last_page - page_length + 1, last_page + 1):
-            if i < 1:
-                continue
-            pages.append(i)
-
-    else:
-        for i in range(page - page_length / 2, page + int(ceil(page_length / 2.0))):
-            pages.append(i)
-            if i == last_page or last_page == 0:
-                break
-
-    return render_template('operate_rules_show.html', operate_rules_ret=operate_rules_ret,
-                           boot_jobs_mapping_by_id=boot_jobs_mapping_by_id, resource_path=resource_path,
-                           page=page, page_size=page_size, keyword=keyword, pages=pages, order_by=order_by, order=order,
-                           last_page=last_page)
-
-
-def create():
-    host_url = request.host_url.rstrip('/')
-
-    if request.method == 'POST':
-        boot_job_id = int(request.form.get('boot_job_id'))
-        kind = int(request.form.get('kind'))
-        sequence = int(request.form.get('sequence'))
-
-        payload = {
-            "boot_job_id": boot_job_id,
-            "kind": kind,
-            "sequence": sequence
-        }
-
-        if kind == OperateRuleKind.cmd.value:
-            payload['command'] = request.form.get('command', '')
-
-        else:
-            payload['path'] = request.form.get('path', '')
-            payload['content'] = request.form.get('content', '')
-
-        url = host_url + '/api/operate_rule'
-        headers = {'content-type': 'application/json'}
-        r = requests.post(url, data=json.dumps(payload), headers=headers, cookies=request.cookies)
-        j_r = json.loads(r.content)
-        return render_template('success.html', go_back_url='/operate_rules', timeout=10000, title='提交成功',
-                               message_title='添加启动作业操作细则的请求已被接受',
-                               message='您所提交的启动作业操作细则已创建。页面将在10秒钟后自动跳转到模板列表页面!')
-
-    else:
-        return redirect(url_for('v_operate_rules.show'))
-
-

+ 0 - 144
views/os_template.py

@@ -1,144 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-
-import json
-from flask import Blueprint, render_template, url_for, request, redirect
-import requests
-from math import ceil
-
-
-__author__ = 'James Iter'
-__date__ = '2017/7/11'
-__contact__ = 'james.iter.cn@gmail.com'
-__copyright__ = '(c) 2017 by James Iter.'
-
-
-blueprint = Blueprint(
-    'v_os_template',
-    __name__,
-    url_prefix='/os_template'
-)
-
-blueprints = Blueprint(
-    'v_os_templates',
-    __name__,
-    url_prefix='/os_templates'
-)
-
-
-def show():
-    args = list()
-    page = int(request.args.get('page', 1))
-    page_size = int(request.args.get('page_size', 10))
-    keyword = request.args.get('keyword', None)
-    guest_uuid = request.args.get('guest_uuid', None)
-    sequence = request.args.get('sequence', None)
-    order_by = request.args.get('order_by', None)
-    order = request.args.get('order', None)
-    filters = list()
-    resource_path = request.path
-
-    if page is not None:
-        args.append('page=' + page.__str__())
-
-    if page_size is not None:
-        args.append('page_size=' + page_size.__str__())
-
-    if keyword is not None:
-        args.append('keyword=' + keyword.__str__())
-
-    if guest_uuid is not None:
-        filters.append('guest_uuid:in:' + guest_uuid.__str__())
-
-    if sequence is not None:
-        filters.append('sequence:in:' + sequence.__str__())
-
-    if order_by is not None:
-        args.append('order_by=' + order_by)
-
-    if order is not None:
-        args.append('order=' + order)
-
-    if filters.__len__() > 0:
-        args.append('filter=' + ','.join(filters))
-
-    host_url = request.host_url.rstrip('/')
-
-    os_templates_url = host_url + url_for('api_os_templates.r_get_by_filter')
-    if keyword is not None:
-        os_templates_url = host_url + url_for('api_os_templates.r_content_search')
-
-    boot_job_url = host_url + url_for('api_boot_jobs.r_get_by_filter')
-
-    if args.__len__() > 0:
-        os_templates_url = os_templates_url + '?' + '&'.join(args)
-
-    os_templates_ret = requests.get(url=os_templates_url, cookies=request.cookies)
-    os_templates_ret = json.loads(os_templates_ret.content)
-
-    boot_jobs_ret = requests.get(url=boot_job_url, cookies=request.cookies)
-    boot_jobs_ret = json.loads(boot_jobs_ret.content)
-    boot_jobs_mapping_by_id = dict()
-    for boot_job in boot_jobs_ret['data']:
-        boot_jobs_mapping_by_id[boot_job['id']] = boot_job
-
-    last_page = int(ceil(os_templates_ret['paging']['total'] / float(page_size)))
-    page_length = 5
-    pages = list()
-    if page < int(ceil(page_length / 2.0)):
-        for i in range(1, page_length + 1):
-            pages.append(i)
-            if i == last_page or last_page == 0:
-                break
-
-    elif last_page - page < page_length / 2:
-        for i in range(last_page - page_length + 1, last_page + 1):
-            if i < 1:
-                continue
-            pages.append(i)
-
-    else:
-        for i in range(page - page_length / 2, page + int(ceil(page_length / 2.0))):
-            pages.append(i)
-            if i == last_page or last_page == 0:
-                break
-
-    return render_template('os_templates_show.html', os_templates_ret=os_templates_ret,
-                           boot_jobs_mapping_by_id=boot_jobs_mapping_by_id, resource_path=resource_path,
-                           page=page, page_size=page_size, keyword=keyword, pages=pages, order_by=order_by, order=order,
-                           last_page=last_page)
-
-
-def create():
-    host_url = request.host_url.rstrip('/')
-
-    if request.method == 'POST':
-        label = request.form.get('label')
-        path = request.form.get('path')
-        os_type = request.form.get('os_type')
-        icon = request.form.get('icon')
-        boot_job_id = request.form.get('boot_job_id')
-
-        payload = {
-            "label": label,
-            "path": path,
-            "os_type": int(os_type),
-            "active": True,
-            "icon": icon,
-            "boot_job_id": int(boot_job_id)
-        }
-
-        url = host_url + '/api/os_template'
-        headers = {'content-type': 'application/json'}
-        r = requests.post(url, data=json.dumps(payload), headers=headers, cookies=request.cookies)
-        j_r = json.loads(r.content)
-        return render_template('success.html', go_back_url='/os_templates', timeout=10000, title='提交成功',
-                               message_title='添加模板的请求已被接受',
-                               message='您所提交的模板已创建。页面将在10秒钟后自动跳转到模板列表页面!')
-
-    else:
-        return redirect(url_for('v_os_templates.show'))
-
-
-

+ 0 - 12
views_route_table.py

@@ -11,7 +11,6 @@ from views import dashboard
 from views import config
 from views import config
 from views import misc
 from views import misc
 from views import os_template_image
 from views import os_template_image
-from views import os_template, boot_job, operate_rule
 
 
 
 
 __author__ = 'James Iter'
 __author__ = 'James Iter'
@@ -35,8 +34,6 @@ add_rule_views(guest.blueprints, '/create', views_func='guest.create', methods=[
 add_rule_views(guest.blueprints, '/success', views_func='guest.success', methods=['GET'])
 add_rule_views(guest.blueprints, '/success', views_func='guest.success', methods=['GET'])
 add_rule_views(guest.blueprint, '/vnc/<uuid>', views_func='guest.vnc', methods=['GET'])
 add_rule_views(guest.blueprint, '/vnc/<uuid>', views_func='guest.vnc', methods=['GET'])
 add_rule_views(guest.blueprint, '/detail/<uuid>', views_func='guest.detail', methods=['GET'])
 add_rule_views(guest.blueprint, '/detail/<uuid>', views_func='guest.detail', methods=['GET'])
-add_rule_views(guest.blueprint, '/boot_jobs/<uuid>', views_func='guest.show_boot_job', methods=['GET'])
-add_rule_views(guest.blueprints, '/boot_jobs_list', views_func='guest.show_guests_boot_jobs', methods=['GET'])
 
 
 add_rule_views(disk.blueprints, '', views_func='disk.show', methods=['GET'])
 add_rule_views(disk.blueprints, '', views_func='disk.show', methods=['GET'])
 add_rule_views(disk.blueprints, '/create', views_func='disk.create', methods=['GET', 'POST'])
 add_rule_views(disk.blueprints, '/create', views_func='disk.create', methods=['GET', 'POST'])
@@ -47,15 +44,6 @@ add_rule_views(log.blueprints, '', views_func='log.show', methods=['GET'])
 add_rule_views(os_template_image.blueprints, '', views_func='os_template_image.show', methods=['GET'])
 add_rule_views(os_template_image.blueprints, '', views_func='os_template_image.show', methods=['GET'])
 add_rule_views(os_template_image.blueprint, '', views_func='os_template_image.create', methods=['POST'])
 add_rule_views(os_template_image.blueprint, '', views_func='os_template_image.create', methods=['POST'])
 
 
-add_rule_views(os_template.blueprints, '', views_func='os_template.show', methods=['GET'])
-add_rule_views(os_template.blueprint, '', views_func='os_template.create', methods=['POST'])
-
-add_rule_views(boot_job.blueprints, '', views_func='boot_job.show', methods=['GET'])
-add_rule_views(boot_job.blueprint, '', views_func='boot_job.create', methods=['POST'])
-
-add_rule_views(operate_rule.blueprints, '', views_func='operate_rule.show', methods=['GET'])
-add_rule_views(operate_rule.blueprint, '', views_func='operate_rule.create', methods=['POST'])
-
 add_rule_views(host.blueprints, '', views_func='host.show', methods=['GET'])
 add_rule_views(host.blueprints, '', views_func='host.show', methods=['GET'])
 add_rule_views(host.blueprint, '/detail/<node_id>', views_func='host.detail', methods=['GET'])
 add_rule_views(host.blueprint, '/detail/<node_id>', views_func='host.detail', methods=['GET'])