add billing detail and billing history detail

This commit is contained in:
GallenShao 2017-12-04 11:52:45 +08:00
parent cfa073a85f
commit 8dc8cc2cb6
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 a_cpu = 500 # seconds
b_mem = 2000000 # MB b_mem = 2000000 # MB
c_disk = 4000 # MB c_disk = 4000 # MB
d_port = 1
# major dict to store the monitoring data # major dict to store the monitoring data
# only use on Master # only use on Master
@ -119,7 +120,12 @@ class Container_Collector(threading.Thread):
workercinfo[container] = {} workercinfo[container] = {}
workercinfo[container]['basic_info'] = {} workercinfo[container]['basic_info'] = {}
workercinfo[container]['basic_info']['billing'] = vnode.billing 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']['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: except:
laststopcpuval[container] = 0 laststopcpuval[container] = 0
laststopruntime[container] = 0 laststopruntime[container] = 0
@ -158,9 +164,10 @@ class Container_Collector(threading.Thread):
global a_cpu global a_cpu
global b_mem global b_mem
global c_disk global c_disk
global d_port
cpu_val = '0' cpu_val = '0'
if vnode_name not in workercinfo.keys(): if vnode_name not in workercinfo.keys():
return 0 return {'total': 0}
if 'cpu_use' in workercinfo[vnode_name].keys(): if 'cpu_use' in workercinfo[vnode_name].keys():
cpu_val = workercinfo[vnode_name]['cpu_use']['val'] cpu_val = workercinfo[vnode_name]['cpu_use']['val']
if vnode_name not in increment.keys(): if vnode_name not in increment.keys():
@ -182,13 +189,23 @@ class Container_Collector(threading.Thread):
# get ports # get ports
ports_count = count_port_mapping(vnode_name) ports_count = count_port_mapping(vnode_name)
# billing value = cpu used/a + memory used/b + disk quota/c + ports # 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: if billingval > 100:
# report outsize billing value # report outsize billing value
logger.info("Huge Billingval for "+vnode_name+". cpu_increment:"+str(cpu_increment)+" avemem:"+str(avemem)+" disk:"+str(disk_quota)+"\n") logger.info("Huge Billingval for "+vnode_name+". cpu_increment:"+str(cpu_increment)+" avemem:"+str(avemem)+" disk:"+str(disk_quota)+"\n")
if not isreal: if not isreal:
# only compute # only compute
return math.ceil(billingval) return billing
# initialize increment for next billing # initialize increment for next billing
increment[vnode_name]['lastcputime'] = cpu_val increment[vnode_name]['lastcputime'] = cpu_val
increment[vnode_name]['memincrement'] = 0 increment[vnode_name]['memincrement'] = 0
@ -200,6 +217,12 @@ class Container_Collector(threading.Thread):
nowbillingval = workercinfo[vnode_name]['basic_info']['billing'] nowbillingval = workercinfo[vnode_name]['basic_info']['billing']
nowbillingval += billingval nowbillingval += billingval
workercinfo[vnode_name]['basic_info']['billing'] = nowbillingval 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 # update vnodes' tables in database
try: try:
vnode = VNode.query.get(vnode_name) vnode = VNode.query.get(vnode_name)
@ -221,7 +244,7 @@ class Container_Collector(threading.Thread):
auth_key = env.getenv('AUTH_KEY') auth_key = env.getenv('AUTH_KEY')
data = {"owner_name":owner_name,"billing":billingval, "auth_key":auth_key} data = {"owner_name":owner_name,"billing":billingval, "auth_key":auth_key}
request_master("/billing/beans/",data) request_master("/billing/beans/",data)
return billingval return billing
# the main function to collect monitoring data of a container # the main function to collect monitoring data of a container
def collect_containerinfo(self,container_name): def collect_containerinfo(self,container_name):
@ -243,7 +266,7 @@ class Container_Collector(threading.Thread):
basic_info['RunningTime'] = 0 basic_info['RunningTime'] = 0
basic_info['billing'] = 0 basic_info['billing'] = 0
if 'billing_this_hour' not in basic_info.keys(): 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['Name'] = container_name
basic_info['State'] = container.state basic_info['State'] = container.state
#if basic_exist: #if basic_exist:
@ -524,22 +547,72 @@ def get_owner(container_name):
names = container_name.split('-') names = container_name.split('-')
return names[0] 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): def count_port_mapping(vnode_name):
user = get_owner(vnode_name) clusters_dir = env.getenv("FS_PREFIX")+"/global/users/"+get_owner(vnode_name)+"/clusters/"
fspath = env.getenv("FS_PREFIX") if not os.path.exists(clusters_dir):
if not os.path.exists(fspath+"/global/users/"+user+"/clusters"):
return 0 return 0
clusters = os.listdir(fspath+"/global/users/"+user+"/clusters") clusters = os.listdir(clusters_dir)
ports_count = 0 ports_count = 0
for cluster in clusters: for cluster in clusters:
clusterpath = fspath + "/global/users/" + get_owner(vnode_name) + "/clusters/" + cluster clusterpath = clusters_dir + cluster
if not os.path.isfile(clusterpath): if not os.path.isfile(clusterpath):
return 0 continue
infofile = open(clusterpath, 'r') infofile = open(clusterpath, 'r')
info = json.loads(infofile.read()) info = json.loads(infofile.read())
infofile.close()
ports_count += len([mapping for mapping in info['port_mapping'] if mapping['node_name'] == vnode_name]) ports_count += len([mapping for mapping in info['port_mapping'] if mapping['node_name'] == vnode_name])
return ports_count 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 # the thread to collect data from each worker and store them in monitor_hosts and monitor_vnodes
class Master_Collector(threading.Thread): class Master_Collector(threading.Thread):

