hdfs.ko.js 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. // Licensed to Cloudera, Inc. under one
  2. // or more contributor license agreements. See the NOTICE file
  3. // distributed with this work for additional information
  4. // regarding copyright ownership. Cloudera, Inc. licenses this file
  5. // to you under the Apache License, Version 2.0 (the
  6. // "License"); you may not use this file except in compliance
  7. // with the License. You may obtain a copy of the License at
  8. //
  9. // http://www.apache.org/licenses/LICENSE-2.0
  10. //
  11. // Unless required by applicable law or agreed to in writing, software
  12. // distributed under the License is distributed on an "AS IS" BASIS,
  13. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. // See the License for the specific language governing permissions and
  15. // limitations under the License.
  16. function parseAcl(acl) {
  17. // (default:)?(user|group|mask|other):[[A-Za-z_][A-Za-z0-9._-]]*:([rwx-]{3})?
  18. m = acl.match(/(default:)?(user|group|mask|other):(.*?):(.)(.)(.)/);
  19. var acl = ko.mapping.fromJS({
  20. 'isDefault': m[1] != null,
  21. 'type': m[2],
  22. 'name': m[3],
  23. 'r': m[4] != '-',
  24. 'w': m[5] != '-',
  25. 'x': m[6] != '-',
  26. 'status': ''
  27. });
  28. acl.type.subscribe(function () {
  29. acl.status('modified');
  30. });
  31. acl.name.subscribe(function () {
  32. acl.status('modified');
  33. });
  34. acl.r.subscribe(function () {
  35. acl.status('modified');
  36. });
  37. acl.w.subscribe(function () {
  38. acl.status('modified');
  39. });
  40. acl.x.subscribe(function () {
  41. acl.status('modified');
  42. });
  43. return acl;
  44. }
  45. function printAcl(acl) {
  46. return (acl.isDefault() ? 'default:' : '') + acl.type() + ':' + acl.name() + ':' + (acl.r() ? 'r' : '-') + (acl.w() ? 'w' : '-') + (acl.x() ? 'x' : '-');
  47. }
  48. var Assist = function (vm, assist) {
  49. var self = this;
  50. self.isLoadingAcls = ko.observable(false);
  51. self.showAclsAsText = ko.observable(false);
  52. self.isDiffMode = ko.observable(false);
  53. self.treeData = ko.observable({nodes:[]});
  54. self.loadData = function(data) {
  55. self.treeData(new NodeModel(data));
  56. };
  57. self.growingTree = ko.observable({
  58. name: "/",
  59. path: "/",
  60. aclBit: false,
  61. selected: false,
  62. nodes: []
  63. });
  64. self.path = ko.observable('');
  65. self.path.subscribe(function () {
  66. self.fetchPath();
  67. });
  68. self.files = ko.observableArray();
  69. self.acls = ko.observableArray();
  70. self.originalAcls = ko.observableArray();
  71. self.regularAcls = ko.computed(function () {
  72. return $.grep(self.acls(), function (acl) {
  73. return ! acl.isDefault();
  74. });
  75. });
  76. self.defaultAcls = ko.computed(function () {
  77. return $.grep(self.acls(), function (acl) {
  78. return acl.isDefault();
  79. });
  80. });
  81. self.changedAcls = ko.computed(function () {
  82. return $.grep(self.acls(), function (acl) {
  83. return ['new', 'deleted', 'modified'].indexOf(acl.status()) != -1;
  84. });
  85. });
  86. self.owner = ko.observable('');
  87. self.group = ko.observable('');
  88. self.addAcl = function () {
  89. var newAcl = parseAcl('group::---');
  90. newAcl.status('new');
  91. self.acls.push(newAcl);
  92. };
  93. self.addDefaultAcl = function () {
  94. var newAcl = parseAcl('default:group::---');
  95. newAcl.status('new');
  96. self.acls.push(newAcl);
  97. };
  98. self.removeAcl = function (acl) {
  99. if (acl.status() == 'new') {
  100. self.acls.remove(acl);
  101. } else {
  102. acl.status('deleted');
  103. }
  104. };
  105. self.convertItemToObject = function (item) {
  106. var _path = item.path;
  107. var _parent = _path.substr(0, _path.lastIndexOf("/"));
  108. if (_parent == "") {
  109. _parent = "/";
  110. }
  111. if (_path != "/") {
  112. self.growingTree(self.traversePath(self.growingTree(), _parent, item));
  113. }
  114. }
  115. self.traversePath = function(leaf, parent, item){
  116. var _mainFound = false;
  117. leaf.nodes.forEach(function(node){
  118. if (node.path == item.path){
  119. _mainFound = true;
  120. }
  121. if (parent.indexOf(node.path) > -1){
  122. self.traversePath(node, parent, item);
  123. }
  124. });
  125. if (!_mainFound && leaf.path == parent){
  126. var _chunks = item.path.split("/");
  127. leaf.nodes.push({
  128. name: _chunks[_chunks.length-1],
  129. path: item.path,
  130. aclBit: item.rwx.indexOf('+') != -1,
  131. isDir: item.type == "dir",
  132. nodes: []
  133. });
  134. }
  135. return leaf;
  136. }
  137. self.setPath = function (obj) {
  138. self.path(obj.path());
  139. }
  140. self.openPath = function (obj) {
  141. window.open("/filebrowser/view" + obj.path(), '_blank');
  142. }
  143. self.loadParents = function(breadcrumbs) {
  144. if (typeof breadcrumbs != "undefined" && breadcrumbs != null) {
  145. breadcrumbs.forEach(function (crumb, idx) {
  146. if (idx < breadcrumbs.length - 1 && crumb.url != "") {
  147. var _item = {
  148. path: crumb.url,
  149. name: crumb.label,
  150. rwx: ""
  151. }
  152. self.convertItemToObject(_item);
  153. }
  154. });
  155. }
  156. }
  157. self.fetchPath = function () {
  158. $.getJSON('/filebrowser/view' + self.path(), {
  159. 'pagesize': 15,
  160. 'format': 'json',
  161. 'doas': vm.doAs(),
  162. }, function (data) {
  163. self.loadParents(data.breadcrumbs);
  164. if (data['files'] && data['files'][0]['type'] == 'dir') { // Hack for now
  165. self.files.removeAll();
  166. $.each(data.files, function (index, item) {
  167. self.convertItemToObject(item);
  168. self.files.push(ko.mapping.fromJS({
  169. 'path': item.path,
  170. 'aclBit': item.rwx.indexOf('+') != -1
  171. })
  172. );
  173. });
  174. self.loadData(self.growingTree());
  175. }
  176. self.getAcls();
  177. }).fail(function (xhr, textStatus, errorThrown) {
  178. $(document).trigger("error", xhr.responseText);
  179. });
  180. };
  181. self.getAcls = function () {
  182. $(".jHueNotify").hide();
  183. var _isLoading = window.setTimeout(function(){
  184. self.isLoadingAcls(true);
  185. }, 1000);
  186. logGA('get_acls');
  187. $.getJSON('/security/api/hdfs/get_acls', {
  188. 'path': self.path()
  189. }, function (data) {
  190. window.clearTimeout(_isLoading);
  191. if (data != null) {
  192. self.acls.removeAll();
  193. self.originalAcls.removeAll();
  194. $.each(data.entries, function (index, item) {
  195. self.acls.push(parseAcl(item));
  196. self.originalAcls.push(parseAcl(item));
  197. });
  198. self.owner(data.owner);
  199. self.group(data.group);
  200. self.isLoadingAcls(false);
  201. $(document).trigger("loaded.acls");
  202. }
  203. }).fail(function (xhr, textStatus, errorThrown) {
  204. if (xhr.responseText.search('FileNotFoundException') == -1) { // TODO only fetch on existing path
  205. $(document).trigger("error", xhr.responseText);
  206. self.isLoadingAcls(false);
  207. }
  208. });
  209. };
  210. self.updateAcls = function () {
  211. $(".jHueNotify").hide();
  212. logGA('updateAcls');
  213. $.post("/security/api/hdfs/update_acls", {
  214. 'path': self.path(),
  215. 'acls': ko.mapping.toJSON(self.acls()),
  216. 'originalAcls': ko.mapping.toJSON(self.originalAcls())
  217. }, function (data) {
  218. var toDelete = []
  219. $.each(self.acls(), function (index, item) {
  220. if (item.status() == 'deleted') {
  221. toDelete.push(item);
  222. } else {
  223. item.status('');
  224. }
  225. });
  226. $.each(toDelete, function (index, item) {
  227. self.acls.remove(item);
  228. });
  229. $(document).trigger("info", 'Done!');
  230. }
  231. ).fail(function (xhr, textStatus, errorThrown) {
  232. $(document).trigger("error", JSON.parse(xhr.responseText).message);
  233. });
  234. }
  235. }
  236. var NodeModel = function(data) {
  237. var self = this;
  238. self.isExpanded = ko.observable(true);
  239. self.description = ko.observable();
  240. self.name = ko.observable();
  241. self.nodes = ko.observableArray([]);
  242. self.toggleVisibility = function() {
  243. self.isExpanded(! self.isExpanded());
  244. };
  245. ko.mapping.fromJS(data, self.mapOptions, self);
  246. };
  247. NodeModel.prototype.mapOptions = {
  248. nodes: {
  249. create: function(args) {
  250. return new NodeModel(args.data);
  251. }
  252. }
  253. };
  254. var HdfsViewModel = function (initial) {
  255. var self = this;
  256. self.assist = new Assist(self, initial);
  257. self.doAs = ko.observable('');
  258. self.doAs.subscribe(function() {
  259. self.assist.fetchPath();
  260. });
  261. self.availableHadoopUsers = ko.observableArray();
  262. self.availableHadoopGroups = ko.observableArray();
  263. self.init = function () {
  264. self.fetchUsers();
  265. self.assist.path('/');
  266. }
  267. self.fetchUsers = function () {
  268. $.getJSON('/desktop/api/users/autocomplete', function (data) {
  269. $.each(data.users, function (i, user) {
  270. self.availableHadoopUsers.push(user.username);
  271. });
  272. $.each(data.groups, function (i, group) {
  273. self.availableHadoopGroups.push(group.name);
  274. });
  275. });
  276. }
  277. };
  278. function logGA(page) {
  279. if (typeof trackOnGA == 'function') {
  280. trackOnGA('security/hdfs' + page);
  281. }
  282. }