Merge pull request #384 from zhongyehong/master

add page for migrating host
This commit is contained in:
zhong yehong 2019-04-24 22:04:43 +08:00 committed by GitHub
commit e37c9eb6de
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 120 additions and 4 deletions

View File

@ -432,6 +432,23 @@ def migrate_cluster():
finally:
G_ulockmgr.release(user)
@app.route("/host/migrate/", methods=['POST'])
@login_required
def migrate_host(user, beans, form):
global G_vclustermgr
global G_ulockmgr
src_host = request.form.get('src_host', None)
dst_host_list = request.form.getlist('dst_host_list', None)
if src_host is None or dst_host_list is None:
return json.dumps({'success':'false', 'message': 'src host or dst host list is null'})
[status, msg] = G_vclustermgr.migrate_host(src_host, dst_host_list)
if status:
return json.dumps({'success': 'true', 'action': 'migrate_host'})
else:
return json.dumps({'success': 'false', 'message': msg})
@app.route("/image/list/", methods=['POST'])
@login_required

View File

@ -789,14 +789,14 @@ class VclusterMgr(object):
self.imgmgr.removeImage(username,imagename)
return [True,""]
def migrate_cluster(self, clustername, username, new_host_list, user_info):
def migrate_cluster(self, clustername, username, src_host, new_host_list, user_info):
[status, info] = self.get_clusterinfo(clustername, username)
if not status:
return [False, "cluster not found"]
prestatus = info['status']
self.stop_cluster(clustername, username)
for container in info['containers']:
if container['host'] in new_host_list:
if not container['host'] == src_host:
continue
random.shuffle(new_host_list)
for new_host in new_host_list:
@ -816,6 +816,29 @@ class VclusterMgr(object):
return [False, msg]
return [True, ""]
def migrate_host(self, src_host, new_host_list):
[status, vcluster_list] = self.get_all_clusterinfo()
if not status:
return [False, vcluster_list]
auth_key = env.getenv('AUTH_KEY')
res = post_to_user("/master/user/groupinfo/", {'auth_key':auth_key})
groups = json.loads(res['groups'])
quotas = {}
for group in groups:
quotas[group['name']] = group['quotas']
for vcluster in vcluster_list:
try:
clustername = vcluster['clustername']
username = vcluster['ownername']
rc_info = post_to_user("/master/user/recoverinfo/", {'username':username,'auth_key':auth_key})
groupname = rc_info['groupname']
user_info = {"data":{"id":rc_info['uid'],"groupinfo":quotas[groupname]}}
self.migrate_cluster(clustername, username, src_host, new_host_list, user_info)
except Exception as ex:
return [False, str(ex)]
return [True, ""]
def is_cluster(self, clustername, username):
[status, clusters] = self.list_clusters(username)
if clustername in clusters:
@ -862,6 +885,14 @@ class VclusterMgr(object):
else:
return [True, vcluster]
def get_all_clusterinfo(self):
vcluster_list = VCluster.query.all()
logger.info(str(vcluster_list))
if vcluster_list is None:
return [False, None]
else:
return [True, json.loads(str(vcluster_list))]
# acquire cluster id from etcd
def _acquire_id(self):
self.clusterid_locks.acquire()

View File

@ -15,6 +15,12 @@
</ol>
{% endblock %}
{% block css_src %}
<link href="//cdn.bootcss.com/datatables/1.10.11/css/dataTables.bootstrap.min.css" rel="stylesheet">
<link href="//cdn.bootcss.com/datatables/1.10.11/css/jquery.dataTables_themeroller.css" rel="stylesheet">
<link href="/static/dist/css/modalconfig.css" rel="stylesheet">
{% endblock %}
{% block content %}
<ul class="nav nav-tabs" role="tablist" id="myTabs">
{% for master in allmachines %}
@ -59,7 +65,7 @@
<th>Mem used</th>
<th>Disk used</th>
<th>Summary</th>
<th>Delete</th>
<th>Operation</th>
</tr>
</thead>
<tbody>
@ -80,7 +86,50 @@
<td id='{{master.split("@")[1]}}_{{ loop.index }}_mem'>--</td>
<td id='{{master.split("@")[1]}}_{{ loop.index }}_disk'>--</td>
<td><a class="btn btn-info btn-xs" href='/hosts/{{master.split("@")[0]}}/{{ phym['ip'] }}/'>Realtime</a></td>
<td><button class="btn btn-xs btn-default">Delete</button></td>
<td><button class="btn btn-xs btn-default">Delete</button>
<button class="btn btn-xs btn-danger" data-toggle="modal" data-target="#Migrate_{{loop.index}}_{{master.split("@")[1]}}">Migrate</button>
<div class="modal inmodal" id="Migrate_{{loop.index}}_{{master.split("@")[1]}}" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content animated fadeIn">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">&times;</span><span class="sr-only">Close</span></button>
<i class="fa fa-plus modal-icon"></i>
<h4 class="modal-title">Migrate Container from {{phym['ip']}} to Another Hosts [dangerous!!!]</h4>
</div>
<div class="modal-body">
<form action="/hosts/{{master.split("@")[0]}}/migrate/{{ phym['ip'] }}/" method="POST" id="MigrateForm">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
<table class="table table-striped table-bordered table-hover table-image">
<thead>
<tr>
<th>HostIp</th>
<th>Nodes</th>
<th>choose</th>
</tr>
</thead>
<tbody>
{% for tphym in allmachines[master] %}
{% if not phym == tphym %}
<tr>
<td>{{ tphym['ip'] }}</td>
<td>{{ tphym['containers']['running']}} / {{ tphym['containers']['total'] }}</td>
<td><input type="checkbox" name="target" value="{{tphym['ip']}}"></td>
</tr>
{% endif %}
{% endfor %}
</tbody>
</table>
<div class="modal-footer">
<button type="button" class="btn btn-white" data-dismiss="modal">Close</button>
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</td>
</tr>
{% endfor %}
</tbody>

View File

@ -315,6 +315,7 @@ def masterdesc(mastername):
descriptionMasterView.desc=env.getenv(mastername+"_desc")[1:-1]
return descriptionMasterView.as_view()
@app.route("/image/<masterip>/list/", methods=['POST'])
@login_required
def image_list(masterip):
@ -376,6 +377,14 @@ def updatebaseImage(image,masterip):
def hosts():
return hostsView.as_view()
@app.route("/hosts/<masterip>/migrate/<hostip>/", methods=['POST'])
@administration_required
def hostMigrate(hostip, masterip):
hostMigrateView.hostip = hostip
hostMigrateView.masterip = masterip
hostMigrateView.target = request.form.getlist('target')
return hostMigrateView.as_view()
@app.route("/hosts/<masterip>/<com_ip>/", methods=['GET'])
@administration_required
def hostsRealtime(com_ip,masterip):

View File

@ -113,3 +113,13 @@ class updatebaseImageView(normalView):
}
dockletRequest.post('/image/updatebase/', data)
return redirect("/settings/")
class hostMigrateView(normalView):
@classmethod
def post(self):
data = {
"src_host": self.hostip,
"dst_host_list": self.target
}
dockletRequest.post("/host/migrate/", data, self.masterip)
return redirect("/hosts/")