Kaynağa Gözat

[security] Remove an HDFS acl

Romain Rigaux 11 yıl önce
ebeveyn
işleme
83692509bd

+ 8 - 0
apps/security/src/security/api/hdfs.py

@@ -32,3 +32,11 @@ def modify_acl_entries(request):
   aclspec = request.GET.get('aclspec')
   info = request.fs.modify_acl_entries(path, aclspec)
   return HttpResponse(json.dumps(info), mimetype="application/json")
+
+
+def remove_acl_entries(request):  
+  path = request.GET.get('path')
+  aclspec = request.GET.get('aclspec')
+  info = request.fs.remove_acl_entries(path, aclspec)
+  return HttpResponse(json.dumps(info), mimetype="application/json")
+

+ 4 - 4
apps/security/src/security/templates/hdfs.mako

@@ -58,13 +58,13 @@ ${ layout.menubar(section='hdfs') }
               <span data-bind="text: $root.assist.group"></span>
               <div data-bind="foreach: $root.assist.acls">
                 ## Xeditable for edition?
-                <div>
+                <div data-bind="visible: status() != 'deleted'">
                   <input type="radio" value="group" data-bind="checked: type, attr: { name: 'aclType' + $index()} "/> ${ _('Group') }
                   <input type="radio" value="user" data-bind="checked: type, attr: { name: 'aclType' + $index()}"/> ${ _('User') }
                   <input type="text" data-bind="value: name" class="input-small" placeholder="${ _('name...') }"/>
-                  <input type="checkbox" data-bind="checked: r() != '-'"/>
-                  <input type="checkbox" data-bind="checked: w() != '-'"/>
-                  <input type="checkbox" data-bind="checked: x() != '-'"/>
+                  <input type="checkbox" data-bind="checked: r"/>
+                  <input type="checkbox" data-bind="checked: w"/>
+                  <input type="checkbox" data-bind="checked: x"/>
                   <a href="javascript: void(0)"
                     <i class="fa fa-minus" data-bind="click: $root.assist.removeAcl"></i>
                   </a>

+ 75 - 0
apps/security/src/security/templates/layout.mako

@@ -0,0 +1,75 @@
+## Licensed to Cloudera, Inc. under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  Cloudera, Inc. licenses this file
+## to you under the Apache License, Version 2.0 (the
+## "License"); you may not use this file except in compliance
+## with the License.  You may obtain a copy of the License at
+##
+##     http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing, software
+## distributed under the License is distributed on an "AS IS" BASIS,
+## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+## See the License for the specific language governing permissions and
+## limitations under the License.
+
+<%!
+from django.utils.translation import ugettext as _
+
+
+def is_selected(section, matcher):
+  if section == matcher:
+    return "active"
+  else:
+    return ""
+%>
+
+<%def name="render_field(field, show_label=True, extra_attrs={})">
+  % if not field.is_hidden:
+    <% group_class = field.errors and "error" or "" %>
+    <div class="control-group ${group_class}"
+      rel="popover" data-original-title="${ field.label }" data-content="${ field.help_text }">
+      % if show_label:
+        <label class="control-label">${ field.label }</label>
+      % endif
+      <div class="controls">
+        <% field.field.widget.attrs.update(extra_attrs) %>
+        ${ field | n,unicode }
+        % if field.errors:
+          <span class="help-inline">${ field.errors | n,unicode }</span>
+        % endif
+      </div>
+    </div>
+  %endif
+</%def>
+
+
+<%def name="menubar(section='')">
+  <div class="navbar navbar-inverse navbar-fixed-top">
+      <div class="navbar-inner">
+        <div class="container-fluid">
+          <div class="nav-collapse">
+			<div class="pull-right" style="padding-right:50px; padding-top:10px">
+			  % if user.is_superuser:
+			    <button type="button" title="${ _('Edit') }" rel="tooltip" data-placement="bottom"><i class="fa fa-pencil"></i></button>
+			    <button type="button" title="${ _('Save') }" rel="tooltip" data-placement="bottom" data-loading-text="${ _("Saving...") }"><i class="fa fa-save"></i></button>
+			  % endif
+			</div>           
+            <ul class="nav">           
+              <li class="currentApp">
+                <a href="/${app_name}">
+                  <i class="fa fa-lock"></i>
+                  ${ _('Hadoop Security') }
+                </a>
+              </li>
+              <li class="${is_selected(section, 'hive')}"><a href="${ url('security:hive') }">${_('Hive')}</a></li>
+              <li class="${is_selected(section, 'hdfs')}"><a href="${ url('security:hdfs') }">${_('HDFS')}</a></li>
+              <li class="${is_selected(section, 'solr')}"><a href="${ url('security:hive') }s">${_('Solr')}</a></li>
+              <li class="${is_selected(section, 'hbase')}"><a href="${ url('security:hive') }">${_('HBase')}</a></li>
+            </ul>
+          </div>
+        </div>
+      </div>
+  </div>
+</%def>