View File

@ -15,6 +15,12 @@
</ol> </ol>
{% endblock %} {% 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 %} {% block content %}
<div class="row"> <div class="row">
<div class="col-md-12"> <div class="col-md-12">
@ -82,6 +88,105 @@
</div> </div>
<div class="box-body table-responsive"> <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></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"> <table class="table table-bordered">
<thead> <thead>
<tr> <tr>
@ -114,9 +219,9 @@
<td id='{{master.split("@")[1]}}_{{clustername}}_{{ loop.index }}_cpu'>--</td> <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 }}_mem'>--</td>
<td id='{{master.split("@")[1]}}_{{clustername}}_{{ loop.index }}_disk'>--</td> <td id='{{master.split("@")[1]}}_{{clustername}}_{{ loop.index }}_disk'>--</td>
<td id='{{master.split("@")[1]}}_{{clustername}}_{{ loop.index }}_billing'>--</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 id='{{master.split("@")[1]}}_{{clustername}}_{{ loop.index }}_billingthishour'>--</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> <td><a class="btn btn-info btn-xs" href='/vclusters/{{master.split("@")[0]}}/{{ clustername }}/{{ container['containername'] }}/'>Realtime</a></td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
@ -132,6 +237,11 @@
{% endblock %} {% endblock %}
{% block script_src %} {% 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'> <script type='text/javascript'>
function update(url,index) function update(url,index)
{ {
@ -152,8 +262,29 @@
var secs = Math.floor(total % 3600 % 60); var secs = Math.floor(total % 3600 % 60);
console.log(index,hour,min,secs); console.log(index,hour,min,secs);
$("#"+index+"_time").html(hour+"h "+min+"m "+secs+"s") $("#"+index+"_time").html(hour+"h "+min+"m "+secs+"s")
$("#"+index+"_billing").html(data.monitor.basic_info.billing+" <img src='/static/img/bean.png' />") $("#"+index+"_billing").html(data.monitor.basic_info.billing)
$("#"+index+"_billingthishour").html(data.monitor.basic_info.billing_this_hour+" <img src='/static/img/bean.png' />") $("#"+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; var state = data.monitor.basic_info.State;
if(state == 'RUNNING') if(state == 'RUNNING')