Prechádzať zdrojové kódy

[security] Add some HDFS acls

Romain Rigaux 11 rokov pred
rodič
commit
cd04d98e4e

+ 9 - 0
apps/security/src/security/api.py

@@ -23,6 +23,8 @@ from django.utils.translation import ugettext as _
 from libsentry.api import get_api
 
 
+# TODO split by module
+
 # HDFS
 
 def get_acls(request):  
@@ -31,6 +33,13 @@ def get_acls(request):
   return HttpResponse(json.dumps(acls['AclStatus']), mimetype="application/json")
 
 
+def modify_acl_entries(request):  
+  path = request.GET.get('path')
+  aclspec = request.GET.get('aclspec')
+  info = request.fs.modify_acl_entries(path, aclspec)
+  return HttpResponse(json.dumps(info), mimetype="application/json")
+
+
 # Hive
 
 def list_sentry_roles_by_group(request):

+ 16 - 6
apps/security/src/security/templates/hdfs.mako

@@ -57,17 +57,27 @@ ${ layout.menubar(section='hdfs') }
               <span data-bind="text: $root.assist.owner"></span>
               <span data-bind="text: $root.assist.group"></span>
               <div data-bind="foreach: $root.assist.acls">
-                ## xeditable for edition
-                <div data-bind="text: ko.mapping.toJSON($data)"></div><i class="fa fa-minus"></i>
+                ## Xeditable for edition?
+                <div>
+                  <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() != '-'"/>
+                  <a href="javascript: void(0)"
+                    <i class="fa fa-minus" data-bind="click: $root.assist.removeAcl"></i>
+                  </a>
+                </div>
               </div>
-              <a href="javascript: void(0)" data-bind='click: $root.assist.addAcl'>
+              <a href="javascript: void(0)" data-bind="click: $root.assist.addAcl">
                 <i class="fa fa-plus"></i>
               </a>
-              <div data-bind="visible: $root.assist.changed">
+              <div data-bind="visible: $root.assist.changed().length">
                 <button type="button" rel="tooltip" data-placement="bottom" data-original-title="${ _('Cancel') }" class="btn">
-                  <i class="fa fa-undo"></i>
+                  <i class="fa fa-times"></i>
                 </button>
-                <button type="button" rel="tooltip" data-placement="bottom" data-loading-text="${ _('Saving...') }" data-original-title="${ _('Save') }" class="btn">
+                <button type="button" data-bind="click: $root.assist.updateAcls" rel="tooltip" data-placement="bottom" data-loading-text="${ _('Saving...') }" data-original-title="${ _('Save') }" class="btn">
                   <i class="fa fa-save"></i>
                 </button>
               <div>              

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

@@ -27,6 +27,7 @@ urlpatterns = patterns('security.views',
 
 urlpatterns += patterns('security.api',
   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'),
 )
 
 urlpatterns += patterns('security.api',

+ 41 - 19
apps/security/static/js/hdfs.ko.js

@@ -16,17 +16,19 @@
 
 function parseAcl(acl) {
   m = acl.match(/(.*?):(.*?):(.)(.)(.)/);
-  return {
+  return ko.mapping.fromJS({
     'type': m[1],
     'name': m[2],
      'r': m[3],
      'w': m[4],
      'x': m[5],
-  }
+     'changed': false,
+  });
 }
 
 function printAcl(acl) {
-  return acl['type'] + ':' + acl['name'] + ':' + acl['r'] + acl['w'] + acl['x'];
+  // ^(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();
 }
 
 var Assist = function (vm, assist) {
@@ -42,19 +44,28 @@ var Assist = function (vm, assist) {
   self.owner = ko.observable('');
   self.group = ko.observable('');
   
-  self.changed = ko.observable(true); // mocking to true
+  self.changed = ko.computed(function() {
+	return [1]; //$.grep(self.acls(), function(acl){ return acl.changed(); });
+  });
   
   self.addAcl = function() {
-	// should have a good template, also understable for non user, user/group icons button
-	self.acls.push(parseAcl('::---'));
+	var newAcl = parseAcl('group::---');
+	newAcl.changed(true);
+	self.acls.push(newAcl);
   };
+  
+  self.removeAcl = function(acl) {
+	self.acls.remove(acl);
+  };  
     
   self.fetchPath = function () {
-    $.getJSON('/filebrowser/view' + self.path() + "?pagesize=15&format=json", function (data) { // Will create a cleaner API by calling directly directly webhdfs#LISTDIR?
-      self.files.removeAll();
-      $.each(data.files, function(index, item) {
-    	self.files.push(item.path); 
-      });
+    $.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
+        self.files.removeAll();
+        $.each(data.files, function(index, item) {
+    	  self.files.push(item.path); 
+        });
+      }
       self.getAcls();
     }).fail(function (xhr, textStatus, errorThrown) {
       $(document).trigger("error", xhr.responseText);
@@ -67,24 +78,35 @@ var Assist = function (vm, assist) {
       }, function (data) {
         self.acls.removeAll();
         $.each(data.entries, function(index, item) {
-    	  self.acls.push(item); 
+    	  self.acls.push(parseAcl(item));
         });
-        self.acls.push(parseAcl("user:joe:r-x")); // mocking
-        self.acls.push(parseAcl("group::r--")); // mocking
-        self.acls.push(parseAcl("group:execs:rw-")); // mocking
         self.owner(data.owner);
         self.group(data.group);
     }).fail(function (xhr, textStatus, errorThrown) {
-      $(document).trigger("error", xhr.responseText);
+      if (xhr.responseText.search('FileNotFoundException') == -1) { // TODO only fetch on existing path
+        $(document).trigger("error", xhr.responseText);
+      }
     });
   };
   
-  self.save = function () {
-	// update acls, add new ones, remove ones?
+  self.updateAcls = function () {
+	var aclSpec = []
+	$.each(self.acls(), function (index, acl) {
+	  aclSpec.push(printAcl(acl));
+	});
+	// grep modified + update them: printAcl
+    $.getJSON('/security/api/hdfs/modify_acl_entries', {
+    	'path': self.path(),
+    	'aclspec': aclSpec.join()
+      }, function (data) {
+      $(document).trigger("info", 'Done!');
+    }).fail(function (xhr, textStatus, errorThrown) {
+      $(document).trigger("error", xhr.responseText);
+    }); 
   }
 }
 
-// not sure if we should merge Assist here yet
+// Might rename Assist to Acls and create Assist for the tree widget?
 
 var HdfsViewModel = function (context_json) {
   var self = this;