21
21
* Implements the Hadoop FileSystem Interface to allow applications to store
22
22
* files on GlusterFS and run Map/Reduce jobs on the data.
23
23
*/
24
-
25
24
package org .apache .hadoop .fs .glusterfs ;
26
25
27
26
import java .io .*;
28
27
import java .net .*;
29
28
29
+ import java .util .StringTokenizer ;
30
+ import java .util .TreeMap ;
30
31
import java .util .regex .*;
31
32
32
33
import org .apache .hadoop .conf .Configuration ;
39
40
import org .apache .hadoop .fs .BlockLocation ;
40
41
import org .apache .hadoop .fs .permission .FsPermission ;
41
42
import org .apache .hadoop .util .Progressable ;
42
-
43
- import java . util .TreeMap ;
43
+ import org . apache . hadoop . util . Shell ;
44
+ import org . apache . hadoop . util .StringUtils ;
44
45
45
46
/*
46
47
* This package provides interface for hadoop jobs (incl. Map/Reduce)
@@ -76,23 +77,22 @@ public boolean FUSEMount(String volname, String server, String mount)
76
77
boolean ret = true ;
77
78
int retVal = 0 ;
78
79
Process p = null ;
80
+ String s = null ;
79
81
String mountCmd = null ;
80
82
81
- mountCmd = "mount -t glusterfs " + server + ":" + "/" + volname + " " + mount ;
82
- System .out .println ("Running: " + mountCmd );
83
+ mountCmd = "mount -t glusterfs " + server + ":" + "/" + volname + " "
84
+ + mount ;
85
+ System .out .println (mountCmd );
83
86
try {
84
87
p = Runtime .getRuntime ().exec (mountCmd );
85
-
86
88
retVal = p .waitFor ();
87
89
if (retVal != 0 )
88
90
ret = false ;
89
91
}
90
92
catch (IOException e ) {
91
- e .printStackTrace ();
92
- System .out .println ("Error calling mount, Continuing.., hopefully its already been mounted." );
93
- //throw new RuntimeException("Problem mounting FUSE mount on: "+ mount);
93
+ System .out .println ("Problem mounting FUSE mount on: " + mount );
94
+ throw new RuntimeException (e );
94
95
}
95
-
96
96
return ret ;
97
97
}
98
98
@@ -113,14 +113,19 @@ public void initialize(URI uri, Configuration conf) throws IOException {
113
113
remoteGFSServer = conf .get ("fs.glusterfs.server" , null );
114
114
needQuickRead = conf .get ("quick.slave.io" , null );
115
115
116
+ /*
117
+ * bail out if we do not have enough information to do a FUSE mount
118
+ */
116
119
if ((volName .length () == 0 ) || (remoteGFSServer .length () == 0 )
117
120
|| (glusterMount .length () == 0 ))
118
- throw new RuntimeException ("Not enough info to mount FUSE: volname=" +volName + " glustermount=" + glusterMount );
121
+ throw new RuntimeException (
122
+ "Not enough info for FUSE Mount : volname=" + volName
123
+ + ",server=" + remoteGFSServer
124
+ + ",glustermount=" + glusterMount );
119
125
120
-
121
126
ret = FUSEMount (volName , remoteGFSServer , glusterMount );
122
127
if (!ret ) {
123
- throw new RuntimeException ("Initialize: Failed to mount GlusterFS " );
128
+ throw new RuntimeException ("Failed to init Gluster FS " );
124
129
}
125
130
126
131
if ((needQuickRead .length () != 0 )
@@ -142,8 +147,7 @@ public void initialize(URI uri, Configuration conf) throws IOException {
142
147
setConf (conf );
143
148
}
144
149
catch (Exception e ) {
145
- e .printStackTrace ();
146
- throw new RuntimeException ("Unable to initialize GlusterFS " + e .getMessage ());
150
+ throw new RuntimeException (e );
147
151
}
148
152
}
149
153
@@ -261,31 +265,137 @@ public FileStatus getFileStatusFromFileString(String path)
261
265
return getFileStatus (nPath );
262
266
}
263
267
268
+ public static class FUSEFileStatus extends FileStatus {
269
+ File theFile ;
270
+
271
+ public FUSEFileStatus (File f ) {
272
+ super ();
273
+ theFile = f ;
274
+ }
275
+
276
+ public FUSEFileStatus (File f , boolean isdir , int block_replication ,
277
+ long blocksize , Path path ) {
278
+ // if its a dir, 0 length
279
+ super (isdir ? 0 : f .length (), isdir , block_replication , blocksize ,
280
+ f .lastModified (), path );
281
+ theFile = f ;
282
+ }
283
+
284
+ /**
285
+ * Wrapper to "ls -aFL" - this should fix BZ908898
286
+ */
287
+ @ Override
288
+ public String getOwner () {
289
+ try {
290
+ return FileInfoUtil .getLSinfo (theFile .getAbsolutePath ()).
291
+ get ("owner" );
292
+ }
293
+ catch (Exception e ) {
294
+ throw new RuntimeException (e );
295
+ }
296
+ }
297
+
298
+ public FsPermission getPermission () {
299
+ //should be amortized, see method.
300
+ loadPermissionInfo ();
301
+ return super .getPermission ();
302
+ }
303
+
304
+ boolean permsLoaded =false ;
305
+
306
+ /// loads permissions, owner, and group from `ls -ld`
307
+ private void loadPermissionInfo () {
308
+ if (permsLoaded ) {
309
+ return ;
310
+ }
311
+ IOException e = null ;
312
+ try {
313
+ String output ;
314
+ StringTokenizer t = new StringTokenizer (
315
+ output =execCommand (theFile ,
316
+ Shell .getGET_PERMISSION_COMMAND ()));
317
+
318
+ //System.out.println("Output of PERMISSION command = " + output + " for " + this.getPath());
319
+ //expected format
320
+ //-rw------- 1 username groupname ...
321
+ String permission = t .nextToken ();
322
+ if (permission .length () > 10 ) { //files with ACLs might have a '+'
323
+ permission = permission .substring (0 , 10 );
324
+ }
325
+ setPermission (FsPermission .valueOf (permission ));
326
+ t .nextToken ();
327
+ setOwner (t .nextToken ());
328
+ setGroup (t .nextToken ());
329
+ } catch (Shell .ExitCodeException ioe ) {
330
+ if (ioe .getExitCode () != 1 ) {
331
+ e = ioe ;
332
+ } else {
333
+ setPermission (null );
334
+ setOwner (null );
335
+ setGroup (null );
336
+ }
337
+ permsLoaded =true ;
338
+ }
339
+ catch (IOException ioe ) {
340
+ e = ioe ;
341
+ }
342
+ finally {
343
+ if (e != null ) {
344
+ throw new RuntimeException ("Error while running command to get " +
345
+ "file permissions : " +
346
+ StringUtils .stringifyException (e ));
347
+ }
348
+ }
349
+ }
350
+
351
+ }
352
+
353
+ public static String execCommand (File f , String ... cmd ) throws IOException {
354
+ String [] args = new String [cmd .length + 1 ];
355
+ System .arraycopy (cmd , 0 , args , 0 , cmd .length );
356
+ args [cmd .length ] = f .getCanonicalPath ();
357
+ String output = Shell .execCommand (args );
358
+ return output ;
359
+ }
360
+
361
+ /**
362
+ * We ultimately use chmod to set permissions, same as in
363
+ * https://svn.apache.org/repos/asf/hadoop/common/branches/HADOOP-3628/src/core/org/apache/hadoop/fs/RawLocalFileSystem.java
364
+ */
365
+ @ Override
366
+ public void setPermission (Path p , FsPermission permission ){
367
+ try {
368
+ Path absolute = makeAbsolute (p );
369
+ final File f = new File (absolute .toUri ().getPath ());
370
+
371
+ execCommand (f , Shell .SET_PERMISSION_COMMAND ,
372
+ String .format ("%05o" , permission .toShort ()));
373
+ }
374
+ catch (Exception e ){
375
+ throw new RuntimeException (e );
376
+ }
377
+ }
378
+
379
+
264
380
public FileStatus getFileStatus (Path path ) throws IOException {
265
381
Path absolute = makeAbsolute (path );
266
- File f = new File (absolute .toUri ().getPath ());
382
+ final File f = new File (absolute .toUri ().getPath ());
267
383
268
384
if (!f .exists ())
269
385
throw new FileNotFoundException ("File " + f .getPath ()
270
386
+ " does not exist." );
271
-
272
387
FileStatus fs ;
388
+
273
389
// simple version - should work . we'll see.
390
+ // TODO COMPARE these w/ original signatures - do we retain the correct
391
+ // default args?
274
392
if (f .isDirectory ())
275
- fs = new FileStatus (0 , true , 1 , 0 , f .lastModified (),
276
- path .makeQualified (this )) {
277
- public String getOwner () {
278
- return "root" ;
279
- }
280
- };
393
+ fs = new FUSEFileStatus (f , true , 1 , 0 , path .makeQualified (this ));
281
394
else
282
- fs = new FileStatus (f .length (), false , 0 , getDefaultBlockSize (),
283
- f .lastModified (), path .makeQualified (this )) {
284
- public String getOwner () {
285
- return "root" ;
286
- }
287
- };
395
+ fs = new FUSEFileStatus (f , false , 0 , getDefaultBlockSize (),
396
+ path .makeQualified (this ));
288
397
return fs ;
398
+
289
399
}
290
400
291
401
/*
0 commit comments