guest_detail.html 24 KB

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