hdfs.mako 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  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. <%!
  17. from desktop.views import commonheader, commonfooter
  18. from django.utils.translation import ugettext as _
  19. %>
  20. <%namespace name="layout" file="layout.mako" />
  21. <%namespace name="tree" file="common_tree.mako" />
  22. ${ commonheader(_('Hadoop Security'), "security", user) | n,unicode }
  23. ${ layout.menubar(section='hdfs') }
  24. <script type="text/html" id="aclDisplay">
  25. <div data-bind="visible: status() != 'deleted'">
  26. <span data-bind="text: printAcl($data)"></span>
  27. </div>
  28. </script>
  29. <script type="text/html" id="aclEdit">
  30. <div data-bind="visible: status() != 'deleted'" class="acl-block">
  31. <a class="pointer pull-right" style="margin-right: 4px" data-bind="click: $root.assist.removeAcl">
  32. <i class="fa fa-times"></i>
  33. </a>
  34. <label class="radio inline-block">
  35. <input type="radio" value="group" data-bind="checked: type, attr: { name: 'aclType' + $index() + (isDefault() ? 'isDefault' : 'notDefault') }"/> ${ _('group') }
  36. </label>
  37. <label class="radio inline-block">
  38. <input type="radio" value="user" data-bind="checked: type, attr: { name: 'aclType' + $index() + (isDefault() ? 'isDefault' : 'notDefault') }"/> ${ _('user') }
  39. </label>
  40. <label class="radio inline-block">
  41. <input type="radio" value="mask" data-bind="checked: type, attr: { name: 'aclType' + $index() + (isDefault() ? 'isDefault' : 'notDefault') }"/> ${ _('mask') }
  42. </label>
  43. <label class="radio inline-block">
  44. <input type="radio" value="other" data-bind="checked: type, attr: { name: 'aclType' + $index() + (isDefault() ? 'isDefault' : 'notDefault') }"/> ${ _('other') }
  45. </label>
  46. <div style="margin-left: 6px">
  47. <div data-bind="visible: type() == 'user'">
  48. <select class="user-list-acl" data-bind="options: $root.selectableHadoopUsers, select2: { placeholder: '${ _("Select a user") }', update: name, type: 'user'}" style="width: 200px"></select>
  49. </div>
  50. <div data-bind="visible: type() == 'group'">
  51. <select class="group-list-acl" data-bind="options: $root.selectableHadoopGroups, select2: { placeholder: '${ _("Select a group") }', update: name, type: 'group'}" style="width: 200px"></select>
  52. </div>
  53. <input type="text" data-bind="value: name, valueUpdate: 'afterkeydown', visible: type() == 'mask' || type() == 'other'" placeholder="${ _('name ...') }" style="width: 180px; margin-bottom: 0px; height: 26px; min-height: 26px"/>
  54. </div>
  55. <br/>
  56. <label class="checkbox inline-block">
  57. <input type="checkbox" data-bind="checked: r"/>
  58. ${ _('Read') } <span class="muted">(r)</span>
  59. </label>
  60. <label class="checkbox inline-block">
  61. <input type="checkbox" data-bind="checked: w"/>
  62. ${ _('Write') } <span class="muted">(w)</span>
  63. </label>
  64. <label class="checkbox inline-block">
  65. <input type="checkbox" data-bind="checked: x"/>
  66. ${ _('Execute') } <span class="muted">(x)</span>
  67. </label>
  68. </div>
  69. </script>
  70. <div class="container-fluid">
  71. <div class="row-fluid">
  72. <div class="span12">
  73. <div class="card card-small">
  74. <h1 class="card-heading simple">
  75. ${ _('HDFS ACLs') }
  76. </h1>
  77. <div class="card-body">
  78. <div class="row-fluid">
  79. <div class="span8">
  80. <div class="path-container">
  81. <div class="input-append span12">
  82. <input id="path" class="path" type="text" data-bind="value: $root.assist.path" autocomplete="off" />
  83. <a data-bind="attr: { href: '/filebrowser/view' + $root.assist.path() }" target="_blank" title="${ _('Open in File Browser') }" class="btn btn-inverse">
  84. <i class="fa fa-external-link"></i>
  85. </a>
  86. </div>
  87. <div class="clearfix"></div>
  88. <div class="tree-toolbar">
  89. <div class="pull-right">
  90. <div class="dropdown inline-block" style="margin-right: 6px">
  91. <a class="dropdown-toggle" data-toggle="dropdown" href="#"><i class="fa fa-eye-slash" data-bind="visible: $root.assist.isDiffMode"></i><i class="fa fa-eye" data-bind="visible: ! $root.assist.isDiffMode()"></i> <span data-bind="visible: $root.assist.isDiffMode">${ _('Show non accessible files for') }</span><span data-bind="visible: ! $root.assist.isDiffMode()">${ _('Impersonate the user') }</span></a>
  92. <ul class="dropdown-menu">
  93. <li data-bind="visible: ! $root.assist.isDiffMode(), click: function() { $root.assist.isDiffMode(true); }"><a tabindex="-1" href="#">${ _('Show non accessible files') }</a></li>
  94. <li data-bind="visible: $root.assist.isDiffMode(), click: function() { $root.assist.isDiffMode(false); }"><a tabindex="-1" href="#">${ _('Impersonate the user') }</a></li>
  95. </ul>
  96. </div>
  97. <select class="user-list" data-bind="options: $root.selectableHadoopUsers, select2: { placeholder: '${ _("Select a user") }', update: $root.doAs, type: 'user'}" style="width: 120px"></select>
  98. <i class="fa fa-group" title="List of groups in popover for this user?"></i>
  99. </div>
  100. <div>
  101. <i class="fa fa-spinner fa-spin" data-bind="visible: $root.assist.isLoadingTree()"></i>
  102. <a class="pointer" data-bind="click: $root.assist.collapseOthers" rel="tooltip" data-placement="right" title="${_('Close other nodes')}">
  103. <i class="fa fa-compress"></i>
  104. </a>
  105. &nbsp;
  106. <a class="pointer" data-bind="click: $root.assist.refreshTree" rel="tooltip" data-placement="right" title="${_('Refresh the tree')}">
  107. <i class="fa fa-refresh"></i>
  108. </a>
  109. &nbsp;
  110. <a class="pointer" data-bind="visible: $root.assist.checkedItems().length > 0, click: function(){ $('#bulkActionsModal').modal('show'); }" rel="tooltip" data-placement="right" title="${ _('Add, replace or remove ACLs for the checked paths') }">
  111. <i class="fa fa-copy"></i>
  112. </a>
  113. </div>
  114. </div>
  115. </div>
  116. ${ tree.render(id='expandableTree', data='$root.assist.treeData', afterRender='$root.assist.afterRender') }
  117. </div>
  118. <div class="span4">
  119. <div class="acl-panel" data-bind="visible: ! $root.assist.isLoadingAcls()">
  120. <ul class="nav nav-tabs">
  121. <li data-bind="css: {'active': ! $root.assist.showAclsAsText()}"><a class="pointer" data-bind="click: function() { $root.assist.showAclsAsText(false); }"><i class="fa fa-pencil"></i> ${ _('Edit') }</a></li>
  122. <li data-bind="css: {'active': $root.assist.showAclsAsText()}"><a class="pointer" data-bind="click: function() { $root.assist.showAclsAsText(true); }"><i class="fa fa-header"></i> ${ _('View as text') }</a></li>
  123. </ul>
  124. <div class="acl-panel-content">
  125. <span class="fake-pre" data-bind="visible: $root.assist.showAclsAsText">
  126. # file: <a class="force-word-break" data-bind="attr: { href: '/filebrowser/view' + $root.assist.path() }, text: $root.assist.path()" target="_blank"></a><br/>
  127. # owner: <span data-bind="text: $root.assist.owner"></span><br/>
  128. # group: <span data-bind="text: $root.assist.group"></span><br/>
  129. <div data-bind="foreach: $root.assist.regularAcls">
  130. <div data-bind="template: {name: 'aclDisplay'}"></div>
  131. </div>
  132. <div data-bind="foreach: $root.assist.defaultAcls">
  133. <div data-bind="template: {name: 'aclDisplay'}"></div>
  134. </div>
  135. </span>
  136. <span data-bind="visible: ! $root.assist.showAclsAsText()">
  137. <h4>${ _('Path') }</h4>
  138. <a class="force-word-break" data-bind="attr: { href: '/filebrowser/view' + $root.assist.path() }, text: $root.assist.path()" target="_blank" title="${ _('Open in File Browser') }" rel="tooltip"></a>
  139. <h4>${ _('User/Group') }</h4>
  140. <i class="fa fa-user" style="color: #999999" title="${_('User')}"></i> <span title="${_('User')}" data-bind="text: $root.assist.owner"></span>&nbsp;
  141. <i class="fa fa-users" style="color: #999999" title="${_('Group')}"></i> <span title="${_('Group')}" data-bind="text: $root.assist.group"></span>
  142. <h4>${ _('ACLs') }</h4>
  143. <div data-bind="foreach: $root.assist.regularAcls">
  144. <div data-bind="template: {name: 'aclEdit'}"></div>
  145. </div>
  146. <div class="acl-block acl-actions">
  147. <span class="pointer" data-bind="click: $root.assist.addAcl"><i class="fa fa-plus"></i></span>
  148. <span class="pointer" data-bind="visible: $root.assist.changedRegularAcls().length, click: $root.assist.getAcls"> &nbsp; <i class="fa fa-undo"></i></span>
  149. <span class="pointer" data-bind="visible: $root.assist.changedRegularAcls().length, click: $root.assist.updateAcls"> &nbsp; <i class="fa fa-save"></i></span>
  150. </div>
  151. <h4>${ _('Default ACLs') }</h4>
  152. <div data-bind="foreach: $root.assist.defaultAcls">
  153. <div data-bind="template: {name: 'aclEdit'}"></div>
  154. </div>
  155. <div class="acl-block acl-actions">
  156. <span class="pointer" data-bind="click: $root.assist.addDefaultAcl"><i class="fa fa-plus"></i></span>
  157. <span class="pointer" data-bind="visible: $root.assist.defaultAcls().length, click: $root.assist.getAcls"> &nbsp; <i class="fa fa-undo"></i></span>
  158. <span class="pointer" data-bind="visible: $root.assist.defaultAcls().length, click: $root.assist.updateAcls"> &nbsp; <i class="fa fa-save"></i></span>
  159. </div>
  160. </span>
  161. </div>
  162. </div>
  163. <div class="loading-popover center" data-bind="visible: $root.assist.isLoadingAcls()"><i class="fa fa-spinner fa-spin fa-5x"></i></div>
  164. </div>
  165. </div>
  166. </div>
  167. </div>
  168. </div>
  169. </div>
  170. </div>
  171. <div id="bulkActionsModal" class="modal hide fade in" role="dialog">
  172. <div class="modal-header">
  173. <a href="#" class="close" data-dismiss="modal">&times;</a>
  174. <h3>${ _('Apply some bulk operations') }</h3>
  175. </div>
  176. <div class="modal-body" style="overflow-x: hidden">
  177. <div class="row-fluid">
  178. <div class="span6">
  179. <h4>${ _('Checked paths') }</h4>
  180. <ul class="unstyled modal-panel" data-bind="foreach: $root.assist.checkedItems">
  181. <li><a class="force-word-break" data-bind="attr: { href: '/filebrowser/view' + path }, text: path" target="_blank" title="${ _('Open in File Browser') }" rel="tooltip"></a></li>
  182. </ul>
  183. </div>
  184. <div class="span6">
  185. <h4>${ _('Selected path for ACLs actions') }</h4>
  186. <span class="fake-pre modal-panel">
  187. # file: <a class="force-word-break" data-bind="attr: { href: '/filebrowser/view' + $root.assist.path() }, text: $root.assist.path()" target="_blank"></a><br/>
  188. # owner: <span data-bind="text: $root.assist.owner"></span><br/>
  189. # group: <span data-bind="text: $root.assist.group"></span><br/>
  190. <div data-bind="foreach: $root.assist.regularAcls">
  191. <div data-bind="template: {name: 'aclDisplay'}"></div>
  192. </div>
  193. <div data-bind="foreach: $root.assist.defaultAcls">
  194. <div data-bind="template: {name: 'aclDisplay'}"></div>
  195. </div>
  196. </span>
  197. </div>
  198. </div>
  199. <h4>${ _('Choose your action') }</h4>
  200. <div class="row-fluid">
  201. <div class="span4 center">
  202. <div class="big-btn" data-bind="css: {'selected': $root.assist.bulkAction() == 'add'}, click: function(){$root.assist.bulkAction('add')}">
  203. <i class="fa fa-plus"></i><br/><br/>
  204. <span class="bulk-action-description">${ _('Add current ACLs to checkbox selection') }</span>
  205. </div>
  206. </div>
  207. <div class="span4 center">
  208. <div class="big-btn" data-bind="css: {'selected': $root.assist.bulkAction() == 'sync'}, click: function(){$root.assist.bulkAction('sync')}">
  209. <i class="fa fa-eraser"></i><br/><br/>
  210. <span class="bulk-action-description">${ _('Replace checkbox selection with current ACLs') }</span>
  211. </div>
  212. </div>
  213. <div class="span4 center">
  214. <div class="big-btn" data-bind="css: {'selected': $root.assist.bulkAction() == 'delete'}, click: function(){$root.assist.bulkAction('delete')}">
  215. <i class="fa fa-times"></i><br/><br/>
  216. <span class="bulk-action-description">${ _('Remove all ACLs of checkbox selection') }</span>
  217. </div>
  218. </div>
  219. </div>
  220. </div>
  221. <div class="modal-footer">
  222. <label class="checkbox pull-left"><input type="checkbox" data-bind="checked: $root.assist.recursive"> ${ _('Apply recursively to all subfolders and files') }</label>
  223. <button class="btn" data-dismiss="modal" aria-hidden="true">${ _('Cancel') }</button>
  224. <button class="btn" data-bind="css: {'btn-primary': $root.assist.bulkAction() != 'delete', 'btn-danger': $root.assist.bulkAction() == 'delete'}, click: $root.assist.bulkPerfomAction">${ _('Confirm') }</button>
  225. </div>
  226. </div>
  227. <%def name="treeIcons()">
  228. 'fa-folder-open-o': isDir() && nodes().length > 0 && !aclBit(),
  229. 'fa-folder-open': isDir() && nodes().length > 0 && aclBit(),
  230. 'fa-folder-o': isDir() && nodes().length == 0 && !aclBit(),
  231. 'fa-folder': isDir() && nodes().length == 0 && aclBit(),
  232. 'fa-file-o': !isDir() && !aclBit(),
  233. 'fa-file': !isDir() && aclBit(),
  234. 'striked': striked()
  235. </%def>
  236. <%def name="aclBitPullRight()">
  237. <div class="pull-right rwx" data-bind="style: { color: aclBit() ? '#338bb8': '#999999'}">
  238. <span data-bind="text: rwx"></span>
  239. </div>
  240. <div class="pull-right">
  241. <i class="fa fa-shield" data-bind="visible: aclBit()" style="color: #338bb8" title="${ _('Has some ACLs') }"></i>
  242. </div>
  243. </%def>
  244. ${ tree.import_templates(itemClick='$root.assist.setPath', iconClick='$root.assist.togglePath', itemSelected='$root.assist.path() == path()', iconModifier=treeIcons, styleModifier='aclBit', styleModifierPullRight=aclBitPullRight, anchorProperty='path', showMore='$root.assist.loadMore', strikedProperty='striked', itemChecked='isChecked') }
  245. <script src="/static/ext/js/knockout-min.js" type="text/javascript" charset="utf-8"></script>
  246. <script src="/static/ext/js/knockout.mapping-2.3.2.js" type="text/javascript" charset="utf-8"></script>
  247. <script src="/security/static/js/common.ko.js" type="text/javascript" charset="utf-8"></script>
  248. <script src="/security/static/js/hdfs.ko.js" type="text/javascript" charset="utf-8"></script>
  249. <script src="/static/js/jquery.hdfsautocomplete.js" type="text/javascript" charset="utf-8"></script>
  250. <script type="text/javascript">
  251. var viewModel = new HdfsViewModel(${ initial | n,unicode });
  252. ko.applyBindings(viewModel);
  253. $(document).ready(function () {
  254. $(document).on("loaded.users", function(){
  255. $(".user-list").select2("val", viewModel.doAs());
  256. });
  257. var _initialPath = "/";
  258. if (window.location.hash != "") {
  259. _initialPath = window.location.hash.substr(1);
  260. }
  261. viewModel.init(_initialPath);
  262. $("#path").jHueHdfsAutocomplete({
  263. home: viewModel.assist.path(),
  264. onPathChange: function (path) {
  265. viewModel.assist.path(path);
  266. },
  267. onEnter: function (el) {
  268. viewModel.assist.path(el.val());
  269. },
  270. smartTooltip: "${_('Did you know? You can use the tab key or CTRL + Space to autocomplete file and folder names')}"
  271. });
  272. function resizeComponents () {
  273. $("#path").width($(".tree-toolbar").width() - 64);
  274. $("#expandableTree").height($(window).height() - 260);
  275. $(".acl-panel-content").height($(window).height() - 260);
  276. }
  277. resizeComponents();
  278. $(document).on("rendered.tree", function() {
  279. var _path = viewModel.assist.path();
  280. if (_path[_path.length-1] == "/"){
  281. _path = _path.substr(0, _path.length - 1);
  282. }
  283. if ($("a.anchor[href^='"+_path+"']").length > 0){
  284. $("#expandableTree").animate({
  285. scrollTop: ($("a.anchor[href^='"+_path+"']:first").position().top + $("#expandableTree").scrollTop() - $("#expandableTree").position().top - 4)+"px"
  286. });
  287. }
  288. });
  289. $(document).on("updated.acls", function() {
  290. $(document).trigger("info", "${ _('The selected ACLs have been successfully updated.') }");
  291. });
  292. $(document).on("added.bulk.acls", function() {
  293. $(document).trigger("info", "${ _('The current ACLs have been successfully added to the checked paths.') }");
  294. $("#bulkActionsModal").modal("hide");
  295. });
  296. $(document).on("deleted.bulk.acls", function() {
  297. $(document).trigger("info", "${ _('All the ACLs have been successfully removed from the checked paths.') }");
  298. $("#bulkActionsModal").modal("hide");
  299. });
  300. $(document).on("syncd.bulk.acls", function() {
  301. $(document).trigger("info", "${ _('All the ACLs for the checked items have been replaced with the current selection.') }");
  302. $("#bulkActionsModal").modal("hide");
  303. });
  304. var _resizeTimeout = -1;
  305. $(window).resize(function(){
  306. window.clearTimeout(_resizeTimeout);
  307. _resizeTimeout = window.setTimeout(resizeComponents, 100);
  308. });
  309. window.onpopstate = function() {
  310. viewModel.assist.path(window.location.hash.substr(1));
  311. };
  312. $("#bulkActionsModal").modal({
  313. show: false
  314. });
  315. });
  316. </script>
  317. ${ commonfooter(messages) | n,unicode }