Skip to content

Commit c449cde

Browse files
committed
HDDS-807. Period should be an invalid character in bucket names. Contributed by Siddharth Wagle.
1 parent dcb0de8 commit c449cde

File tree

5 files changed

+197
-16
lines changed

5 files changed

+197
-16
lines changed

hadoop-hdds/docs/content/OzoneFS.md

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,16 +51,14 @@ Please add the following entry to the core-site.xml.
5151
</property>
5252
{{< /highlight >}}
5353

54-
This will make this bucket to be the default file system for HDFS dfs commands and register the o3fs file system type..
54+
This will make this bucket to be the default file system for HDFS dfs commands and register the o3fs file system type.
5555

5656
You also need to add the ozone-filesystem.jar file to the classpath:
5757

5858
{{< highlight bash >}}
5959
export HADOOP_CLASSPATH=/opt/ozone/share/ozonefs/lib/hadoop-ozone-filesystem-lib-current.*.jar:$HADOOP_CLASSPATH
6060
{{< /highlight >}}
6161

62-
63-
6462
Once the default Filesystem has been setup, users can run commands like ls, put, mkdir, etc.
6563
For example,
6664

@@ -76,7 +74,16 @@ hdfs dfs -mkdir /users
7674

7775

7876
Or put command etc. In other words, all programs like Hive, Spark, and Distcp will work against this file system.
79-
Please note that any keys created/deleted in the bucket using methods apart from OzoneFileSystem will show up as diectories and files in the Ozone File System.
77+
Please note that any keys created/deleted in the bucket using methods apart from OzoneFileSystem will show up as directories and files in the Ozone File System.
78+
79+
Note: Bucket and volume names are not allowed to have a period in them.
80+
Moreover, the filesystem URI can take a fully qualified form with the OM host and port as a part of the path following the volume name.
81+
For example,
82+
83+
{{< highlight bash>}}
84+
hdfs dfs -ls o3fs://bucket.volume.om-host.example.com:5678/key
85+
{{< /highlight >}}
86+
8087

8188
## Legacy mode
8289

hadoop-ozone/ozonefs/pom.xml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@
165165
<dependency>
166166
<groupId>org.mockito</groupId>
167167
<artifactId>mockito-all</artifactId>
168+
<version>1.10.19</version>
168169
<scope>test</scope>
169170
</dependency>
170171
<dependency>
@@ -188,5 +189,29 @@
188189
<artifactId>hadoop-mapreduce-client-jobclient</artifactId>
189190
<scope>test</scope>
190191
</dependency>
192+
<dependency>
193+
<groupId>org.powermock</groupId>
194+
<artifactId>powermock-module-junit4</artifactId>
195+
<version>1.6.5</version>
196+
<scope>test</scope>
197+
<exclusions>
198+
<exclusion>
199+
<groupId>org.javassist</groupId>
200+
<artifactId>javassist</artifactId>
201+
</exclusion>
202+
</exclusions>
203+
</dependency>
204+
<dependency>
205+
<groupId>org.powermock</groupId>
206+
<artifactId>powermock-api-mockito</artifactId>
207+
<version>1.6.5</version>
208+
<scope>test</scope>
209+
<exclusions>
210+
<exclusion>
211+
<groupId>org.hamcrest</groupId>
212+
<artifactId>hamcrest-core</artifactId>
213+
</exclusion>
214+
</exclusions>
215+
</dependency>
191216
</dependencies>
192217
</project>

hadoop-ozone/ozonefs/src/main/java/org/apache/hadoop/fs/ozone/OzoneClientAdapterImpl.java

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,14 @@
1717
*/
1818
package org.apache.hadoop.fs.ozone;
1919

20+
import static org.apache.hadoop.ozone.OzoneConsts.OZONE_URI_DELIMITER;
21+
2022
import java.io.IOException;
2123
import java.io.InputStream;
2224
import java.util.HashMap;
2325
import java.util.Iterator;
2426

