Merge branch 'master' of https://github.com/unias/docklet into networkbillings

This commit is contained in:
Firmlyzhu 2017-12-05 15:54:01 +08:00
commit 911e7b2f6e
2 changed files with 220 additions and 16 deletions

View File

@ -34,6 +34,7 @@ from httprest import post_to_user
a_cpu = 500 # seconds
b_mem = 2000000 # MB
c_disk = 4000 # MB
d_port = 1
# major dict to store the monitoring data
# only use on Master
@ -125,7 +126,12 @@ class Container_Collector(threading.Thread):
workercinfo[container] = {}
workercinfo[container]['basic_info'] = {}
workercinfo[container]['basic_info']['billing'] = vnode.billing
workercinfo[container]['basic_info']['billing_history'] = get_billing_history(container)
workercinfo[container]['basic_info']['RunningTime'] = vnode.laststopruntime
workercinfo[container]['basic_info']['a_cpu'] = a_cpu
workercinfo[container]['basic_info']['b_mem'] = b_mem
workercinfo[container]['basic_info']['c_disk'] = c_disk
workercinfo[container]['basic_info']['d_port'] = d_port
except:
laststopcpuval[container] = 0
laststopruntime[container] = 0
@ -164,9 +170,10 @@ class Container_Collector(threading.Thread):
global a_cpu
global b_mem
global c_disk
global d_port
cpu_val = '0'
if vnode_name not in workercinfo.keys():
return 0
return {'total': 0}
if 'cpu_use' in workercinfo[vnode_name].keys():
cpu_val = workercinfo[vnode_name]['cpu_use']['val']
if vnode_name not in increment.keys():
@ -188,13 +195,23 @@ class Container_Collector(threading.Thread):
# get ports
ports_count = count_port_mapping(vnode_name)
# billing value = cpu used/a + memory used/b + disk quota/c + ports
billingval = math.ceil(cpu_increment/a_cpu + avemem/b_mem + float(disk_quota)/1024.0/1024.0/c_disk + ports_count)
billing = {}
billing['cpu'] = round(cpu_increment/a_cpu, 2)
billing['cpu_time'] = round(cpu_increment, 2)
billing['mem'] = round(avemem/b_mem, 2)
billing['mem_use'] = round(avemem, 2)
billing['disk'] = round(float(disk_quota)/1024.0/1024.0/c_disk, 2)
billing['disk_use'] = round(float(disk_quota)/1024.0/1024.0, 2)
billing['port'] = round(ports_count/d_port, 2)
billing['port_use'] = ports_count
billing['total'] = math.ceil(billing['cpu'] + billing['mem'] + billing['disk'] + billing['port'])
billingval = billing['total']
if billingval > 100:
# report outsize billing value
logger.info("Huge Billingval for "+vnode_name+". cpu_increment:"+str(cpu_increment)+" avemem:"+str(avemem)+" disk:"+str(disk_quota)+"\n")
if not isreal:
# only compute
return math.ceil(billingval)
return billing
# initialize increment for next billing
increment[vnode_name]['lastcputime'] = cpu_val
increment[vnode_name]['memincrement'] = 0
@ -206,6 +223,12 @@ class Container_Collector(threading.Thread):
nowbillingval = workercinfo[vnode_name]['basic_info']['billing']
nowbillingval += billingval
workercinfo[vnode_name]['basic_info']['billing'] = nowbillingval
workercinfo[vnode_name]['basic_info']['billing_history']['cpu'] += billing['cpu']
workercinfo[vnode_name]['basic_info']['billing_history']['mem'] += billing['mem']
workercinfo[vnode_name]['basic_info']['billing_history']['disk'] += billing['disk']
workercinfo[vnode_name]['basic_info']['billing_history']['port'] += billing['port']
# update vnodes billing history
save_billing_history(vnode_name, workercinfo[vnode_name]['basic_info']['billing_history'])
# update vnodes' tables in database
try:
vnode = VNode.query.get(vnode_name)
@ -227,7 +250,7 @@ class Container_Collector(threading.Thread):
auth_key = env.getenv('AUTH_KEY')
data = {"owner_name":owner_name,"billing":billingval, "auth_key":auth_key}
request_master("/billing/beans/",data)
return billingval
return billing
# Collect net statistics of containers by psutil
def collect_net_stats(self):
@ -276,7 +299,7 @@ class Container_Collector(threading.Thread):
basic_info['RunningTime'] = 0
basic_info['billing'] = 0
if 'billing_this_hour' not in basic_info.keys():
basic_info['billing_this_hour'] = 0
basic_info['billing_this_hour'] = {'total': 0}
basic_info['Name'] = container_name
basic_info['State'] = container.state
#if basic_exist:
@ -564,22 +587,72 @@ def get_owner(container_name):
names = container_name.split('-')
return names[0]
# get cluster id of a container
def get_cluster(container_name):
names = container_name.split('-')
return names[1]
def count_port_mapping(vnode_name):
user = get_owner(vnode_name)
fspath = env.getenv("FS_PREFIX")
if not os.path.exists(fspath+"/global/users/"+user+"/clusters"):
clusters_dir = env.getenv("FS_PREFIX")+"/global/users/"+get_owner(vnode_name)+"/clusters/"
if not os.path.exists(clusters_dir):
return 0
clusters = os.listdir(fspath+"/global/users/"+user+"/clusters")
clusters = os.listdir(clusters_dir)
ports_count = 0
for cluster in clusters:
clusterpath = fspath + "/global/users/" + get_owner(vnode_name) + "/clusters/" + cluster
clusterpath = clusters_dir + cluster
if not os.path.isfile(clusterpath):
return 0
continue
infofile = open(clusterpath, 'r')
info = json.loads(infofile.read())
infofile.close()
ports_count += len([mapping for mapping in info['port_mapping'] if mapping['node_name'] == vnode_name])
return ports_count
def save_billing_history(vnode_name, billing_history):
clusters_dir = env.getenv("FS_PREFIX")+"/global/users/"+get_owner(vnode_name)+"/clusters/"
if not os.path.exists(clusters_dir):
return
clusters = os.listdir(clusters_dir)
vnode_cluster_id = get_cluster(vnode_name)
for cluster in clusters:
clusterpath = clusters_dir + cluster
if not os.path.isfile(clusterpath):
continue
infofile = open(clusterpath, 'r')
info = json.loads(infofile.read())
infofile.close()
if vnode_cluster_id != str(info['clusterid']):
continue
if 'billing_history' not in info:
info['billing_history'] = {}
info['billing_history'][vnode_name] = billing_history
infofile = open(clusterpath, 'w')
infofile.write(json.dumps(info))
infofile.close()
break
return
def get_billing_history(vnode_name):
clusters_dir = env.getenv("FS_PREFIX")+"/global/users/"+get_owner(vnode_name)+"/clusters/"
if os.path.exists(clusters_dir):
clusters = os.listdir(clusters_dir)
for cluster in clusters:
clusterpath = clusters_dir + cluster
if not os.path.isfile(clusterpath):
continue
infofile = open(clusterpath, 'r')
info = json.loads(infofile.read())
infofile.close()
if 'billing_history' not in info or vnode_name not in info['billing_history']:
continue
return info['billing_history'][vnode_name]
default = {}
default['cpu'] = 0
default['mem'] = 0
default['disk'] = 0
default['port'] = 0
return default
# the thread to collect data from each worker and store them in monitor_hosts and monitor_vnodes
class Master_Collector(threading.Thread):

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 %}
<div class="row">
<div class="col-md-12">
@ -117,6 +123,105 @@
</div>
<div class="box-body table-responsive">
{% for container in clusterinfo['containers'] %}
<div class="modal inmodal" id='DetailModal_{{master.split("@")[1]}}_{{clustername}}_{{ loop.index }}' 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>
<h4 class="modal-title">{{ container['containername'] }} Billing Detail</h4>
<small class="font-bold">The Detail of the Billing In This Hour<br>Billing = cpu(s) / <span id='{{master.split("@")[1]}}_{{clustername}}_{{ loop.index }}_billing_cpu_a'>?</span> + mem(MiB) / <span id='{{master.split("@")[1]}}_{{clustername}}_{{ loop.index }}_billing_mem_b'>?</span> + Disk(MiB) / <span id='{{master.split("@")[1]}}_{{clustername}}_{{ loop.index }}_billing_disk_c'>?</span> + Ports / <span id='{{master.split("@")[1]}}_{{clustername}}_{{ loop.index }}_billing_port_d'>?</span>, <a target='_blank' title='How to figure out it?' href='https://unias.github.io/docklet/book/en/billing/billing.html'>See User Guide</a></small>
</div>
<div class="modal-body">
<table class="table table-bordered">
<thead>
<tr>
<th>Field</th>
<th>Usage</th>
<th>Cost</th>
</tr>
</thead>
<tbody>
<tr>
<td>Cpu</td>
<td id='{{master.split("@")[1]}}_{{clustername}}_{{ loop.index }}_billing_cpu_use'>--</td>
<td><span id='{{master.split("@")[1]}}_{{clustername}}_{{ loop.index }}_billing_cpu'>--</span></td>
</tr>
<tr>
<td>Memory</td>
<td id='{{master.split("@")[1]}}_{{clustername}}_{{ loop.index }}_billing_mem_use'>--</td>
<td><span id='{{master.split("@")[1]}}_{{clustername}}_{{ loop.index }}_billing_mem'>--</span></td>
</tr>
<tr>
<td>Disk</td>
<td id='{{master.split("@")[1]}}_{{clustername}}_{{ loop.index }}_billing_disk_use'>--</td>
<td><span id='{{master.split("@")[1]}}_{{clustername}}_{{ loop.index }}_billing_disk'>--</span></td>
</tr>
<tr>
<td>Ports</td>
<td id='{{master.split("@")[1]}}_{{clustername}}_{{ loop.index }}_billing_port_use'>--</td>
<td><span id='{{master.split("@")[1]}}_{{clustername}}_{{ loop.index }}_billing_port'>--</span></td>
</tr>
<tr>
<td colspan="2">Total</td>
<td><span id='{{master.split("@")[1]}}_{{clustername}}_{{ loop.index }}_billing_total'>--</span></td>
</tr>
</tbody>
</table>
<div class="modal-footer">
<button type="button" class="btn btn-white" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
</div>
<div class="modal inmodal" id='HistoryDetailModal_{{master.split("@")[1]}}_{{clustername}}_{{ loop.index }}' 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>
<h4 class="modal-title">{{ container['containername'] }} Total Billing Detail</h4>
</div>
<div class="modal-body">
<table class="table table-bordered">
<thead>
<tr>
<th>Field</th>
<th>Cost</th>
</tr>
</thead>
<tbody>
<tr>
<td>Cpu</td>
<td><span id='{{master.split("@")[1]}}_{{clustername}}_{{ loop.index }}_billing_history_cpu'>--</span></td>
</tr>
<tr>
<td>Memory</td>
<td><span id='{{master.split("@")[1]}}_{{clustername}}_{{ loop.index }}_billing_history_mem'>--</span></td>
</tr>
<tr>
<td>Disk</td>
<td><span id='{{master.split("@")[1]}}_{{clustername}}_{{ loop.index }}_billing_history_disk'>--</span></td>
</tr>
<tr>
<td>Ports</td>
<td><span id='{{master.split("@")[1]}}_{{clustername}}_{{ loop.index }}_billing_history_port'>--</span></td>
</tr>
<tr>
<td>Total</td>
<td><span id='{{master.split("@")[1]}}_{{clustername}}_{{ loop.index }}_billing_history_total'>--</span></td>
</tr>
</tbody>
</table>
<div class="modal-footer">
<button type="button" class="btn btn-white" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
</div>
{% endfor %}
<table class="table table-bordered">
<thead>
<tr>
@ -149,9 +254,9 @@
<td id='{{master.split("@")[1]}}_{{clustername}}_{{ loop.index }}_cpu'>--</td>
<td id='{{master.split("@")[1]}}_{{clustername}}_{{ loop.index }}_mem'>--</td>
<td id='{{master.split("@")[1]}}_{{clustername}}_{{ loop.index }}_disk'>--</td>
<td id='{{master.split("@")[1]}}_{{clustername}}_{{ loop.index }}_billing'>--</td>
<td id='{{master.split("@")[1]}}_{{clustername}}_{{ loop.index }}_billingthishour'>--</td>
<td><a class="btn btn-info btn-xs" href='/vclusters/{{master.split("@")[0]}}/{{ clustername }}/{{ container['containername'] }}/'>Realtime</a></td>
<td><a role="button" id='{{master.split("@")[1]}}_{{clustername}}_{{ loop.index }}_billing' data-toggle="modal" data-target='#HistoryDetailModal_{{master.split("@")[1]}}_{{clustername}}_{{ loop.index }}'>--</a> <img src='/static/img/bean.png' /></td>
<td ><a role="button" id='{{master.split("@")[1]}}_{{clustername}}_{{ loop.index }}_billingthishour' data-toggle="modal" data-target='#DetailModal_{{master.split("@")[1]}}_{{clustername}}_{{ loop.index }}'>--</a> <img src='/static/img/bean.png' /></td>
<td><a class="btn btn-info btn-xs" href='/vclusters/{{master.split("@")[0]}}/{{ clustername }}/{{ container['containername'] }}/'>Realtime</a></td>
</tr>
{% endfor %}
</tbody>
@ -167,6 +272,11 @@
{% endblock %}
{% block script_src %}
<script src="http://cdn.bootcss.com/datatables/1.10.11/js/jquery.dataTables.js"></script>
<script src="http://cdn.bootcss.com/datatables/1.10.11/js/dataTables.bootstrap.js"></script>
<script src="http://cdn.bootcss.com/datatables-tabletools/2.1.5/js/TableTools.min.js"></script>
<script type='text/javascript'>
function num2human(data)
{
@ -212,8 +322,29 @@ function num2human(data)
var secs = Math.floor(total % 3600 % 60);
console.log(index,hour,min,secs);
$("#"+index+"_time").html(hour+"h "+min+"m "+secs+"s")
$("#"+index+"_billing").html("<a target='_blank' title='How to figure out it?' href='https://unias.github.io/docklet/book/en/billing/billing.html'>"+data.monitor.basic_info.billing+" <img src='/static/img/bean.png' /></a>")
$("#"+index+"_billingthishour").html("<a target='_blank' title='How to figure out it?' href='https://unias.github.io/docklet/book/en/billing/billing.html'>"+data.monitor.basic_info.billing_this_hour+" <img src='/static/img/bean.png' /></a>")
$("#"+index+"_billing").html(data.monitor.basic_info.billing)
$("#"+index+"_billingthishour").html(data.monitor.basic_info.billing_this_hour.total)
$("#"+index+"_billing_total").html(data.monitor.basic_info.billing_this_hour.total)
if (parseInt(data.monitor.basic_info.billing_this_hour.total) != 0) {
$("#"+index+"_billing_cpu").html(data.monitor.basic_info.billing_this_hour.cpu)
$("#"+index+"_billing_cpu_use").html(data.monitor.basic_info.billing_this_hour.cpu_time + " s")
$("#"+index+"_billing_mem").html(data.monitor.basic_info.billing_this_hour.mem)
$("#"+index+"_billing_mem_use").html(data.monitor.basic_info.billing_this_hour.mem_use + " MiB")
$("#"+index+"_billing_disk").html(data.monitor.basic_info.billing_this_hour.disk)
$("#"+index+"_billing_disk_use").html(data.monitor.basic_info.billing_this_hour.disk_use + " MiB")
$("#"+index+"_billing_port").html(data.monitor.basic_info.billing_this_hour.port)
$("#"+index+"_billing_port_use").html(data.monitor.basic_info.billing_this_hour.port_use)
}
$("#"+index+"_billing_history_cpu").html(data.monitor.basic_info.billing_history.cpu)
$("#"+index+"_billing_history_mem").html(data.monitor.basic_info.billing_history.mem)
$("#"+index+"_billing_history_disk").html(data.monitor.basic_info.billing_history.disk)
$("#"+index+"_billing_history_port").html(data.monitor.basic_info.billing_history.port)
$("#"+index+"_billing_history_total").html(data.monitor.basic_info.billing)
$("#"+index+"_billing_cpu_a").html(data.monitor.basic_info.a_cpu)
$("#"+index+"_billing_mem_b").html(data.monitor.basic_info.b_mem)
$("#"+index+"_billing_disk_c").html(data.monitor.basic_info.c_disk)
$("#"+index+"_billing_port_d").html(data.monitor.basic_info.d_port)
var state = data.monitor.basic_info.State;
if(state == 'RUNNING')