From c8608495b2ba9f5bcc599a75980a000cd3adf92b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=83=AD=E6=94=80?= Date: Tue, 13 Dec 2016 15:59:37 +0800 Subject: [PATCH 01/21] =?UTF-8?q?=E5=9F=BA=E6=9C=AC=E5=AE=8C=E6=88=90?= =?UTF-8?q?=E4=BA=86=E8=AE=A1=E7=AE=97=E8=B5=84=E6=BA=90=E7=94=A8=E9=87=8F?= =?UTF-8?q?=E7=9A=84=E5=90=8E=E5=8F=B0=E5=BC=80=E5=8F=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Aries/kd_agent/models.py | 53 +++++++++++++++ Aries/kd_agent/toolsmanager.py | 37 ++++++++++ Aries/kd_agent/urls.py | 2 + Aries/kd_agent/views.py | 120 ++++++++++++++++++++++++++++++++- 4 files changed, 210 insertions(+), 2 deletions(-) diff --git a/Aries/kd_agent/models.py b/Aries/kd_agent/models.py index 5795eeb..0699420 100644 --- a/Aries/kd_agent/models.py +++ b/Aries/kd_agent/models.py @@ -1 +1,54 @@ # -*- coding: UTF-8 -*- + +from django.db import models + +from kd_agent.toolsmanager import InfluxDBQueryStrManager as ISM + +class ResourceUsageCache(models.Model): + datetime = models.DateTimeField() + namespace = models.CharField( max_length=1024 ) + + cpu_request = models.BigIntegerField( default=0 ) + cpu_limit = models.BigIntegerField( default=0 ) + cpu_usage = models.BigIntegerField( default=0 ) + + # 这里的memory的workingset指标没有被保存。如果有需要,这里再保存一下即可 + memory_request = models.BigIntegerField( default=0 ) + memory_limit = models.BigIntegerField( default=0 ) + memory_usage = models.BigIntegerField( default=0 ) + + + # 方便地生成一个对象 + # data_json 是一个json对象,其中的key应该与 ISM 中定义的一致,如下 + # ISM.M_CPU_USAGE + # ISM.M_CPU_LIMIT + # ISM.M_CPU_REQUEST + # ISM.M_MEMORY_USAGE + # ISM.M_MEMORY_LIMIT + # ISM.M_MEMORY_REQUEST + @staticmethod + def generate_obj_by_measurement_key( datetime,namespace,data_json ): + keys_map = { + ISM.M_CPU_REQUEST:'cpu_request', + ISM.M_CPU_LIMIT:'cpu_limit', + ISM.M_CPU_USAGE:'cpu_usage', + ISM.M_MEMORY_REQUEST:'memory_request', + ISM.M_MEMORY_LIMIT:'memory_limit', + ISM.M_MEMORY_USAGE:'memory_usage', + } + obj = {} + for k,v in keys_map.items(): + obj[ v ] = data_json.get(k,0) + return ResourceUsageCache( datetime=datetime,namespace=namespace,**obj ) + + def to_measurement_keys(self): + return { + ISM.M_CPU_REQUEST:self.cpu_request, + ISM.M_CPU_LIMIT:self.cpu_limit, + ISM.M_CPU_USAGE:self.cpu_usage, + ISM.M_MEMORY_REQUEST:self.memory_request, + ISM.M_MEMORY_LIMIT:self.memory_limit, + ISM.M_MEMORY_USAGE:self.memory_usage, + } + + diff --git a/Aries/kd_agent/toolsmanager.py b/Aries/kd_agent/toolsmanager.py index bf8670f..380c4bd 100644 --- a/Aries/kd_agent/toolsmanager.py +++ b/Aries/kd_agent/toolsmanager.py @@ -127,6 +127,12 @@ class InfluxDBQueryStrManager: WHERE "type" = '{type}' AND "pod_namespace" = '{namespace}' AND "pod_name"='{pod_name}' AND time > {time_start} and time < {time_end} GROUP BY time(1m) fill(null)''' + # 这里本来应该直接 group by time(1440m) (汇总1天数据),但是不知道为什么汇总出来的是2条数据 + # 因此就降一级,按照小时汇总数据,然后吧所有数据都加起来 + SQL_NAMESPACE_RESOURCE_USAGE = '''SELECT sum("value") FROM "{measurement}" + WHERE "type" = '{type}' AND "pod_namespace" = '{namespace}' AND time >= {time_start} and time < {time_end} + GROUP BY time(60m) fill(null)''' + M_CPU_USAGE = 'cpu/usage_rate' M_CPU_LIMIT = 'cpu/limit' @@ -169,6 +175,16 @@ def format_namespace_poddetail_query_str(measurement,time_start ,time_end ,names type=InfluxDBQueryStrManager.T_POD, pod_name=pod_name) + @staticmethod + def format_namespace_resourceusage_query_str(measurement,time_start ,time_end ,namespace ): + return InfluxDBQueryStrManager.SQL_NAMESPACE_RESOURCE_USAGE.format( + measurement=measurement, + time_start=time_start, + time_end=time_end, + namespace=namespace, + type=InfluxDBQueryStrManager.T_POD) + + @staticmethod def get_measurement_disname_dict(): @@ -270,6 +286,27 @@ def get_namespace_poddetail_data( measurement,time_start,time_end,namespace,pod_ kd_logger.error( traceback_str ) return generate_failure( traceback_str ) + @staticmethod + def get_namespace_resourceusage_data( measurement,time_start,time_end,namespace ): + kd_logger.info( 'call get_namespace_resourceusage_data with args : %s %s %s %s' % (measurement,time_start,time_end,namespace) ) + try: + sql_str = InfluxDBQueryStrManager.format_namespace_resourceusage_query_str( + measurement=measurement, + time_start='%ss' % time_start , + time_end='%ss' % time_end, + namespace=namespace) + kd_logger.info( 'generate sql_str : %s' % (sql_str) ) + + retu_data = InfluxDBQueryStrManager.get_influxdb_data(sql_str=sql_str) + if retu_data['code'] == RETU_INFO_SUCCESS: + kd_logger.debug( 'get influxdb data by sql_str return data : %s' % retu_data['data'] ) + else: + kd_logger.error( 'get influxdb data by sql_str return error : %s' % retu_data['msg'] ) + return retu_data + except: + traceback_str = traceback.format_exc() + kd_logger.error( traceback_str ) + return generate_failure( traceback_str ) diff --git a/Aries/kd_agent/urls.py b/Aries/kd_agent/urls.py index 53b853b..a32761c 100644 --- a/Aries/kd_agent/urls.py +++ b/Aries/kd_agent/urls.py @@ -15,6 +15,8 @@ url(r'^api/namespaces/(?P\w{1,64})/replicationcontrollers/downloadjson$',views.download_rc_json), url(r'^apis/extensions/v1beta1/namespaces/(?P\w{1,64})/ingresses/downloadjson$',views.download_ingress_json ), + url(r'^api/namespaces/(?P\w{1,64})/resourceusage/$',views.resource_usage), + url(r'^api/namespaces/mytaskgraph$', views.get_mytask_graph), url(r'^download/$', views.download), url(r'^api/namespaces/mytasklist/getoldrecords', views.mytask_get_old_records), diff --git a/Aries/kd_agent/views.py b/Aries/kd_agent/views.py index 4cc401b..a300c9f 100644 --- a/Aries/kd_agent/views.py +++ b/Aries/kd_agent/views.py @@ -6,9 +6,14 @@ import requests import os import codecs +import math from django.http import StreamingHttpResponse -from datetime import datetime +from datetime import datetime,timedelta + +# 由于前面有 import time ,为了防止重名,因此这里改下名 +from datetime import time as datetime_time + from django.conf import settings from django.views.decorators.csrf import csrf_exempt from django.db.models import Q @@ -21,7 +26,7 @@ from kd_agent.toolsmanager import K8sRequestManager as KRM from kd_agent.toolsmanager import InfluxDBQueryStrManager as ISM - +from kd_agent.models import ResourceUsageCache kd_logger = logging.getLogger("kd_agent_log") @@ -705,6 +710,117 @@ def get_poddetail_filesystem_info(request,namespace,minutes): +def get_resource_usage_from_influxdb( start_date,end_date,namespace ): + # 由于传入的时间是local time,而influxdb中保存的时间戳是 utc time,因此需要做一个简单的转换 + s_timestamp = int(time.mktime( start_date.timetuple() )) + e_timestamp = int(time.mktime( end_date.timetuple() )) + + # 这里只计算CPU、Memory的 + measurements = [ ISM.M_CPU_USAGE,ISM.M_CPU_LIMIT,ISM.M_CPU_REQUEST ] + \ + [ ISM.M_MEMORY_USAGE,ISM.M_MEMORY_LIMIT,ISM.M_MEMORY_REQUEST ] + + retu_obj = {} + for m in measurements: + retu_data = ISM.get_namespace_resourceusage_data( m,s_timestamp,e_timestamp,namespace ) + + if retu_data['code'] != RETU_INFO_SUCCESS: + return retu_data + + # 如果某个space下,influxdb返回的 results 为是空数组,则表明数据库中没有该筛选条件下的数据,因此置为0 + try: + data_arr = [ item[1] if item[1] else 0 \ + for item in retu_data['data']['results'][0]['series'][0]['values'] ] + retu_obj[m] = sum(data_arr) + except Exception as e: + retu_obj[m] = 0 + + return generate_success( data = retu_obj ) + + +# 检查mysql数据库中是否已经缓存了数据。如果有,则直接返回;如果没有,则现查 +# 注意,如果 start_date 的年月日与今天的年月日相同,则直接查influxdb,而不存mysqk缓存 +def get_resource_usage_info( start_date,namespace ): + request_influxdb_data = lambda : get_resource_usage_from_influxdb( start_date,start_date+timedelta(seconds=24*60*60),namespace ) + + # 保证 start_date 时分秒都为0 + start_date = datetime.combine( start_date,datetime_time() ) + + + # 如果 start_date 与当前的年月日相同,则直接查询influxdb并返回,且不缓存数据到mysql + if start_date.strftime('%Y-%m-%d') == datetime.now().strftime('%Y-%m-%d'): + return request_influxdb_data() + else: + records = list(ResourceUsageCache.objects.filter( datetime=start_date,namespace=namespace )) + if len(records) == 0: + # 如果数据库中无缓存,则需要查询influxdb + retu_data = request_influxdb_data() + + # 查询失败,则直接返回 + if retu_data['code'] != RETU_INFO_SUCCESS: + return retu_data + + # 如果查询成功,但是缓存失败,也可以直接返回,而不做任何处理 + try: + ResourceUsageCache.generate_obj_by_measurement_key( start_date,namespace,retu_data['data'] ).save() + except: + pass + return retu_data + else: + return generate_success(data=records[0].to_measurement_keys()) + + +@csrf_exempt +@return_http_json +@trans_return_json +def resource_usage(request,namespace): + start_date_str = request.GET.get('startdate',datetime.now().strftime('%Y-%m-%d')) + days = request.GET.get('days',1) + + # 从时间字符串初始化一个datetime对象 + start_date = datetime.strptime( start_date_str,'%Y-%m-%d' ) + + retu_infos = [] + for index in range(days): + s = start_date+timedelta(seconds=24*60*60)*index + retu_data = get_resource_usage_info(s,namespace) + + if retu_data['code'] != RETU_INFO_SUCCESS: + return retu_data + + data_obj = retu_data['data'] + data_obj['usage'] = calc_virtual_machine_day( data_obj[ISM.M_CPU_USAGE],data_obj[ISM.M_MEMORY_USAGE] ) + + # date 是可以直接显示到页面上的日期(没有时分秒) + retu_infos.append({ + 'date':s.strftime('%Y-%m-%d'), + 'data':data_obj + }) + + return generate_success(data=retu_infos) + +# u 多少个0.5VCPU (1VCPU == cpu/1000 ,0.5VCPU是预设的值) +# v 多少个128MB内存 ( 128MB是预设的值 ) +# 计算公式为: u*0.025 + 0.003*v / (8*u) +# 同时,这个结果保留两位有效小数(0.01)(且直接进位) +# 即如果结果是 0.0212 则,应该显示 0.03 +def calc_virtual_machine_day( cpu_value,memory_value ): + u = cpu_value/1000/0.5 + v = memory_value/128/1024/1024 + try: + v = u*0.025 + 0.003*v / (8*u) + except: + v = 0 + + # 先放大100倍,然后向上取整。之后再缩小100倍。由于缩小之后,获取的数不会严格100倍,因此round一下 + # 如: + # >>> 1.3/10000 + # 0.00013000000000000002 + return round( math.ceil(v/0.01)*0.01,2 ) + + + + + From 2565b0b366e778ff69b0e85b1f13954784b80afb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=83=AD=E6=94=80?= Date: Wed, 14 Dec 2016 17:53:55 +0800 Subject: [PATCH 02/21] =?UTF-8?q?=E5=9F=BA=E6=9C=AC=E5=AE=8C=E6=88=90?= =?UTF-8?q?=E8=B5=84=E6=BA=90=E7=94=A8=E9=87=8F=E5=89=8D=E7=AB=AF=E9=A1=B5?= =?UTF-8?q?=E9=9D=A2=E7=9A=84=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Aries/kd_agent/urls.py | 2 +- Aries/kd_agent/views.py | 2 +- package/Aries/src/App.jsx | 1 + .../CalcManageDataRequester/requester.js | 10 + .../CalcManage/ClusterInfo/poddetail.jsx | 2 +- .../CalcManage/ResourceUsage/index.jsx | 312 ++++++++++++++++++ .../CalcManage/ResourceUsage/index.less | 31 ++ package/Aries/src/public/Conf/Conf.js | 7 + package/Aries/src/router.jsx | 6 + 9 files changed, 370 insertions(+), 3 deletions(-) create mode 100644 package/Aries/src/functions/CalcManage/ResourceUsage/index.jsx create mode 100644 package/Aries/src/functions/CalcManage/ResourceUsage/index.less diff --git a/Aries/kd_agent/urls.py b/Aries/kd_agent/urls.py index a32761c..f395f33 100644 --- a/Aries/kd_agent/urls.py +++ b/Aries/kd_agent/urls.py @@ -15,7 +15,7 @@ url(r'^api/namespaces/(?P\w{1,64})/replicationcontrollers/downloadjson$',views.download_rc_json), url(r'^apis/extensions/v1beta1/namespaces/(?P\w{1,64})/ingresses/downloadjson$',views.download_ingress_json ), - url(r'^api/namespaces/(?P\w{1,64})/resourceusage/$',views.resource_usage), + url(r'^api/namespaces/(?P\w{1,64})/resourceusage$',views.resource_usage), url(r'^api/namespaces/mytaskgraph$', views.get_mytask_graph), url(r'^download/$', views.download), diff --git a/Aries/kd_agent/views.py b/Aries/kd_agent/views.py index a300c9f..b96cef2 100644 --- a/Aries/kd_agent/views.py +++ b/Aries/kd_agent/views.py @@ -774,7 +774,7 @@ def get_resource_usage_info( start_date,namespace ): @trans_return_json def resource_usage(request,namespace): start_date_str = request.GET.get('startdate',datetime.now().strftime('%Y-%m-%d')) - days = request.GET.get('days',1) + days = int(request.GET.get('days',1)) # 从时间字符串初始化一个datetime对象 start_date = datetime.strptime( start_date_str,'%Y-%m-%d' ) diff --git a/package/Aries/src/App.jsx b/package/Aries/src/App.jsx index 94de6f2..6272613 100644 --- a/package/Aries/src/App.jsx +++ b/package/Aries/src/App.jsx @@ -162,6 +162,7 @@ const App = React.createClass({ + {/* 暂时下面没有任何节点,因此注释掉 diff --git a/package/Aries/src/functions/CalcManage/CalcManageDataRequester/requester.js b/package/Aries/src/functions/CalcManage/CalcManageDataRequester/requester.js index de04793..b7bf0d2 100644 --- a/package/Aries/src/functions/CalcManage/CalcManageDataRequester/requester.js +++ b/package/Aries/src/functions/CalcManage/CalcManageDataRequester/requester.js @@ -37,9 +37,19 @@ var CalcManageDataRequester = { 'rcjsondownload': '{baseUrl}v1/k8s/api/namespaces/{nameSpace}/replicationcontrollers/downloadjson?rcname={rcName}', 'ingressjsondownload': '{baseUrl}v1/k8s/apis/extensions/v1beta1/namespaces/{nameSpace}/ingresses/downloadjson?ingressname={ingressName}', + 'resourceusage': 'v1/k8s/api/namespaces/{nameSpace}/resourceusage?startdate={startdate}&days={days}' } }, + getResourceUsageInfo( nameSpace, startdate, days, callback){ + let url = Toolkit.strFormatter.formatString(this.getUrlForm()['resourceusage'],{ + 'nameSpace':nameSpace, + 'startdate': startdate, + 'days': days + }) + this.xhrGetDataEnhanced(url, callback) + }, + // 下载文件必须使用 button + url 的方式,不能使用ajax请求,因此这里只返回 url getPodJsonDownloadUrl(nameSpace, podName){ return Toolkit.strFormatter.formatString(this.getUrlForm()['podjsondownload'], { diff --git a/package/Aries/src/functions/CalcManage/ClusterInfo/poddetail.jsx b/package/Aries/src/functions/CalcManage/ClusterInfo/poddetail.jsx index 7e3485e..11596ba 100644 --- a/package/Aries/src/functions/CalcManage/ClusterInfo/poddetail.jsx +++ b/package/Aries/src/functions/CalcManage/ClusterInfo/poddetail.jsx @@ -220,7 +220,7 @@ var PodDetailElement = React.createClass({ let userUnSelectedPodDetailInfo = [['请选择Pod']] return( - + 容器基本信息 监控 diff --git a/package/Aries/src/functions/CalcManage/ResourceUsage/index.jsx b/package/Aries/src/functions/CalcManage/ResourceUsage/index.jsx new file mode 100644 index 0000000..00994f7 --- /dev/null +++ b/package/Aries/src/functions/CalcManage/ResourceUsage/index.jsx @@ -0,0 +1,312 @@ +import React from 'react' +import ReactDOM from 'react-dom' +import echarts from 'echarts' + +import { Tabs, TabList, Tab, TabPanel } from 'bfd/Tabs' +import FixedTable from 'bfd/FixedTable' + +import { AutoLayoutDiv , layoutInfoGenerator } from 'public/AutoLayout' +import NavigationInPage from 'public/NavigationInPage' +import Toolkit from 'public/Toolkit/index.js' +import ResourceMonitorEchart from 'public/ResourceMonitorEchart' + +import CMDR from '../CalcManageDataRequester/requester.js' +import CalcManageConf from '../UrlConf' +import './index.less' + + +var mod = React.createClass({ + + getInitialState(){ + let days = 90 + let today_start = new Date(Toolkit.generateTimeStrByMilliSeconds(-1).slice(0,'YYYY-MM-DD'.length)) + let start_date_str = Toolkit.generateTimeStrByMilliSeconds(today_start.getTime() - days*24*60*60*1000).slice(0,'YYYY-MM-DD'.length) + + return { + 'days':90, + 'startdate':start_date_str, + 'fixedTableDataList':[], + 'fixedTableHeight':0 + } + }, + componentWillMount(){ + this.initUserData() + }, + componentDidMount(){ + this.initCharts() + this.checkToRequestData() + }, + componentDidUpdate(){ + this.checkToRequestData() + }, + + checkToRequestData(){ + let curNameSpace = CMDR.getCurNameSpace(this) + if ( this.curNameSpace !== curNameSpace ){ + this.curNameSpace = curNameSpace + this.requestData() + } + }, + + onHeightChanged(newHeight){ + this.setState({'fixedTableHeight':newHeight-60}) + }, + + // 对cpu、memory、用量等数据进行进制转换、单位变换 + renderResourceUsageValue( v ){ + return v + ' 机器/天' + }, + // cpu数据的含义是毫核的个数,但是要求界面上展示虚拟核的个数,因此直接除以 1000 + renderCPUUsageValue(v){ + let toolTipInfo = this.userData['echartToolTipFormatterInfo']['cpu'] + return v/1000 + ' VCPU' + }, + renderMemoryUsageValue(v){ + let toolTipInfo = this.userData['echartToolTipFormatterInfo']['memory'] + return Toolkit.unitConversion( + v, + toolTipInfo['base'], + toolTipInfo['unitArr'], + toolTipInfo['significantFractionBit'] + ) + }, + + resetResourceUsageData(executedData){ + this.userData['resourceUsageData'] = executedData + + // 汇总echart的x、y轴数据 + let values = [] + let date_keys = [] + for ( let index = 0 ; index < executedData.length ; index ++ ){ + date_keys.push( executedData[index]['date'] ) + values.push( executedData[index]['data']['usage'] ) + } + this.userData['echartDatas'] = { + 'xAxisData':date_keys, + 'seriesData':values + } + + // 转换数据格式,方便 FixedTable 使用 + let toolTipInfo = this.userData['echartToolTipFormatterInfo'] + let fixedTableDataList = [] + for ( let i in executedData ){ + let curData = executedData[executedData.length-1-i] + + fixedTableDataList.push({ + 'Date':curData['date'], + 'ResourceUsage':this.renderResourceUsageValue(curData['data']['usage']), + 'CPUUsage':this.renderCPUUsageValue(curData['data'][toolTipInfo['cpu']['key']]), + 'MemoryUsage':this.renderMemoryUsageValue(curData['data'][toolTipInfo['memory']['key']]), + }) + } + this.userData['fixedTableDataList'] = fixedTableDataList + }, + + initUserData(){ + this.userData = { + 'echartObj':undefined, + 'echartTitleText':'资源用量', + 'resourceUsageData':undefined, + 'keywords':['cpu','memory'] + } + + this.userData['divIDs'] = { + rootDivID:Toolkit.generateGUID(), + navigationInPageID:Toolkit.generateGUID(), + tabPanelID:Toolkit.generateGUID(), + } + this.userData['autoLayoutInfos'] = [ + layoutInfoGenerator( this.userData['divIDs']['rootDivID'],true ), + layoutInfoGenerator( this.userData['divIDs']['navigationInPageID'],false,'Const' ), + layoutInfoGenerator( this.userData['divIDs']['tabPanelID'],false,'Var',( newHeight )=>{ + this.onHeightChanged( newHeight ) + } ), + ] + + this.userData['fixedTableColumn'] = [ + { title:'日期', key:'Date' }, + { title:'资源用量', key:'ResourceUsage' }, + { title:'CPU用量', key:'CPUUsage' }, + { title:'Memory用量', key:'MemoryUsage' }, + ] + this.userData['echartToolTipFormatterInfo'] = { + 'cpu':{ + 'name':'CPU用量', + 'key':'cpu/usage_rate', + 'renderFunc':this.renderCPUUsageValue, + }, + 'memory':{ + 'unitArr':['B','KiB','MiB','GiB','TiB','PiB'], + 'significantFractionBit':2, + 'base':1024, + + 'name':'Memory用量', + 'key':'memory/usage', + 'renderFunc':this.renderMemoryUsageValue, + }, + } + this.userData['echartTooltipFormatterFunc'] = ( params, ticket, callback ) => { + if ( !this.userData['resourceUsageData'] ){ + return + } + let dataInfo = this.userData['resourceUsageData'][params[0]['dataIndex']]['data'] + let templateStr = this.generateTooltipFormatterStr(3) + + let dataObj = {} + dataObj['time'] = params[0]['name'] + + // 计算好的资源用量 + dataObj['name'+0] = params[0]['seriesName'] + dataObj['value'+0] = this.renderResourceUsageValue(params[0]['data']) + + for ( let i = 0 ; i < this.userData['keywords'].length ; i ++ ){ + let k = this.userData['keywords'][i] + let toolTipInfo = this.userData['echartToolTipFormatterInfo'][k] + + dataObj['name'+(i+1)] = toolTipInfo['name'] + dataObj['value'+(i+1)] = toolTipInfo['renderFunc'](dataInfo[toolTipInfo['key']]) + } + return Toolkit.strFormatter.formatString( templateStr,dataObj) + } + + }, + + initCharts(){ + // 在没有加载到数据的时候,先显示出来空白的图标,这样会比较好看 + let initOptions = { + 'title': { + 'text': this.userData['echartTitleText'] + }, + toolbox: { + 'show':true, + 'feature':{ + 'mark':{ + 'show': true + }, + 'magicType':{ + 'show':true, + 'type':['line', 'bar'] + }, + } + }, + 'tooltip' : { + 'trigger': 'axis', + 'formatter': this.userData['echartTooltipFormatterFunc'] + }, + 'xAxis': [{ + 'type' : 'category', + 'data': [] + }], + 'yAxis':{ + 'axisLabel':{ + 'show':true, + //'formatter':undefined + } + }, + dataZoom: [{ + show: true, + start: 80, + end: 100 + }], + } + this.userData['echartObj'] = echarts.init(document.getElementById( 'ResourceUsageEchartDiv' )) + this.userData['echartObj'].setOption(initOptions) + }, + + requestData(){ + this.userData['echartObj'].showLoading() + this.setState({ 'fixedTableDataList':[] }) + CMDR.getResourceUsageInfo( + CMDR.getCurNameSpace(this), + this.state.startdate, + this.state.days+1, // +1,获取当天的用量 + (executedData)=>{ + this.userData['echartObj'].hideLoading() + this.resetResourceUsageData(executedData) + this.insertDataToEchart() + this.insertDataToTable() + } + ) + }, + + insertDataToEchart(){ + if (!this.userData['resourceUsageData']){ + return + } + this.userData['echartObj'].setOption({ + 'legend':{ + 'data':[this.userData['echartTitleText']] + }, + 'xAxis': { + 'type' : 'category', + 'position' : 'bottom', + 'boundaryGap': false, + 'data': this.userData['echartDatas']['xAxisData'] + }, + 'series': [{ + 'type': 'bar', + 'name':this.userData['echartTitleText'], + 'data':this.userData['echartDatas']['seriesData'], + }] + }) + }, + + insertDataToTable(){ + this.setState({ 'fixedTableDataList':this.userData['fixedTableDataList'] }) + }, + + generateTooltipFormatterStr( lineNumber ){ + let templateStr = '{time}' + for ( let i = 0 ; i < lineNumber ; i ++ ){ + templateStr += '' + templateStr += '{name'+i+'}' + templateStr += '' + templateStr += '{value'+i+'}' + templateStr += '' + } + return '' + templateStr + '
' + }, + + render: function() { + return ( +
+
+ +
+
+ + + + + + +
+ + +
+ +
+
+ +
+ +
+ ) + } +}); + + +export default mod; \ No newline at end of file diff --git a/package/Aries/src/functions/CalcManage/ResourceUsage/index.less b/package/Aries/src/functions/CalcManage/ResourceUsage/index.less new file mode 100644 index 0000000..a5a45ca --- /dev/null +++ b/package/Aries/src/functions/CalcManage/ResourceUsage/index.less @@ -0,0 +1,31 @@ + +div.ResourceUsageRootDiv{ + table.TooltipTable td.SpaceTdDistraction { + width: 10px; + } + + div.FixedTableFatherDiv { + padding-top:13px; // DataTable的表头文本距离上边框为17px + padding-left:20px; + padding-right:8px; + } + + div.cTabs{ + .bfd-tabs__list { + margin-top:-30px; + float: right; + border-bottom:0px + } + .bfd-tabs__list li a{ + background-color: #FFFFFF; + margin-right: 20px; + } + .bfd-tabs__list li a:hover , .nav.nav-tabs li a:focus{ + background-color: #FFFFFF; + border-bottom: 1.5px solid #00BFFF; + } + } + +} + + diff --git a/package/Aries/src/public/Conf/Conf.js b/package/Aries/src/public/Conf/Conf.js index ac27363..3f82d82 100644 --- a/package/Aries/src/public/Conf/Conf.js +++ b/package/Aries/src/public/Conf/Conf.js @@ -337,6 +337,13 @@ const conf = { url: "/CloudContainer/CalcManage/Overview?cur_space=${spaceName}" }] }, + ResourceUsage: { + headText: "资源用量", + navigationTexts: [{ + text: "资源用量", + url: "/CloudContainer/CalcManage/ResourceUsage?cur_space=${spaceName}" + }] + }, PodInfo: { headText: "Pod信息", navigationTexts: [{ diff --git a/package/Aries/src/router.jsx b/package/Aries/src/router.jsx index a08934d..fdd9614 100644 --- a/package/Aries/src/router.jsx +++ b/package/Aries/src/router.jsx @@ -104,6 +104,12 @@ export default render(( cb(null, require('./functions/CalcManage/ClusterInfo/ingressinfo').default) }) }}/> + { + require.ensure([], require => { + cb(null, require('./functions/CalcManage/ResourceUsage').default) + }) + }}/> + { From 42ddddebaafab9bf17bfe642d83bf693f0eebebd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=83=AD=E6=94=80?= Date: Wed, 14 Dec 2016 18:26:26 +0800 Subject: [PATCH 03/21] =?UTF-8?q?=E5=89=8D=E7=AB=AF=E9=A1=B5=E9=9D=A2?= =?UTF-8?q?=E6=A0=B7=E5=BC=8F=E5=BE=AE=E8=B0=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CalcManage/ResourceUsage/index.jsx | 10 ++++--- .../CalcManage/ResourceUsage/index.less | 28 ++++++++++++++----- 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/package/Aries/src/functions/CalcManage/ResourceUsage/index.jsx b/package/Aries/src/functions/CalcManage/ResourceUsage/index.jsx index 00994f7..278c1fc 100644 --- a/package/Aries/src/functions/CalcManage/ResourceUsage/index.jsx +++ b/package/Aries/src/functions/CalcManage/ResourceUsage/index.jsx @@ -49,7 +49,7 @@ var mod = React.createClass({ }, onHeightChanged(newHeight){ - this.setState({'fixedTableHeight':newHeight-60}) + this.setState({'fixedTableHeight':newHeight}) }, // 对cpu、memory、用量等数据进行进制转换、单位变换 @@ -58,7 +58,6 @@ var mod = React.createClass({ }, // cpu数据的含义是毫核的个数,但是要求界面上展示虚拟核的个数,因此直接除以 1000 renderCPUUsageValue(v){ - let toolTipInfo = this.userData['echartToolTipFormatterInfo']['cpu'] return v/1000 + ' VCPU' }, renderMemoryUsageValue(v){ @@ -289,12 +288,15 @@ var mod = React.createClass({ -
+
+
+
diff --git a/package/Aries/src/functions/CalcManage/ResourceUsage/index.less b/package/Aries/src/functions/CalcManage/ResourceUsage/index.less index a5a45ca..d159475 100644 --- a/package/Aries/src/functions/CalcManage/ResourceUsage/index.less +++ b/package/Aries/src/functions/CalcManage/ResourceUsage/index.less @@ -4,15 +4,8 @@ div.ResourceUsageRootDiv{ width: 10px; } - div.FixedTableFatherDiv { - padding-top:13px; // DataTable的表头文本距离上边框为17px - padding-left:20px; - padding-right:8px; - } - div.cTabs{ .bfd-tabs__list { - margin-top:-30px; float: right; border-bottom:0px } @@ -26,6 +19,27 @@ div.ResourceUsageRootDiv{ } } + div.ResourceUsageEchartFatherDiv{ + overflow-y: auto; + margin:auto; + width: 100%; + } + + div#ResourceUsageEchartDiv{ + margin:auto; + width:1000px; + height:500px; + padding-top: 40px; + } + div.FixedTableFatherDiv { + padding-top:13px; // DataTable的表头文本距离上边框为17px + border: 1px solid #ECECEC; + } + + div#ResourceUsageEchartDiv , div.FixedTableFatherDiv{ + margin-top: 30px; + } + } From 70097b0eca5810ebec76d50341aef68478f0df3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=83=AD=E6=94=80?= Date: Mon, 19 Dec 2016 10:54:45 +0800 Subject: [PATCH 04/21] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E8=B5=84=E6=BA=90?= =?UTF-8?q?=E7=94=A8=E9=87=8F=E9=A1=B5=E9=9D=A2=E5=B1=95=E7=A4=BA=E7=9A=84?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=EF=BC=88=E4=B9=8B=E5=89=8D=E6=98=AF=E5=B1=95?= =?UTF-8?q?=E7=A4=BA=E6=8C=87=E6=A0=87=E7=9A=84usage=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=EF=BC=8C=E4=BD=86=E5=AE=9E=E9=99=85=E4=B8=8A=E5=BA=94=E8=AF=A5?= =?UTF-8?q?=E5=B1=95=E7=A4=BArequest=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Aries/kd_agent/views.py | 31 ++++++++++++------- .../CalcManage/ResourceUsage/index.jsx | 8 ++--- 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/Aries/kd_agent/views.py b/Aries/kd_agent/views.py index b96cef2..c045e54 100644 --- a/Aries/kd_agent/views.py +++ b/Aries/kd_agent/views.py @@ -709,7 +709,7 @@ def get_poddetail_filesystem_info(request,namespace,minutes): return execute_clusterinfo_request( data_dict,time_range ) - +# 这里获取某个时间段内,cpu、memory相应指标的总和 def get_resource_usage_from_influxdb( start_date,end_date,namespace ): # 由于传入的时间是local time,而influxdb中保存的时间戳是 utc time,因此需要做一个简单的转换 s_timestamp = int(time.mktime( start_date.timetuple() )) @@ -737,23 +737,23 @@ def get_resource_usage_from_influxdb( start_date,end_date,namespace ): return generate_success( data = retu_obj ) -# 检查mysql数据库中是否已经缓存了数据。如果有,则直接返回;如果没有,则现查 -# 注意,如果 start_date 的年月日与今天的年月日相同,则直接查influxdb,而不存mysqk缓存 +# 1. 检查mysql数据库中是否已经缓存了数据。如果有,则直接返回;如果没有,则现查 +# 注意,如果 start_date 的年月日与今天的年月日相同,则直接查influxdb,而不存mysql缓存 +# 2. get_resource_usage_from_influxdb 返回的值是相应指标的总和,即将1天内24×60个分钟的采样数据全部加起来; +# 但是计算使用量所需要的是1天内平均每分钟的指标值。之所以缓存的值也是总和,是为了防止浮点存储数据不一致的为题( 0.1+0.2 == 0.3 返回False ) def get_resource_usage_info( start_date,namespace ): - request_influxdb_data = lambda : get_resource_usage_from_influxdb( start_date,start_date+timedelta(seconds=24*60*60),namespace ) - # 保证 start_date 时分秒都为0 start_date = datetime.combine( start_date,datetime_time() ) + end_date = start_date+timedelta(seconds=24*60*60) - - # 如果 start_date 与当前的年月日相同,则直接查询influxdb并返回,且不缓存数据到mysql - if start_date.strftime('%Y-%m-%d') == datetime.now().strftime('%Y-%m-%d'): - return request_influxdb_data() + # 如果 start_date 与当前的年月日相同或者大,则直接查询influxdb并返回,且不缓存数据到mysql + if start_date >= datetime.combine( datetime.now(),datetime_time() ): + return get_resource_usage_from_influxdb( start_date,end_date,namespace ) else: records = list(ResourceUsageCache.objects.filter( datetime=start_date,namespace=namespace )) if len(records) == 0: # 如果数据库中无缓存,则需要查询influxdb - retu_data = request_influxdb_data() + retu_data = get_resource_usage_from_influxdb( start_date,end_date,namespace ) # 查询失败,则直接返回 if retu_data['code'] != RETU_INFO_SUCCESS: @@ -788,8 +788,17 @@ def resource_usage(request,namespace): return retu_data data_obj = retu_data['data'] - data_obj['usage'] = calc_virtual_machine_day( data_obj[ISM.M_CPU_USAGE],data_obj[ISM.M_MEMORY_USAGE] ) + # 将获取到的指标数据的总和在分钟上进行平均,得到每分钟的指标值 + measurements = [ ISM.M_CPU_USAGE,ISM.M_CPU_LIMIT,ISM.M_CPU_REQUEST ] + \ + [ ISM.M_MEMORY_USAGE,ISM.M_MEMORY_LIMIT,ISM.M_MEMORY_REQUEST ] + for m in measurements: + data_obj[m] = data_obj[m]/(24*60) + + data_obj['usage'] = calc_virtual_machine_day( data_obj[ISM.M_CPU_USAGE],data_obj[ISM.M_MEMORY_USAGE] ) + data_obj['limit'] = calc_virtual_machine_day( data_obj[ISM.M_CPU_LIMIT],data_obj[ISM.M_MEMORY_LIMIT] ) + data_obj['request'] = calc_virtual_machine_day( data_obj[ISM.M_CPU_REQUEST],data_obj[ISM.M_MEMORY_REQUEST] ) + # date 是可以直接显示到页面上的日期(没有时分秒) retu_infos.append({ 'date':s.strftime('%Y-%m-%d'), diff --git a/package/Aries/src/functions/CalcManage/ResourceUsage/index.jsx b/package/Aries/src/functions/CalcManage/ResourceUsage/index.jsx index 278c1fc..868f059 100644 --- a/package/Aries/src/functions/CalcManage/ResourceUsage/index.jsx +++ b/package/Aries/src/functions/CalcManage/ResourceUsage/index.jsx @@ -78,7 +78,7 @@ var mod = React.createClass({ let date_keys = [] for ( let index = 0 ; index < executedData.length ; index ++ ){ date_keys.push( executedData[index]['date'] ) - values.push( executedData[index]['data']['usage'] ) + values.push( executedData[index]['data']['request'] ) } this.userData['echartDatas'] = { 'xAxisData':date_keys, @@ -93,7 +93,7 @@ var mod = React.createClass({ fixedTableDataList.push({ 'Date':curData['date'], - 'ResourceUsage':this.renderResourceUsageValue(curData['data']['usage']), + 'ResourceUsage':this.renderResourceUsageValue(curData['data']['request']), 'CPUUsage':this.renderCPUUsageValue(curData['data'][toolTipInfo['cpu']['key']]), 'MemoryUsage':this.renderMemoryUsageValue(curData['data'][toolTipInfo['memory']['key']]), }) @@ -131,7 +131,7 @@ var mod = React.createClass({ this.userData['echartToolTipFormatterInfo'] = { 'cpu':{ 'name':'CPU用量', - 'key':'cpu/usage_rate', + 'key':'cpu/request', 'renderFunc':this.renderCPUUsageValue, }, 'memory':{ @@ -140,7 +140,7 @@ var mod = React.createClass({ 'base':1024, 'name':'Memory用量', - 'key':'memory/usage', + 'key':'memory/request', 'renderFunc':this.renderMemoryUsageValue, }, } From 00f359f28521293ea4883a63b58bb424bb53412f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=83=AD=E6=94=80?= Date: Mon, 19 Dec 2016 14:22:55 +0800 Subject: [PATCH 05/21] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E8=AE=A1=E7=AE=97?= =?UTF-8?q?=E7=94=A8=E9=87=8F=E6=97=B6=E6=95=B4=E6=95=B0=E9=99=A4=E5=BE=97?= =?UTF-8?q?0=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Aries/kd_agent/views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Aries/kd_agent/views.py b/Aries/kd_agent/views.py index c045e54..60c9518 100644 --- a/Aries/kd_agent/views.py +++ b/Aries/kd_agent/views.py @@ -813,8 +813,8 @@ def resource_usage(request,namespace): # 同时,这个结果保留两位有效小数(0.01)(且直接进位) # 即如果结果是 0.0212 则,应该显示 0.03 def calc_virtual_machine_day( cpu_value,memory_value ): - u = cpu_value/1000/0.5 - v = memory_value/128/1024/1024 + u = float(cpu_value)/1000/0.5 + v = float(memory_value)/128/1024/1024 try: v = u*0.025 + 0.003*v / (8*u) except: From eaebad28ac4feb1e692a38c694163d61e3967641 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=83=AD=E6=94=80?= Date: Mon, 19 Dec 2016 16:13:14 +0800 Subject: [PATCH 06/21] =?UTF-8?q?=E8=B5=84=E6=BA=90=E7=94=A8=E9=87=8F?= =?UTF-8?q?=E5=90=8E=E5=8F=B0=E9=87=8D=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Aries/kd_agent/models.py | 49 ++++++++++++++++++++++++++++++++++++++-- Aries/kd_agent/views.py | 36 ++++------------------------- 2 files changed, 51 insertions(+), 34 deletions(-) diff --git a/Aries/kd_agent/models.py b/Aries/kd_agent/models.py index 0699420..912f430 100644 --- a/Aries/kd_agent/models.py +++ b/Aries/kd_agent/models.py @@ -1,10 +1,12 @@ # -*- coding: UTF-8 -*- from django.db import models +import math + from kd_agent.toolsmanager import InfluxDBQueryStrManager as ISM -class ResourceUsageCache(models.Model): +class ResourceUsageDailyCache(models.Model): datetime = models.DateTimeField() namespace = models.CharField( max_length=1024 ) @@ -17,7 +19,13 @@ class ResourceUsageCache(models.Model): memory_limit = models.BigIntegerField( default=0 ) memory_usage = models.BigIntegerField( default=0 ) + # 注意,上面的 cpu、memory 指标数据是相对比较原始的数据,即将 1 天内 1440 个分钟的采样数据全部加起来 + # 但是下面的 request、limit、usage 数据是经过计算之后得到的(calc_virtual_machine_day) + request = models.FloatField() + limit = models.FloatField() + usage = models.FloatField() + # 方便地生成一个对象 # data_json 是一个json对象,其中的key应该与 ISM 中定义的一致,如下 # ISM.M_CPU_USAGE @@ -28,6 +36,8 @@ class ResourceUsageCache(models.Model): # ISM.M_MEMORY_REQUEST @staticmethod def generate_obj_by_measurement_key( datetime,namespace,data_json ): + RUDC = ResourceUsageDailyCache + keys_map = { ISM.M_CPU_REQUEST:'cpu_request', ISM.M_CPU_LIMIT:'cpu_limit', @@ -39,7 +49,13 @@ def generate_obj_by_measurement_key( datetime,namespace,data_json ): obj = {} for k,v in keys_map.items(): obj[ v ] = data_json.get(k,0) - return ResourceUsageCache( datetime=datetime,namespace=namespace,**obj ) + + # 根据提供的cpu、memory、usage数据来计算资源用量 + obj['usage'] = RUDC.calc_virtual_machine_day( obj['cpu_usage'],obj['memory_usage'] ) + obj['limit'] = RUDC.calc_virtual_machine_day( obj['cpu_limit'],obj['memory_limit'] ) + obj['request'] = RUDC.calc_virtual_machine_day( obj['cpu_request'],obj['memory_request'] ) + + return RUDC( datetime=datetime,namespace=namespace,**obj ) def to_measurement_keys(self): return { @@ -49,6 +65,35 @@ def to_measurement_keys(self): ISM.M_MEMORY_REQUEST:self.memory_request, ISM.M_MEMORY_LIMIT:self.memory_limit, ISM.M_MEMORY_USAGE:self.memory_usage, + 'request':self.request, + 'limit':self.limit, + 'usage':self.usage, } + # u 多少个0.5VCPU (1VCPU == cpu/1000 ,0.5VCPU是预设的值) + # v 多少个128MB内存 ( 128MB是预设的值 ) + # 计算公式为: u*0.025 + 0.003*v / (8*u) + # 同时,这个结果保留两位有效小数(0.01)(且直接进位) + # 即如果结果是 0.0212 则,应该显示 0.03 + @staticmethod + def calc_virtual_machine_day( cpu_value,memory_value ): + # 先计算出来平均值 + cpu_value = float(cpu_value)/(24*60) + memory_value = float(memory_value)/(24*60) + + u = cpu_value/1000/0.5 + v = memory_value/128/1024/1024 + try: + v = u*0.025 + 0.003*v / (8*u) + except: + v = 0 + + # 先放大100倍,然后向上取整。之后再缩小100倍。由于缩小之后,获取的数不会严格100倍,因此round一下 + # 如: + # >>> 1.3/10000 + # 0.00013000000000000002 + return round( math.ceil(v/0.01)*0.01,2 ) + + + diff --git a/Aries/kd_agent/views.py b/Aries/kd_agent/views.py index 60c9518..1f9b3c8 100644 --- a/Aries/kd_agent/views.py +++ b/Aries/kd_agent/views.py @@ -6,7 +6,6 @@ import requests import os import codecs -import math from django.http import StreamingHttpResponse from datetime import datetime,timedelta @@ -26,7 +25,7 @@ from kd_agent.toolsmanager import K8sRequestManager as KRM from kd_agent.toolsmanager import InfluxDBQueryStrManager as ISM -from kd_agent.models import ResourceUsageCache +from kd_agent.models import ResourceUsageDailyCache kd_logger = logging.getLogger("kd_agent_log") @@ -750,7 +749,7 @@ def get_resource_usage_info( start_date,namespace ): if start_date >= datetime.combine( datetime.now(),datetime_time() ): return get_resource_usage_from_influxdb( start_date,end_date,namespace ) else: - records = list(ResourceUsageCache.objects.filter( datetime=start_date,namespace=namespace )) + records = list(ResourceUsageDailyCache.objects.filter( datetime=start_date,namespace=namespace )) if len(records) == 0: # 如果数据库中无缓存,则需要查询influxdb retu_data = get_resource_usage_from_influxdb( start_date,end_date,namespace ) @@ -761,7 +760,7 @@ def get_resource_usage_info( start_date,namespace ): # 如果查询成功,但是缓存失败,也可以直接返回,而不做任何处理 try: - ResourceUsageCache.generate_obj_by_measurement_key( start_date,namespace,retu_data['data'] ).save() + ResourceUsageDailyCache.generate_obj_by_measurement_key( start_date,namespace,retu_data['data'] ).save() except: pass return retu_data @@ -788,16 +787,6 @@ def resource_usage(request,namespace): return retu_data data_obj = retu_data['data'] - - # 将获取到的指标数据的总和在分钟上进行平均,得到每分钟的指标值 - measurements = [ ISM.M_CPU_USAGE,ISM.M_CPU_LIMIT,ISM.M_CPU_REQUEST ] + \ - [ ISM.M_MEMORY_USAGE,ISM.M_MEMORY_LIMIT,ISM.M_MEMORY_REQUEST ] - for m in measurements: - data_obj[m] = data_obj[m]/(24*60) - - data_obj['usage'] = calc_virtual_machine_day( data_obj[ISM.M_CPU_USAGE],data_obj[ISM.M_MEMORY_USAGE] ) - data_obj['limit'] = calc_virtual_machine_day( data_obj[ISM.M_CPU_LIMIT],data_obj[ISM.M_MEMORY_LIMIT] ) - data_obj['request'] = calc_virtual_machine_day( data_obj[ISM.M_CPU_REQUEST],data_obj[ISM.M_MEMORY_REQUEST] ) # date 是可以直接显示到页面上的日期(没有时分秒) retu_infos.append({ @@ -807,24 +796,7 @@ def resource_usage(request,namespace): return generate_success(data=retu_infos) -# u 多少个0.5VCPU (1VCPU == cpu/1000 ,0.5VCPU是预设的值) -# v 多少个128MB内存 ( 128MB是预设的值 ) -# 计算公式为: u*0.025 + 0.003*v / (8*u) -# 同时,这个结果保留两位有效小数(0.01)(且直接进位) -# 即如果结果是 0.0212 则,应该显示 0.03 -def calc_virtual_machine_day( cpu_value,memory_value ): - u = float(cpu_value)/1000/0.5 - v = float(memory_value)/128/1024/1024 - try: - v = u*0.025 + 0.003*v / (8*u) - except: - v = 0 - - # 先放大100倍,然后向上取整。之后再缩小100倍。由于缩小之后,获取的数不会严格100倍,因此round一下 - # 如: - # >>> 1.3/10000 - # 0.00013000000000000002 - return round( math.ceil(v/0.01)*0.01,2 ) + From f6ff3f0f0438d60d94d642112719f0d2aefb6409 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=83=AD=E6=94=80?= Date: Mon, 19 Dec 2016 17:37:39 +0800 Subject: [PATCH 07/21] =?UTF-8?q?=E8=B5=84=E6=BA=90=E7=94=A8=E9=87=8F?= =?UTF-8?q?=E5=90=8E=E5=8F=B0=E9=87=8D=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Aries/kd_agent/models.py | 42 +++++++++++++++++++++------------------- Aries/kd_agent/views.py | 28 ++++++++++++++------------- 2 files changed, 37 insertions(+), 33 deletions(-) diff --git a/Aries/kd_agent/models.py b/Aries/kd_agent/models.py index 912f430..6272185 100644 --- a/Aries/kd_agent/models.py +++ b/Aries/kd_agent/models.py @@ -26,6 +26,8 @@ class ResourceUsageDailyCache(models.Model): limit = models.FloatField() usage = models.FloatField() + calc_minute_ave = lambda v:float(v)/(24*60) + # 方便地生成一个对象 # data_json 是一个json对象,其中的key应该与 ISM 中定义的一致,如下 # ISM.M_CPU_USAGE @@ -36,8 +38,6 @@ class ResourceUsageDailyCache(models.Model): # ISM.M_MEMORY_REQUEST @staticmethod def generate_obj_by_measurement_key( datetime,namespace,data_json ): - RUDC = ResourceUsageDailyCache - keys_map = { ISM.M_CPU_REQUEST:'cpu_request', ISM.M_CPU_LIMIT:'cpu_limit', @@ -49,22 +49,26 @@ def generate_obj_by_measurement_key( datetime,namespace,data_json ): obj = {} for k,v in keys_map.items(): obj[ v ] = data_json.get(k,0) - + return ResourceUsageDailyCache.generate_obj_by_base_keys( datetime,namespace,obj ) + + @staticmethod + def generate_obj_by_base_keys( datetime,namespace,obj ): + CVMD = ResourceUsageDailyCache.calc_virtual_machine_day # 根据提供的cpu、memory、usage数据来计算资源用量 - obj['usage'] = RUDC.calc_virtual_machine_day( obj['cpu_usage'],obj['memory_usage'] ) - obj['limit'] = RUDC.calc_virtual_machine_day( obj['cpu_limit'],obj['memory_limit'] ) - obj['request'] = RUDC.calc_virtual_machine_day( obj['cpu_request'],obj['memory_request'] ) - - return RUDC( datetime=datetime,namespace=namespace,**obj ) + obj['usage'] = CVMD( obj['cpu_usage'],obj['memory_usage'] ) + obj['limit'] = CVMD( obj['cpu_limit'],obj['memory_limit'] ) + obj['request'] = CVMD( obj['cpu_request'],obj['memory_request'] ) + return ResourceUsageDailyCache( datetime=datetime,namespace=namespace,**obj ) - def to_measurement_keys(self): + def to_minuteaverge_measurementkey_json(self): + CMA = ResourceUsageDailyCache.calc_minute_ave return { - ISM.M_CPU_REQUEST:self.cpu_request, - ISM.M_CPU_LIMIT:self.cpu_limit, - ISM.M_CPU_USAGE:self.cpu_usage, - ISM.M_MEMORY_REQUEST:self.memory_request, - ISM.M_MEMORY_LIMIT:self.memory_limit, - ISM.M_MEMORY_USAGE:self.memory_usage, + ISM.M_CPU_REQUEST:CMA(self.cpu_request), + ISM.M_CPU_LIMIT:CMA(self.cpu_limit), + ISM.M_CPU_USAGE:CMA(self.cpu_usage), + ISM.M_MEMORY_REQUEST:CMA(self.memory_request), + ISM.M_MEMORY_LIMIT:CMA(self.memory_limit), + ISM.M_MEMORY_USAGE:CMA(self.memory_usage), 'request':self.request, 'limit':self.limit, 'usage':self.usage, @@ -77,12 +81,10 @@ def to_measurement_keys(self): # 即如果结果是 0.0212 则,应该显示 0.03 @staticmethod def calc_virtual_machine_day( cpu_value,memory_value ): - # 先计算出来平均值 - cpu_value = float(cpu_value)/(24*60) - memory_value = float(memory_value)/(24*60) + CMA = ResourceUsageDailyCache.calc_minute_ave - u = cpu_value/1000/0.5 - v = memory_value/128/1024/1024 + u = CMA(cpu_value)/1000/0.5 + v = CMA(memory_value)/128/1024/1024 try: v = u*0.025 + 0.003*v / (8*u) except: diff --git a/Aries/kd_agent/views.py b/Aries/kd_agent/views.py index 1f9b3c8..9b41f25 100644 --- a/Aries/kd_agent/views.py +++ b/Aries/kd_agent/views.py @@ -25,7 +25,7 @@ from kd_agent.toolsmanager import K8sRequestManager as KRM from kd_agent.toolsmanager import InfluxDBQueryStrManager as ISM -from kd_agent.models import ResourceUsageDailyCache +from kd_agent.models import ResourceUsageDailyCache as RUDC kd_logger = logging.getLogger("kd_agent_log") @@ -736,10 +736,8 @@ def get_resource_usage_from_influxdb( start_date,end_date,namespace ): return generate_success( data = retu_obj ) -# 1. 检查mysql数据库中是否已经缓存了数据。如果有,则直接返回;如果没有,则现查 -# 注意,如果 start_date 的年月日与今天的年月日相同,则直接查influxdb,而不存mysql缓存 -# 2. get_resource_usage_from_influxdb 返回的值是相应指标的总和,即将1天内24×60个分钟的采样数据全部加起来; -# 但是计算使用量所需要的是1天内平均每分钟的指标值。之所以缓存的值也是总和,是为了防止浮点存储数据不一致的为题( 0.1+0.2 == 0.3 返回False ) +# 检查mysql数据库中是否已经缓存了数据。如果有,则直接返回;如果没有,则现查 +# 注意,如果 start_date 的年月日与今天的年月日相同,则直接查influxdb,而不存mysql缓存 def get_resource_usage_info( start_date,namespace ): # 保证 start_date 时分秒都为0 start_date = datetime.combine( start_date,datetime_time() ) @@ -747,9 +745,14 @@ def get_resource_usage_info( start_date,namespace ): # 如果 start_date 与当前的年月日相同或者大,则直接查询influxdb并返回,且不缓存数据到mysql if start_date >= datetime.combine( datetime.now(),datetime_time() ): - return get_resource_usage_from_influxdb( start_date,end_date,namespace ) + retu_data = get_resource_usage_from_influxdb( start_date,end_date,namespace ) + if retu_data['code'] != RETU_INFO_SUCCESS: + return retu_data + else: + obj = RUDC.generate_obj_by_measurement_key( start_date,namespace,retu_data['data'] ) + return generate_success( data=obj.to_minuteaverge_measurementkey_json() ) else: - records = list(ResourceUsageDailyCache.objects.filter( datetime=start_date,namespace=namespace )) + records = list(RUDC.objects.filter( datetime=start_date,namespace=namespace )) if len(records) == 0: # 如果数据库中无缓存,则需要查询influxdb retu_data = get_resource_usage_from_influxdb( start_date,end_date,namespace ) @@ -759,13 +762,14 @@ def get_resource_usage_info( start_date,namespace ): return retu_data # 如果查询成功,但是缓存失败,也可以直接返回,而不做任何处理 + obj = RUDC.generate_obj_by_measurement_key( start_date,namespace,retu_data['data'] ) try: - ResourceUsageDailyCache.generate_obj_by_measurement_key( start_date,namespace,retu_data['data'] ).save() + obj.save() except: pass - return retu_data + return generate_success(data=obj.to_minuteaverge_measurementkey_json()) else: - return generate_success(data=records[0].to_measurement_keys()) + return generate_success(data=records[0].to_minuteaverge_measurementkey_json()) @csrf_exempt @@ -786,12 +790,10 @@ def resource_usage(request,namespace): if retu_data['code'] != RETU_INFO_SUCCESS: return retu_data - data_obj = retu_data['data'] - # date 是可以直接显示到页面上的日期(没有时分秒) retu_infos.append({ 'date':s.strftime('%Y-%m-%d'), - 'data':data_obj + 'data':retu_data['data'] }) return generate_success(data=retu_infos) From 19b1ccbd26820be4f088bd5cfe1c9afbe74d15cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=83=AD=E6=94=80?= Date: Mon, 19 Dec 2016 18:09:41 +0800 Subject: [PATCH 08/21] =?UTF-8?q?=E8=A7=A3=E5=86=B3=E5=90=8E=E5=8F=B0pytho?= =?UTF-8?q?n=E7=9A=84=E4=B8=80=E4=B8=AA=E5=87=BD=E6=95=B0=E8=B0=83?= =?UTF-8?q?=E7=94=A8=E5=A4=B1=E8=B4=A5=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Aries/kd_agent/models.py | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/Aries/kd_agent/models.py b/Aries/kd_agent/models.py index 6272185..41fc45c 100644 --- a/Aries/kd_agent/models.py +++ b/Aries/kd_agent/models.py @@ -6,6 +6,9 @@ from kd_agent.toolsmanager import InfluxDBQueryStrManager as ISM +def calc_minute_ave(v): + return float(v)/(24*60) + class ResourceUsageDailyCache(models.Model): datetime = models.DateTimeField() namespace = models.CharField( max_length=1024 ) @@ -26,8 +29,6 @@ class ResourceUsageDailyCache(models.Model): limit = models.FloatField() usage = models.FloatField() - calc_minute_ave = lambda v:float(v)/(24*60) - # 方便地生成一个对象 # data_json 是一个json对象,其中的key应该与 ISM 中定义的一致,如下 # ISM.M_CPU_USAGE @@ -61,14 +62,13 @@ def generate_obj_by_base_keys( datetime,namespace,obj ): return ResourceUsageDailyCache( datetime=datetime,namespace=namespace,**obj ) def to_minuteaverge_measurementkey_json(self): - CMA = ResourceUsageDailyCache.calc_minute_ave return { - ISM.M_CPU_REQUEST:CMA(self.cpu_request), - ISM.M_CPU_LIMIT:CMA(self.cpu_limit), - ISM.M_CPU_USAGE:CMA(self.cpu_usage), - ISM.M_MEMORY_REQUEST:CMA(self.memory_request), - ISM.M_MEMORY_LIMIT:CMA(self.memory_limit), - ISM.M_MEMORY_USAGE:CMA(self.memory_usage), + ISM.M_CPU_REQUEST:calc_minute_ave(self.cpu_request), + ISM.M_CPU_LIMIT:calc_minute_ave(self.cpu_limit), + ISM.M_CPU_USAGE:calc_minute_ave(self.cpu_usage), + ISM.M_MEMORY_REQUEST:calc_minute_ave(self.memory_request), + ISM.M_MEMORY_LIMIT:calc_minute_ave(self.memory_limit), + ISM.M_MEMORY_USAGE:calc_minute_ave(self.memory_usage), 'request':self.request, 'limit':self.limit, 'usage':self.usage, @@ -81,10 +81,9 @@ def to_minuteaverge_measurementkey_json(self): # 即如果结果是 0.0212 则,应该显示 0.03 @staticmethod def calc_virtual_machine_day( cpu_value,memory_value ): - CMA = ResourceUsageDailyCache.calc_minute_ave - u = CMA(cpu_value)/1000/0.5 - v = CMA(memory_value)/128/1024/1024 + u = calc_minute_ave(cpu_value)/1000/0.5 + v = calc_minute_ave(memory_value)/128/1024/1024 try: v = u*0.025 + 0.003*v / (8*u) except: From 3b4c44b1abbfc8dfa0563f08200b8e43ef75e7d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=83=AD=E6=94=80?= Date: Mon, 19 Dec 2016 18:27:30 +0800 Subject: [PATCH 09/21] =?UTF-8?q?=E5=89=8D=E7=AB=AF=E9=A1=B5=E9=9D=A2?= =?UTF-8?q?=E5=B0=8F=E6=95=B0=E8=BF=9B=E8=A1=8C=E5=9B=9B=E8=88=8D=E4=BA=94?= =?UTF-8?q?=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/functions/CalcManage/ResourceUsage/index.jsx | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/package/Aries/src/functions/CalcManage/ResourceUsage/index.jsx b/package/Aries/src/functions/CalcManage/ResourceUsage/index.jsx index 868f059..3e3087a 100644 --- a/package/Aries/src/functions/CalcManage/ResourceUsage/index.jsx +++ b/package/Aries/src/functions/CalcManage/ResourceUsage/index.jsx @@ -17,6 +17,10 @@ import './index.less' var mod = React.createClass({ + fix(v){ + return Number(v).toFixed(2) + }, + getInitialState(){ let days = 90 let today_start = new Date(Toolkit.generateTimeStrByMilliSeconds(-1).slice(0,'YYYY-MM-DD'.length)) @@ -54,11 +58,11 @@ var mod = React.createClass({ // 对cpu、memory、用量等数据进行进制转换、单位变换 renderResourceUsageValue( v ){ - return v + ' 机器/天' + return this.fix(v) + ' 机器/天' }, // cpu数据的含义是毫核的个数,但是要求界面上展示虚拟核的个数,因此直接除以 1000 renderCPUUsageValue(v){ - return v/1000 + ' VCPU' + return this.fix(v/1000) + ' VCPU' }, renderMemoryUsageValue(v){ let toolTipInfo = this.userData['echartToolTipFormatterInfo']['memory'] @@ -78,7 +82,7 @@ var mod = React.createClass({ let date_keys = [] for ( let index = 0 ; index < executedData.length ; index ++ ){ date_keys.push( executedData[index]['date'] ) - values.push( executedData[index]['data']['request'] ) + values.push( this.fix(executedData[index]['data']['request']) ) } this.userData['echartDatas'] = { 'xAxisData':date_keys, From f3844a03f3f6838ea1f64b2d6bc5d098c6d5185d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=83=AD=E6=94=80?= Date: Mon, 26 Dec 2016 16:37:07 +0800 Subject: [PATCH 10/21] =?UTF-8?q?=E5=AF=B9=E8=B5=84=E6=BA=90=E7=94=A8?= =?UTF-8?q?=E9=87=8F=E9=A1=B5=E9=9D=A2=E8=BF=9B=E8=A1=8C=E6=8B=86=E5=88=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package/Aries/src/App.jsx | 3 +- .../CalcManage/ResourceUsageBilling/index.jsx | 178 ++++++++++++++++++ .../ResourceUsageBilling/index.less | 15 ++ .../index.jsx | 74 ++------ .../index.less | 2 +- package/Aries/src/public/Conf/Conf.js | 15 +- package/Aries/src/router.jsx | 9 +- 7 files changed, 228 insertions(+), 68 deletions(-) create mode 100644 package/Aries/src/functions/CalcManage/ResourceUsageBilling/index.jsx create mode 100644 package/Aries/src/functions/CalcManage/ResourceUsageBilling/index.less rename package/Aries/src/functions/CalcManage/{ResourceUsage => ResourceUsageRecently}/index.jsx (74%) rename package/Aries/src/functions/CalcManage/{ResourceUsage => ResourceUsageRecently}/index.less (96%) diff --git a/package/Aries/src/App.jsx b/package/Aries/src/App.jsx index 6272613..61234d3 100644 --- a/package/Aries/src/App.jsx +++ b/package/Aries/src/App.jsx @@ -162,7 +162,8 @@ const App = React.createClass({ - + + {/* 暂时下面没有任何节点,因此注释掉 diff --git a/package/Aries/src/functions/CalcManage/ResourceUsageBilling/index.jsx b/package/Aries/src/functions/CalcManage/ResourceUsageBilling/index.jsx new file mode 100644 index 0000000..dd89c97 --- /dev/null +++ b/package/Aries/src/functions/CalcManage/ResourceUsageBilling/index.jsx @@ -0,0 +1,178 @@ +import React from 'react' +import ReactDOM from 'react-dom' + +import FixedTable from 'bfd/FixedTable' + +import { AutoLayoutDiv , layoutInfoGenerator } from 'public/AutoLayout' +import NavigationInPage from 'public/NavigationInPage' +import Toolkit from 'public/Toolkit/index.js' + +import CMDR from '../CalcManageDataRequester/requester.js' +import CalcManageConf from '../UrlConf' +import './index.less' + + +var mod = React.createClass({ + + fix(v){ + return Number(v).toFixed(2) + }, + + getInitialState(){ + let days = 90 + let today_start = new Date(Toolkit.generateTimeStrByMilliSeconds(-1).slice(0,'YYYY-MM-DD'.length)) + let start_date_str = Toolkit.generateTimeStrByMilliSeconds(today_start.getTime() - days*24*60*60*1000).slice(0,'YYYY-MM-DD'.length) + + return { + 'days':days+1, // +1,获取当天的用量 + 'startdate':start_date_str, + 'fixedTableDataList':[], + 'fixedTableHeight':0 + } + }, + componentWillMount(){ + this.initUserData() + }, + componentDidMount(){ + this.checkToRequestData() + }, + componentDidUpdate(){ + this.checkToRequestData() + }, + + checkToRequestData(){ + let curNameSpace = CMDR.getCurNameSpace(this) + if ( this.curNameSpace !== curNameSpace ){ + this.curNameSpace = curNameSpace + this.requestData() + } + }, + + onHeightChanged(newHeight){ + this.setState({'fixedTableHeight':newHeight}) + }, + + // 对cpu、memory、用量等数据进行进制转换、单位变换 + renderResourceUsageValue( v ){ + return this.fix(v) + ' 机器/天' + }, + // cpu数据的含义是毫核的个数,但是要求界面上展示虚拟核的个数,因此直接除以 1000 + renderCPUUsageValue(v){ + return this.fix(v/1000) + ' VCPU' + }, + renderMemoryUsageValue(v){ + let toolTipInfo = this.userData['dataFormatterInfo']['memory'] + return Toolkit.unitConversion( + v, + toolTipInfo['base'], + toolTipInfo['unitArr'], + toolTipInfo['significantFractionBit'] + ) + }, + + resetResourceUsageData(executedData){ + this.userData['resourceUsageData'] = executedData + + // 转换数据格式,方便 FixedTable 使用 + let toolTipInfo = this.userData['dataFormatterInfo'] + let fixedTableDataList = [] + for ( let i in executedData ){ + let curData = executedData[executedData.length-1-i] + + fixedTableDataList.push({ + 'Date':curData['date'], + 'ResourceUsage':this.renderResourceUsageValue(curData['data']['request']), + 'CPUUsage':this.renderCPUUsageValue(curData['data'][toolTipInfo['cpu']['key']]), + 'MemoryUsage':this.renderMemoryUsageValue(curData['data'][toolTipInfo['memory']['key']]), + }) + } + this.userData['fixedTableDataList'] = fixedTableDataList + }, + + initUserData(){ + this.userData = { + 'resourceUsageData':undefined, + 'keywords':['cpu','memory'] + } + + this.userData['divIDs'] = { + rootDivID:Toolkit.generateGUID(), + navigationInPageID:Toolkit.generateGUID(), + FixedTableFatherDivID:Toolkit.generateGUID(), + } + this.userData['autoLayoutInfos'] = [ + layoutInfoGenerator( this.userData['divIDs']['rootDivID'],true ), + layoutInfoGenerator( this.userData['divIDs']['navigationInPageID'],false,'Const' ), + layoutInfoGenerator( this.userData['divIDs']['FixedTableFatherDivID'],false,'Var',( newHeight )=>{ + this.onHeightChanged( newHeight ) + } ), + ] + + this.userData['fixedTableColumn'] = [ + { title:'日期', key:'Date' }, + { title:'资源用量', key:'ResourceUsage' }, + { title:'CPU用量', key:'CPUUsage' }, + { title:'Memory用量', key:'MemoryUsage' }, + ] + this.userData['dataFormatterInfo'] = { + 'cpu':{ + 'name':'CPU用量', + 'key':'cpu/request', + 'renderFunc':this.renderCPUUsageValue, + }, + 'memory':{ + 'unitArr':['B','KiB','MiB','GiB','TiB','PiB'], + 'significantFractionBit':2, + 'base':1024, + + 'name':'Memory用量', + 'key':'memory/request', + 'renderFunc':this.renderMemoryUsageValue, + }, + } + }, + + + requestData(){ + this.setState({ 'fixedTableDataList':[] }) + CMDR.getResourceUsageInfo( + CMDR.getCurNameSpace(this), + this.state.startdate, + this.state.days, + (executedData)=>{ + this.resetResourceUsageData(executedData) + this.setState({ 'fixedTableDataList':this.userData['fixedTableDataList'] }) + } + ) + }, + + render: function() { + return ( +
+
+ +
+
+ +
+ +
+ ) + } +}); + + +export default mod; \ No newline at end of file diff --git a/package/Aries/src/functions/CalcManage/ResourceUsageBilling/index.less b/package/Aries/src/functions/CalcManage/ResourceUsageBilling/index.less new file mode 100644 index 0000000..bc889d5 --- /dev/null +++ b/package/Aries/src/functions/CalcManage/ResourceUsageBilling/index.less @@ -0,0 +1,15 @@ + +div.ResourceUsageBillingRootDiv{ + + div.FixedTableFatherDiv { + padding-top:30px; // DataTable的表头文本距离上边框为17px + + > * { + border: 1px solid #ECECEC; + } + } + + +} + + diff --git a/package/Aries/src/functions/CalcManage/ResourceUsage/index.jsx b/package/Aries/src/functions/CalcManage/ResourceUsageRecently/index.jsx similarity index 74% rename from package/Aries/src/functions/CalcManage/ResourceUsage/index.jsx rename to package/Aries/src/functions/CalcManage/ResourceUsageRecently/index.jsx index 3e3087a..2fef770 100644 --- a/package/Aries/src/functions/CalcManage/ResourceUsage/index.jsx +++ b/package/Aries/src/functions/CalcManage/ResourceUsageRecently/index.jsx @@ -3,7 +3,6 @@ import ReactDOM from 'react-dom' import echarts from 'echarts' import { Tabs, TabList, Tab, TabPanel } from 'bfd/Tabs' -import FixedTable from 'bfd/FixedTable' import { AutoLayoutDiv , layoutInfoGenerator } from 'public/AutoLayout' import NavigationInPage from 'public/NavigationInPage' @@ -27,10 +26,9 @@ var mod = React.createClass({ let start_date_str = Toolkit.generateTimeStrByMilliSeconds(today_start.getTime() - days*24*60*60*1000).slice(0,'YYYY-MM-DD'.length) return { - 'days':90, + 'days':days+1, // +1,获取当天的用量 'startdate':start_date_str, - 'fixedTableDataList':[], - 'fixedTableHeight':0 + 'echartFatherDivHeight':0, } }, componentWillMount(){ @@ -53,7 +51,7 @@ var mod = React.createClass({ }, onHeightChanged(newHeight){ - this.setState({'fixedTableHeight':newHeight}) + this.setState({'echartFatherDivHeight':newHeight}) }, // 对cpu、memory、用量等数据进行进制转换、单位变换 @@ -88,21 +86,6 @@ var mod = React.createClass({ 'xAxisData':date_keys, 'seriesData':values } - - // 转换数据格式,方便 FixedTable 使用 - let toolTipInfo = this.userData['echartToolTipFormatterInfo'] - let fixedTableDataList = [] - for ( let i in executedData ){ - let curData = executedData[executedData.length-1-i] - - fixedTableDataList.push({ - 'Date':curData['date'], - 'ResourceUsage':this.renderResourceUsageValue(curData['data']['request']), - 'CPUUsage':this.renderCPUUsageValue(curData['data'][toolTipInfo['cpu']['key']]), - 'MemoryUsage':this.renderMemoryUsageValue(curData['data'][toolTipInfo['memory']['key']]), - }) - } - this.userData['fixedTableDataList'] = fixedTableDataList }, initUserData(){ @@ -116,22 +99,16 @@ var mod = React.createClass({ this.userData['divIDs'] = { rootDivID:Toolkit.generateGUID(), navigationInPageID:Toolkit.generateGUID(), - tabPanelID:Toolkit.generateGUID(), + echartFatherDivID:Toolkit.generateGUID(), } this.userData['autoLayoutInfos'] = [ layoutInfoGenerator( this.userData['divIDs']['rootDivID'],true ), layoutInfoGenerator( this.userData['divIDs']['navigationInPageID'],false,'Const' ), - layoutInfoGenerator( this.userData['divIDs']['tabPanelID'],false,'Var',( newHeight )=>{ + layoutInfoGenerator( this.userData['divIDs']['echartFatherDivID'],false,'Var',( newHeight )=>{ this.onHeightChanged( newHeight ) } ), ] - this.userData['fixedTableColumn'] = [ - { title:'日期', key:'Date' }, - { title:'资源用量', key:'ResourceUsage' }, - { title:'CPU用量', key:'CPUUsage' }, - { title:'Memory用量', key:'MemoryUsage' }, - ] this.userData['echartToolTipFormatterInfo'] = { 'cpu':{ 'name':'CPU用量', @@ -218,16 +195,14 @@ var mod = React.createClass({ requestData(){ this.userData['echartObj'].showLoading() - this.setState({ 'fixedTableDataList':[] }) CMDR.getResourceUsageInfo( CMDR.getCurNameSpace(this), this.state.startdate, - this.state.days+1, // +1,获取当天的用量 + this.state.days, (executedData)=>{ this.userData['echartObj'].hideLoading() this.resetResourceUsageData(executedData) this.insertDataToEchart() - this.insertDataToTable() } ) }, @@ -254,10 +229,6 @@ var mod = React.createClass({ }) }, - insertDataToTable(){ - this.setState({ 'fixedTableDataList':this.userData['fixedTableDataList'] }) - }, - generateTooltipFormatterStr( lineNumber ){ let templateStr = '{time}' for ( let i = 0 ; i < lineNumber ; i ++ ){ @@ -272,41 +243,24 @@ var mod = React.createClass({ render: function() { return ( -
+
-
- - - - - - -
-
-
- - -
- -
-
- +
+
+
+
diff --git a/package/Aries/src/functions/CalcManage/ResourceUsage/index.less b/package/Aries/src/functions/CalcManage/ResourceUsageRecently/index.less similarity index 96% rename from package/Aries/src/functions/CalcManage/ResourceUsage/index.less rename to package/Aries/src/functions/CalcManage/ResourceUsageRecently/index.less index d159475..8d8b5f7 100644 --- a/package/Aries/src/functions/CalcManage/ResourceUsage/index.less +++ b/package/Aries/src/functions/CalcManage/ResourceUsageRecently/index.less @@ -1,5 +1,5 @@ -div.ResourceUsageRootDiv{ +div.ResourceUsageRecentlyRootDiv{ table.TooltipTable td.SpaceTdDistraction { width: 10px; } diff --git a/package/Aries/src/public/Conf/Conf.js b/package/Aries/src/public/Conf/Conf.js index 3f82d82..e4e62ed 100644 --- a/package/Aries/src/public/Conf/Conf.js +++ b/package/Aries/src/public/Conf/Conf.js @@ -337,13 +337,20 @@ const conf = { url: "/CloudContainer/CalcManage/Overview?cur_space=${spaceName}" }] }, - ResourceUsage: { - headText: "资源用量", + ResourceUsageRecently: { + headText: "资源用量-近期", navigationTexts: [{ - text: "资源用量", - url: "/CloudContainer/CalcManage/ResourceUsage?cur_space=${spaceName}" + text: "资源用量-近期", + url: "/CloudContainer/CalcManage/ResourceUsageRecently?cur_space=${spaceName}" }] }, + ResourceUsageBilling: { + headText: "资源用量-账单", + navigationTexts: [{ + text: "资源用量-账单", + url: "/CloudContainer/CalcManage/ResourceUsageBilling?cur_space=${spaceName}" + }] + }, PodInfo: { headText: "Pod信息", navigationTexts: [{ diff --git a/package/Aries/src/router.jsx b/package/Aries/src/router.jsx index fdd9614..54a7378 100644 --- a/package/Aries/src/router.jsx +++ b/package/Aries/src/router.jsx @@ -104,9 +104,14 @@ export default render(( cb(null, require('./functions/CalcManage/ClusterInfo/ingressinfo').default) }) }}/> - { + { require.ensure([], require => { - cb(null, require('./functions/CalcManage/ResourceUsage').default) + cb(null, require('./functions/CalcManage/ResourceUsageRecently').default) + }) + }}/> + { + require.ensure([], require => { + cb(null, require('./functions/CalcManage/ResourceUsageBilling').default) }) }}/> From 3cb8845b3de29f7c681ee5f6718cb78de35669d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=83=AD=E6=94=80?= Date: Wed, 28 Dec 2016 14:38:51 +0800 Subject: [PATCH 11/21] =?UTF-8?q?=E8=B5=84=E6=BA=90=E7=94=A8=E9=87=8F-?= =?UTF-8?q?=E8=B4=A6=E5=8D=95=E9=A1=B5=E9=9D=A2=E7=9A=84=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CalcManage/ResourceUsageBilling/index.jsx | 137 ++++++++++++++---- .../ResourceUsageBilling/index.less | 30 +++- package/Aries/src/public/Toolkit/index.js | 18 +++ 3 files changed, 153 insertions(+), 32 deletions(-) diff --git a/package/Aries/src/functions/CalcManage/ResourceUsageBilling/index.jsx b/package/Aries/src/functions/CalcManage/ResourceUsageBilling/index.jsx index dd89c97..c8f925b 100644 --- a/package/Aries/src/functions/CalcManage/ResourceUsageBilling/index.jsx +++ b/package/Aries/src/functions/CalcManage/ResourceUsageBilling/index.jsx @@ -2,10 +2,13 @@ import React from 'react' import ReactDOM from 'react-dom' import FixedTable from 'bfd/FixedTable' +import message from 'bfd/message' +import MonthSelectControl from 'public/MonthSelectControl' import { AutoLayoutDiv , layoutInfoGenerator } from 'public/AutoLayout' import NavigationInPage from 'public/NavigationInPage' import Toolkit from 'public/Toolkit/index.js' +import Button from 'bfd/Button' import CMDR from '../CalcManageDataRequester/requester.js' import CalcManageConf from '../UrlConf' @@ -19,13 +22,7 @@ var mod = React.createClass({ }, getInitialState(){ - let days = 90 - let today_start = new Date(Toolkit.generateTimeStrByMilliSeconds(-1).slice(0,'YYYY-MM-DD'.length)) - let start_date_str = Toolkit.generateTimeStrByMilliSeconds(today_start.getTime() - days*24*60*60*1000).slice(0,'YYYY-MM-DD'.length) - return { - 'days':days+1, // +1,获取当天的用量 - 'startdate':start_date_str, 'fixedTableDataList':[], 'fixedTableHeight':0 } @@ -33,19 +30,9 @@ var mod = React.createClass({ componentWillMount(){ this.initUserData() }, - componentDidMount(){ - this.checkToRequestData() - }, - componentDidUpdate(){ - this.checkToRequestData() - }, - checkToRequestData(){ - let curNameSpace = CMDR.getCurNameSpace(this) - if ( this.curNameSpace !== curNameSpace ){ - this.curNameSpace = curNameSpace - this.requestData() - } + componentDidMount(){ + this.onSearchButtonClicked() }, onHeightChanged(newHeight){ @@ -76,6 +63,11 @@ var mod = React.createClass({ // 转换数据格式,方便 FixedTable 使用 let toolTipInfo = this.userData['dataFormatterInfo'] let fixedTableDataList = [] + + let totalBilling = 0.0 + let totalCPU = 0.0 + let totalMemory = 0.0 + for ( let i in executedData ){ let curData = executedData[executedData.length-1-i] @@ -85,8 +77,15 @@ var mod = React.createClass({ 'CPUUsage':this.renderCPUUsageValue(curData['data'][toolTipInfo['cpu']['key']]), 'MemoryUsage':this.renderMemoryUsageValue(curData['data'][toolTipInfo['memory']['key']]), }) + totalBilling += curData['data']['request'] + totalCPU += curData['data'][toolTipInfo['cpu']['key']] + totalMemory += curData['data'][toolTipInfo['memory']['key']] } this.userData['fixedTableDataList'] = fixedTableDataList + this.userData['totalBilling'] = this.renderResourceUsageValue(totalBilling) + this.userData['totalCPU'] = this.renderCPUUsageValue(totalCPU) + this.userData['totalMemory'] = this.renderMemoryUsageValue(totalMemory) + return fixedTableDataList }, initUserData(){ @@ -97,12 +96,16 @@ var mod = React.createClass({ this.userData['divIDs'] = { rootDivID:Toolkit.generateGUID(), - navigationInPageID:Toolkit.generateGUID(), + navigationInPageID:Toolkit.generateGUID(), + monthSelectControlID:Toolkit.generateGUID(), + billingTitleDivID:Toolkit.generateGUID(), FixedTableFatherDivID:Toolkit.generateGUID(), } this.userData['autoLayoutInfos'] = [ layoutInfoGenerator( this.userData['divIDs']['rootDivID'],true ), layoutInfoGenerator( this.userData['divIDs']['navigationInPageID'],false,'Const' ), + layoutInfoGenerator( this.userData['divIDs']['monthSelectControlID'],false,'Const' ), + layoutInfoGenerator( this.userData['divIDs']['billingTitleDivID'],false,'Const' ), layoutInfoGenerator( this.userData['divIDs']['FixedTableFatherDivID'],false,'Var',( newHeight )=>{ this.onHeightChanged( newHeight ) } ), @@ -132,21 +135,49 @@ var mod = React.createClass({ } }, - - requestData(){ + requestData( startDate,days ){ this.setState({ 'fixedTableDataList':[] }) - CMDR.getResourceUsageInfo( - CMDR.getCurNameSpace(this), - this.state.startdate, - this.state.days, - (executedData)=>{ - this.resetResourceUsageData(executedData) - this.setState({ 'fixedTableDataList':this.userData['fixedTableDataList'] }) - } + CMDR.getResourceUsageInfo( CMDR.getCurNameSpace(this),startDate,days,(executedData)=>{ + this.resetResourceUsageData(executedData) + this.setState({ 'fixedTableDataList':this.userData['fixedTableDataList'] }) + }) + }, + + checkDateValid(dateStr){ + let date = new Date(dateStr) + let curDate = new Date() + if ( date.getFullYear() > curDate.getFullYear() ){ + return false + } else if ( date.getFullYear() == curDate.getFullYear() ){ + return (date.getMonth() < curDate.getMonth()) + } else { + return true + } + }, + + onSearchButtonClicked(){ + let dateStr = this.refs.MonthSelectControlRef.getDate() + if ( !this.checkDateValid(dateStr) ){ + message.danger( '指定月份的账单尚未生成' ) + return + } + + this.requestData( + dateStr.slice(0,'YYYY-MM-DD'.length), + Toolkit.calcMonthDays(dateStr) ) }, render: function() { + let lastMonthDate = new Date(new Date().getTime() - Toolkit.calcMonthDays(new Date())*24*60*60*1000) + let defaultSearchDateStr = Toolkit.generateTimeStrByMilliSeconds(lastMonthDate.getTime()).slice( 0,'YYYY-MM'.length ) + + let dStr = this.refs.MonthSelectControlRef ? this.refs.MonthSelectControlRef.getValue() : defaultSearchDateStr + let billingTitle = Toolkit.strFormatter.formatString('{date} {nameSpace} 账单信息',{ + 'nameSpace':CalcManageConf.getCurSpace(this), + 'date':dStr.split('-').join('年') + '月' + }) + return (
@@ -161,9 +192,53 @@ var mod = React.createClass({ spaceName:CalcManageConf.getCurSpace(this) })} />
-
+
+ + + + + + + + + + +
+
+
+

{billingTitle}

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
空间{CalcManageConf.getCurSpace(this)}
总账单{this.userData['totalBilling']}
总CPU{this.userData['totalCPU']}
总内存{this.userData['totalMemory']}
+
+
diff --git a/package/Aries/src/functions/CalcManage/ResourceUsageBilling/index.less b/package/Aries/src/functions/CalcManage/ResourceUsageBilling/index.less index bc889d5..f7fa1e5 100644 --- a/package/Aries/src/functions/CalcManage/ResourceUsageBilling/index.less +++ b/package/Aries/src/functions/CalcManage/ResourceUsageBilling/index.less @@ -1,11 +1,39 @@ div.ResourceUsageBillingRootDiv{ + .MiddleBillingBlock{ + width: 60%; + margin-left: auto; + margin-right: auto; + } + + table.BillingOverviewInfoTable{ + font-size: 15px; + font-weight: bold; + td:nth-child(1){ width: 10px; } + td:nth-child(3){ width: 30px; } + } + + table.SearchLayoutTable{ + width: 100%; + + td:nth-child(1){ width:38% } + td:nth-child(2){ width:10% } + td:nth-child(3){ width:4% } + td:nth-child(4){ width:15% } + td:nth-child(5){ width:33% } + } + + div.FixedTableFatherDiv { - padding-top:30px; // DataTable的表头文本距离上边框为17px + padding-top:10px; // DataTable的表头文本距离上边框为17px > * { border: 1px solid #ECECEC; + padding-top: 42px; + th > div{ + margin-top: 12px; + } } } diff --git a/package/Aries/src/public/Toolkit/index.js b/package/Aries/src/public/Toolkit/index.js index 87fe445..9df84e0 100644 --- a/package/Aries/src/public/Toolkit/index.js +++ b/package/Aries/src/public/Toolkit/index.js @@ -2,6 +2,24 @@ var Toolkit = { + // 计算某年某月共多少天 + calcMonthDays(date){ + if (date){ + date = new Date(date) + } else { + date = new Date() + } + let biggerDays = 0 + while ( date.getMonth() == new Date(date.getTime()+biggerDays*24*60*60*1000).getMonth() ){ + biggerDays += 1 + } + let smallerDays = 0 + while ( date.getMonth() == new Date(date.getTime()-smallerDays*24*60*60*1000).getMonth() ){ + smallerDays += 1 + } + return biggerDays+smallerDays-1 + }, + // 传入开始时间字符串,计算出开始时间距离现在大约多长时间 calcAge(createTime){ if ( !createTime ){ From 9a52d79e3696d8296ec6bab7457b1fe847f112ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=83=AD=E6=94=80?= Date: Wed, 28 Dec 2016 16:33:57 +0800 Subject: [PATCH 12/21] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E6=9C=88=E4=BB=BD?= =?UTF-8?q?=E9=80=89=E6=8B=A9=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/public/MonthSelectControl/index.jsx | 182 ++++++++++++++++++ .../src/public/MonthSelectControl/index.less | 67 +++++++ 2 files changed, 249 insertions(+) create mode 100644 package/Aries/src/public/MonthSelectControl/index.jsx create mode 100644 package/Aries/src/public/MonthSelectControl/index.less diff --git a/package/Aries/src/public/MonthSelectControl/index.jsx b/package/Aries/src/public/MonthSelectControl/index.jsx new file mode 100644 index 0000000..1cf9444 --- /dev/null +++ b/package/Aries/src/public/MonthSelectControl/index.jsx @@ -0,0 +1,182 @@ + +import React from 'react' +import ReactDOM from 'react-dom' + +import { Dropdown, DropdownToggle, DropdownMenu } from 'bfd/Dropdown' +import { Select, Option } from 'bfd/Select' +import Input from 'bfd/Input' +import Button from 'bfd/Button' + +import './index.less' + +/* +月份选择控件: +输入: + years 年份数组,比如 [2015,2016,2017] ,如果不传,则将会默认展示过去四年的年份 + defaultValue 默认年月,比如 '2016-11' ,如果不传,则使用当前的年月 + onChange 当用户更改日期的时候的回调函数 +输出: + 可以通过该组建的 ref 来调用 getValue 函数,即可返回用户选择的年月,返回的格式为: 2016-12(字符串) + 也可以通过该组建的 ref 来调用 getDate 函数,即可返回用户选择的年月所对应的Date对象(该年月第一天的凌晨) + +*/ + +var MonthSelectControl = React.createClass({ + + getInitialState(){ + return { + 'dropdownOpenState':false, + 'hasBindButtonCallBack':false, + 'inputValue':'', + } + }, + + executePropInfo( propYears,propDefaultDateStr ){ + + let years = [] + if ( propYears ){ + years = propYears + } else { + let curYear = ( new Date() ).getFullYear() + for ( let i = 3 ; i >= 0 ; i -- ){ + years.push( curYear-i ) + } + } + + let defaultDate = propDefaultDateStr ? (new Date(propDefaultDateStr)) : (new Date()) + let defaultYear = defaultDate.getFullYear() + if ( years.indexOf( defaultYear ) == -1 ){ + defaultYear = years[years.length-1] + } + + return { + 'years':years, + 'defaultYear':defaultYear, + 'defaultMonth':defaultDate.getMonth()+1 + } + }, + + componentWillMount(){ + this.userData = {} + + this.userData['monthInfoList'] = [ + ['01','02','03','04'], + ['05','06','07','08'], + ['09','10','11','12'] + ] + + this.userData['executedPropInfos'] = this.executePropInfo(this.props.years,this.props.defaultValue) + this.state.inputValue = this.combineDateInfo( + this.userData['executedPropInfos']['defaultYear'], + this.userData['executedPropInfos']['defaultMonth'] + ) + + this.userData['selectInfos'] = { + 'selectedYear':undefined, + 'selectedMonth':undefined, + } + }, + + componentDidMount(){ + ReactDOM.findDOMNode( this.refs.InputRef ).addEventListener( 'click',()=>{ + this.refs.PleaseSelectMonthControlDropDownRef.setState({ 'dropdownOpenState':true }) + + // js是单线程的,因此setState之后并不会马上进入setState的回调函数中,因此这里过500ms再进行绑定 + setTimeout( ()=>{ this.bindButtonClickCallBack() },500 ); + } ) + }, + + // 由于在 componentDidMount 函数中不能保证 DropdownMenu 的内容已经被渲染到页面上(lazy渲染),因此需要存储月份按钮是否绑定click事件的状态 + bindButtonClickCallBack(){ + if ( this.userData['hasBindButtonCallBack'] != true ){ + this.userData['monthInfoList'].map( (curLine)=>{ + curLine.map( (monthIndex)=>{ + ReactDOM.findDOMNode( this.refs['MonthButtonRef'+monthIndex] ).addEventListener( 'click',()=>{ + this.onMonthButtonClicked( monthIndex ) + } ) + } ) + } ) + this.userData['hasBindButtonCallBack'] = true + } + }, + + onMonthButtonClicked(month){ + this.userData['selectedMonth'] = month + this.refreshInputValue() + }, + + onYearSelectValueChanged(year){ + this.userData['selectedYear'] = year + this.refreshInputValue() + }, + + refreshInputValue(){ + let dateStr = this.getValue() + this.setState({'inputValue':dateStr}) + this.props.onChange && this.props.onChange( dateStr ) + }, + + combineDateInfo(year,month){ + year = Number(year) + month = Number(month) + month = (month < 10) ? '0'+month : ''+month + return year+'-'+month + }, + + getValue(){ + return this.combineDateInfo( + this.userData['selectedYear'] ? this.userData['selectedYear'] : this.userData['executedPropInfos']['defaultYear'], + this.userData['selectedMonth'] ? this.userData['selectedMonth'] : this.userData['executedPropInfos']['defaultMonth'] + ) + }, + getDate(){ + return this.getValue() + '-01 00:00:00' + }, + + render:function (){ + + return ( +
+ + + + + + + + + + + {this.userData['monthInfoList'].map( (curLine)=>{ + return ( + + {curLine.map( (curMonthNumber)=>{ + return ( + + ) + })} + + ) + })} + +
+ +
+
{curMonthNumber}
+
+
+
+
+ + ) + } +}) + +export default MonthSelectControl + diff --git a/package/Aries/src/public/MonthSelectControl/index.less b/package/Aries/src/public/MonthSelectControl/index.less new file mode 100644 index 0000000..259756d --- /dev/null +++ b/package/Aries/src/public/MonthSelectControl/index.less @@ -0,0 +1,67 @@ + +div.MonthSelectControlRootDiv { + +} + + + +// 由于DropDown实现的原因,在html节点树上,MonthButton 并不是 MonthSelectControlRootDiv 的子孙节点 + +table.MonthSelectTable{ + @buttonSideLength: 24px; + @buttonMargin: 2px; + + // 下拉框的最小宽度要重新调整一下 + tr:nth-child(1) > td { + > *{ + min-width: 4*(@buttonSideLength+2*@buttonMargin); + max-width: 4*(@buttonSideLength+2*@buttonMargin); + margin-bottom: 6px; + } + } + + tr{ + margin: 0px; + padding: 0px; + td{ + width: @buttonSideLength+2*@buttonMargin; + max-width: @buttonSideLength+2*@buttonMargin; + min-width: @buttonSideLength+2*@buttonMargin; + + height: @buttonSideLength+2*@buttonMargin; + max-height: @buttonSideLength+2*@buttonMargin; + min-height: @buttonSideLength+2*@buttonMargin; + } + } + + tr td { + div.MonthButton{ + font-weight: bold; + cursor: pointer; + + margin: @buttonMargin; + + width: @buttonSideLength; + min-width: @buttonSideLength; + max-width: @buttonSideLength; + height: @buttonSideLength; + min-height: @buttonSideLength; + max-height: @buttonSideLength; + line-height: @buttonSideLength; + + text-align: center; + + border: 1px solid #42a5f5; + border-radius: 2px; + } + div.MonthButton{ + color: #42a5f5; + background-color: white; + } + div.MonthButton:hover{ + color: white; + background-color: #42a5f5; + } + + } +} From 132baed51bbf99aad39e42bdf6b6a43e558dbf0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=83=AD=E6=94=80?= Date: Wed, 28 Dec 2016 16:58:50 +0800 Subject: [PATCH 13/21] =?UTF-8?q?=E8=B0=83=E6=95=B4=E4=BA=86=E5=90=8E?= =?UTF-8?q?=E5=8F=B0=E8=AE=A1=E7=AE=97=E8=B5=84=E6=BA=90=E7=94=A8=E9=87=8F?= =?UTF-8?q?=E7=9A=84=E7=B2=BE=E5=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Aries/kd_agent/models.py | 12 ++++++------ .../CalcManage/ResourceUsageBilling/index.jsx | 4 ++-- .../CalcManage/ResourceUsageRecently/index.jsx | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Aries/kd_agent/models.py b/Aries/kd_agent/models.py index 41fc45c..21627e8 100644 --- a/Aries/kd_agent/models.py +++ b/Aries/kd_agent/models.py @@ -77,23 +77,23 @@ def to_minuteaverge_measurementkey_json(self): # u 多少个0.5VCPU (1VCPU == cpu/1000 ,0.5VCPU是预设的值) # v 多少个128MB内存 ( 128MB是预设的值 ) # 计算公式为: u*0.025 + 0.003*v / (8*u) - # 同时,这个结果保留两位有效小数(0.01)(且直接进位) - # 即如果结果是 0.0212 则,应该显示 0.03 + # 结果保留11位有效小数(1e-11)(且直接进位) 即如果结果是 1.11e-11 则,应该显示 1.2e-11 @staticmethod def calc_virtual_machine_day( cpu_value,memory_value ): u = calc_minute_ave(cpu_value)/1000/0.5 v = calc_minute_ave(memory_value)/128/1024/1024 try: - v = u*0.025 + 0.003*v / (8*u) + value = u*0.025 + 0.003*v / (8*u) except: - v = 0 + value = 0 - # 先放大100倍,然后向上取整。之后再缩小100倍。由于缩小之后,获取的数不会严格100倍,因此round一下 + # 先放大1e11倍,然后向上取整。之后再缩小1e11倍。由于缩小之后,获取的数不会严格1e11倍,因此round一下 # 如: # >>> 1.3/10000 # 0.00013000000000000002 - return round( math.ceil(v/0.01)*0.01,2 ) + d = 1e-11 + return round( math.ceil(value/d)*d,11 ) diff --git a/package/Aries/src/functions/CalcManage/ResourceUsageBilling/index.jsx b/package/Aries/src/functions/CalcManage/ResourceUsageBilling/index.jsx index c8f925b..ab231da 100644 --- a/package/Aries/src/functions/CalcManage/ResourceUsageBilling/index.jsx +++ b/package/Aries/src/functions/CalcManage/ResourceUsageBilling/index.jsx @@ -18,7 +18,7 @@ import './index.less' var mod = React.createClass({ fix(v){ - return Number(v).toFixed(2) + return Number(v).toFixed(4) }, getInitialState(){ @@ -125,7 +125,7 @@ var mod = React.createClass({ }, 'memory':{ 'unitArr':['B','KiB','MiB','GiB','TiB','PiB'], - 'significantFractionBit':2, + 'significantFractionBit':4, 'base':1024, 'name':'Memory用量', diff --git a/package/Aries/src/functions/CalcManage/ResourceUsageRecently/index.jsx b/package/Aries/src/functions/CalcManage/ResourceUsageRecently/index.jsx index 2fef770..2d60e47 100644 --- a/package/Aries/src/functions/CalcManage/ResourceUsageRecently/index.jsx +++ b/package/Aries/src/functions/CalcManage/ResourceUsageRecently/index.jsx @@ -17,7 +17,7 @@ import './index.less' var mod = React.createClass({ fix(v){ - return Number(v).toFixed(2) + return Number(v).toFixed(4) }, getInitialState(){ @@ -117,7 +117,7 @@ var mod = React.createClass({ }, 'memory':{ 'unitArr':['B','KiB','MiB','GiB','TiB','PiB'], - 'significantFractionBit':2, + 'significantFractionBit':4, 'base':1024, 'name':'Memory用量', From 1bbb9a2240ba8a0685195a3b75b0acc84e56d454 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=83=AD=E6=94=80?= Date: Thu, 29 Dec 2016 16:08:30 +0800 Subject: [PATCH 14/21] =?UTF-8?q?=E9=87=8D=E6=9E=84=E4=BA=86=E8=B5=84?= =?UTF-8?q?=E6=BA=90=E7=94=A8=E9=87=8F-=E8=BF=91=E6=9C=9F=E9=A1=B5?= =?UTF-8?q?=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CalcManage/ResourceUsageBilling/index.jsx | 5 +- .../ResourceUsageRecently/index.jsx | 388 ++++++++++++------ .../ResourceUsageRecently/index.less | 55 ++- 3 files changed, 295 insertions(+), 153 deletions(-) diff --git a/package/Aries/src/functions/CalcManage/ResourceUsageBilling/index.jsx b/package/Aries/src/functions/CalcManage/ResourceUsageBilling/index.jsx index ab231da..a3e8f5a 100644 --- a/package/Aries/src/functions/CalcManage/ResourceUsageBilling/index.jsx +++ b/package/Aries/src/functions/CalcManage/ResourceUsageBilling/index.jsx @@ -156,6 +156,7 @@ var mod = React.createClass({ }, onSearchButtonClicked(){ + this.setState({ 'fixedTableDataList':[] }) let dateStr = this.refs.MonthSelectControlRef.getDate() if ( !this.checkDateValid(dateStr) ){ message.danger( '指定月份的账单尚未生成' ) @@ -235,10 +236,12 @@ var mod = React.createClass({ +
+

详单

diff --git a/package/Aries/src/functions/CalcManage/ResourceUsageRecently/index.jsx b/package/Aries/src/functions/CalcManage/ResourceUsageRecently/index.jsx index 2d60e47..fa73973 100644 --- a/package/Aries/src/functions/CalcManage/ResourceUsageRecently/index.jsx +++ b/package/Aries/src/functions/CalcManage/ResourceUsageRecently/index.jsx @@ -21,14 +21,11 @@ var mod = React.createClass({ }, getInitialState(){ - let days = 90 - let today_start = new Date(Toolkit.generateTimeStrByMilliSeconds(-1).slice(0,'YYYY-MM-DD'.length)) - let start_date_str = Toolkit.generateTimeStrByMilliSeconds(today_start.getTime() - days*24*60*60*1000).slice(0,'YYYY-MM-DD'.length) - return { - 'days':days+1, // +1,获取当天的用量 - 'startdate':start_date_str, 'echartFatherDivHeight':0, + 'totalResourceUsage':undefined, + 'totalCPU':undefined, + 'totalMemory':undefined, } }, componentWillMount(){ @@ -37,11 +34,23 @@ var mod = React.createClass({ componentDidMount(){ this.initCharts() this.checkToRequestData() + window.addEventListener( 'resize',this.onWindowResize ) }, + componentDidUpdate(){ this.checkToRequestData() }, + onWindowResize(){ + window.removeEventListener( 'resize',this.onWindowResize ) + for ( let i in this.userData['keywords'] ){ + let obj = this.userData['echartObjs'][ this.userData['keywords'][i] ] + obj && obj.resize() + } + + window.addEventListener( 'resize',this.onWindowResize ) + }, + checkToRequestData(){ let curNameSpace = CMDR.getCurNameSpace(this) if ( this.curNameSpace !== curNameSpace ){ @@ -50,112 +59,238 @@ var mod = React.createClass({ } }, - onHeightChanged(newHeight){ - this.setState({'echartFatherDivHeight':newHeight}) - }, - - // 对cpu、memory、用量等数据进行进制转换、单位变换 - renderResourceUsageValue( v ){ - return this.fix(v) + ' 机器/天' - }, - // cpu数据的含义是毫核的个数,但是要求界面上展示虚拟核的个数,因此直接除以 1000 - renderCPUUsageValue(v){ - return this.fix(v/1000) + ' VCPU' - }, - renderMemoryUsageValue(v){ - let toolTipInfo = this.userData['echartToolTipFormatterInfo']['memory'] - return Toolkit.unitConversion( - v, - toolTipInfo['base'], - toolTipInfo['unitArr'], - toolTipInfo['significantFractionBit'] - ) - }, - - resetResourceUsageData(executedData){ - this.userData['resourceUsageData'] = executedData + resetrequestedUsageData(executedData,recentDaysStartDate,monthFirstDate){ + this.userData['requestedUsageData'] = executedData + let echartBaseInfo = this.userData['echartBaseInfo'] // 汇总echart的x、y轴数据 - let values = [] - let date_keys = [] + let dateKeys = [] + let resourceUsageValues = [] + let cpuUsageValues = [] + let memoryUsageValues = [] for ( let index = 0 ; index < executedData.length ; index ++ ){ - date_keys.push( executedData[index]['date'] ) - values.push( this.fix(executedData[index]['data']['request']) ) + // 走势图显示近14天的数据 + if ( recentDaysStartDate.getTime() <= new Date(executedData[index]['date']).getTime() ){ + dateKeys.push( executedData[index]['date'] ) + resourceUsageValues.push( executedData[index]['data'][ echartBaseInfo['resourceUsage']['key'] ] ) + cpuUsageValues.push( executedData[index]['data'][ echartBaseInfo['cpu']['key'] ] ) + memoryUsageValues.push( executedData[index]['data'][ echartBaseInfo['memory']['key'] ] ) + } } - this.userData['echartDatas'] = { - 'xAxisData':date_keys, - 'seriesData':values + this.userData['echartData']['resourceUsage'] = { + 'xAxisData':dateKeys, + 'seriesData':resourceUsageValues } + this.userData['echartData']['cpu'] = { + 'xAxisData':dateKeys, + 'seriesData':cpuUsageValues + } + this.userData['echartData']['memory'] = { + 'xAxisData':dateKeys, + 'seriesData':memoryUsageValues + } + + // 计算出来本月的CPU、内存、用量总和 + let totalResourceUsage = 0.0 + let totalCPU = 0.0 + let totalMemory = 0.0 + + for ( let i in executedData ){ + let curData = executedData[executedData.length-1-i] + // 汇总数据显示月初到当天的汇总 + if ( monthFirstDate.getTime() <= new Date(curData['date']).getTime() ){ + totalResourceUsage += curData['data'][ echartBaseInfo['resourceUsage']['key'] ] + totalCPU += curData['data'][ echartBaseInfo['cpu']['key'] ] + totalMemory += curData['data'][ echartBaseInfo['memory']['key'] ] + } + } + + this.setState({'totalResourceUsage':totalResourceUsage}) + this.setState({'totalCPU':totalCPU}) + this.setState({'totalMemory':totalMemory}) }, initUserData(){ - this.userData = { - 'echartObj':undefined, - 'echartTitleText':'资源用量', - 'resourceUsageData':undefined, - 'keywords':['cpu','memory'] - } + this.userData = {} + // AutoLayout 需要使用的一些信息 this.userData['divIDs'] = { - rootDivID:Toolkit.generateGUID(), - navigationInPageID:Toolkit.generateGUID(), - echartFatherDivID:Toolkit.generateGUID(), + 'rootDivID':Toolkit.generateGUID(), + 'navigationInPageID':Toolkit.generateGUID(), + 'recentlyTitleDivID':Toolkit.generateGUID(), + 'echartFatherDivID':Toolkit.generateGUID(), } this.userData['autoLayoutInfos'] = [ layoutInfoGenerator( this.userData['divIDs']['rootDivID'],true ), layoutInfoGenerator( this.userData['divIDs']['navigationInPageID'],false,'Const' ), + layoutInfoGenerator( this.userData['divIDs']['recentlyTitleDivID'],false,'Const' ), layoutInfoGenerator( this.userData['divIDs']['echartFatherDivID'],false,'Var',( newHeight )=>{ - this.onHeightChanged( newHeight ) + this.setState({'echartFatherDivHeight':newHeight}) } ), ] - this.userData['echartToolTipFormatterInfo'] = { + // echart保存的一些信息 + this.userData['echartObjs'] = {} + this.userData['keywords'] = ['resourceUsage','cpu','memory'] + this.userData['recentlyDays'] = 14 + this.userData['requestedUsageData'] = undefined // 它保存了从后台请求到的原始数据 + + this.userData['echartBaseInfo'] = { + 'resourceUsage':{ + 'name':'资源用量', + 'key':'request', + 'renderFunc':this.renderResourceUsageValue, + 'divID':'ResourceUsageEchartDiv', + 'tooltipFormatterFunc':undefined, + 'yAxisLabelFormatterFunc':undefined, + }, 'cpu':{ 'name':'CPU用量', 'key':'cpu/request', 'renderFunc':this.renderCPUUsageValue, + 'divID':'CPUEchartDiv', + 'tooltipFormatterFunc':undefined, + 'yAxisLabelFormatterFunc':undefined, }, 'memory':{ - 'unitArr':['B','KiB','MiB','GiB','TiB','PiB'], - 'significantFractionBit':4, - 'base':1024, - 'name':'Memory用量', 'key':'memory/request', 'renderFunc':this.renderMemoryUsageValue, + 'divID':'MemoryEchartDiv', + 'tooltipFormatterFunc':undefined, + 'yAxisLabelFormatterFunc':undefined, + + 'unitArr':['B','KiB','MiB','GiB','TiB','PiB'], + 'significantFractionBit':4, + 'base':1024, }, } - this.userData['echartTooltipFormatterFunc'] = ( params, ticket, callback ) => { - if ( !this.userData['resourceUsageData'] ){ + + // 从后台请求到的数据并进行处理之后,会放到这里 + this.userData['echartData'] = { + 'resourceUsage':{}, + 'cpu':{}, + 'memory':{}, + } + + // 用来渲染数据的单位的函数 + this.userData['echartBaseInfo']['resourceUsage']['renderFunc'] = (v)=>{ return this.fix(v) + ' 机器/天' } + // cpu数据的含义是毫核的个数,但是要求界面上展示虚拟核的个数,因此直接除以 1000 + this.userData['echartBaseInfo']['cpu']['renderFunc'] = (v)=>{ return this.fix(v/1000) + ' VCPU' } + this.userData['echartBaseInfo']['memory']['renderFunc'] = (v)=>{ + let echartBaseInfo = this.userData['echartBaseInfo']['memory'] + return Toolkit.unitConversion( + v, + echartBaseInfo['base'], + echartBaseInfo['unitArr'], + echartBaseInfo['significantFractionBit'] + ) + } + + // 用来渲染echart的tooltip的回调函数 + let tooltipFormatterFunc = (echartBaseInfo,x,y,yLabel)=>{ + if ( !this.userData['requestedUsageData'] ){ return } - let dataInfo = this.userData['resourceUsageData'][params[0]['dataIndex']]['data'] - let templateStr = this.generateTooltipFormatterStr(3) - - let dataObj = {} - dataObj['time'] = params[0]['name'] - - // 计算好的资源用量 - dataObj['name'+0] = params[0]['seriesName'] - dataObj['value'+0] = this.renderResourceUsageValue(params[0]['data']) - - for ( let i = 0 ; i < this.userData['keywords'].length ; i ++ ){ - let k = this.userData['keywords'][i] - let toolTipInfo = this.userData['echartToolTipFormatterInfo'][k] - - dataObj['name'+(i+1)] = toolTipInfo['name'] - dataObj['value'+(i+1)] = toolTipInfo['renderFunc'](dataInfo[toolTipInfo['key']]) - } - return Toolkit.strFormatter.formatString( templateStr,dataObj) + return Toolkit.strFormatter.formatString( this.generateTooltipFormatterStr(1),{ + 'time':x, + 'name0':yLabel, + 'value0':echartBaseInfo['renderFunc'](y) + }) + } + this.userData['echartBaseInfo']['resourceUsage']['tooltipFormatterFunc'] = ( params, ticket, callback ) => { + let echartBaseInfo = this.userData['echartBaseInfo']['resourceUsage'] + return tooltipFormatterFunc( echartBaseInfo,params[0]['name'],params[0]['data'],params[0]['seriesName'] ) + } + this.userData['echartBaseInfo']['cpu']['tooltipFormatterFunc'] = ( params, ticket, callback ) => { + let echartBaseInfo = this.userData['echartBaseInfo']['cpu'] + return tooltipFormatterFunc( echartBaseInfo,params[0]['name'],params[0]['data'],params[0]['seriesName'] ) + } + this.userData['echartBaseInfo']['memory']['tooltipFormatterFunc'] = ( params, ticket, callback ) => { + let echartBaseInfo = this.userData['echartBaseInfo']['memory'] + return tooltipFormatterFunc( echartBaseInfo,params[0]['name'],params[0]['data'],params[0]['seriesName'] ) } + // 用来渲染echart的y轴标签的回调函数 + this.userData['echartBaseInfo']['resourceUsage']['yAxisLabelFormatterFunc'] = ( value, index ) => { + return this.userData['echartBaseInfo']['resourceUsage']['renderFunc'](value) + } + this.userData['echartBaseInfo']['cpu']['yAxisLabelFormatterFunc'] = ( value, index ) => { + return this.userData['echartBaseInfo']['cpu']['renderFunc'](value) + } + this.userData['echartBaseInfo']['memory']['yAxisLabelFormatterFunc'] = ( value, index ) => { + return this.userData['echartBaseInfo']['memory']['renderFunc'](value) + } }, initCharts(){ - // 在没有加载到数据的时候,先显示出来空白的图标,这样会比较好看 - let initOptions = { + for ( let i in this.userData['keywords'] ){ + let k = this.userData['keywords'][i] + let echartBaseInfo = this.userData['echartBaseInfo'][k] + + this.userData['echartObjs'][k] = echarts.init(document.getElementById( echartBaseInfo['divID'] )) + this.userData['echartObjs'][k].setOption( this.generateInitEchartOption( + echartBaseInfo['name'],echartBaseInfo['tooltipFormatterFunc'],echartBaseInfo['yAxisLabelFormatterFunc'] + ) ) + } + }, + + requestData(){ + // 该页面需要两块数据:账单信息要求显示本月初到今天的数据。走势图需要近14天的数据,为了一次请求成功,因此需要把这两个时间段的数据汇总起来 + let todayStartStr = Toolkit.generateTimeStrByMilliSeconds(-1).slice(0,'YYYY-MM-DD'.length) + let sDate1 = new Date(new Date(todayStartStr).getTime() - (this.userData['recentlyDays']-1)*24*60*60*1000) // 最近14天 + let sDate2 = new Date(todayStartStr.slice(0,'YYYY-MM'.length)+'-01') // 月初 + + let days = undefined + let sDate = undefined + if ( sDate1.getTime() < sDate2.getTime() ){ + sDate = sDate1 + days = this.userData['recentlyDays'] + } else { + sDate = sDate2 + days = new Date(todayStartStr).getDate() + } + let startDateStr = Toolkit.generateTimeStrByMilliSeconds(sDate.getTime()).slice(0,'YYYY-MM-DD'.length) + + for ( let i in this.userData['keywords'] ){ + this.userData['echartObjs'][ this.userData['keywords'][i] ].showLoading() + } + CMDR.getResourceUsageInfo(CMDR.getCurNameSpace(this),startDateStr,days,(executedData)=>{ + this.resetrequestedUsageData(executedData,sDate1,sDate2) + this.insertDataToEchart() + for ( let i in this.userData['keywords'] ){ + this.userData['echartObjs'][ this.userData['keywords'][i] ].hideLoading() + } + }) + }, + + insertDataToEchart(){ + if (!this.userData['requestedUsageData']){ + return + } + for ( let i in this.userData['keywords'] ){ + let k = this.userData['keywords'][i] + this.userData['echartObjs'][k].setOption({ + 'legend':{ + 'data':[this.userData['echartBaseInfo'][k]['name']] + }, + 'xAxis': { + 'type' : 'category', + 'data': this.userData['echartData'][k]['xAxisData'] + }, + 'series': [{ + 'type': 'bar', + 'name':this.userData['echartBaseInfo'][k]['name'], + 'data':this.userData['echartData'][k]['seriesData'], + }] + }) + } + }, + + generateInitEchartOption( title,tooltipFormatterFunc,yAxisLabelFormatterFunc ){ + return { 'title': { - 'text': this.userData['echartTitleText'] + 'text': title }, toolbox: { 'show':true, @@ -171,7 +306,10 @@ var mod = React.createClass({ }, 'tooltip' : { 'trigger': 'axis', - 'formatter': this.userData['echartTooltipFormatterFunc'] + 'formatter': tooltipFormatterFunc + }, + grid:{ + 'x': 120 }, 'xAxis': [{ 'type' : 'category', @@ -180,53 +318,10 @@ var mod = React.createClass({ 'yAxis':{ 'axisLabel':{ 'show':true, - //'formatter':undefined + 'formatter':yAxisLabelFormatterFunc } }, - dataZoom: [{ - show: true, - start: 80, - end: 100 - }], } - this.userData['echartObj'] = echarts.init(document.getElementById( 'ResourceUsageEchartDiv' )) - this.userData['echartObj'].setOption(initOptions) - }, - - requestData(){ - this.userData['echartObj'].showLoading() - CMDR.getResourceUsageInfo( - CMDR.getCurNameSpace(this), - this.state.startdate, - this.state.days, - (executedData)=>{ - this.userData['echartObj'].hideLoading() - this.resetResourceUsageData(executedData) - this.insertDataToEchart() - } - ) - }, - - insertDataToEchart(){ - if (!this.userData['resourceUsageData']){ - return - } - this.userData['echartObj'].setOption({ - 'legend':{ - 'data':[this.userData['echartTitleText']] - }, - 'xAxis': { - 'type' : 'category', - 'position' : 'bottom', - 'boundaryGap': false, - 'data': this.userData['echartDatas']['xAxisData'] - }, - 'series': [{ - 'type': 'bar', - 'name':this.userData['echartTitleText'], - 'data':this.userData['echartDatas']['seriesData'], - }] - }) }, generateTooltipFormatterStr( lineNumber ){ @@ -242,6 +337,19 @@ var mod = React.createClass({ }, render: function() { + + let monthFirstDayStr = Toolkit.generateTimeStrByMilliSeconds((new Date()).getTime()).slice( 0,'YYYY-MM'.length ) + let recentlyTitle = Toolkit.strFormatter.formatString('{date} {nameSpace} 账单信息(截至到当前时间)',{ + 'nameSpace':CalcManageConf.getCurSpace(this), + 'date':monthFirstDayStr.split('-').join('年') + '月' + }) + + let picTitle = Toolkit.strFormatter.formatString('近 {days} 天资源走势图',{'days':this.userData['recentlyDays']}) + + let totalResourceUsage = this.state.totalResourceUsage != undefined ? this.userData['echartBaseInfo']['resourceUsage']['renderFunc'](this.state.totalResourceUsage) : '' + let totalCPU = this.state.totalCPU != undefined ? this.userData['echartBaseInfo']['cpu']['renderFunc'](this.state.totalCPU) : '' + let totalMemory = this.state.totalMemory != undefined ? this.userData['echartBaseInfo']['memory']['renderFunc'](this.state.totalMemory) : '' + return (
@@ -256,10 +364,44 @@ var mod = React.createClass({ spaceName:CalcManageConf.getCurSpace(this) })} />
-
-
+
+

{recentlyTitle}

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
空间{CalcManageConf.getCurSpace(this)}
总账单{totalResourceUsage}
总CPU{totalCPU}
总内存{totalMemory}
+
+

{picTitle}

+
+
+
+
+
diff --git a/package/Aries/src/functions/CalcManage/ResourceUsageRecently/index.less b/package/Aries/src/functions/CalcManage/ResourceUsageRecently/index.less index 8d8b5f7..7150e0e 100644 --- a/package/Aries/src/functions/CalcManage/ResourceUsageRecently/index.less +++ b/package/Aries/src/functions/CalcManage/ResourceUsageRecently/index.less @@ -1,45 +1,42 @@ div.ResourceUsageRecentlyRootDiv{ + table.TooltipTable td.SpaceTdDistraction { width: 10px; } - div.cTabs{ - .bfd-tabs__list { - float: right; - border-bottom:0px - } - .bfd-tabs__list li a{ - background-color: #FFFFFF; - margin-right: 20px; - } - .bfd-tabs__list li a:hover , .nav.nav-tabs li a:focus{ - background-color: #FFFFFF; - border-bottom: 1.5px solid #00BFFF; - } + table.RecentlyOverviewInfoTable{ + font-size: 15px; + font-weight: bold; + td:nth-child(1){ width: 10px; } + td:nth-child(3){ width: 30px; } } - div.ResourceUsageEchartFatherDiv{ - overflow-y: auto; - margin:auto; - width: 100%; + .MiddleMainBlock{ + width: 80%; + margin-left: auto; + margin-right: auto; } - div#ResourceUsageEchartDiv{ + div.EchartFatherDiv{ + overflow-x: hidden; + overflow-y: auto; margin:auto; - width:1000px; - height:500px; - padding-top: 40px; - } - div.FixedTableFatherDiv { - padding-top:13px; // DataTable的表头文本距离上边框为17px - border: 1px solid #ECECEC; - } + width: 80%; - div#ResourceUsageEchartDiv , div.FixedTableFatherDiv{ - margin-top: 30px; + div#ResourceUsageEchartDiv{ + margin-top: 30px; + margin:auto; + width:85%; + height:400px; + } + div#CPUEchartDiv,div#MemoryEchartDiv{ + display: inline-block; + margin:auto; + width:50%; + height:280px; + } } - } From b0eb7d85fb2114488172aafb71133c0bf5617400 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=83=AD=E6=94=80?= Date: Fri, 30 Dec 2016 12:21:57 +0800 Subject: [PATCH 15/21] =?UTF-8?q?=E9=9A=8FDropdown=E7=BB=84=E4=BB=B6?= =?UTF-8?q?=E7=9A=84bug=E4=BF=AE=E5=A4=8D=E6=89=80=E5=81=9A=E7=9A=84?= =?UTF-8?q?=E4=B8=80=E4=BA=9B=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package/Aries/package.json | 2 +- .../src/public/MonthSelectControl/index.jsx | 16 ++++++---------- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/package/Aries/package.json b/package/Aries/package.json index 1579d25..3f980b6 100644 --- a/package/Aries/package.json +++ b/package/Aries/package.json @@ -8,7 +8,7 @@ "dependencies": { "antd": "^1.8.0", "bfd-bootstrap": "0.0.22", - "bfd-ui": "^1.3.0", + "bfd-ui": "^1.5.0", "echarts": "^3.2.3", "js-cookie": "^2.1.2", "less": "^2.7.1", diff --git a/package/Aries/src/public/MonthSelectControl/index.jsx b/package/Aries/src/public/MonthSelectControl/index.jsx index 1cf9444..48739bb 100644 --- a/package/Aries/src/public/MonthSelectControl/index.jsx +++ b/package/Aries/src/public/MonthSelectControl/index.jsx @@ -77,13 +77,8 @@ var MonthSelectControl = React.createClass({ } }, - componentDidMount(){ - ReactDOM.findDOMNode( this.refs.InputRef ).addEventListener( 'click',()=>{ - this.refs.PleaseSelectMonthControlDropDownRef.setState({ 'dropdownOpenState':true }) - - // js是单线程的,因此setState之后并不会马上进入setState的回调函数中,因此这里过500ms再进行绑定 - setTimeout( ()=>{ this.bindButtonClickCallBack() },500 ); - } ) + onDropdownToggle(state){ + state && setTimeout( ()=>{ this.bindButtonClickCallBack() },500 ) }, // 由于在 componentDidMount 函数中不能保证 DropdownMenu 的内容已经被渲染到页面上(lazy渲染),因此需要存储月份按钮是否绑定click事件的状态 @@ -93,6 +88,7 @@ var MonthSelectControl = React.createClass({ curLine.map( (monthIndex)=>{ ReactDOM.findDOMNode( this.refs['MonthButtonRef'+monthIndex] ).addEventListener( 'click',()=>{ this.onMonthButtonClicked( monthIndex ) + this.refs.PleaseSelectMonthControlDropDownRef.close() } ) } ) } ) @@ -138,10 +134,10 @@ var MonthSelectControl = React.createClass({ return (
+ aligned={false} + onToggle={this.onDropdownToggle}> - + From 8a23fc16bc25485473265d3d94b6f8efd82e6d15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=83=AD=E6=94=80?= Date: Fri, 30 Dec 2016 13:15:23 +0800 Subject: [PATCH 16/21] =?UTF-8?q?=E6=9C=88=E8=B5=84=E6=BA=90=E7=94=A8?= =?UTF-8?q?=E9=87=8F=E7=BB=9F=E8=AE=A1=E5=86=85=E5=AE=B9=E7=AE=97=E6=B3=95?= =?UTF-8?q?=E7=9A=84=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CalcManage/ResourceUsageBilling/index.jsx | 12 +++++----- .../ResourceUsageRecently/index.jsx | 23 +++++++++++-------- .../src/public/MonthSelectControl/index.jsx | 2 +- 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/package/Aries/src/functions/CalcManage/ResourceUsageBilling/index.jsx b/package/Aries/src/functions/CalcManage/ResourceUsageBilling/index.jsx index a3e8f5a..0424842 100644 --- a/package/Aries/src/functions/CalcManage/ResourceUsageBilling/index.jsx +++ b/package/Aries/src/functions/CalcManage/ResourceUsageBilling/index.jsx @@ -82,9 +82,9 @@ var mod = React.createClass({ totalMemory += curData['data'][toolTipInfo['memory']['key']] } this.userData['fixedTableDataList'] = fixedTableDataList - this.userData['totalBilling'] = this.renderResourceUsageValue(totalBilling) - this.userData['totalCPU'] = this.renderCPUUsageValue(totalCPU) - this.userData['totalMemory'] = this.renderMemoryUsageValue(totalMemory) + this.userData['totalBilling'] = this.renderResourceUsageValue(totalBilling / executedData.length) + this.userData['totalCPU'] = this.renderCPUUsageValue(totalCPU / executedData.length) + this.userData['totalMemory'] = this.renderMemoryUsageValue(totalMemory / executedData.length) return fixedTableDataList }, @@ -218,19 +218,19 @@ var mod = React.createClass({ - + - + - + diff --git a/package/Aries/src/functions/CalcManage/ResourceUsageRecently/index.jsx b/package/Aries/src/functions/CalcManage/ResourceUsageRecently/index.jsx index fa73973..7d92211 100644 --- a/package/Aries/src/functions/CalcManage/ResourceUsageRecently/index.jsx +++ b/package/Aries/src/functions/CalcManage/ResourceUsageRecently/index.jsx @@ -90,6 +90,7 @@ var mod = React.createClass({ 'seriesData':memoryUsageValues } + let days = 0.0 // 计算出来本月的CPU、内存、用量总和 let totalResourceUsage = 0.0 let totalCPU = 0.0 @@ -99,15 +100,16 @@ var mod = React.createClass({ let curData = executedData[executedData.length-1-i] // 汇总数据显示月初到当天的汇总 if ( monthFirstDate.getTime() <= new Date(curData['date']).getTime() ){ + days += 1 totalResourceUsage += curData['data'][ echartBaseInfo['resourceUsage']['key'] ] totalCPU += curData['data'][ echartBaseInfo['cpu']['key'] ] totalMemory += curData['data'][ echartBaseInfo['memory']['key'] ] } } - this.setState({'totalResourceUsage':totalResourceUsage}) - this.setState({'totalCPU':totalCPU}) - this.setState({'totalMemory':totalMemory}) + this.setState({'totalResourceUsage':totalResourceUsage/days}) + this.setState({'totalCPU':totalCPU/days}) + this.setState({'totalMemory':totalMemory/days}) }, initUserData(){ @@ -224,14 +226,17 @@ var mod = React.createClass({ }, initCharts(){ + let colorPool = ['rgba(38,166,154,0.9)','rgba(255,138,101,0.9)','rgba(102,187,106,0.9)'] + for ( let i in this.userData['keywords'] ){ let k = this.userData['keywords'][i] let echartBaseInfo = this.userData['echartBaseInfo'][k] + let initOptions = this.generateInitEchartOption(echartBaseInfo['name'],echartBaseInfo['tooltipFormatterFunc'],echartBaseInfo['yAxisLabelFormatterFunc']) + initOptions['color'] = [colorPool[i]] + this.userData['echartObjs'][k] = echarts.init(document.getElementById( echartBaseInfo['divID'] )) - this.userData['echartObjs'][k].setOption( this.generateInitEchartOption( - echartBaseInfo['name'],echartBaseInfo['tooltipFormatterFunc'],echartBaseInfo['yAxisLabelFormatterFunc'] - ) ) + this.userData['echartObjs'][k].setOption( initOptions ) } }, @@ -376,19 +381,19 @@ var mod = React.createClass({ - + - + - + diff --git a/package/Aries/src/public/MonthSelectControl/index.jsx b/package/Aries/src/public/MonthSelectControl/index.jsx index 48739bb..774f76a 100644 --- a/package/Aries/src/public/MonthSelectControl/index.jsx +++ b/package/Aries/src/public/MonthSelectControl/index.jsx @@ -81,7 +81,7 @@ var MonthSelectControl = React.createClass({ state && setTimeout( ()=>{ this.bindButtonClickCallBack() },500 ) }, - // 由于在 componentDidMount 函数中不能保证 DropdownMenu 的内容已经被渲染到页面上(lazy渲染),因此需要存储月份按钮是否绑定click事件的状态 + // 由于在 onDropdownToggle 函数中不能保证 DropdownMenu 的内容已经被渲染到页面上,因此需要存储月份按钮是否绑定click事件的状态 bindButtonClickCallBack(){ if ( this.userData['hasBindButtonCallBack'] != true ){ this.userData['monthInfoList'].map( (curLine)=>{ From b354b58788887dc31c64fa0fd631d5e655e446c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=83=AD=E6=94=80?= Date: Wed, 4 Jan 2017 16:21:26 +0800 Subject: [PATCH 17/21] =?UTF-8?q?=E5=88=9D=E6=AD=A5=E5=AE=8C=E6=88=90?= =?UTF-8?q?=E6=8E=A8=E9=80=81=E6=95=B0=E6=8D=AE=E5=88=B0=E8=BF=90=E7=BB=B4?= =?UTF-8?q?=E7=9A=84=E8=84=9A=E6=9C=AC=E5=BC=80=E5=8F=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Aries/Aries/settings.py | 13 +- Aries/kd_agent/management/__init__.py | 0 .../kd_agent/management/commands/__init__.py | 0 .../management/commands/pushk8sdata.py | 119 ++++++++++++++++++ Aries/kd_agent/models.py | 19 ++- Dockerfile | 4 +- 6 files changed, 152 insertions(+), 3 deletions(-) create mode 100644 Aries/kd_agent/management/__init__.py create mode 100644 Aries/kd_agent/management/commands/__init__.py create mode 100644 Aries/kd_agent/management/commands/pushk8sdata.py diff --git a/Aries/Aries/settings.py b/Aries/Aries/settings.py index 968d03c..0156bbb 100644 --- a/Aries/Aries/settings.py +++ b/Aries/Aries/settings.py @@ -153,8 +153,14 @@ 'level':'DEBUG', 'class':'logging.FileHandler', 'formatter': 'complete', - 'filename' :'{0}/service.log'.format(LOG_BASE_DIR).replace('\\','/') + 'filename' :'{0}/kd_agent.log'.format(LOG_BASE_DIR).replace('\\','/') }, + 'kd_agent_pushclusterinfo_file': { + 'level':'DEBUG', + 'class':'logging.FileHandler', + 'formatter': 'complete', + 'filename' :'{0}/kd_agent_pushclusterinfo.log'.format(LOG_BASE_DIR).replace('\\','/') + }, 'openstack_log': { 'level': 'DEBUG', 'class': 'logging.FileHandler', @@ -195,6 +201,11 @@ 'kd_agent_log': { 'handlers':['kd_agent_file','console'], 'propagate': False, + 'level':'INFO', + }, + 'kd_agent_pushclusterinfo_log': { + 'handlers':['kd_agent_pushclusterinfo_file','console'], + 'propagate': False, 'level':'DEBUG', }, 'openstack_log': { diff --git a/Aries/kd_agent/management/__init__.py b/Aries/kd_agent/management/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Aries/kd_agent/management/commands/__init__.py b/Aries/kd_agent/management/commands/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Aries/kd_agent/management/commands/pushk8sdata.py b/Aries/kd_agent/management/commands/pushk8sdata.py new file mode 100644 index 0000000..89751df --- /dev/null +++ b/Aries/kd_agent/management/commands/pushk8sdata.py @@ -0,0 +1,119 @@ +# -*- coding: UTF-8 -*- + +import traceback +import datetime +import logging +import os +import requests +import json + +from django.core.management.base import BaseCommand, CommandError +from django.db import IntegrityError + +from kd_agent.toolsmanager import RETU_INFO_SUCCESS,RETU_INFO_ERROR +from kd_agent.toolsmanager import generate_success,generate_failure +from kd_agent.models import ResourceUsageDailyCache as RUDC +from kd_agent.models import NamespaceDepartmentRef as NDR +from kd_agent.models import ClusterUsagePushFailureRecords as CUPFR +from kd_agent.views import get_resource_usage_info + + +logger = logging.getLogger("kd_agent_pushclusterinfo_log") + + +# 将需要推送的数据的关键信息放到失败记录表中(ClusterUsagePushFailureRecords),之后再统一推送 +def refresh_failure_record(): + date = datetime.datetime.combine( datetime.datetime.now(),datetime.time() ) + yesterday = date - datetime.timedelta(seconds=24*60*60) + + # 在数据库中插入记录,然后统一根据记录来往运维推送 + for record in NDR.objects.all(): + try: + CUPFR( namespace=record,datetime=yesterday ).save() + logger.debug( 'insert undo record(%s,%s) success' % (record.namespace,yesterday) ) + except IntegrityError: # (主键重复的异常)如果数据库中已经存在了这条记录,则该异常可以直接忽略 + pass + except: + logger.error( 'insert undo record(%s,%s) failure : %s' % (record.namespace,yesterday,traceback.format_exc()) ) + +def get_push_url(): + return 'http://li.app/v1/om/source/Sirius/addSirius' + +def push_data(): + for record in CUPFR.objects.all(): + try: + namespace = record.namespace.namespace + department = record.namespace.department + + # django存到mysql的datetime对象是不带有时区的, + # # 因此这里为了方便处理,直接把不含时区的datetime对象转换为含有时区(本地时区)的datetime对象 + date = record.datetime+datetime.timedelta(seconds=8*60*60) + date = datetime.datetime.strptime( date.strftime('%Y-%m-%d'),'%Y-%m-%d' ) + + retu_data = push_identify_data(date,namespace,department) + if retu_data['code'] == RETU_INFO_SUCCESS: + record.delete() + logger.debug('push_identify_data(%s,%s,%s) success' % (date,namespace,department)) + else: + logger.error('push_identify_data(%s,%s,%s) failure : %s' % (date,namespace,department,retu_data['msg'])) + except: + logger.error( 'push_identify_data(%s,%s,%s) raise exception : %s' % (date,namespace,department,traceback.format_exc()) ) + +def push_identify_data(date,namespace,department): + retu_data = get_resource_usage_info( date,namespace ) + if retu_data['code'] != RETU_INFO_SUCCESS: + s = 'get_resource_usage_info(%s,%s) failure : %s' % (date,namespace,retu_data['msg']) + return generate_failure( s ) + return push_http(date,department,retu_data['data']['request']) + +''' +接口所接受的post数据的格式: + usage:[{ + department:'基础研发部' 标识部门名称的字符串,可能是二级部门、一级部门、中心的名字 + date:'2016-12-01' 标识该记录是哪个时间段的数据统计汇总出来的( 2016-12-01 00:00:00:000 至 2016-12-01 59:59:59:999 ) + usage:'11.03' 标识该部门在这天的机器用量,单位是 机器/天 + },{ + ... + }] + +备注:接口支持一次性传输多条记录,但是我这里为了方便,每次只传输一条记录 +''' +def push_http(date,department,usage): + post_data = { + 'usage':[{ + 'department':department, + 'date':date.strftime('%Y-%m-%d'), + 'usage':str(usage) + }] + } + req = requests.post(get_push_url(), data=json.dumps(post_data)) + if req.status_code != requests.codes.ok: + s = 'requests.post(%s,%s) return req.status_code is not requests.codes.ok' % \ + ( get_push_url(),json.dumps(post_data) ) + return generate_failure( s ) + + retu_obj = req.json() + if retu_obj['status'] == True: + return generate_success() + else: + s = 'requests.post(%s,%s) return status is not True : %s' % ( get_push_url(),json.dumps(post_data),retu_obj ) + return generate_failure( s ) + + +class Command(BaseCommand): + help = 'Push k8s cluster usage to operation' + + # 由于该脚本执行的命令较为简单,因此不接受参数 + def add_arguments(self, parser): + return None + + def handle(self, *args, **options): + command_str = str(__file__) + command_str = os.path.split(command_str)[1] + command_str = os.path.splitext(command_str)[0] + try: + refresh_failure_record() + push_data() + logger.info( 'execute command %s success' % command_str ) + except: + logger.error( 'execute command %s failure : \n%s' % (command_str,traceback.format_exc()) ) diff --git a/Aries/kd_agent/models.py b/Aries/kd_agent/models.py index 21627e8..bd09244 100644 --- a/Aries/kd_agent/models.py +++ b/Aries/kd_agent/models.py @@ -9,9 +9,12 @@ def calc_minute_ave(v): return float(v)/(24*60) +# 建库语句 +# create database DecisionMakingSurvey default charset utf8 collate utf8_unicode_ci; + class ResourceUsageDailyCache(models.Model): datetime = models.DateTimeField() - namespace = models.CharField( max_length=1024 ) + namespace = models.CharField( max_length=255 ) cpu_request = models.BigIntegerField( default=0 ) cpu_limit = models.BigIntegerField( default=0 ) @@ -96,5 +99,19 @@ def calc_virtual_machine_day( cpu_value,memory_value ): return round( math.ceil(value/d)*d,11 ) +# 该表中记录namespace到部门名的一个对照,只用做向运维推送集群每天某个namespace的资源用量 +# 由于推送数据与Sirius的主要业务不相关,因此这里会尽量降低它与Sirius业务相关表的耦合度 +class NamespaceDepartmentRef(models.Model): + namespace = models.CharField( max_length=255,primary_key=True ) + department = models.CharField( max_length=1024 ) + +# 该表是为了记录推送的状态。比如某天的数据推送失败,则该表中将会有一条push_success为False的记录 +# 等到下次推送的时候,将会查找这些记录并重新推送 +class ClusterUsagePushFailureRecords(models.Model): + namespace = models.ForeignKey( NamespaceDepartmentRef ) + datetime = models.DateTimeField() + class Meta: + unique_together = ("namespace", "datetime") + diff --git a/Dockerfile b/Dockerfile index 1d572bc..f3a4c3f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -40,5 +40,7 @@ EXPOSE 10086 #CMD /opt/Sirius/sbin/Aries.sh start >>/opt/Sirius/log/uwsgi.log CMD sh $SIRIUS_PATH/docker-k8s/script/start_script.sh - +# 启动一个crontab进程,定时往运维推送数据 +CMD echo '* * * * * /opt/Python-2.7/bin/python '$SIRIUS_PATH'/Aries/manage.py pushk8sdata' >> /var/spool/cron/root +CMD service crond restart From b9cdb1a5a9ee554dcd20360b3a16f3bec4939b99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=83=AD=E6=94=80?= Date: Thu, 5 Jan 2017 13:32:15 +0800 Subject: [PATCH 18/21] =?UTF-8?q?Sirius=E5=90=AF=E5=8A=A8=E6=97=B6?= =?UTF-8?q?=EF=BC=8C=E5=90=AF=E5=8A=A8=E5=AE=9A=E6=97=B6=E4=BB=BB=E5=8A=A1?= =?UTF-8?q?=E5=90=91=E8=BF=90=E7=BB=B4=E6=8E=A8=E9=80=81=E6=95=B0=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Dockerfile | 9 ++------- docker-k8s/script/start_script.sh | 7 +++++++ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/Dockerfile b/Dockerfile index f3a4c3f..3f3826b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ -FROM docker.baifendian.com/sjx/sirius_base -MAINTAINER jingxia.sun +FROM docker.baifendian.com/guopan/sirius_base +MAINTAINER pan.guo ENV SIRIUS_PATH /opt/Sirius RUN mkdir -p /opt/Sirius @@ -39,8 +39,3 @@ RUN chmod +x $SIRIUS_PATH/sbin/Aries.sh &&\ EXPOSE 10086 #CMD /opt/Sirius/sbin/Aries.sh start >>/opt/Sirius/log/uwsgi.log CMD sh $SIRIUS_PATH/docker-k8s/script/start_script.sh - -# 启动一个crontab进程,定时往运维推送数据 -CMD echo '* * * * * /opt/Python-2.7/bin/python '$SIRIUS_PATH'/Aries/manage.py pushk8sdata' >> /var/spool/cron/root -CMD service crond restart - diff --git a/docker-k8s/script/start_script.sh b/docker-k8s/script/start_script.sh index 6dc6088..5b18c1b 100644 --- a/docker-k8s/script/start_script.sh +++ b/docker-k8s/script/start_script.sh @@ -95,5 +95,12 @@ sed -i "s#YARN_YARN_RESOURCEMANAGER_WEBAPP_ADDRESS_RM2#$YARN_YARN_RESOURCEMANAGE sed -i "s#YARN_YARN_RESOURCEMANAGER_RESOURCE_TRACKER_ADDRESS_RM2#$YARN_YARN_RESOURCEMANAGER_RESOURCE_TRACKER_ADDRESS_RM2#g" /opt/hadoop/etc/hadoop/yarn-site.xml sed -i "s#YARN_YARN_RESOURCEMANAGER_ADMIN_ADDRESS_RM2#$YARN_YARN_RESOURCEMANAGER_ADMIN_ADDRESS_RM2#g" /opt/hadoop/etc/hadoop/yarn-site.xml + +# 启动一个crontab进程,定时往运维推送数据 +sed -i '/session required pam_loginuid.so/c\session sufficient pam_loginuid.so' /etc/pam.d/crond +echo '0 2 * * * /opt/Python-2.7/bin/python /opt/Sirius/Aries/manage.py pushk8sdata' >> /var/spool/cron/root +chmod 600 /var/spool/cron/root +service crond restart + source /etc/profile /opt/Sirius/sbin/Aries.sh start From 56ed4c35ec2e3dbf6a4421c89510d9633b3e81ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=83=AD=E6=94=80?= Date: Fri, 6 Jan 2017 14:26:24 +0800 Subject: [PATCH 19/21] =?UTF-8?q?=E5=B0=86=E8=AE=A1=E7=AE=97hdfs=E9=85=8D?= =?UTF-8?q?=E9=A2=9D=E4=BF=A1=E6=81=AF=E7=9A=84=E7=BA=BF=E7=A8=8B=E6=8F=90?= =?UTF-8?q?=E5=8F=96=E5=87=BA=E6=9D=A5=EF=BC=8C=E5=8D=95=E7=8B=AC=E6=89=A7?= =?UTF-8?q?=E8=A1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Aries/Aries/settings.py | 7 ++----- Aries/hdfs/management/__init__.py | 0 Aries/hdfs/management/commands/__init__.py | 0 .../hdfs/management/commands/calcsumspace.py | 19 +++++++++++++++++++ docker-k8s/script/start_script.sh | 2 ++ 5 files changed, 23 insertions(+), 5 deletions(-) create mode 100644 Aries/hdfs/management/__init__.py create mode 100644 Aries/hdfs/management/commands/__init__.py create mode 100644 Aries/hdfs/management/commands/calcsumspace.py diff --git a/Aries/Aries/settings.py b/Aries/Aries/settings.py index 0156bbb..4df80e3 100644 --- a/Aries/Aries/settings.py +++ b/Aries/Aries/settings.py @@ -35,7 +35,7 @@ yaml_file = open(file_name) OPENSTACK_KEY_PATH = os.path.join(BASE_DIR,"openstack/middleware/common/key.yaml") SETTINGS = yaml.load(yaml_file) -print SETTINGS +# print SETTINGS # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/1.8/howto/deployment/checklist/ @@ -322,10 +322,7 @@ PORT_CINDER = OPENSTACK_SETTINGS["PORT_CINDER"] MONITOR_URL = OPENSTACK_SETTINGS['MONITOR_URL'] -#启动一个线程开始定时统计配额. default: 10m -POLL_TIME = 600 -import sumSpace -sumSpace.run(POLL_TIME) + #admin页面白名单IP WHITELIST_SETTINGS = SETTINGS['WHITELIST'] diff --git a/Aries/hdfs/management/__init__.py b/Aries/hdfs/management/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Aries/hdfs/management/commands/__init__.py b/Aries/hdfs/management/commands/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Aries/hdfs/management/commands/calcsumspace.py b/Aries/hdfs/management/commands/calcsumspace.py new file mode 100644 index 0000000..d090564 --- /dev/null +++ b/Aries/hdfs/management/commands/calcsumspace.py @@ -0,0 +1,19 @@ +# -*- coding: UTF-8 -*- + +from django.core.management.base import BaseCommand + +from Aries import sumSpace + +POLL_TIME = 600 + +#启动一个线程开始定时统计配额. default: 10m + +class Command(BaseCommand): + help = 'start a thread to calc statistical quota every 10 minutes' + + # 由于该脚本执行的命令较为简单,因此不接受参数 + def add_arguments(self, parser): + return None + + def handle(self, *args, **options): + sumSpace.run( POLL_TIME ) diff --git a/docker-k8s/script/start_script.sh b/docker-k8s/script/start_script.sh index 5b18c1b..1ab951f 100644 --- a/docker-k8s/script/start_script.sh +++ b/docker-k8s/script/start_script.sh @@ -104,3 +104,5 @@ service crond restart source /etc/profile /opt/Sirius/sbin/Aries.sh start + +/opt/Python-2.7/bin/python /opt/Sirius/Aries/manage.py calcsumspace From c22afb76749f5f1eb414ac243d46f62c3fb28485 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=83=AD=E6=94=80?= Date: Fri, 6 Jan 2017 15:54:37 +0800 Subject: [PATCH 20/21] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=9B=A0=E4=B8=BAAries?= =?UTF-8?q?.sh=E9=98=BB=E5=A1=9E=E5=AF=BC=E8=87=B4sumspace=E6=97=A0?= =?UTF-8?q?=E6=B3=95=E6=89=A7=E8=A1=8C=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docker-k8s/script/start_script.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docker-k8s/script/start_script.sh b/docker-k8s/script/start_script.sh index 1ab951f..716a7ad 100644 --- a/docker-k8s/script/start_script.sh +++ b/docker-k8s/script/start_script.sh @@ -102,7 +102,8 @@ echo '0 2 * * * /opt/Python-2.7/bin/python /opt/Sirius/Aries/manage.py pushk8sda chmod 600 /var/spool/cron/root service crond restart +nohup /opt/Python-2.7/bin/python /opt/Sirius/Aries/manage.py calcsumspace > /opt/Sirius/log/nohup.out 2>&1 & + source /etc/profile /opt/Sirius/sbin/Aries.sh start -/opt/Python-2.7/bin/python /opt/Sirius/Aries/manage.py calcsumspace From 128732bcc2dd8fc12ebca775570b43cc37055407 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=83=AD=E6=94=80?= Date: Fri, 6 Jan 2017 17:47:22 +0800 Subject: [PATCH 21/21] =?UTF-8?q?=E5=8E=BB=E6=8E=89=E2=80=9C=E8=B5=84?= =?UTF-8?q?=E6=BA=90=E7=94=A8=E9=87=8F-=E8=BF=91=E6=9C=9F=E2=80=9D?= =?UTF-8?q?=E9=A1=B5=E9=9D=A2=E5=BD=93=E5=A4=A9=E6=95=B0=E6=8D=AE=E7=9A=84?= =?UTF-8?q?=E5=B1=95=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../functions/CalcManage/ResourceUsageRecently/index.jsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package/Aries/src/functions/CalcManage/ResourceUsageRecently/index.jsx b/package/Aries/src/functions/CalcManage/ResourceUsageRecently/index.jsx index 7d92211..9cf47d6 100644 --- a/package/Aries/src/functions/CalcManage/ResourceUsageRecently/index.jsx +++ b/package/Aries/src/functions/CalcManage/ResourceUsageRecently/index.jsx @@ -243,7 +243,7 @@ var mod = React.createClass({ requestData(){ // 该页面需要两块数据:账单信息要求显示本月初到今天的数据。走势图需要近14天的数据,为了一次请求成功,因此需要把这两个时间段的数据汇总起来 let todayStartStr = Toolkit.generateTimeStrByMilliSeconds(-1).slice(0,'YYYY-MM-DD'.length) - let sDate1 = new Date(new Date(todayStartStr).getTime() - (this.userData['recentlyDays']-1)*24*60*60*1000) // 最近14天 + let sDate1 = new Date(new Date(todayStartStr).getTime() - (this.userData['recentlyDays'])*24*60*60*1000) // 最近14天 let sDate2 = new Date(todayStartStr.slice(0,'YYYY-MM'.length)+'-01') // 月初 let days = undefined @@ -253,7 +253,7 @@ var mod = React.createClass({ days = this.userData['recentlyDays'] } else { sDate = sDate2 - days = new Date(todayStartStr).getDate() + days = (new Date(todayStartStr).getDate())-1 } let startDateStr = Toolkit.generateTimeStrByMilliSeconds(sDate.getTime()).slice(0,'YYYY-MM-DD'.length) @@ -344,7 +344,7 @@ var mod = React.createClass({ render: function() { let monthFirstDayStr = Toolkit.generateTimeStrByMilliSeconds((new Date()).getTime()).slice( 0,'YYYY-MM'.length ) - let recentlyTitle = Toolkit.strFormatter.formatString('{date} {nameSpace} 账单信息(截至到当前时间)',{ + let recentlyTitle = Toolkit.strFormatter.formatString('{date} {nameSpace} 账单信息(截至到当天凌晨)',{ 'nameSpace':CalcManageConf.getCurSpace(this), 'date':monthFirstDayStr.split('-').join('年') + '月' })
总账单月账单 {this.userData['totalBilling']}
总CPU月平均CPU {this.userData['totalCPU']}
总内存月平均内存 {this.userData['totalMemory']}
总账单月账单 {totalResourceUsage}
总CPU月平均CPU {totalCPU}
总内存月平均内存 {totalMemory}