+ 2 - 0
apps/security/src/security/urls.py

@@ -28,9 +28,11 @@ urlpatterns = patterns('security.views',
 urlpatterns += patterns('security.api.hdfs',
   url(r'^api/hdfs/get_acls$', 'get_acls', name='get_acls'),
   url(r'^api/hdfs/modify_acl_entries', 'modify_acl_entries', name='modify_acl_entries'),
+  url(r'^api/hdfs/remove_acl_entries', 'remove_acl_entries', name='remove_acl_entries'),
 )
 
 
+
 urlpatterns += patterns('security.api.hive',
   url(r'^api/hive/list_sentry_roles_by_group', 'list_sentry_roles_by_group', name='list_sentry_roles_by_group'),
   url(r'^api/hive/list_sentry_privileges_by_role', 'list_sentry_privileges_by_role', name='list_sentry_privileges_by_role'),

+ 29 - 15
apps/security/static/js/hdfs.ko.js

@@ -15,20 +15,20 @@
 // limitations under the License.
 
 function parseAcl(acl) {
+  // ^(default:)?(user|group|mask|other):[[A-Za-z_][A-Za-z0-9._-]]*:([rwx-]{3})?(,(default:)?(user|group|mask|other):[[A-Za-z_][A-Za-z0-9._-]]*:([rwx-]{3})?)*$
   m = acl.match(/(.*?):(.*?):(.)(.)(.)/);
   return ko.mapping.fromJS({
     'type': m[1],
     'name': m[2],
-     'r': m[3],
-     'w': m[4],
-     'x': m[5],
-     'changed': false,
+     'r': m[3] != '-',
+     'w': m[4] != '-',
+     'x': m[5] != '-',
+     'status': '',
   });
 }
 
 function printAcl(acl) {
-  // ^(default:)?(user|group|mask|other):[[A-Za-z_][A-Za-z0-9._-]]*:([rwx-]{3})?(,(default:)?(user|group|mask|other):[[A-Za-z_][A-Za-z0-9._-]]*:([rwx-]{3})?)*$
-  return acl.type() + ':' + acl.name() + ':' + acl.r() + acl.w() + acl.x();
+  return acl.type() + ':' + acl.name() + ':' + (acl.r() ? 'r' : '-') + (acl.w() ? 'w' : '-') + (acl.x() ? 'x' : '-');
 }
 
 var Assist = function (vm, assist) {
@@ -50,14 +50,18 @@ var Assist = function (vm, assist) {
   
   self.addAcl = function() {
 	var newAcl = parseAcl('group::---');
-	newAcl.changed(true);
+	newAcl.status('new');
 	self.acls.push(newAcl);
   };
   
   self.removeAcl = function(acl) {
-	self.acls.remove(acl);
-  };  
-    
+	if (acl.status() == 'new') {
+	  self.acls.remove(acl);
+	} else {
+	  acl.status('deleted');
+	}
+  };
+
   self.fetchPath = function () {
     $.getJSON('/filebrowser/view' + self.path() + "?pagesize=15&format=json", function (data) { // Might need to create a cleaner API by calling directly webhdfs#LISTDIR
       if (data['files'] && data['files'][0]['type'] == 'dir') { // Hack for now
@@ -94,12 +98,24 @@ var Assist = function (vm, assist) {
 	$.each(self.acls(), function (index, acl) {
 	  aclSpec.push(printAcl(acl));
 	});
-	// grep modified + update them: printAcl
+    
+    $.ajax({
+      type: "POST",
+      url: "/security/api/hdfs/remove_acl_entries",
+      data: {
+        'path': self.path(),
+        'aclspec': $.grep(self.acls(), function(acl){ return acl.status() == 'deleted'; }).join()
+      },
+      async: false
+    }).fail(function (xhr, textStatus, errorThrown) {
+      $(document).trigger("error", xhr.responseText);
+    });
+
     $.getJSON('/security/api/hdfs/modify_acl_entries', {
     	'path': self.path(),
     	'aclspec': aclSpec.join()
       }, function (data) {
-      $(document).trigger("info", 'Done!');
+        $(document).trigger("info", 'Done!');
     }).fail(function (xhr, textStatus, errorThrown) {
       $(document).trigger("error", xhr.responseText);
     }); 
@@ -111,10 +127,8 @@ var Assist = function (vm, assist) {
 var HdfsViewModel = function (context_json) {
   var self = this;
 
-  // Models
   self.assist = new Assist(self, context_json.assist);
-
-  self.assist.path('/tmp');
+  self.assist.path('/tmp/acl');
 
 
   function logGA(page) {