Explorar el Código

重构操作系统模板管理功能。完成相关数据库的设计、模型、API部分。

James Iter hace 8 años
padre
commit
3c750c853a

+ 150 - 0
api/os_template_image.py

@@ -0,0 +1,150 @@
+#!/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 OSTemplateImage, OSTemplateProfile
+from models import Rules
+from models import Utils
+
+
+__author__ = 'James Iter'
+__date__ = '2018/2/4'
+__contact__ = 'james.iter.cn@gmail.com'
+__copyright__ = '(c) 2018 by James Iter.'
+
+
+blueprint = Blueprint(
+    'api_os_template_image',
+    __name__,
+    url_prefix='/api/os_template_image'
+)
+
+blueprints = Blueprint(
+    'api_os_templates_image',
+    __name__,
+    url_prefix='/api/os_templates_image'
+)
+
+
+os_template_image_base = Base(the_class=OSTemplateImage, the_blueprint=blueprint, the_blueprints=blueprints)
+
+
+@Utils.dumps2response
+def r_create():
+
+    os_template_image = OSTemplateImage()
+
+    args_rules = [
+        Rules.OS_TEMPLATE_PROFILE_ID_EXT.value,
+        Rules.PATH.value,
+        Rules.ACTIVE.value
+    ]
+
+    os_template_image.path = request.json.get('path')
+    os_template_image.active = request.json.get('active')
+    os_template_image.os_template_profile_id = request.json.get('os_template_profile_id')
+
+    try:
+        ji.Check.previewing(args_rules, os_template_image.__dict__)
+
+        ret = dict()
+        ret['state'] = ji.Common.exchange_state(20000)
+
+        if os_template_image.exist_by('path'):
+            ret['state'] = ji.Common.exchange_state(40901)
+            ret['state']['sub']['zh-cn'] = ''.join([ret['state']['sub']['zh-cn'], ': ', os_template_image.path])
+            return ret
+
+        os_template_profile = OSTemplateProfile()
+        os_template_profile.id = os_template_image.os_template_profile_id
+        if not os_template_profile.exist():
+            ret['state'] = ji.Common.exchange_state(40401)
+            ret['state']['sub']['zh-cn'] = ''.join([ret['state']['sub']['zh-cn'], u': 操作系统模板描述文件ID: ',
+                                                    os_template_image.os_template_profile_id.__str__()])
+            return ret
+
+        os_template_image.create()
+        os_template_image.get_by('path')
+        ret['data'] = os_template_image.__dict__
+        return ret
+    except ji.PreviewingError, e:
+        return json.loads(e.message)
+
+
+@Utils.dumps2response
+def r_update(_id):
+
+    os_template_image = OSTemplateImage()
+
+    args_rules = [
+        Rules.ID.value
+    ]
+
+    if 'path' in request.json:
+        args_rules.append(
+            Rules.PATH.value,
+        )
+
+    if 'active' in request.json:
+        args_rules.append(
+            Rules.ACTIVE.value,
+        )
+
+    if 'os_template_profile_id' in request.json:
+        args_rules.append(
+            Rules.OS_TEMPLATE_PROFILE_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_image.id = request.json.get('id')
+
+        os_template_image.get()
+        os_template_image.path = request.json.get('path', os_template_image.path)
+        os_template_image.active = request.json.get('active', os_template_image.active)
+        os_template_image.os_template_profile_id = \
+            request.json.get('os_template_profile_id', os_template_image.os_template_profile_id)
+
+        os_template_image.update()
+        os_template_image.get()
+
+        ret = dict()
+        ret['state'] = ji.Common.exchange_state(20000)
+        ret['data'] = os_template_image.__dict__
+        return ret
+    except ji.PreviewingError, e:
+        return json.loads(e.message)
+
+
+@Utils.dumps2response
+def r_delete(ids):
+    return os_template_image_base.delete(ids=ids, ids_rule=Rules.IDS.value, by_field='id')
+
+
+@Utils.dumps2response
+def r_get(ids):
+    return os_template_image_base.get(ids=ids, ids_rule=Rules.IDS.value, by_field='id')
+
+
+@Utils.dumps2response
+def r_get_by_filter():
+    return os_template_image_base.get_by_filter()
+
+
+@Utils.dumps2response
+def r_content_search():
+    return os_template_image_base.content_search()
+

+ 212 - 0
api/os_template_initialize_operate.py

@@ -0,0 +1,212 @@
+#!/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 import OSTemplateInitializeOperate
+from models import OSTemplateInitializeOperateSet
+from models.status import OSTemplateInitializeOperateKind
+
+
+__author__ = 'James Iter'
+__date__ = '2018/2/4'
+__contact__ = 'james.iter.cn@gmail.com'
+__copyright__ = '(c) 2018 by James Iter.'
+
+
+blueprint = Blueprint(
+    'api_os_template_initialize_operate',
+    __name__,
+    url_prefix='/api/os_template_initialize_operate'
+)
+
+blueprints = Blueprint(
+    'api_os_template_initialize_operates',
+    __name__,
+    url_prefix='/api/os_template_initialize_operates'
+)
+
+
+os_template_initialize_operate_base = \
+    Base(the_class=OSTemplateInitializeOperate, the_blueprint=blueprint, the_blueprints=blueprints)
+
+
+@Utils.dumps2response
+def r_create():
+
+    os_template_initialize_operate_set = OSTemplateInitializeOperateSet()
+    os_template_initialize_operate = OSTemplateInitializeOperate()
+
+    args_rules = [
+        Rules.OS_TEMPLATE_INITIALIZE_OPERATE_SET_ID_EXT.value,
+        Rules.OS_TEMPLATE_INITIALIZE_OPERATE_KIND.value,
+        Rules.OS_TEMPLATE_INITIALIZE_OPERATE_SEQUENCE.value
+    ]
+
+    os_template_initialize_operate.os_template_initialize_operate_set_id = \
+        request.json.get('os_template_initialize_operate_set_id')
+    os_template_initialize_operate.kind = request.json.get('kind')
+    os_template_initialize_operate.path = request.json.get('path', '')
+    os_template_initialize_operate.sequence = request.json.get('sequence', 0)
+    os_template_initialize_operate.content = request.json.get('content', '')
+    os_template_initialize_operate.command = request.json.get('command', '')
+
+    if os_template_initialize_operate.kind == OSTemplateInitializeOperateKind.cmd.value:
+        args_rules.append(
+            Rules.OS_TEMPLATE_INITIALIZE_OPERATE_COMMAND.value
+        )
+
+    else:
+        args_rules.extend([
+            Rules.OS_TEMPLATE_INITIALIZE_OPERATE_PATH.value,
+            Rules.OS_TEMPLATE_INITIALIZE_OPERATE_CONTENT.value
+        ])
+
+    try:
+        ji.Check.previewing(args_rules, os_template_initialize_operate.__dict__)
+
+        ret = dict()
+        ret['state'] = ji.Common.exchange_state(20000)
+
+        os_template_initialize_operate_set.id = os_template_initialize_operate.os_template_initialize_operate_set_id
+        if not os_template_initialize_operate_set.exist():
+            ret['state'] = ji.Common.exchange_state(40401)
+            ret['state']['sub']['zh-cn'] = ''.join([ret['state']['sub']['zh-cn'], u': 操作系统初始化操作集ID: ',
+                                                    os_template_initialize_operate_set.id.__str__()])
+            return ret
+
+        if os_template_initialize_operate.kind == OSTemplateInitializeOperateKind.cmd.value:
+            data, total = os_template_initialize_operate.get_by_filter(
+                filter_str=':'.join(['os_template_initialize_operate_set_id', 'eq',
+                                     os_template_initialize_operate.os_template_initialize_operate_set_id.__str__()]) +
+                           ';' + ':'.join(['command', 'eq', os_template_initialize_operate.command]))
+
+        else:
+            data, total = os_template_initialize_operate.get_by_filter(
+                filter_str=':'.join(['os_template_initialize_operate_set_id', 'eq',
+                                     os_template_initialize_operate.os_template_initialize_operate_set_id.__str__()]) +
+                           ';' + ':'.join(['path', 'eq', os_template_initialize_operate.path]))
+
+        if data.__len__() > 0:
+            ret['state'] = ji.Common.exchange_state(40901)
+
+            if os_template_initialize_operate.kind == OSTemplateInitializeOperateKind.cmd.value:
+                ret['state']['sub']['zh-cn'] = ''.join(
+                    [ret['state']['sub']['zh-cn'], u', 命令: ', os_template_initialize_operate.command,
+                     u', 已存在于操作集ID ',
+                     os_template_initialize_operate.os_template_initialize_operate_set_id.__str__(), u' 中。'])
+
+            else:
+                ret['state']['sub']['zh-cn'] = ''.join([
+                    ret['state']['sub']['zh-cn'], u', 路径: ', os_template_initialize_operate.path,
+                    u', 已存在于操作集ID ',
+                    os_template_initialize_operate.os_template_initialize_operate_set_id.__str__(), u' 中。'])
+            return ret
+
+        os_template_initialize_operate.create()
+        data, total = os_template_initialize_operate.get_by_filter(
+            filter_str=':'.join(['os_template_initialize_operate_set_id', 'eq',
+                                 os_template_initialize_operate.os_template_initialize_operate_set_id.__str__()]) + ';'
+                       + ':'.join(['path', 'eq', os_template_initialize_operate.path]))
+        ret['data'] = data[0]
+        return ret
+
+    except ji.PreviewingError, e:
+        return json.loads(e.message)
+
+
+@Utils.dumps2response
+def r_update(_id):
+
+    os_template_initialize_operate = OSTemplateInitializeOperate()
+
+    args_rules = [
+        Rules.ID.value
+    ]
+
+    if 'os_template_initialize_operate_set_id' in request.json:
+        args_rules.append(
+            Rules.OS_TEMPLATE_INITIALIZE_OPERATE_SET_ID_EXT.value,
+        )
+
+    if 'kind' in request.json:
+        args_rules.append(
+            Rules.OS_TEMPLATE_INITIALIZE_OPERATE_KIND.value,
+        )
+
+    if 'sequence' in request.json:
+        args_rules.append(
+            Rules.OS_TEMPLATE_INITIALIZE_OPERATE_SEQUENCE.value,
+        )
+
+    if 'path' in request.json:
+        args_rules.append(
+            Rules.OS_TEMPLATE_INITIALIZE_OPERATE_PATH.value,
+        )
+
+    if 'content' in request.json:
+        args_rules.append(
+            Rules.OS_TEMPLATE_INITIALIZE_OPERATE_CONTENT.value,
+        )
+
+    if 'command' in request.json:
+        args_rules.append(
+            Rules.OS_TEMPLATE_INITIALIZE_OPERATE_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)
+        os_template_initialize_operate.id = request.json.get('id')
+        os_template_initialize_operate.get()
+        os_template_initialize_operate.os_template_initialize_operate_set_id = \
+            request.json.get('os_template_initialize_operate_set_id',
+                             os_template_initialize_operate.os_template_initialize_operate_set_id)
+        os_template_initialize_operate.kind = request.json.get('kind', os_template_initialize_operate.kind)
+        os_template_initialize_operate.sequence = request.json.get('sequence', os_template_initialize_operate.sequence)
+        os_template_initialize_operate.path = request.json.get('path', os_template_initialize_operate.path)
+        os_template_initialize_operate.content = request.json.get('content', os_template_initialize_operate.content)
+        os_template_initialize_operate.command = request.json.get('command', os_template_initialize_operate.command)
+
+        os_template_initialize_operate.update()
+        os_template_initialize_operate.get()
+
+        ret = dict()
+        ret['state'] = ji.Common.exchange_state(20000)
+        ret['data'] = os_template_initialize_operate.__dict__
+        return ret
+    except ji.PreviewingError, e:
+        return json.loads(e.message)
+
+
+@Utils.dumps2response
+def r_delete(ids):
+    return os_template_initialize_operate_base.delete(ids=ids, ids_rule=Rules.IDS.value, by_field='id')
+
+
+@Utils.dumps2response
+def r_get(ids):
+    return os_template_initialize_operate_base.get(ids=ids, ids_rule=Rules.IDS.value, by_field='id')
+
+
+@Utils.dumps2response
+def r_get_by_filter():
+    return os_template_initialize_operate_base.get_by_filter()
+
+
+@Utils.dumps2response
+def r_content_search():
+    return os_template_initialize_operate_base.content_search()

+ 148 - 0
api/os_template_initialize_operate_set.py

@@ -0,0 +1,148 @@
+#!/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 import OSTemplateInitializeOperateSet, OSTemplateInitializeOperate
+
+
+__author__ = 'James Iter'
+__date__ = '2018/2/4'
+__contact__ = 'james.iter.cn@gmail.com'
+__copyright__ = '(c) 2018 by James Iter.'
+
+
+blueprint = Blueprint(
+    'api_os_template_initialize_operate_set',
+    __name__,
+    url_prefix='/api/os_template_initialize_operate_set'
+)
+
+blueprints = Blueprint(
+    'api_os_templates_initialize_operate_set',
+    __name__,
+    url_prefix='/api/os_templates_initialize_operate_set'
+)
+
+
+os_template_initialize_operate_set_base = Base(the_class=OSTemplateInitializeOperateSet,
+                                               the_blueprint=blueprint, the_blueprints=blueprints)
+
+
+@Utils.dumps2response
+def r_create():
+
+    os_template_initialize_operate_set = OSTemplateInitializeOperateSet()
+
+    args_rules = [
+        Rules.LABEL.value,
+        Rules.DESCRIBE.value,
+        Rules.ACTIVE.value
+    ]
+
+    os_template_initialize_operate_set.label = request.json.get('label')
+    os_template_initialize_operate_set.describe = request.json.get('describe')
+    os_template_initialize_operate_set.active = request.json.get('active')
+
+    try:
+        ji.Check.previewing(args_rules, os_template_initialize_operate_set.__dict__)
+
+        ret = dict()
+        ret['state'] = ji.Common.exchange_state(20000)
+
+        if os_template_initialize_operate_set.exist_by('label'):
+            ret['state'] = ji.Common.exchange_state(40901)
+            ret['state']['sub']['zh-cn'] = ''.join([ret['state']['sub']['zh-cn'], ': ',
+                                                    os_template_initialize_operate_set.label])
+            return ret
+
+        os_template_initialize_operate_set.create()
+        os_template_initialize_operate_set.get_by('label')
+        ret['data'] = os_template_initialize_operate_set.__dict__
+        return ret
+    except ji.PreviewingError, e:
+        return json.loads(e.message)
+
+
+@Utils.dumps2response
+def r_update(_id):
+
+    os_template_initialize_operate_set = OSTemplateInitializeOperateSet()
+
+    args_rules = [
+        Rules.ID.value
+    ]
+
+    if 'label' in request.json:
+        args_rules.append(
+            Rules.LABEL.value,
+        )
+
+    if 'describe' in request.json:
+        args_rules.append(
+            Rules.DESCRIBE.value,
+        )
+
+    if 'active' in request.json:
+        args_rules.append(
+            Rules.ACTIVE.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_initialize_operate_set.id = request.json.get('id')
+        os_template_initialize_operate_set.get()
+        os_template_initialize_operate_set.label = request.json.get('label', os_template_initialize_operate_set.label)
+        os_template_initialize_operate_set.describe = \
+            request.json.get('describe', os_template_initialize_operate_set.describe)
+        os_template_initialize_operate_set.active = \
+            request.json.get('active', os_template_initialize_operate_set.active)
+
+        os_template_initialize_operate_set.update()
+        os_template_initialize_operate_set.get()
+
+        ret = dict()
+        ret['state'] = ji.Common.exchange_state(20000)
+        ret['data'] = os_template_initialize_operate_set.__dict__
+        return ret
+    except ji.PreviewingError, e:
+        return json.loads(e.message)
+
+
+@Utils.dumps2response
+def r_delete(ids):
+    os_template_initialize_operate_base = Base(the_class=OSTemplateInitializeOperate)
+    os_template_initialize_operate_base.delete(ids=ids, ids_rule=Rules.IDS.value,
+                                               by_field='os_template_initialize_operate_set_id')
+
+    return os_template_initialize_operate_set_base.delete(ids=ids, ids_rule=Rules.IDS.value, by_field='id')
+
+
+@Utils.dumps2response
+def r_get(ids):
+    return os_template_initialize_operate_set_base.get(ids=ids, ids_rule=Rules.IDS.value, by_field='id')
+
+
+@Utils.dumps2response
+def r_get_by_filter():
+    return os_template_initialize_operate_set_base.get_by_filter()
+
+
+@Utils.dumps2response
+def r_content_search():
+    return os_template_initialize_operate_set_base.content_search()
+

+ 208 - 0
api/os_template_profile.py

@@ -0,0 +1,208 @@
+#!/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 OSTemplateProfile
+from models import Rules
+from models import Utils
+
+
+__author__ = 'James Iter'
+__date__ = '2018/2/4'
+__contact__ = 'james.iter.cn@gmail.com'
+__copyright__ = '(c) 2018 by James Iter.'
+
+
+blueprint = Blueprint(
+    'api_os_template_profile',
+    __name__,
+    url_prefix='/api/os_template_profile'
+)
+
+blueprints = Blueprint(
+    'api_os_templates_profile',
+    __name__,
+    url_prefix='/api/os_templates_profile'
+)
+
+
+os_template_profile_base = Base(the_class=OSTemplateProfile, the_blueprint=blueprint, the_blueprints=blueprints)
+
+
+@Utils.dumps2response
+def r_create():
+
+    os_template_profile = OSTemplateProfile()
+
+    args_rules = [
+        Rules.LABEL.value,
+        Rules.DESCRIBE.value,
+        Rules.OS_TYPE.value,
+        Rules.OS_DISTRO.value,
+        Rules.OS_MAJOR.value,
+        Rules.OS_MINOR.value,
+        Rules.OS_ARCH.value,
+        Rules.OS_PRODUCT_NAME.value,
+        Rules.ACTIVE.value,
+        Rules.ICON.value,
+        Rules.OS_TEMPLATE_INITIALIZE_OPERATE_SET_ID_EXT.value
+    ]
+
+    os_template_profile.label = request.json.get('label')
+    os_template_profile.describe = request.json.get('describe')
+    os_template_profile.os_type = request.json.get('os_type')
+    os_template_profile.os_distro = request.json.get('os_distro')
+    os_template_profile.os_major = request.json.get('os_major')
+    os_template_profile.os_minor = request.json.get('os_minor')
+    os_template_profile.os_arch = request.json.get('os_arch')
+    os_template_profile.os_product_name = request.json.get('os_product_name')
+    os_template_profile.active = request.json.get('active')
+    os_template_profile.icon = request.json.get('icon')
+    os_template_profile.os_template_initialize_operate_set_id = \
+        request.json.get('os_template_initialize_operate_set_id')
+
+    try:
+        ji.Check.previewing(args_rules, os_template_profile.__dict__)
+
+        ret = dict()
+        ret['state'] = ji.Common.exchange_state(20000)
+
+        if os_template_profile.exist_by('label'):
+            ret['state'] = ji.Common.exchange_state(40901)
+            ret['state']['sub']['zh-cn'] = ''.join([ret['state']['sub']['zh-cn'], ': ', os_template_profile.label])
+            return ret
+
+        os_template_profile.create()
+        os_template_profile.get_by('label')
+        ret['data'] = os_template_profile.__dict__
+        return ret
+    except ji.PreviewingError, e:
+        return json.loads(e.message)
+
+
+@Utils.dumps2response
+def r_update(_id):
+
+    os_template_profile = OSTemplateProfile()
+
+    args_rules = [
+        Rules.ID.value
+
+    ]
+
+    if 'label' in request.json:
+        args_rules.append(
+            Rules.LABEL.value,
+        )
+
+    if 'describe' in request.json:
+        args_rules.append(
+            Rules.DESCRIBE.value,
+        )
+
+    if 'os_type' in request.json:
+        args_rules.append(
+            Rules.OS_TYPE.value,
+        )
+
+    if 'os_distro' in request.json:
+        args_rules.append(
+            Rules.OS_DISTRO.value,
+        )
+
+    if 'os_major' in request.json:
+        args_rules.append(
+            Rules.OS_MAJOR.value,
+        )
+
+    if 'os_minor' in request.json:
+        args_rules.append(
+            Rules.OS_MINOR.value,
+        )
+
+    if 'os_arch' in request.json:
+        args_rules.append(
+            Rules.OS_ARCH.value,
+        )
+
+    if 'os_product_name' in request.json:
+        args_rules.append(
+            Rules.OS_PRODUCT_NAME.value,
+        )
+
+    if 'active' in request.json:
+        args_rules.append(
+            Rules.ACTIVE.value,
+        )
+
+    if 'icon' in request.json:
+        args_rules.append(
+            Rules.ICON.value,
+        )
+
+    if 'os_template_initialize_operate_set_id' in request.json:
+        args_rules.append(
+            Rules.OS_TEMPLATE_INITIALIZE_OPERATE_SET_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_profile.id = request.json.get('id')
+
+        os_template_profile.get()
+        os_template_profile.label = request.json.get('label', os_template_profile.label)
+        os_template_profile.describe = request.json.get('describe', os_template_profile.describe)
+        os_template_profile.os_type = request.json.get('os_type', os_template_profile.os_type)
+        os_template_profile.os_distro = request.json.get('os_distro', os_template_profile.os_distro)
+        os_template_profile.os_major = request.json.get('os_major', os_template_profile.os_major)
+        os_template_profile.os_minor = request.json.get('os_minor', os_template_profile.os_minor)
+        os_template_profile.os_arch = request.json.get('os_arch', os_template_profile.os_arch)
+        os_template_profile.os_product_name = request.json.get('os_product_name', os_template_profile.os_product_name)
+        os_template_profile.active = request.json.get('active', os_template_profile.active)
+        os_template_profile.icon = request.json.get('icon', os_template_profile.icon)
+        os_template_profile.os_template_initialize_operate_set_id = request.json.get(
+            'os_template_initialize_operate_set_id', os_template_profile.os_template_initialize_operate_set_id)
+
+        os_template_profile.update()
+        os_template_profile.get()
+
+        ret = dict()
+        ret['state'] = ji.Common.exchange_state(20000)
+        ret['data'] = os_template_profile.__dict__
+        return ret
+    except ji.PreviewingError, e:
+        return json.loads(e.message)
+
+
+@Utils.dumps2response
+def r_delete(ids):
+    return os_template_profile_base.delete(ids=ids, ids_rule=Rules.IDS.value, by_field='id')
+
+
+@Utils.dumps2response
+def r_get(ids):
+    return os_template_profile_base.get(ids=ids, ids_rule=Rules.IDS.value, by_field='id')
+
+
+@Utils.dumps2response
+def r_get_by_filter():
+    return os_template_profile_base.get_by_filter()
+
+
+@Utils.dumps2response
+def r_content_search():
+    return os_template_profile_base.content_search()
+

+ 49 - 0
api_route_table.py

@@ -10,6 +10,10 @@ 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_profile
+from api import os_template_initialize_operate_set
+from api import os_template_initialize_operate
 from api import log
 from api import host
 from api import guest_performance
@@ -60,6 +64,51 @@ add_rule_api(os_template.blueprints, '/<ids>', api_func='os_template.r_get', met
 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, '/<_id>', api_func='os_template_image.r_update', methods=['PATCH'])
+add_rule_api(os_template_image.blueprints, '/<ids>', api_func='os_template_image.r_delete', methods=['DELETE'])
+add_rule_api(os_template_image.blueprints, '/<ids>', api_func='os_template_image.r_get', methods=['GET'])
+add_rule_api(os_template_image.blueprints, '', api_func='os_template_image.r_get_by_filter', methods=['GET'])
+add_rule_api(os_template_image.blueprints, '/_search', api_func='os_template_image.r_content_search', methods=['GET'])
+
+# 系统模板描述文件操作
+add_rule_api(os_template_profile.blueprint, '', api_func='os_template_profile.r_create', methods=['POST'])
+add_rule_api(os_template_profile.blueprint, '/<_id>', api_func='os_template_profile.r_update', methods=['PATCH'])
+add_rule_api(os_template_profile.blueprints, '/<ids>', api_func='os_template_profile.r_delete', methods=['DELETE'])
+add_rule_api(os_template_profile.blueprints, '/<ids>', api_func='os_template_profile.r_get', methods=['GET'])
+add_rule_api(os_template_profile.blueprints, '', api_func='os_template_profile.r_get_by_filter', methods=['GET'])
+add_rule_api(os_template_profile.blueprints, '/_search', api_func='os_template_profile.r_content_search',
+             methods=['GET'])
+
+# 系统模板初始化操作集操作
+add_rule_api(os_template_initialize_operate_set.blueprint, '',
+             api_func='os_template_initialize_operate_set.r_create', methods=['POST'])
+add_rule_api(os_template_initialize_operate_set.blueprint, '/<_id>',
+             api_func='os_template_initialize_operate_set.r_update', methods=['PATCH'])
+add_rule_api(os_template_initialize_operate_set.blueprints, '/<ids>',
+             api_func='os_template_initialize_operate_set.r_delete', methods=['DELETE'])
+add_rule_api(os_template_initialize_operate_set.blueprints, '/<ids>',
+             api_func='os_template_initialize_operate_set.r_get', methods=['GET'])
+add_rule_api(os_template_initialize_operate_set.blueprints, '',
+             api_func='os_template_initialize_operate_set.r_get_by_filter', methods=['GET'])
+add_rule_api(os_template_initialize_operate_set.blueprints, '/_search',
+             api_func='os_template_initialize_operate_set.r_content_search', methods=['GET'])
+
+# 系统模板初始化操作细则
+add_rule_api(os_template_initialize_operate.blueprint, '',
+             api_func='os_template_initialize_operate.r_create', methods=['POST'])
+add_rule_api(os_template_initialize_operate.blueprint, '/<_id>',
+             api_func='os_template_initialize_operate.r_update', methods=['PATCH'])
+add_rule_api(os_template_initialize_operate.blueprints, '/<ids>',
+             api_func='os_template_initialize_operate.r_delete', methods=['DELETE'])
+add_rule_api(os_template_initialize_operate.blueprints, '/<ids>',
+             api_func='os_template_initialize_operate.r_get', methods=['GET'])
+add_rule_api(os_template_initialize_operate.blueprints, '',
+             api_func='os_template_initialize_operate.r_get_by_filter', methods=['GET'])
+add_rule_api(os_template_initialize_operate.blueprints, '/_search',
+             api_func='os_template_initialize_operate.r_content_search', methods=['GET'])
+
 # Guest操作
 # 创建虚拟机
 add_rule_api(guest.blueprint, '', api_func='guest.r_create', methods=['POST'])

+ 67 - 28
misc/init.sql

@@ -112,32 +112,61 @@ ALTER TABLE disk ADD INDEX (node_id);
 ALTER TABLE disk ADD INDEX (remark);
 
 
-CREATE TABLE IF NOT EXISTS os_template(
+-- 操作系统模板镜像
+CREATE TABLE IF NOT EXISTS os_template_image(
     id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
-    label VARCHAR(255) NOT NULL,
+    os_template_profile_id BIGINT UNSIGNED NOT NULL,
     path VARCHAR(255) NOT NULL,
-    os_type TINYINT UNSIGNED NOT NULL,
+    active BOOLEAN NOT NULL DEFAULT TRUE,
+    PRIMARY KEY (id))
+    ENGINE=InnoDB
+    DEFAULT CHARSET=utf8;
+
+
+-- 操作系统模板描述文件
+CREATE TABLE IF NOT EXISTS os_template_profile(
+    id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
+    label VARCHAR(255) NOT NULL,
+    describe TEXT NOT NULL DEFAULT '',
+    -- http://libguestfs.org/guestfish.1.html#inspect-get-type
+    os_type VARCHAR(10) NOT NULL,
+    -- http://libguestfs.org/guestfish.1.html#inspect-get-distro
+    os_distro VARCHAR(20) NOT NULL,
+    os_major TINYINT UNSIGNED NOT NULL,
+    os_minor TINYINT UNSIGNED NOT NULL,
+    -- http://libguestfs.org/guestfish.1.html#inspect-get-arch  http://libguestfs.org/guestfish.1.html#file-architecture
+    os_arch VARCHAR(10) NOT NULL,
+    os_product_name VARCHAR(255) NOT NULL,
     active BOOLEAN NOT NULL DEFAULT TRUE,
     icon VARCHAR(255) NOT NULL,
-    boot_job_id BIGINT UNSIGNED NOT NULL DEFAULT 0,
+    os_template_initialize_operate_set_id BIGINT UNSIGNED NOT NULL,
     PRIMARY KEY (id))
     ENGINE=InnoDB
     DEFAULT CHARSET=utf8;
 
+ALTER TABLE os_template_profile ADD INDEX (label);
+ALTER TABLE os_template_profile ADD INDEX (os_type);
+ALTER TABLE os_template_profile ADD INDEX (os_distro);
+ALTER TABLE os_template_profile ADD INDEX (os_product_name);
 
-CREATE TABLE IF NOT EXISTS boot_job(
+
+-- 操作系统模板初始化操作集
+CREATE TABLE IF NOT EXISTS os_template_initialize_operate_set(
     id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
-    name VARCHAR(255) NOT NULL,
-    use_for TINYINT UNSIGNED NOT NULL DEFAULT 0,
-    remark VARCHAR(255) NOT NULL DEFAULT '',
+    label VARCHAR(255) NOT NULL,
+    describe TEXT NOT NULL DEFAULT '',
+    active BOOLEAN NOT NULL DEFAULT TRUE,
     PRIMARY KEY (id))
     ENGINE=InnoDB
     DEFAULT CHARSET=utf8;
 
+ALTER TABLE os_template_initialize_operate_set ADD INDEX (label);
 
-CREATE TABLE IF NOT EXISTS operate_rule(
+
+-- 操作系统模板初始化操作细则
+CREATE TABLE IF NOT EXISTS os_template_initialize_operate(
     id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
-    boot_job_id BIGINT UNSIGNED NOT NULL,
+    os_template_initialize_operate_set_id BIGINT UNSIGNED NOT NULL,
     kind TINYINT UNSIGNED NOT NULL DEFAULT 0,
     sequence TINYINT UNSIGNED NOT NULL DEFAULT 0,
     path VARCHAR(255) NOT NULL,
@@ -147,6 +176,8 @@ CREATE TABLE IF NOT EXISTS operate_rule(
     ENGINE=InnoDB
     DEFAULT CHARSET=utf8;
 
+ALTER TABLE os_template_initialize_operate ADD INDEX (os_template_initialize_operate_set_id);
+
 
 CREATE TABLE IF NOT EXISTS config(
     id BIGINT UNSIGNED NOT NULL DEFAULT 1,
@@ -323,19 +354,15 @@ ALTER TABLE host_disk_usage_io ADD INDEX (timestamp);
 ALTER TABLE host_disk_usage_io ADD INDEX (node_id, mountpoint, timestamp);
 
 
-INSERT INTO boot_job (name, use_for, remark) VALUES ('Reset password for Linux', 1, '重置 Linux 平台管理员密码。');
-INSERT INTO boot_job (name, use_for, remark) VALUES ('CentOS-Systemd', 0, '用作 Redhat Systemd 系列的系统初始化。初始化操作依据 CentOS 7 来实现。');
-INSERT INTO boot_job (name, use_for, remark) VALUES ('CentOS-SysV', 0, '用作 Redhat SysV 系列的系统初始化。初始化操作依据 CentOS 6.8 来实现。');
-INSERT INTO boot_job (name, use_for, remark) VALUES ('Gentoo-OpenRC', 0, '用作 Gentoo OpenRC 系列的系统初始化。');
-INSERT INTO boot_job (name, use_for, remark) VALUES ('Windows', 0, '用作 MS-Windos 系列的系统初始化。初始化操作依据 Windows 2012 来实现。');
-
--- For Reset password for Linux
-INSERT INTO operate_rule (boot_job_id, kind, sequence, path, content, command) VALUES (1, 0, 0, '', '', 'echo "root:{PASSWORD}" | chpasswd');
+INSERT INTO os_template_initialize_operate_set (label, describe, active) VALUES ('CentOS-Systemd', '用作 Redhat Systemd 系列的系统初始化。初始化操作依据 CentOS 7 来实现。', 1);
+INSERT INTO os_template_initialize_operate_set (label, describe, active) VALUES ('CentOS-SysV', '用作 Redhat SysV 系列的系统初始化。初始化操作依据 CentOS 6.8 来实现。', 1);
+INSERT INTO os_template_initialize_operate_set (label, describe, active) VALUES ('Gentoo-OpenRC', '用作 Gentoo OpenRC 系列的系统初始化。', 1);
+INSERT INTO os_template_initialize_operate_set (label, describe, active) VALUES ('Windows', '用作 MS-Windows 系列的系统初始化。初始化操作依据 Windows 2012 来实现。', 1);
 
 -- For CentOS-Systemd
-INSERT INTO operate_rule (boot_job_id, kind, sequence, path, content, command) VALUES (2, 1, 0, '/etc/resolv.conf', 'nameserver {DNS1}
+INSERT INTO os_template_initialize_operate (os_template_initialize_operate_set_id, kind, sequence, path, content, command) VALUES (1, 1, 0, '/etc/resolv.conf', 'nameserver {DNS1}
 nameserver {DNS2}', '');
-INSERT INTO operate_rule (boot_job_id, kind, sequence, path, content, command) VALUES (2, 1, 0, '/etc/sysconfig/network-scripts/ifcfg-eth0', 'DEVICE=eth0
+INSERT INTO os_template_initialize_operate (os_template_initialize_operate_set_id, kind, sequence, path, content, command) VALUES (1, 1, 1, '/etc/sysconfig/network-scripts/ifcfg-eth0', 'DEVICE=eth0
 TYPE=Ethernet
 ONBOOT=yes
 BOOTPROTO="static"
@@ -346,12 +373,13 @@ DNS1={DNS1}
 DNS2={DNS2}
 IPV6INIT=no
 NAME=eth0', '');
-INSERT INTO operate_rule (boot_job_id, kind, sequence, path, content, command) VALUES (2, 1, 0, '/etc/hostname', '{HOSTNAME}', '');
+INSERT INTO os_template_initialize_operate (os_template_initialize_operate_set_id, kind, sequence, path, content, command) VALUES (1, 1, 2, '/etc/hostname', '{HOSTNAME}', '');
+INSERT INTO os_template_initialize_operate (os_template_initialize_operate_set_id, kind, sequence, path, content, command) VALUES (1, 0, 3, '', '', 'echo "root:{PASSWORD}" | chpasswd');
 
 -- For CentOS-SysV
-INSERT INTO operate_rule (boot_job_id, kind, sequence, path, content, command) VALUES (3, 1, 0, '/etc/resolv.conf', 'nameserver {DNS1}
+INSERT INTO os_template_initialize_operate (os_template_initialize_operate_set_id, kind, sequence, path, content, command) VALUES (2, 1, 0, '/etc/resolv.conf', 'nameserver {DNS1}
 nameserver {DNS2}', '');
-INSERT INTO operate_rule (boot_job_id, kind, sequence, path, content, command) VALUES (3, 1, 0, '/etc/sysconfig/network-scripts/ifcfg-eth0', 'DEVICE=eth0
+INSERT INTO os_template_initialize_operate (os_template_initialize_operate_set_id, kind, sequence, path, content, command) VALUES (2, 1, 1, '/etc/sysconfig/network-scripts/ifcfg-eth0', 'DEVICE=eth0
 TYPE=Ethernet
 ONBOOT=yes
 BOOTPROTO="static"
@@ -360,18 +388,20 @@ NETMASK={NETMASK}
 GATEWAY={GATEWAY}
 IPV6INIT=no
 NAME=eth0', '');
-INSERT INTO operate_rule (boot_job_id, kind, sequence, path, content, command) VALUES (3, 1, 0, '/etc/sysconfig/network', 'NETWORKING=yes
+INSERT INTO os_template_initialize_operate (os_template_initialize_operate_set_id, kind, sequence, path, content, command) VALUES (2, 1, 2, '/etc/sysconfig/network', 'NETWORKING=yes
 HOSTNAME="{HOSTNAME}"', '');
+INSERT INTO os_template_initialize_operate (os_template_initialize_operate_set_id, kind, sequence, path, content, command) VALUES (2, 0, 3, '', '', 'echo "root:{PASSWORD}" | chpasswd');
 
 -- For Gentoo-OpenRC
-INSERT INTO operate_rule (boot_job_id, kind, sequence, path, content, command) VALUES (4, 1, 0, '/etc/resolv.conf', 'nameserver {DNS1}
+INSERT INTO os_template_initialize_operate (os_template_initialize_operate_set_id, kind, sequence, path, content, command) VALUES (3, 1, 0, '/etc/resolv.conf', 'nameserver {DNS1}
 nameserver {DNS2}', '');
-INSERT INTO operate_rule (boot_job_id, kind, sequence, path, content, command) VALUES (4, 1, 0, '/etc/conf.d/net', 'config_eth0="{IP}/{NETMASK}"
+INSERT INTO os_template_initialize_operate (os_template_initialize_operate_set_id, kind, sequence, path, content, command) VALUES (3, 1, 1, '/etc/conf.d/net', 'config_eth0="{IP}/{NETMASK}"
 routes_eth0="default via {GATEWAY}"', '');
-INSERT INTO operate_rule (boot_job_id, kind, sequence, path, content, command) VALUES (4, 1, 0, '/etc/conf.d/hostname', 'hostname="{HOSTNAME}"', '');
+INSERT INTO os_template_initialize_operate (os_template_initialize_operate_set_id, kind, sequence, path, content, command) VALUES (3, 1, 2, '/etc/conf.d/hostname', 'hostname="{HOSTNAME}"', '');
+INSERT INTO os_template_initialize_operate (os_template_initialize_operate_set_id, kind, sequence, path, content, command) VALUES (3, 0, 3, '', '', 'echo "root:{PASSWORD}" | chpasswd');
 
 -- For Windows
-INSERT INTO operate_rule (boot_job_id, kind, sequence, path, content, command) VALUES (5, 1, 0, '/Windows/jimv_init.bat', 'netsh interface ip set address name="Ethernet" source=static {IP} {NETMASK} {GATEWAY}
+INSERT INTO os_template_initialize_operate (os_template_initialize_operate_set_id, kind, sequence, path, content, command) VALUES (4, 1, 0, '/Windows/jimv_init.bat', 'netsh interface ip set address name="Ethernet" source=static {IP} {NETMASK} {GATEWAY}
 netsh interface ip set dns "Ethernet" static {DNS1} primary
 netsh interface ip add dns "Ethernet" {DNS2}
 wmic computersystem where name="%COMPUTERNAME%" call rename name="{HOSTNAME}"
@@ -382,3 +412,12 @@ del C:\\Windows\\jimv_init.bat
 timeout 2 > NUL
 shutdown -r -t 0', '');
 
+
+INSERT INTO os_template_profile (label, describe, os_type, os_distro, os_major, os_minor, os_arch, os_product_name, active, icon, os_template_initialize_operate_set_id)
+VALUES ('CentOS-7.4', 'CentOS 7.4。', 'linux', 'centos', 7, 4, 'x86_64', 'CentOS Linux release 7.4.1708 (Core)', 1, 'icon-os icon-os-centos', 1);
+INSERT INTO os_template_profile (label, describe, os_type, os_distro, os_major, os_minor, os_arch, os_product_name, active, icon, os_template_initialize_operate_set_id)
+VALUES ('CentOS-6.8', 'CentOS 6.8。', 'linux', 'centos', 6, 8, 'x86_64', 'CentOS release 6.8 (Final)', 1, 'icon-os icon-os-centos', 2);
+INSERT INTO os_template_profile (label, describe, os_type, os_distro, os_major, os_minor, os_arch, os_product_name, active, icon, os_template_initialize_operate_set_id)
+VALUES ('Gentoo-2.2', 'Gentoo 2.2。', 'linux', 'gentoo', 2, 2, 'x86_64', 'Gentoo Base System release 2.2', 1, 'icon-os icon-os-gentoo', 3);
+INSERT INTO os_template_profile (label, describe, os_type, os_distro, os_major, os_minor, os_arch, os_product_name, active, icon, os_template_initialize_operate_set_id)
+VALUES ('Windows-2012-R2-Standard', 'Windows 2012 R2 Standard。', 'windows', 'windows', 6, 3, 'x86_64', 'Windows Server 2012 R2 Standard', 1, 'icon-os icon-os-gentoo', 4);

+ 17 - 0
models/__init__.py

@@ -47,6 +47,22 @@ from os_template import (
     OSTemplate
 )
 
+from os_template_image import (
+    OSTemplateImage
+)
+
+from os_template_profile import (
+    OSTemplateProfile
+)
+
+from os_template_initialize_operate_set import (
+    OSTemplateInitializeOperateSet
+)
+
+from os_template_initialize_operate import (
+    OSTemplateInitializeOperate
+)
+
 from status import (
     EmitKind,
     GuestState,
@@ -94,6 +110,7 @@ __copyright__ = '(c) 2017 by James Iter.'
 __all__ = [
     'Rules', 'Utils', 'Init', 'Database', 'FilterFieldType', 'Filter', 'EmitKind', 'GuestState', 'DiskState', 'OSType',
     'LogLevel', 'ORM', 'User', 'Config', 'Guest', 'Disk', 'BootJob', 'OperateRule', 'OSTemplate', 'GuestXML', 'Log',
+    'OSTemplateImage', 'OSTemplateProfile', 'OSTemplateInitializeOperateSet', 'OSTemplateInitializeOperate',
     'EventProcessor', 'ResponseState', 'GuestCPUMemory', 'GuestTraffic', 'GuestDiskIO', 'HostCPUMemory', 'HostTraffic',
     'HostDiskUsageIO', 'Host'
 ]

+ 42 - 0
models/os_template_image.py

@@ -0,0 +1,42 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+
+from models import FilterFieldType
+from models import ORM
+
+
+__author__ = 'James Iter'
+__date__ = '2018/2/4'
+__contact__ = 'james.iter.cn@gmail.com'
+__copyright__ = '(c) 2018 by James Iter.'
+
+
+class OSTemplateImage(ORM):
+
+    _table_name = 'os_template_image'
+    _primary_key = 'id'
+
+    def __init__(self):
+        super(OSTemplateImage, self).__init__()
+        self.id = 0
+        self.os_template_profile_id = None
+        self.path = None
+        self.active = True
+
+    @staticmethod
+    def get_filter_keywords():
+        return {
+            'id': FilterFieldType.INT.value,
+            'os_template_profile_id': FilterFieldType.INT.value,
+            'path': FilterFieldType.STR.value,
+            'active': FilterFieldType.INT.value
+        }
+
+    @staticmethod
+    def get_allow_update_keywords():
+        return []
+
+    @staticmethod
+    def get_allow_content_search_keywords():
+        return ['path']

+ 48 - 0
models/os_template_initialize_operate.py

@@ -0,0 +1,48 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+
+from models import FilterFieldType
+from models import ORM
+
+
+__author__ = 'James Iter'
+__date__ = '2018/2/4'
+__contact__ = 'james.iter.cn@gmail.com'
+__copyright__ = '(c) 2018 by James Iter.'
+
+
+class OSTemplateInitializeOperate(ORM):
+
+    _table_name = 'os_template_initialize_operate'
+    _primary_key = 'id'
+
+    def __init__(self):
+        super(OSTemplateInitializeOperate, self).__init__()
+        self.id = 0
+        self.os_template_initialize_operate_set_id = None
+        self.kind = None
+        self.sequence = None
+        self.path = None
+        self.content = None
+        self.command = None
+
+    @staticmethod
+    def get_filter_keywords():
+        return {
+            'id': FilterFieldType.INT.value,
+            'os_template_initialize_operate_set_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 ['os_template_initialize_operate_set_id']
+
+    @staticmethod
+    def get_allow_content_search_keywords():
+        return ['command', 'path', 'content']
+

+ 42 - 0
models/os_template_initialize_operate_set.py

@@ -0,0 +1,42 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+
+from models import FilterFieldType
+from models import ORM
+
+
+__author__ = 'James Iter'
+__date__ = '2018/2/4'
+__contact__ = 'james.iter.cn@gmail.com'
+__copyright__ = '(c) 2018 by James Iter.'
+
+
+class OSTemplateInitializeOperateSet(ORM):
+
+    _table_name = 'os_template_initialize_operate_set'
+    _primary_key = 'id'
+
+    def __init__(self):
+        super(OSTemplateInitializeOperateSet, self).__init__()
+        self.id = 0
+        self.label = None
+        self.describe = ''
+        self.active = True
+
+    @staticmethod
+    def get_filter_keywords():
+        return {
+            'id': FilterFieldType.INT.value,
+            'label': FilterFieldType.STR.value,
+            'active': FilterFieldType.INT.value
+        }
+
+    @staticmethod
+    def get_allow_update_keywords():
+        return []
+
+    @staticmethod
+    def get_allow_content_search_keywords():
+        return ['label']
+

+ 54 - 0
models/os_template_profile.py

@@ -0,0 +1,54 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+
+from models import FilterFieldType
+from models import ORM
+
+
+__author__ = 'James Iter'
+__date__ = '2018/2/4'
+__contact__ = 'james.iter.cn@gmail.com'
+__copyright__ = '(c) 2018 by James Iter.'
+
+
+class OSTemplateProfile(ORM):
+
+    _table_name = 'os_template_profile'
+    _primary_key = 'id'
+
+    def __init__(self):
+        super(OSTemplateProfile, self).__init__()
+        self.id = 0
+        self.label = None
+        self.describe = ''
+        self.os_type = None
+        self.os_distro = None
+        self.os_major = None
+        self.os_minor = None
+        self.os_arch = None
+        self.os_product_name = None
+        self.active = True
+        self.icon = None
+        self.os_template_initialize_operate_set_id = None
+
+    @staticmethod
+    def get_filter_keywords():
+        return {
+            'id': FilterFieldType.INT.value,
+            'label': FilterFieldType.STR.value,
+            'os_type': FilterFieldType.STR.value,
+            'os_distro': FilterFieldType.STR.value,
+            'os_product_name': FilterFieldType.STR.value,
+            'os_template_initialize_operate_set_id': FilterFieldType.INT.value,
+            'active': FilterFieldType.INT.value
+        }
+
+    @staticmethod
+    def get_allow_update_keywords():
+        return ['os_type', 'os_distro', 'os_arch', 'active', 'icon', 'os_template_initialize_operate_set_id']
+
+    @staticmethod
+    def get_allow_content_search_keywords():
+        return ['label', 'os_type', 'os_distro', 'os_product_name']
+

+ 15 - 1
models/rules.py

@@ -86,11 +86,25 @@ class Rules(Enum):
     REMARK = (basestring, 'remark')
     USE_FOR = (int, 'use_for')
     LABEL = (basestring, 'label')
-    OS_TYPE = (int, 'os_type')
+    DESCRIBE = (basestring, 'describe')
+    OS_TYPE = (basestring, 'os_type')
+    OS_DISTRO = (basestring, 'os_distro')
+    OS_MAJOR = (int, 'os_major')
+    OS_MINOR = (int, 'os_minor')
+    OS_ARCH = (basestring, 'os_arch')
+    OS_PRODUCT_NAME = (basestring, 'os_product_name')
     ACTIVE = (bool, 'active')
     ICON = (basestring, 'icon')
 
     BOOT_JOB_ID_EXT = (int, 'boot_job_id')
+    OS_TEMPLATE_PROFILE_ID_EXT = (int, 'os_template_profile_id')
+    OS_TEMPLATE_INITIALIZE_OPERATE_SET_ID_EXT = (int, 'os_template_initialize_operate_set_id')
+    OS_TEMPLATE_INITIALIZE_OPERATE_KIND = (int, 'kind')
+    OS_TEMPLATE_INITIALIZE_OPERATE_SEQUENCE = (int, 'sequence')
+    OS_TEMPLATE_INITIALIZE_OPERATE_PATH = (basestring, 'path')
+    OS_TEMPLATE_INITIALIZE_OPERATE_CONTENT = (basestring, 'content')
+    OS_TEMPLATE_INITIALIZE_OPERATE_COMMAND = (basestring, 'command')
+
     OPERATE_RULE_KIND = (int, 'kind')
     OPERATE_RULE_SEQUENCE = (int, 'sequence')
     OPERATE_RULE_PATH = (basestring, 'path')

+ 6 - 0
models/status.py

@@ -91,6 +91,12 @@ class OperateRuleKind(IntEnum):
     append_file = 2
 
 
+class OSTemplateInitializeOperateKind(IntEnum):
+    cmd = 0
+    write_file = 1
+    append_file = 2
+
+
 class GuestCollectionPerformanceDataKind(IntEnum):
     cpu_memory = 0
     traffic = 1

+ 3 - 3
templates/os_templates_show.html

@@ -734,10 +734,10 @@
                         </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>
+                            <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" selected>Linux</option>
+                                <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>