host.js 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. /**
  2. * Licensed to the Apache Software Foundation (ASF) under one
  3. * or more contributor license agreements. See the NOTICE file
  4. * distributed with this work for additional information
  5. * regarding copyright ownership. The ASF licenses this file
  6. * to you under the Apache License, Version 2.0 (the
  7. * "License"); you may not use this file except in compliance
  8. * with the License. You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. */
  18. var App = require('app');
  19. var misc = require('utils/misc');
  20. DS.attr.transforms.object = {
  21. from: function(serialized) {
  22. return Ember.none(serialized) ? null : Object(serialized);
  23. },
  24. to: function(deserialized) {
  25. return Ember.none(deserialized) ? null : Object(deserialized);
  26. }
  27. };
  28. App.Host = DS.Model.extend({
  29. hostName: DS.attr('string'),
  30. publicHostName: DS.attr('string'),
  31. cluster: DS.belongsTo('App.Cluster'),
  32. hostComponents: DS.hasMany('App.HostComponent'),
  33. cpu: DS.attr('string'),
  34. memory: DS.attr('string'),
  35. diskTotal: DS.attr('number'),
  36. diskFree: DS.attr('number'),
  37. osArch: DS.attr('string'),
  38. ip: DS.attr('string'),
  39. rack: DS.attr('string'),
  40. healthStatus: DS.attr('string'),
  41. cpuUsage: DS.attr('number'),
  42. memoryUsage: DS.attr('number'),
  43. lastHeartBeatTime: DS.attr('number'),
  44. osType: DS.attr("string"),
  45. diskInfo: DS.attr('object'),
  46. loadOne:DS.attr('number'),
  47. loadFive:DS.attr('number'),
  48. loadFifteen:DS.attr('number'),
  49. criticalAlertsCount: function () {
  50. return App.router.get('clusterController.alerts').filterProperty('hostName', this.get('hostName')).filterProperty('isOk', false).filterProperty('ignoredForHosts', false).length;
  51. }.property('App.router.clusterController.alerts.length'),
  52. publicHostNameFormatted: function() {
  53. return this.get('publicHostName').substr(0, 20) + ' ...';
  54. }.property('publicHostName'),
  55. /**
  56. * API return diskTotal and diskFree. Need to save their different
  57. */
  58. diskUsed: function(){
  59. return this.get('diskTotal') - this.get('diskFree');
  60. }.property('diskFree', 'diskTotal'),
  61. /**
  62. * Format diskUsed value to float with 2 digits (also convert to GB)
  63. */
  64. diskUsedFormatted: function() {
  65. return Math.round(this.get('diskUsed') * Math.pow(10, 2)) / Math.pow(10, 2) + 'GB';
  66. }.property('diskUsed'),
  67. /**
  68. * Format diskTotal value to float with 2 digits (also convert to GB)
  69. */
  70. diskTotalFormatted: function() {
  71. return Math.round(this.get('diskTotal') * Math.pow(10, 2)) / Math.pow(10, 2) + 'GB';
  72. }.property('diskTotal'),
  73. /**
  74. * Percent value of used disk space
  75. */
  76. diskUsage: function() {
  77. return (this.get('diskUsed')) / this.get('diskTotal') * 100;
  78. }.property('diskUsed', 'diskTotal'),
  79. /**
  80. * Format diskUsage to float with 2 digits
  81. */
  82. diskUsageFormatted: function() {
  83. if (isNaN(this.get('diskUsage')) || this.get('diskUsage') < 0) {
  84. return 'Data Unavailable';
  85. }
  86. var s = Math.round(this.get('diskUsage') * Math.pow(10, 2)) / Math.pow(10, 2);
  87. if (isNaN(s)) {
  88. s = 0;
  89. }
  90. return s + '%';
  91. }.property('diskUsage'),
  92. diskInfoBar: function() {
  93. if (isNaN(this.get('diskUsage')) || this.get('diskUsage') < 0) {
  94. return this.get('diskUsageFormatted');
  95. }
  96. return this.get('diskUsedFormatted') + '/' + this.get('diskTotalFormatted') + ' (' + this.get('diskUsageFormatted') + ' used)';
  97. }.property('diskUsedFormatted', 'diskTotalFormatted'),
  98. /**
  99. * formatted bytes to appropriate value
  100. */
  101. memoryFormatted: function () {
  102. return misc.formatBandwidth(this.get('memory') * 1024);
  103. }.property('memory'),
  104. /**
  105. * Return true if host not heartbeating last 180 seconds
  106. */
  107. isNotHeartBeating : function(){
  108. return (App.testMode) ? false : ((new Date()).getTime() - this.get('lastHeartBeatTime')) > 180 * 1000;
  109. }.property('lastHeartBeatTime'),
  110. loadAvg: function() {
  111. if (this.get('loadOne') != null) return this.get('loadOne').toFixed(2);
  112. if (this.get('loadFive') != null) return this.get('loadFive').toFixed(2);
  113. if (this.get('loadFifteen') != null) return this.get('loadFifteen').toFixed(2);
  114. }.property('loadOne', 'loadFive', 'loadFifteen'),
  115. // Instead of making healthStatus a computed property that listens on hostComponents.@each.workStatus,
  116. // we are creating a separate observer _updateHealthStatus. This is so that healthStatus is updated
  117. // only once after the run loop. This is because Ember invokes the computed property every time
  118. // a property that it depends on changes. For example, App.statusMapper's map function would invoke
  119. // the computed property too many times and freezes the UI without this hack.
  120. // See http://stackoverflow.com/questions/12467345/ember-js-collapsing-deferring-expensive-observers-or-computed-properties
  121. healthClass: '',
  122. _updateHealthClass: function(){
  123. Ember.run.once(this, 'updateHealthClass');
  124. }.observes('healthStatus', 'hostComponents.@each.workStatus'),
  125. updateHealthClass: function(){
  126. var healthStatus = this.get('healthStatus');
  127. /**
  128. * Do nothing until load
  129. */
  130. if (!this.get('isLoaded') || this.get('isSaving')) {
  131. } else {
  132. var status;
  133. var masterComponents = this.get('hostComponents').filterProperty('isMaster');
  134. var masterComponentsRunning = masterComponents.everyProperty('workStatus', App.HostComponentStatus.started);
  135. var slaveComponents = this.get('hostComponents').filterProperty('isSlave');
  136. var slaveComponentsRunning = slaveComponents.everyProperty('workStatus', App.HostComponentStatus.started);
  137. if (this.get('isNotHeartBeating')) {
  138. status = 'DEAD-YELLOW';
  139. } else if (masterComponentsRunning && slaveComponentsRunning) {
  140. status = 'LIVE';
  141. } else if (masterComponents.length > 0 && !masterComponentsRunning) {
  142. status = 'DEAD-RED';
  143. } else {
  144. status = 'DEAD-ORANGE';
  145. }
  146. if (status) {
  147. healthStatus = status;
  148. }
  149. }
  150. this.set('healthClass', 'health-status-' + healthStatus);
  151. },
  152. healthToolTip: function(){
  153. var hostComponents = this.get('hostComponents').filter(function(item){
  154. if(item.get('workStatus') !== App.HostComponentStatus.started){
  155. return true;
  156. }
  157. });
  158. var output = '';
  159. switch (this.get('healthClass')){
  160. case 'health-status-DEAD-RED':
  161. hostComponents = hostComponents.filterProperty('isMaster', true);
  162. output = Em.I18n.t('hosts.host.healthStatus.mastersDown');
  163. hostComponents.forEach(function(hc, index){
  164. output += (index == (hostComponents.length-1)) ? hc.get('displayName') : (hc.get('displayName')+", ");
  165. }, this);
  166. break;
  167. case 'health-status-DEAD-YELLOW':
  168. output = Em.I18n.t('hosts.host.healthStatus.heartBeatNotReceived');
  169. break;
  170. case 'health-status-DEAD-ORANGE':
  171. hostComponents = hostComponents.filterProperty('isSlave', true);
  172. output = Em.I18n.t('hosts.host.healthStatus.slavesDown');
  173. hostComponents.forEach(function(hc, index){
  174. output += (index == (hostComponents.length-1)) ? hc.get('displayName') : (hc.get('displayName')+", ");
  175. }, this);
  176. break;
  177. }
  178. return output;
  179. }.property('healthClass')
  180. });
  181. App.Host.FIXTURES = [];