27+
import org.apache.commons.lang3.StringUtils;
2528
import org.apache.hadoop.classification.InterfaceAudience;
2629
import org.apache.hadoop.conf.Configuration;
2730
import org.apache.hadoop.hdds.client.ReplicationFactor;
@@ -36,9 +39,6 @@
3639
import org.apache.hadoop.ozone.client.OzoneKey;
3740
import org.apache.hadoop.ozone.client.OzoneVolume;
3841
import org.apache.hadoop.ozone.client.io.OzoneOutputStream;
39-
40-
import static org.apache.hadoop.ozone.OzoneConsts.OZONE_URI_DELIMITER;
41-
4242
import org.apache.hadoop.ozone.security.OzoneTokenIdentifier;
4343
import org.apache.hadoop.security.token.Token;
4444
import org.apache.hadoop.security.token.TokenRenewer;
@@ -100,18 +100,32 @@ private static OzoneConfiguration createConf() {
100100
public OzoneClientAdapterImpl(OzoneConfiguration conf, String volumeStr,
101101
String bucketStr, OzoneFSStorageStatistics storageStatistics)
102102
throws IOException {
103+
this(null, -1, conf, volumeStr, bucketStr, storageStatistics);
104+
}
105+
106+
public OzoneClientAdapterImpl(String omHost, int omPort,
107+
OzoneConfiguration conf, String volumeStr, String bucketStr,
108+
OzoneFSStorageStatistics storageStatistics) throws IOException {
109+
103110
ClassLoader contextClassLoader =
104111
Thread.currentThread().getContextClassLoader();
105112
Thread.currentThread().setContextClassLoader(null);
113+
106114
try {
107115
String replicationTypeConf =
108116
conf.get(OzoneConfigKeys.OZONE_REPLICATION_TYPE,
109117
OzoneConfigKeys.OZONE_REPLICATION_TYPE_DEFAULT);
110118

111119
int replicationCountConf = conf.getInt(OzoneConfigKeys.OZONE_REPLICATION,
112120
OzoneConfigKeys.OZONE_REPLICATION_DEFAULT);
113-
this.ozoneClient =
114-
OzoneClientFactory.getRpcClient(conf);
121+
122+
if (StringUtils.isNotEmpty(omHost) && omPort != -1) {
123+
this.ozoneClient =
124+
OzoneClientFactory.getRpcClient(omHost, omPort, conf);
125+
} else {
126+
this.ozoneClient =
127+
OzoneClientFactory.getRpcClient(conf);
128+
}
115129
objectStore = ozoneClient.getObjectStore();
116130
this.volume = objectStore.getVolume(volumeStr);
117131
this.bucket = volume.getBucket(bucketStr);
@@ -124,6 +138,7 @@ public OzoneClientAdapterImpl(OzoneConfiguration conf, String volumeStr,
124138

125139
}
126140

141+
127142
@Override
128143
public void close() throws IOException {
129144
ozoneClient.close();

hadoop-ozone/ozonefs/src/main/java/org/apache/hadoop/fs/ozone/OzoneFileSystem.java

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import java.util.stream.Collectors;
3535
import java.util.stream.Stream;
3636

37+
import org.apache.commons.lang3.math.NumberUtils;
3738
import org.apache.hadoop.classification.InterfaceAudience;
3839
import org.apache.hadoop.classification.InterfaceStability;
3940
import org.apache.hadoop.conf.Configuration;
@@ -88,33 +89,53 @@ public class OzoneFileSystem extends FileSystem {
8889
private OzoneClientAdapter adapter;
8990
private boolean securityEnabled;
9091

91-
9292
private OzoneFSStorageStatistics storageStatistics;
9393

9494
private static final Pattern URL_SCHEMA_PATTERN =
95-
Pattern.compile("(.+)\\.([^\\.]+)");
95+
Pattern.compile("([^\\.]+)\\.([^\\.]+)\\.{0,1}(.*)");
96+
97+
private static final String URI_EXCEPTION_TEXT = "Ozone file system url " +
98+
"should be either one of the two forms: " +
99+
"o3fs://bucket.volume/key OR " +
100+
"o3fs://bucket.volume.om-host.example.com:5678/key";
96101

97102
@Override
98103
public void initialize(URI name, Configuration conf) throws IOException {
99104
super.initialize(name, conf);
100105
setConf(conf);
101106
Objects.requireNonNull(name.getScheme(), "No scheme provided in " + name);
102-
assert getScheme().equals(name.getScheme());
107+
Preconditions.checkArgument(getScheme().equals(name.getScheme()),
108+
"Invalid scheme provided in " + name);
103109

104110
String authority = name.getAuthority();
105111

106112
Matcher matcher = URL_SCHEMA_PATTERN.matcher(authority);
107113

108114
if (!matcher.matches()) {
109-
throw new IllegalArgumentException("Ozone file system url should be "
110-
+ "in the form o3fs://bucket.volume");
115+
throw new IllegalArgumentException(URI_EXCEPTION_TEXT);
111116
}
112117
String bucketStr = matcher.group(1);
113118
String volumeStr = matcher.group(2);
119+
String remaining = matcher.groupCount() == 3 ? matcher.group(3) : null;
120+
121+
String omHost = null;
122+
String omPort = String.valueOf(-1);
123+
if (StringUtils.isNotEmpty(remaining)) {
124+
String[] parts = remaining.split(":");
125+
if (parts.length != 2) {
126+
throw new IllegalArgumentException(URI_EXCEPTION_TEXT);
127+
}
128+
omHost = parts[0];
129+
omPort = parts[1];
130+
if (!NumberUtils.isParsable(omPort)) {
131+
throw new IllegalArgumentException(URI_EXCEPTION_TEXT);
132+
}
133+
}
114134

115135
try {
116136
uri = new URIBuilder().setScheme(OZONE_URI_SCHEME)
117-
.setHost(authority).build();
137+
.setHost(authority)
138+
.build();
118139
LOG.trace("Ozone URI for ozfs initialization is " + uri);
119140

120141
//isolated is the default for ozonefs-lib-legacy which includes the
@@ -159,11 +180,13 @@ public void initialize(URI name, Configuration conf) throws IOException {
159180
} else {
160181
ozoneConfiguration = new OzoneConfiguration(conf);
161182
}
183+
162184
SecurityConfig secConfig = new SecurityConfig(ozoneConfiguration);
163185
if (secConfig.isSecurityEnabled()) {
164186
this.securityEnabled = true;
165187
}
166-
this.adapter = new OzoneClientAdapterImpl(ozoneConfiguration,
188+
this.adapter = new OzoneClientAdapterImpl(omHost,
189+
Integer.parseInt(omPort), ozoneConfiguration,
167190
volumeStr, bucketStr, storageStatistics);
168191
}
169192

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
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+
* <p>
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
* <p>
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.fs.ozone;
19+
20+
import static org.junit.Assert.assertEquals;
21+
import static org.mockito.Matchers.eq;
22+
import static org.mockito.Mockito.mock;
23+
import static org.mockito.Mockito.when;
24+
25+
import java.net.URI;
26+
27+
import org.apache.hadoop.conf.Configuration;
28+
import org.apache.hadoop.fs.FileSystem;
29+
import org.apache.hadoop.hdds.conf.OzoneConfiguration;
30+
import org.apache.hadoop.ozone.client.ObjectStore;
31+
import org.apache.hadoop.ozone.client.OzoneBucket;
32+
import org.apache.hadoop.ozone.client.OzoneClient;
33+
import org.apache.hadoop.ozone.client.OzoneClientFactory;
34+
import org.apache.hadoop.ozone.client.OzoneVolume;
35+
import org.apache.hadoop.security.UserGroupInformation;
36+
import org.junit.Test;
37+
import org.junit.runner.RunWith;
38+
import org.powermock.api.mockito.PowerMockito;
39+
import org.powermock.core.classloader.annotations.PrepareForTest;
40+
import org.powermock.modules.junit4.PowerMockRunner;
41+
42+
/**
43+
* Ozone File system tests that are light weight and use mocks.
44+
*/
45+
@RunWith(PowerMockRunner.class)
46+
@PrepareForTest({ OzoneClientFactory.class, UserGroupInformation.class })
47+
public class TestOzoneFileSystemWithMocks {
48+
49+
@Test
50+
public void testFSUriWithHostPortOverrides() throws Exception {
51+
Configuration conf = new OzoneConfiguration();
52+
OzoneClient ozoneClient = mock(OzoneClient.class);
53+
ObjectStore objectStore = mock(ObjectStore.class);
54+
OzoneVolume volume = mock(OzoneVolume.class);
55+
OzoneBucket bucket = mock(OzoneBucket.class);
56+
57+
when(ozoneClient.getObjectStore()).thenReturn(objectStore);
58+
when(objectStore.getVolume(eq("volume1"))).thenReturn(volume);
59+
when(volume.getBucket("bucket1")).thenReturn(bucket);
60+
61+
PowerMockito.mockStatic(OzoneClientFactory.class);
62+
PowerMockito.when(OzoneClientFactory.getRpcClient(eq("local.host"),
63+
eq(5899), eq(conf))).thenReturn(ozoneClient);
64+
65+
UserGroupInformation ugi = mock(UserGroupInformation.class);
66+
PowerMockito.mockStatic(UserGroupInformation.class);
67+
PowerMockito.when(UserGroupInformation.getCurrentUser()).thenReturn(ugi);
68+
when(ugi.getShortUserName()).thenReturn("user1");
69+
70+
URI uri = new URI("o3fs://bucket1.volume1.local.host:5899");
71+
72+
FileSystem fileSystem = FileSystem.get(uri, conf);
73+
OzoneFileSystem ozfs = (OzoneFileSystem) fileSystem;
74+
75+
assertEquals(ozfs.getUri().getAuthority(),
76+
"bucket1.volume1.local.host:5899");
77+
PowerMockito.verifyStatic();
78+
OzoneClientFactory.getRpcClient("local.host", 5899, conf);
79+
}
80+
81+
@Test
82+
public void testFSUriHostVersionDefault() throws Exception {
83+
Configuration conf = new OzoneConfiguration();
84+
OzoneClient ozoneClient = mock(OzoneClient.class);
85+
ObjectStore objectStore = mock(ObjectStore.class);
86+
OzoneVolume volume = mock(OzoneVolume.class);
87+
OzoneBucket bucket = mock(OzoneBucket.class);
88+
89+
when(ozoneClient.getObjectStore()).thenReturn(objectStore);
90+
when(objectStore.getVolume(eq("volume1"))).thenReturn(volume);
91+
when(volume.getBucket("bucket1")).thenReturn(bucket);
92+
93+
PowerMockito.mockStatic(OzoneClientFactory.class);
94+
PowerMockito.when(OzoneClientFactory.getRpcClient(eq(conf)))
95+
.thenReturn(ozoneClient);
96+
97+
UserGroupInformation ugi = mock(UserGroupInformation.class);
98+
PowerMockito.mockStatic(UserGroupInformation.class);
99+
PowerMockito.when(UserGroupInformation.getCurrentUser()).thenReturn(ugi);
100+
when(ugi.getShortUserName()).thenReturn("user1");
101+
102+
URI uri = new URI("o3fs://bucket1.volume1/key");
103+
104+
FileSystem fileSystem = FileSystem.get(uri, conf);
105+
OzoneFileSystem ozfs = (OzoneFileSystem) fileSystem;
106+
107+
assertEquals(ozfs.getUri().getAuthority(), "bucket1.volume1");
108+
PowerMockito.verifyStatic();
109+
OzoneClientFactory.getRpcClient(conf);
110+
}
111+
}

0 commit comments

Comments
 (0)