Просмотр исходного кода

实现恢复、删除快照功能

James Iter 8 лет назад
Родитель
Сommit
755da50c3d
7 измененных файлов с 153 добавлено и 8 удалено
  1. 3 0
      .gitignore
  2. 47 0
      api/snapshot.py
  3. 1 0
      api_route_table.py
  4. 7 0
      models/event_processor.py
  5. 2 2
      models/rules.py
  6. 8 0
      templates/layout.html
  7. 85 6
      templates/snapshots_show.html

+ 3 - 0
.gitignore

@@ -55,3 +55,6 @@ target/
 
 
 # PyCharm IDE
 # PyCharm IDE
 .idea/
 .idea/
+
+# MAC .DS_Store
+.DS_Store

+ 47 - 0
api/snapshot.py

@@ -185,6 +185,10 @@ def r_delete(snapshots_id):
                 SnapshotDiskMapping.delete_by_filter(filter_str=':'.join(['snapshot_id', 'eq', snapshot.snapshot_id]))
                 SnapshotDiskMapping.delete_by_filter(filter_str=':'.join(['snapshot_id', 'eq', snapshot.snapshot_id]))
                 snapshot.delete()
                 snapshot.delete()
 
 
+            else:
+                snapshot.progress = 254
+                snapshot.update()
+
         ret = dict()
         ret = dict()
         ret['state'] = ji.Common.exchange_state(20000)
         ret['state'] = ji.Common.exchange_state(20000)
         return ret
         return ret
@@ -192,3 +196,46 @@ def r_delete(snapshots_id):
     except ji.PreviewingError, e:
     except ji.PreviewingError, e:
         return json.loads(e.message)
         return json.loads(e.message)
 
 
+
+@Utils.dumps2response
+def r_revert(snapshot_id):
+
+    args_rules = [
+        Rules.SNAPSHOT_ID.value
+    ]
+
+    try:
+        ret = dict()
+        ret['state'] = ji.Common.exchange_state(20000)
+
+        ji.Check.previewing(args_rules, {'snapshot_id': snapshot_id})
+
+        snapshot = Snapshot()
+        guest = Guest()
+
+        snapshot.snapshot_id = snapshot_id
+        snapshot.get_by('snapshot_id')
+        snapshot.progress = 253
+        snapshot.update()
+        snapshot.get()
+
+        guest.uuid = snapshot.guest_uuid
+        guest.get_by('uuid')
+
+        message = {
+            '_object': 'snapshot',
+            'action': 'revert',
+            'uuid': guest.uuid,
+            'snapshot_id': snapshot.snapshot_id,
+            'node_id': guest.node_id,
+            'passback_parameters': {'id': snapshot.id}
+        }
+
+        Utils.emit_instruction(message=json.dumps(message, ensure_ascii=False))
+
+        ret['data'] = snapshot.__dict__
+        return ret
+
+    except ji.PreviewingError, e:
+        return json.loads(e.message)
+

+ 1 - 0
api_route_table.py

@@ -149,6 +149,7 @@ add_rule_api(snapshot.blueprint, '/<snapshot_id>', api_func='snapshot.r_update',
 add_rule_api(snapshot.blueprints, '/<snapshots_id>', api_func='snapshot.r_get', methods=['GET'])
 add_rule_api(snapshot.blueprints, '/<snapshots_id>', api_func='snapshot.r_get', methods=['GET'])
 add_rule_api(snapshot.blueprints, '', api_func='snapshot.r_get_by_filter', methods=['GET'])
 add_rule_api(snapshot.blueprints, '', api_func='snapshot.r_get_by_filter', methods=['GET'])
 add_rule_api(snapshot.blueprints, '/_search', api_func='snapshot.r_content_search', methods=['GET'])
 add_rule_api(snapshot.blueprints, '/_search', api_func='snapshot.r_content_search', methods=['GET'])
+add_rule_api(snapshot.blueprint, '/_revert/<snapshot_id>', api_func='snapshot.r_revert', methods=['PUT'])
 
 
 # 日志查询
 # 日志查询
 # Guest 性能查询
 # Guest 性能查询

+ 7 - 0
models/event_processor.py

@@ -288,6 +288,13 @@ class EventProcessor(object):
                 else:
                 else:
                     pass
                     pass
 
 
+            if action == 'revert':
+                # 不论恢复成功与否,都使快照恢复至正常状态。
+                cls.snapshot.id = cls.message['message']['passback_parameters']['id']
+                cls.snapshot.get()
+                cls.snapshot.progress = 100
+                cls.snapshot.update()
+
         else:
         else:
             pass
             pass
 
 

+ 2 - 2
models/rules.py

@@ -86,8 +86,8 @@ class Rules(Enum):
     INFLUENCE_CURRENT_GUEST = (bool, 'influence_current_guest')
     INFLUENCE_CURRENT_GUEST = (bool, 'influence_current_guest')
 
 
     GUEST_UUID = (basestring, 'guest_uuid', (36, 36))
     GUEST_UUID = (basestring, 'guest_uuid', (36, 36))
-    SNAPSHOT_ID = (REG_NUMBER, 'snapshot_id')
-    SNAPSHOTS_ID = (REG_NUMBERS, 'snapshots_id')
+    SNAPSHOT_ID = (basestring, 'snapshot_id', (10, 12))
+    SNAPSHOTS_ID = (basestring, 'snapshots_id', (10, 1200))
 
 
     REMARK = (basestring, 'remark')
     REMARK = (basestring, 'remark')
     USE_FOR = (int, 'use_for')
     USE_FOR = (int, 'use_for')

+ 8 - 0
templates/layout.html

@@ -54,6 +54,14 @@
             font-weight: normal;
             font-weight: normal;
             font-style: italic;
             font-style: italic;
         }
         }
