mount_points_based_initializer_mixin.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  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. /**
  20. * Regexp used to determine if mount point is windows-like
  21. *
  22. * @type {RegExp}
  23. */
  24. var winRegex = /^([a-z]):\\?$/;
  25. App.MountPointsBasedInitializerMixin = Em.Mixin.create({
  26. /**
  27. * Map for methods used as value-modifiers for configProperties with values as mount point(s)
  28. * Used if mount point is win-like (@see winRegex)
  29. * Key: id
  30. * Value: method-name
  31. *
  32. * @type {{default: string, file: string, slashes: string}}
  33. */
  34. winReplacersMap: {
  35. default: '_defaultWinReplace',
  36. file: '_winReplaceWithFile',
  37. slashes: '_defaultWinReplaceWithAdditionalSlashes'
  38. },
  39. /**
  40. * Initializer for configs with value as one of the possible mount points
  41. * Only hosts that contains on the components from <code>initializer.components</code> are processed
  42. * Hosts with Windows needs additional processing (@see winReplacersMap)
  43. * Value example: '/', '/some/cool/dir'
  44. *
  45. * @param {configProperty} configProperty
  46. * @param {topologyLocalDB} localDB
  47. * @param {object} dependencies
  48. * @param {object} initializer
  49. * @return {Object}
  50. */
  51. _initAsSingleMountPoint: function (configProperty, localDB, dependencies, initializer) {
  52. var hostsInfo = this._updateHostInfo(localDB.hosts);
  53. var setOfHostNames = this._getSetOfHostNames(localDB, initializer);
  54. var winReplacersMap = this.get('winReplacersMap');
  55. // In Add Host Wizard, if we did not select this slave component for any host, then we don't process any further.
  56. if (!setOfHostNames.length) {
  57. return configProperty;
  58. }
  59. var allMountPoints = this._getAllMountPoints(setOfHostNames, hostsInfo);
  60. var mPoint = allMountPoints[0].mountpoint;
  61. if (mPoint === "/") {
  62. mPoint = Em.get(configProperty, 'recommendedValue');
  63. }
  64. else {
  65. var mp = mPoint.toLowerCase();
  66. if (winRegex.test(mp)) {
  67. var methodName = winReplacersMap[initializer.winReplacer];
  68. mPoint = this[methodName].call(this, configProperty, mp);
  69. }
  70. else {
  71. mPoint = mPoint + Em.get(configProperty, 'recommendedValue');
  72. }
  73. }
  74. Em.setProperties(configProperty, {
  75. value: mPoint,
  76. recommendedValue: mPoint
  77. });
  78. return configProperty;
  79. },
  80. /**
  81. * Initializer for configs with value as all of the possible mount points
  82. * Only hosts that contains on the components from <code>initializer.components</code> are processed
  83. * Hosts with Windows needs additional processing (@see winReplacersMap)
  84. * Value example: '/\n/some/cool/dir' (`\n` - is divider)
  85. *
  86. * @param {Object} configProperty
  87. * @param {topologyLocalDB} localDB
  88. * @param {object} dependencies
  89. * @param {object} initializer
  90. * @return {Object}
  91. */
  92. _initAsMultipleMountPoints: function (configProperty, localDB, dependencies, initializer) {
  93. var hostsInfo = this._updateHostInfo(localDB.hosts);
  94. var self = this;
  95. var setOfHostNames = this._getSetOfHostNames(localDB, initializer);
  96. var winReplacersMap = this.get('winReplacersMap');
  97. // In Add Host Wizard, if we did not select this slave component for any host, then we don't process any further.
  98. if (!setOfHostNames.length) {
  99. return configProperty;
  100. }
  101. var allMountPoints = this._getAllMountPoints(setOfHostNames, hostsInfo);
  102. var mPoint = '';
  103. allMountPoints.forEach(function (eachDrive) {
  104. if (eachDrive.mountpoint === '/') {
  105. mPoint += Em.get(configProperty, 'recommendedValue') + "\n";
  106. }
  107. else {
  108. var mp = eachDrive.mountpoint.toLowerCase();
  109. if (winRegex.test(mp)) {
  110. var methodName = winReplacersMap[initializer.winReplacer];
  111. mPoint += self[methodName].call(this, configProperty, mp);
  112. }
  113. else {
  114. mPoint += eachDrive.mountpoint + Em.get(configProperty, 'recommendedValue') + "\n";
  115. }
  116. }
  117. }, this);
  118. Em.setProperties(configProperty, {
  119. value: mPoint,
  120. recommendedValue: mPoint
  121. });
  122. return configProperty;
  123. },
  124. /**
  125. * Replace drive-based windows-path with 'file:///'
  126. *
  127. * @param {configProperty} configProperty
  128. * @param {string} mountPoint
  129. * @returns {string}
  130. * @private
  131. */
  132. _winReplaceWithFile: function (configProperty, mountPoint) {
  133. var winDriveUrl = mountPoint.toLowerCase().replace(winRegex, 'file:///$1:');
  134. return winDriveUrl + Em.get(configProperty, 'recommendedValue') + '\n';
  135. },
  136. /**
  137. * Replace drive-based windows-path
  138. *
  139. * @param {configProperty} configProperty
  140. * @param {string} mountPoint
  141. * @returns {string}
  142. * @private
  143. */
  144. _defaultWinReplace: function (configProperty, mountPoint) {
  145. var winDrive = mountPoint.toLowerCase().replace(winRegex, '$1:');
  146. var winDir = Em.get(configProperty, 'recommendedValue').replace(/\//g, '\\');
  147. return winDrive + winDir + '\n';
  148. },
  149. /**
  150. * Same to <code>_defaultWinReplace</code>, but with extra-slash in the end
  151. *
  152. * @param {configProperty} configProperty
  153. * @param {string} mountPoint
  154. * @returns {string}
  155. * @private
  156. */
  157. _defaultWinReplaceWithAdditionalSlashes: function (configProperty, mountPoint) {
  158. var winDrive = mountPoint.toLowerCase().replace(winRegex, '$1:');
  159. var winDir = Em.get(configProperty, 'recommendedValue').replace(/\//g, '\\\\');
  160. return winDrive + winDir + '\n';
  161. },
  162. /**
  163. * Update information from localDB using <code>App.Host</code>-model
  164. *
  165. * @param {object} hostsInfo
  166. * @returns {object}
  167. * @private
  168. */
  169. _updateHostInfo: function (hostsInfo) {
  170. App.Host.find().forEach(function (item) {
  171. if (!hostsInfo[item.get('id')]) {
  172. hostsInfo[item.get('id')] = {
  173. name: item.get('id'),
  174. cpu: item.get('cpu'),
  175. memory: item.get('memory'),
  176. disk_info: item.get('diskInfo'),
  177. bootStatus: "REGISTERED",
  178. isInstalled: true
  179. };
  180. }
  181. });
  182. return hostsInfo;
  183. },
  184. /**
  185. * Determines if mount point is valid
  186. * Criterias:
  187. * <ul>
  188. * <li>Should has available space</li>
  189. * <li>Should not be home-dir</li>
  190. * <li>Should not be docker-dir</li>
  191. * <li>Should not be boot-dir</li>
  192. * <li>Should not be dev-dir</li>
  193. * </ul>
  194. *
  195. * @param {{mountpoint: string, available: number}} mPoint
  196. * @returns {boolean} true - valid, false - invalid
  197. * @private
  198. */
  199. _filterMountPoint: function (mPoint) {
  200. var isAvailable = mPoint.available !== 0;
  201. if (!isAvailable) {
  202. return false;
  203. }
  204. var notHome = !['/', '/home'].contains(mPoint.mountpoint);
  205. var notDocker = !['/etc/resolv.conf', '/etc/hostname', '/etc/hosts'].contains(mPoint.mountpoint);
  206. var notBoot = mPoint.mountpoint && !(mPoint.mountpoint.startsWith('/boot')
  207. || mPoint.mountpoint.startsWith('/mnt')
  208. || mPoint.mountpoint.startsWith('/tmp'));
  209. var notDev = !(['devtmpfs', 'tmpfs', 'vboxsf', 'CDFS'].contains(mPoint.type));
  210. return notHome && notDocker && notBoot && notDev;
  211. },
  212. /**
  213. * Get list of hostNames from localDB which contains needed components
  214. *
  215. * @param {topologyLocalDB} localDB
  216. * @param {object} initializer
  217. * @returns {string[]}
  218. * @private
  219. */
  220. _getSetOfHostNames: function (localDB, initializer) {
  221. var masterComponentHostsInDB = Em.getWithDefault(localDB, 'masterComponentHosts', []);
  222. var slaveComponentHostsInDB = Em.getWithDefault(localDB, 'slaveComponentHosts', []);
  223. var hosts = masterComponentHostsInDB.filter(function (master) {
  224. return initializer.components.contains(master.component);
  225. }).mapProperty('hostName');
  226. var sHosts = slaveComponentHostsInDB.find(function (slave) {
  227. return initializer.components.contains(slave.componentName);
  228. });
  229. if (sHosts) {
  230. hosts = hosts.concat(sHosts.hosts.mapProperty('hostName'));
  231. }
  232. return hosts;
  233. },
  234. /**
  235. * Get list of all unique valid mount points for hosts
  236. *
  237. * @param {string[]} setOfHostNames
  238. * @param {object} hostsInfo
  239. * @returns {string[]}
  240. * @private
  241. */
  242. _getAllMountPoints: function (setOfHostNames, hostsInfo) {
  243. var allMountPoints = [];
  244. for (var i = 0; i < setOfHostNames.length; i++) {
  245. var hostname = setOfHostNames[i];
  246. var mountPointsPerHost = hostsInfo[hostname].disk_info;
  247. var mountPointAsRoot = mountPointsPerHost.findProperty('mountpoint', '/');
  248. // If Server does not send any host details information then atleast one mountpoint should be presumed as root
  249. // This happens in a single container Linux Docker environment.
  250. if (!mountPointAsRoot) {
  251. mountPointAsRoot = {
  252. mountpoint: '/'
  253. };
  254. }
  255. mountPointsPerHost.filter(this._filterMountPoint).forEach(function (mPoint) {
  256. if( !allMountPoints.findProperty("mountpoint", mPoint.mountpoint)) {
  257. allMountPoints.push(mPoint);
  258. }
  259. }, this);
  260. }
  261. if (!allMountPoints.length) {
  262. allMountPoints.push(mountPointAsRoot);
  263. }
  264. return allMountPoints;
  265. },
  266. /**
  267. * Settings for <code>single_mountpoint</code>-initializer
  268. * Used for configs with value as one of the possible mount points
  269. *
  270. * @see _initAsSingleMountPoint
  271. * @param {string|string[]} components
  272. * @param {string} winReplacer
  273. * @returns {{components: string[], winReplacer: string, type: string}}
  274. */
  275. getSingleMountPointConfig: function (components, winReplacer) {
  276. winReplacer = winReplacer || 'default';
  277. return {
  278. components: Em.makeArray(components),
  279. winReplacer: winReplacer,
  280. type: 'single_mountpoint'
  281. };
  282. },
  283. /**
  284. * Settings for <code>multiple_mountpoints</code>-initializer
  285. * Used for configs with value as all of the possible mount points
  286. *
  287. * @see _initAsMultipleMountPoints
  288. * @param {string|string[]} components
  289. * @param {string} winReplacer
  290. * @returns {{components: string[], winReplacer: string, type: string}}
  291. */
  292. getMultipleMountPointsConfig: function (components, winReplacer) {
  293. winReplacer = winReplacer || 'default';
  294. return {
  295. components: Em.makeArray(components),
  296. winReplacer: winReplacer,
  297. type: 'multiple_mountpoints'
  298. };
  299. }
  300. });