1 /**
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements.  See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership.  The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License.  You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 package org.apache.hadoop.hdfs.tools.offlineImageViewer;
19 
20 import java.io.File;
21 import java.io.IOException;
22 import java.net.HttpURLConnection;
23 import java.net.URI;
24 import java.net.URISyntaxException;
25 import java.net.URL;
26 import java.util.HashMap;
27 
28 import org.apache.commons.logging.Log;
29 import org.apache.commons.logging.LogFactory;
30 import org.apache.hadoop.conf.Configuration;
31 import org.apache.hadoop.fs.FSDataOutputStream;
32 import org.apache.hadoop.fs.FileSystem;
33 import org.apache.hadoop.fs.Path;
34 import org.apache.hadoop.fs.permission.AclStatus;
35 import org.apache.hadoop.hdfs.DFSConfigKeys;
36 import org.apache.hadoop.hdfs.DistributedFileSystem;
37 import org.apache.hadoop.hdfs.MiniDFSCluster;
38 import org.apache.hadoop.hdfs.protocol.HdfsConstants;
39 import org.apache.hadoop.hdfs.server.namenode.FSImageTestUtil;
40 import org.apache.hadoop.hdfs.web.WebHdfsFileSystem;
41 import org.apache.hadoop.net.NetUtils;
42 import org.junit.AfterClass;
43 import org.junit.BeforeClass;
44 import org.junit.Test;
45 
46 import static org.apache.hadoop.fs.permission.AclEntryScope.ACCESS;
47 import static org.apache.hadoop.fs.permission.AclEntryScope.DEFAULT;
48 import static org.apache.hadoop.fs.permission.AclEntryType.GROUP;
49 import static org.apache.hadoop.fs.permission.AclEntryType.OTHER;
50 import static org.apache.hadoop.fs.permission.AclEntryType.USER;
51 import static org.apache.hadoop.fs.permission.FsAction.ALL;
52 import static org.apache.hadoop.fs.permission.FsAction.READ;
53 import static org.apache.hadoop.fs.permission.FsAction.READ_WRITE;
54 import static org.apache.hadoop.fs.permission.FsAction.READ_EXECUTE;
55 import static org.apache.hadoop.fs.permission.FsAction.NONE;
56 import static org.apache.hadoop.hdfs.server.namenode.AclTestHelpers.aclEntry;
57 import static org.junit.Assert.assertEquals;
58 
59 import com.google.common.collect.Lists;
60 import com.google.common.collect.Maps;
61 
62 /**
63  * Tests OfflineImageViewer if the input fsimage has HDFS ACLs
64  */
65 public class TestOfflineImageViewerForAcl {
66 
67   private static final Log LOG =
68       LogFactory.getLog(TestOfflineImageViewerForAcl.class);
69 
70   private static File originalFsimage = null;
71 
72   // ACLs as set to dfs, to be compared with viewer's output
73   final static HashMap<String, AclStatus> writtenAcls = Maps.newHashMap();
74 
75   /**
76    * Create a populated namespace for later testing. Save its contents to a
77    * data structure and store its fsimage location.
78    * We only want to generate the fsimage file once and use it for
79    * multiple tests.
80    */
81   @BeforeClass
createOriginalFSImage()82   public static void createOriginalFSImage() throws IOException {
83     MiniDFSCluster cluster = null;
84     try {
85       Configuration conf = new Configuration();
86       conf.setBoolean(DFSConfigKeys.DFS_NAMENODE_ACLS_ENABLED_KEY, true);
87       cluster = new MiniDFSCluster.Builder(conf).build();
88       cluster.waitActive();
89       DistributedFileSystem hdfs = cluster.getFileSystem();
90 
91       // Create a reasonable namespace with ACLs
92       Path dir = new Path("/dirWithNoAcl");
93       hdfs.mkdirs(dir);
94       writtenAcls.put(dir.toString(), hdfs.getAclStatus(dir));
95 
96       dir = new Path("/dirWithDefaultAcl");
97       hdfs.mkdirs(dir);
98       hdfs.setAcl(dir, Lists.newArrayList(
99           aclEntry(DEFAULT, USER, ALL),
100           aclEntry(DEFAULT, USER, "foo", ALL),
101           aclEntry(DEFAULT, GROUP, READ_EXECUTE),
102           aclEntry(DEFAULT, OTHER, NONE)));
103       writtenAcls.put(dir.toString(), hdfs.getAclStatus(dir));
104 
105       Path file = new Path("/noAcl");
106       FSDataOutputStream o = hdfs.create(file);
107       o.write(23);
108       o.close();
109       writtenAcls.put(file.toString(), hdfs.getAclStatus(file));
110 
111       file = new Path("/withAcl");
112       o = hdfs.create(file);
113       o.write(23);
114       o.close();
115       hdfs.setAcl(file, Lists.newArrayList(
116           aclEntry(ACCESS, USER, READ_WRITE),
117           aclEntry(ACCESS, USER, "foo", READ),
118           aclEntry(ACCESS, GROUP, READ),
119           aclEntry(ACCESS, OTHER, NONE)));
120       writtenAcls.put(file.toString(), hdfs.getAclStatus(file));
121 
122       file = new Path("/withSeveralAcls");
123       o = hdfs.create(file);
124       o.write(23);
125       o.close();
126       hdfs.setAcl(file, Lists.newArrayList(
127           aclEntry(ACCESS, USER, READ_WRITE),
128           aclEntry(ACCESS, USER, "foo", READ_WRITE),
129           aclEntry(ACCESS, USER, "bar", READ),
130           aclEntry(ACCESS, GROUP, READ),
131           aclEntry(ACCESS, GROUP, "group", READ),
132           aclEntry(ACCESS, OTHER, NONE)));
133       writtenAcls.put(file.toString(), hdfs.getAclStatus(file));
134 
135       // Write results to the fsimage file
136       hdfs.setSafeMode(HdfsConstants.SafeModeAction.SAFEMODE_ENTER, false);
137       hdfs.saveNamespace();
138 
139       // Determine the location of the fsimage file
140       originalFsimage = FSImageTestUtil.findLatestImageFile(FSImageTestUtil
141           .getFSImage(cluster.getNameNode()).getStorage().getStorageDir(0));
142       if (originalFsimage == null) {
143         throw new RuntimeException("Didn't generate or can't find fsimage");
144       }
145       LOG.debug("original FS image file is " + originalFsimage);
146     } finally {
147       if (cluster != null)
148         cluster.shutdown();
149     }
150   }
151 
152   @AfterClass
deleteOriginalFSImage()153   public static void deleteOriginalFSImage() throws IOException {
154     if (originalFsimage != null && originalFsimage.exists()) {
155       originalFsimage.delete();
156     }
157   }
158 
159   @Test
testWebImageViewerForAcl()160   public void testWebImageViewerForAcl() throws Exception {
161     WebImageViewer viewer = new WebImageViewer(
162         NetUtils.createSocketAddr("localhost:0"));
163     try {
164       viewer.initServer(originalFsimage.getAbsolutePath());
165       int port = viewer.getPort();
166 
167       // create a WebHdfsFileSystem instance
168       URI uri = new URI("webhdfs://localhost:" + String.valueOf(port));
169       Configuration conf = new Configuration();
170       WebHdfsFileSystem webhdfs = (WebHdfsFileSystem)FileSystem.get(uri, conf);
171 
172       // GETACLSTATUS operation to a directory without ACL
173       AclStatus acl = webhdfs.getAclStatus(new Path("/dirWithNoAcl"));
174       assertEquals(writtenAcls.get("/dirWithNoAcl"), acl);
175 
176       // GETACLSTATUS operation to a directory with a default ACL
177       acl = webhdfs.getAclStatus(new Path("/dirWithDefaultAcl"));
178       assertEquals(writtenAcls.get("/dirWithDefaultAcl"), acl);
179 
180       // GETACLSTATUS operation to a file without ACL
181       acl = webhdfs.getAclStatus(new Path("/noAcl"));
182       assertEquals(writtenAcls.get("/noAcl"), acl);
183 
184       // GETACLSTATUS operation to a file with a ACL
185       acl = webhdfs.getAclStatus(new Path("/withAcl"));
186       assertEquals(writtenAcls.get("/withAcl"), acl);
187 
188       // GETACLSTATUS operation to a file with several ACL entries
189       acl = webhdfs.getAclStatus(new Path("/withSeveralAcls"));
190       assertEquals(writtenAcls.get("/withSeveralAcls"), acl);
191 
192       // GETACLSTATUS operation to a invalid path
193       URL url = new URL("http://localhost:" + port +
194           "/webhdfs/v1/invalid/?op=GETACLSTATUS");
195       HttpURLConnection connection = (HttpURLConnection) url.openConnection();
196       connection.setRequestMethod("GET");
197       connection.connect();
198       assertEquals(HttpURLConnection.HTTP_NOT_FOUND,
199           connection.getResponseCode());
200     } finally {
201       // shutdown the viewer
202       viewer.close();
203     }
204   }
205 }
206