+
+        .a-disabled {
+            color: #5e6c73 !important;
+            opacity: 0.5;
+            cursor: default;
+            pointer-events: none;
+        }
+
     </style>
     </style>
 
 
 
 

+ 85 - 6
templates/snapshots_show.html

@@ -183,6 +183,42 @@
         });
         });
     }
     }
 
 
+    function revert_snapshot(me) {
+        var snapshot_id = $('#snapshot_id').val();
+        $('#snapshot_revert_modal').modal('hide');
+        $.ajax({
+            url : '/api/snapshot/_revert/' + snapshot_id,
+            type : 'PUT',
+            error : function() {
+                alter_danger('快照恢复失败!');
+            },
+            success : function() {
+                alter_success('快照恢复成功!');
+                setTimeout(function() {
+                    refresh();
+                }, 1000);
+            }
+        });
+    }
+
+    function delete_snapshot(me) {
+        var snapshot_id = $('#snapshot_id').val();
+        $('#snapshot_delete_modal').modal('hide');
+        $.ajax({
+            url : '/api/snapshots/' + snapshot_id,
+            type : 'DELETE',
+            error : function() {
+                alter_danger('快照删除失败!');
+            },
+            success : function() {
+                alter_success('快照删除成功!');
+                setTimeout(function() {
+                    refresh();
+                }, 1000);
+            }
+        });
+    }
+
     function get_selected_element(checked) {
     function get_selected_element(checked) {
         if (checked === null) {
         if (checked === null) {
             checked = true;
             checked = true;
@@ -271,12 +307,17 @@
                             </a>
                             </a>
                         </div>
                         </div>
                     </td>
                     </td>
-                    <td>{% if item.progress == 255 %}
-                        <span style="color: #990000;">创建失败</span>
+                    <td>
+                        {% if item.progress == 255 %}
+                            <span style="color: #990000;">创建失败</span>
+                        {% elif item.progress == 254 %}
+                            <span style="color: #ff0000dd;">删除中...</span>
+                        {% elif item.progress == 253 %}
+                            <span style="color: #009cc5;">恢复中...</span>
                         {% elif item.progress == 100 %}
                         {% elif item.progress == 100 %}
-                        <span style="color: #00BB00;">{{ item.progress }}%</span>
+                            <span style="color: #00BB00;">{{ item.progress }}%</span>
                         {% else %}
                         {% else %}
-                        <span style="color: #e5b715;">{{ item.progress }}%</span>
+                            <span style="color: #e5b715;">{{ item.progress }}%</span>
                         {% endif %}
                         {% endif %}
                     </td>
                     </td>
                     <td>{{ format_guest_status(item.status, 100)|safe }}</td>
                     <td>{{ format_guest_status(item.status, 100)|safe }}</td>
@@ -288,9 +329,11 @@
                     <td>{{ format_datetime_by_tus(item.create_time) }}</td>
                     <td>{{ format_datetime_by_tus(item.create_time) }}</td>
                     <td>
                     <td>
                         <div class="dropdown inline-block">
                         <div class="dropdown inline-block">
-                            <a href="javascript:;" style="color: #0066cc" data-toggle="modal" data-target="#snapshot_revert_modal" onclick="$('#snapshot_id').val($(this).parent().parent().parent().children()[0].textContent)">恢复</a>
+                            <a href="javascript:;" class="{% if item.progress not in [100] %} a-disabled {% endif %}" style="color: #0066cc" data-toggle="modal" data-target="#snapshot_revert_modal" onclick="$('#snapshot_id').val($(this).parent().parent().parent().children()[0].textContent);
+                                                                                                                                            $('#revert_snapshot_instance_desc').text($($(this).parent().parent().parent().children()[2]).find('div a')[0].textContent + '/' + $($(this).parent().parent().parent().children()[2]).find('div p')[0].textContent)">恢复</a>
                             <span> | </span>
                             <span> | </span>
-                            <a href="javascript:;" style="color: #0066cc" data-toggle="modal" data-target="#snapshot_delete_modal" onclick="$('#snapshot_id').val($(this).parent().parent().parent().children()[0].textContent)">删除</a>
+                            <a href="javascript:;" class="{% if item.progress not in [100, 255] %} a-disabled {% endif %}" style="color: #0066cc" data-toggle="modal" data-target="#snapshot_delete_modal" onclick="$('#snapshot_id').val($(this).parent().parent().parent().children()[0].textContent);
+                                                                                                                                            $('#delete_snapshot_instance_desc').text($($(this).parent().parent().parent().children()[2]).find('div a')[0].textContent + '/' + $($(this).parent().parent().parent().children()[2]).find('div p')[0].textContent)">删除</a>
                         </div>
                         </div>
                     </td>
                     </td>
                 </tr>
                 </tr>
@@ -359,4 +402,40 @@
         </div>
         </div>
     </div>
     </div>
 </div>
 </div>
+
+<div class="modal" id="snapshot_revert_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="revert_snapshot_instance_desc"></h3>
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-sm btn-primary" onclick="revert_snapshot();">确定</button>
+                <button type="button" class="btn btn-sm btn-default" data-dismiss="modal">取消</button>
+            </div>
+        </div>
+    </div>
+</div>
+
+<div class="modal" id="snapshot_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_snapshot_instance_desc"></h3>
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-sm btn-primary" onclick="delete_snapshot();">确定</button>
+                <button type="button" class="btn btn-sm btn-default" data-dismiss="modal">取消</button>
+            </div>
+        </div>
+    </div>
+</div>
 {% endblock content %}
 {% endblock content %}