guest_detail.html 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652
  1. {% extends "layout.html" %}
  2. {% block title %} Guest {% endblock %}
  3. {% block head %}
  4. {{ super() }}
  5. <style type="text/css">
  6. @media (min-width: 768px) {
  7. .form-horizontal .control-label {
  8. text-align: left;
  9. }
  10. }
  11. label>span {
  12. color: deepskyblue;
  13. }
  14. .btn,
  15. .form-group>div>div,
  16. .form-control {
  17. border-radius: 0;
  18. }
  19. .table {
  20. font-size: 12px;
  21. border-width: 1px;
  22. line-height: 22px;
  23. }
  24. .table > tbody > tr > td {
  25. color: #424547;
  26. }
  27. .table-bordered > tbody > tr {
  28. padding-top: 10px;
  29. padding-bottom: 10px;
  30. }
  31. .table-bordered > thead > tr > th,
  32. .table-bordered > tbody > tr > th,
  33. .table-bordered > tfoot > tr > th,
  34. .table-bordered > thead > tr > td,
  35. .table-bordered > tbody > tr > td,
  36. .table-bordered > tfoot > tr > td {
  37. border-style: solid;
  38. border-width: 1px 0 0 0;
  39. }
  40. .guest-label {
  41. color: #999999;
  42. }
  43. .guest-desc {
  44. color: #333333;
  45. }
  46. </style>
  47. {% endblock head %}
  48. {% block body %}
  49. <script>
  50. var resource_path = window.location.pathname;
  51. var resource_path_array = resource_path.split('/');
  52. var uuid = resource_path_array[resource_path_array.length - 1];
  53. var cpu_chart = null;
  54. var traffic_chart = null;
  55. var memory_chart = null;
  56. var datetime_format_type = 'time';
  57. function format_time(timestamp, i) {
  58. if (datetime_format_type === 'time') {
  59. return new Date(timestamp).format('HH:MM');
  60. } else {
  61. return new Date(timestamp).format('mm-dd');
  62. }
  63. }
  64. function render_cpu_chart(uuid, granularity) {
  65. var url = '/api/performance/cpu_memory/last_hour/' + uuid;
  66. if (granularity === 'hour') {
  67. url = '/api/performance/cpu_memory/last_hour/' + uuid
  68. } else if (granularity === 'six_hours') {
  69. url = '/api/performance/cpu_memory/last_six_hours/' + uuid
  70. } else if (granularity === 'day') {
  71. url = '/api/performance/cpu_memory/last_day/' + uuid
  72. } else {
  73. url = '/api/performance/cpu_memory/last_seven_days/' + uuid
  74. }
  75. $.ajax({
  76. url : url,
  77. type : 'GET',
  78. contentType: "application/json; charset=utf-8",
  79. dataType: 'json',
  80. error : function() {
  81. alter_danger('获取图表数据失败失败!');
  82. },
  83. success : function(data, textStatus, xhr) {
  84. if (data.data.length > 1) {
  85. if ((data.data[data.data.length - 1]['timestamp'] - data.data[0]['timestamp']) >= 86400) {
  86. datetime_format_type = 'date';
  87. }
  88. }
  89. var option = {
  90. color: ['#3BC0FF'],
  91. title: {
  92. text: 'CPU'
  93. },
  94. legend: {
  95. data:['CPU使用率(%)'],
  96. bottom: 5
  97. },
  98. toolbox: {
  99. feature: {
  100. dataZoom: {
  101. yAxisIndex: 'none'
  102. },
  103. magicType: {type: ['line', 'bar']},
  104. saveAsImage: {
  105. show: true,
  106. pixelRatio: 4
  107. }
  108. }
  109. },
  110. tooltip: {
  111. show: true,
  112. trigger: 'axis',
  113. formatter: (function (params, ticket, callback) {
  114. var cpu_load = params[0].data[1];
  115. var seriesName = params[0].seriesName;
  116. var marker = params[0].marker;
  117. var datetime = new Date(params[0].data[0]).format('yyyy-mm-dd HH:MM:ss');
  118. if (cpu_load === null) {
  119. cpu_load = '无数据';
  120. }
  121. return datetime + '<br />' + [marker, seriesName, cpu_load].join(' ')
  122. })
  123. },
  124. xAxis: {
  125. type: 'time',
  126. axisTick: {
  127. show: false
  128. },
  129. axisLine: {
  130. lineStyle: {
  131. opacity: 0.1,
  132. color: '#3d4245'
  133. }
  134. },
  135. splitLine: {
  136. show: false
  137. },
  138. axisLabel: {
  139. formatter: format_time
  140. }
  141. },
  142. yAxis: {
  143. min: 0,
  144. max: 'dataMax',
  145. minInterval: 2,
  146. axisTick: {
  147. show: false
  148. },
  149. axisLine: {
  150. lineStyle: {
  151. opacity: 0,
  152. color: '#8c8f91'
  153. }
  154. },
  155. splitLine: {
  156. show: true,
  157. lineStyle: {
  158. width: 1,
  159. opacity: 0.5
  160. }
  161. }
  162. },
  163. series: [{
  164. name: 'CPU使用率(%)',
  165. type: 'line',
  166. showSymbol: false,
  167. smooth: true,
  168. lineStyle: {
  169. normal: {
  170. width: 1
  171. }
  172. },
  173. data: (function () {
  174. var d = [];
  175. $.each(data.data, function(i, ele) {
  176. d.push([
  177. ele['timestamp'] * 1000,
  178. ele['cpu_load']
  179. ])
  180. });
  181. return d;
  182. })()
  183. }]
  184. };
  185. cpu_chart.setOption(option);
  186. }
  187. });
  188. }
  189. function render_traffic_chart(uuid, granularity) {
  190. var url = '/api/performance/traffic/last_hour/' + uuid;
  191. if (granularity === 'hour') {
  192. url = '/api/performance/traffic/last_hour/' + uuid
  193. } else if (granularity === 'six_hours') {
  194. url = '/api/performance/traffic/last_six_hours/' + uuid
  195. } else if (granularity === 'day') {
  196. url = '/api/performance/traffic/last_day/' + uuid
  197. } else {
  198. url = '/api/performance/traffic/last_seven_days/' + uuid
  199. }
  200. $.ajax({
  201. url : url,
  202. type : 'GET',
  203. contentType: "application/json; charset=utf-8",
  204. dataType: 'json',
  205. error : function() {
  206. alter_danger('获取图表数据失败失败!');
  207. },
  208. success : function(data, textStatus, xhr) {
  209. if (data.data.length > 1) {
  210. if ((data.data[data.data.length - 1]['timestamp'] - data.data[0]['timestamp']) >= 86400) {
  211. datetime_format_type = 'date';
  212. }
  213. }
  214. var option = {
  215. color: ['#3BC0FF', '#FAB406'],
  216. title: {
  217. text: '网络'
  218. },
  219. legend: {
  220. data:['流入(kbps)', '流出(kbps)'],
  221. bottom: 5
  222. },
  223. toolbox: {
  224. feature: {
  225. dataZoom: {
  226. yAxisIndex: 'none'
  227. },
  228. magicType: {type: ['line', 'bar']},
  229. saveAsImage: {
  230. show: true,
  231. pixelRatio: 4
  232. }
  233. }
  234. },
  235. tooltip: {
  236. show: true,
  237. trigger: 'axis',
  238. formatter: (function (params, ticket, callback) {
  239. var inflowSeriesName = params[0].seriesName;
  240. var outflowSeriesName = params[1].seriesName;
  241. var inflow = params[0].data[1];
  242. var outflow = params[1].data[1];
  243. var inflowMarker = params[0].marker;
  244. var outflowMarker = params[1].marker;
  245. var datetime = new Date(params[0].data[0]).format('yyyy-mm-dd HH:MM:ss');
  246. if (inflow === null) {
  247. inflow = '无数据';
  248. }
  249. if (outflow === null) {
  250. outflow = '无数据';
  251. }
  252. return datetime + '<br />' + [inflowMarker, inflowSeriesName, inflow].join(' ') +
  253. '<br />' + [outflowMarker, outflowSeriesName, outflow].join(' ')
  254. })
  255. },
  256. xAxis: {
  257. type: 'time',
  258. axisTick: {
  259. show: false
  260. },
  261. axisLine: {
  262. lineStyle: {
  263. opacity: 0.1,
  264. color: '#3d4245'
  265. }
  266. },
  267. splitLine: {
  268. show: false
  269. },
  270. axisLabel: {
  271. formatter: format_time
  272. }
  273. },
  274. yAxis: {
  275. min: 0,
  276. max: 'dataMax',
  277. minInterval: 2,
  278. axisTick: {
  279. show: false
  280. },
  281. axisLine: {
  282. lineStyle: {
  283. opacity: 0,
  284. color: '#8c8f91'
  285. }
  286. },
  287. splitLine: {
  288. show: true,
  289. lineStyle: {
  290. width: 1,
  291. opacity: 0.5
  292. }
  293. }
  294. },
  295. series: [{
  296. name: '流入(kbps)',
  297. type: 'line',
  298. showSymbol: false,
  299. smooth: true,
  300. lineStyle: {
  301. normal: {
  302. width: 1
  303. }
  304. },
  305. data: (function () {
  306. var d = [];
  307. $.each(data.data, function(i, ele) {
  308. d.push([
  309. ele['timestamp'] * 1000,
  310. ele['rx_bytes'] !== null ? Math.floor(ele['rx_bytes'] / 1000) : null
  311. ])
  312. });
  313. return d;
  314. })()
  315. },{
  316. name: '流出(kbps)',
  317. type: 'line',
  318. showSymbol: false,
  319. smooth: true,
  320. lineStyle: {
  321. normal: {
  322. width: 1
  323. }
  324. },
  325. data: (function () {
  326. var d = [];
  327. $.each(data.data, function(i, ele) {
  328. d.push([
  329. ele['timestamp'] * 1000,
  330. ele['tx_bytes'] !== null ? Math.floor(ele['tx_bytes'] / 1000) : null
  331. ])
  332. });
  333. return d;
  334. })()
  335. }]
  336. };
  337. traffic_chart.setOption(option);
  338. }
  339. });
  340. }
  341. function render_memory_chart(uuid, granularity) {
  342. var url = '/api/performance/cpu_memory/last_hour/' + uuid;
  343. if (granularity === 'hour') {
  344. url = '/api/performance/cpu_memory/last_hour/' + uuid
  345. } else if (granularity === 'six_hours') {
  346. url = '/api/performance/cpu_memory/last_six_hours/' + uuid
  347. } else if (granularity === 'day') {
  348. url = '/api/performance/cpu_memory/last_day/' + uuid
  349. } else {
  350. url = '/api/performance/cpu_memory/last_seven_days/' + uuid
  351. }
  352. $.ajax({
  353. url: url,
  354. type: 'GET',
  355. contentType: "application/json; charset=utf-8",
  356. dataType: 'json',
  357. error: function () {
  358. alter_danger('获取图表数据失败失败!');
  359. },
  360. success: function (data, textStatus, xhr) {
  361. if (data.data.length > 1) {
  362. if ((data.data[data.data.length - 1]['timestamp'] - data.data[0]['timestamp']) >= 86400) {
  363. datetime_format_type = 'date';
  364. }
  365. }
  366. var option = {
  367. color: ['#35CD03'],
  368. title: {
  369. text: '内存'
  370. },
  371. legend: {
  372. data: ['可用量'],
  373. bottom: 5
  374. },
  375. toolbox: {
  376. feature: {
  377. dataZoom: {
  378. yAxisIndex: 'none'
  379. },
  380. magicType: {type: ['line', 'bar']},
  381. saveAsImage: {
  382. show: true,
  383. pixelRatio: 4
  384. }
  385. }
  386. },
  387. tooltip: {
  388. show: true,
  389. trigger: 'axis',
  390. formatter: (function (params, ticket, callback) {
  391. var seriesName = params[0].seriesName;
  392. var free = params[0].data[1];
  393. var marker = params[0].marker;
  394. var datetime = new Date(params[0].data[0]).format('yyyy-mm-dd HH:MM:ss');
  395. if (free === null) {
  396. free = '无数据';
  397. }
  398. return datetime + '<br />' + [marker, seriesName, free].join(' ')
  399. })
  400. },
  401. xAxis: {
  402. type: 'time',
  403. axisTick: {
  404. show: false
  405. },
  406. axisLine: {
  407. lineStyle: {
  408. opacity: 0.1,
  409. color: '#3d4245'
  410. }
  411. },
  412. splitLine: {
  413. show: false
  414. },
  415. axisLabel: {
  416. formatter: format_time
  417. }
  418. },
  419. yAxis: {
  420. min: 0,
  421. max: 'dataMax',
  422. minInterval: 2,
  423. axisTick: {
  424. show: false
  425. },
  426. axisLine: {
  427. lineStyle: {
  428. opacity: 0,
  429. color: '#8c8f91'
  430. }
  431. },
  432. splitLine: {
  433. show: true,
  434. lineStyle: {
  435. width: 1,
  436. opacity: 0.5
  437. }
  438. }
  439. },
  440. series: [{
  441. name: '可用量(GB)',
  442. type: 'line',
  443. showSymbol: false,
  444. smooth: true,
  445. lineStyle: {
  446. normal: {
  447. width: 1
  448. }
  449. },
  450. areaStyle: {normal: {}},
  451. data: (function () {
  452. var d = [];
  453. $.each(data.data, function (i, ele) {
  454. d.push([
  455. ele['timestamp'] * 1000,
  456. ele['memory_unused'] !== null ? Math.floor(ele['memory_unused'] / 1024) / 1000 : null
  457. ])
  458. });
  459. return d;
  460. })()
  461. }]
  462. };
  463. memory_chart.setOption(option);
  464. }
  465. });
  466. }
  467. $(document).ready(function() {
  468. $('body').addClass('add-transition');
  469. $('.add-page-transition').on('click', function(){
  470. var transAttr = $(this).attr('data-transition');
  471. $('.add-transition').attr('class', 'add-transition');
  472. $('.add-transition').addClass(transAttr);
  473. });
  474. cpu_chart = echarts.init(document.getElementById('cpu_chart'));
  475. traffic_chart = echarts.init(document.getElementById('traffic_chart'));
  476. // memory_chart = echarts.init(document.getElementById('memory_chart'));
  477. render_cpu_chart(uuid, 'hour');
  478. render_traffic_chart(uuid, 'hour');
  479. // render_memory_chart(uuid, 'hour');
  480. });
  481. function refresh_render_with_specify_granularity(granularity) {
  482. render_cpu_chart(uuid, granularity);
  483. render_traffic_chart(uuid, granularity);
  484. }
  485. </script>
  486. <div class="container" style="padding-top: 100px; width: 90%; max-width: 100%;">
  487. <div class="panel">
  488. <div class="panel-body">
  489. <h3 class="title-hero" style="display: inline;">
  490. 虚拟机实例详情
  491. </h3>
  492. <a href="/guests" class="btn btn-xs btn-default add-page-transition" data-transition="pt-page-moveFromLeft-init" style="margin-bottom: 4px; margin-left: 10px;">
  493. <span class="glyph-icon icon-separator" style="transform: rotateY(-180deg);">
  494. <i class="glyph-icon icon-level-up"></i>
  495. </span>
  496. <span class="button-content">
  497. 返回虚拟机列表
  498. </span>
  499. </a>
  500. <div class="row" style="margin-top: 10px;">
  501. <div class="col-xs-4">
  502. <div style="background: #F5f6FA; border: 1px solid #e1e6eb; padding: 10px; font-size: 14px; width: 100%;">
  503. <span>
  504. 实例信息
  505. </span>
  506. </div>
  507. <table class="table table-bordered">
  508. <tbody>
  509. <tr>
  510. <td>
  511. <span class="guest-label">UUID:&nbsp;&nbsp;&nbsp;&nbsp;</span>
  512. <span class="guest-desc">
  513. {{ guest_ret.data.uuid }}
  514. </span>
  515. </td>
  516. </tr>
  517. <tr>
  518. <td>
  519. <span class="guest-label">标识:&nbsp;&nbsp;&nbsp;&nbsp;</span>
  520. <span class="guest-desc">
  521. {{ guest_ret.data.label }}
  522. </span>
  523. </td>
  524. </tr>
  525. <tr>
  526. <td>
  527. <span class="guest-label">名称:&nbsp;&nbsp;&nbsp;&nbsp;</span>
  528. <span class="guest-desc">
  529. {{ guest_ret.data.remark }}
  530. </span>
  531. </td>
  532. </tr>
  533. <tr>
  534. <td>
  535. <span class="guest-label">CPU:&nbsp;&nbsp;&nbsp;&nbsp;</span>
  536. <span class="guest-desc">
  537. {{ guest_ret.data.cpu }} 核
  538. </span>
  539. </td>
  540. </tr>
  541. <tr>
  542. <td>
  543. <span class="guest-label">内存:&nbsp;&nbsp;&nbsp;&nbsp;</span>
  544. <span class="guest-desc">
  545. {{ guest_ret.data.memory }} GB
  546. </span>
  547. </td>
  548. </tr>
  549. <tr>
  550. <td>
  551. <span class="guest-label">操作系统:&nbsp;&nbsp;&nbsp;&nbsp;</span>
  552. <span class="guest-desc">
  553. {{ os_template_ret.data.label }}
  554. </span>&nbsp;&nbsp;&nbsp;&nbsp;
  555. <span class="{{ os_template_ret.data.icon }}"></span>
  556. </td>
  557. </tr>
  558. <tr>
  559. <td>
  560. <span class="guest-label">IP:&nbsp;&nbsp;&nbsp;&nbsp;</span>
  561. <span class="guest-desc">
  562. {{ guest_ret.data.ip }}
  563. </span>
  564. </td>
  565. </tr>
  566. <tr>
  567. <td>
  568. <span class="guest-label">密码:&nbsp;&nbsp;&nbsp;&nbsp;</span>
  569. <span class="guest-desc">
  570. {{ guest_ret.data.password }}
  571. </span>
  572. </td>
  573. </tr>
  574. <tr>
  575. <td>
  576. <span class="guest-label">所在宿主机:&nbsp;&nbsp;&nbsp;&nbsp;</span>
  577. <span class="guest-desc">
  578. {{ guest_ret.data.on_host }}
  579. </span>
  580. </td>
  581. </tr>
  582. <tr>
  583. <td>
  584. <span class="guest-label">创建时间:&nbsp;&nbsp;&nbsp;&nbsp;</span>
  585. <span class="guest-desc">
  586. {{ format_datetime_by_tus(guest_ret.data.create_time) }}
  587. </span>
  588. </td>
  589. </tr>
  590. </tbody>
  591. </table>
  592. </div>
  593. <div class="col-xs-8">
  594. <div class="row" style="margin-bottom: 20px;">
  595. <div class="col-xs-8"></div>
  596. <div class="col-xs-4">
  597. <div class="btn-group btn-group-justified btn-group-xs">
  598. <a class="btn btn-default" role="button" onclick="refresh_render_with_specify_granularity('hour');">1小时</a>
  599. <a class="btn btn-default" role="button" onclick="refresh_render_with_specify_granularity('six_hours');">6小时</a>
  600. <a class="btn btn-default" role="button" onclick="refresh_render_with_specify_granularity('day');">1天</a>
  601. <a class="btn btn-default" role="button" onclick="refresh_render_with_specify_granularity('seven_days');">7天</a>
  602. </div>
  603. </div>
  604. </div>
  605. <div id="cpu_chart" style="width: 800px;height:280px;"></div>
  606. <div id="traffic_chart" style="width: 800px;height:280px;"></div>
  607. <!--<div id="memory_chart" style="width: 800px;height:280px;"></div>-->
  608. </div>
  609. </div>
  610. </div>
  611. </div>
  612. </div>
  613. {% endblock body %}