Skip to content

Commit c0499bd

Browse files
elekanuengineer
authored andcommitted
HDDS-1596. Create service endpoint to download configuration from SCM.
Signed-off-by: Anu Engineer <aengineer@apache.org>
1 parent 55cc115 commit c0499bd

File tree

22 files changed

+504
-23
lines changed

22 files changed

+504
-23
lines changed

hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/conf/OzoneConfiguration.java

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,19 +47,43 @@ public class OzoneConfiguration extends Configuration {
4747
}
4848

4949
public OzoneConfiguration() {
50+
this(false);
51+
}
52+
53+
private OzoneConfiguration(boolean justTheDefaults) {
5054
OzoneConfiguration.activate();
5155
loadDefaults();
56+
if (!justTheDefaults) {
57+
loadConfigFiles();
58+
}
59+
}
60+
61+
private void loadConfigFiles() {
62+
addResource("ozone-global.xml");
63+
addResource("ozone-site.xml");
5264
}
5365

5466
public OzoneConfiguration(Configuration conf) {
67+
this(conf, false);
68+
}
69+
70+
private OzoneConfiguration(Configuration conf, boolean justTheDefaults) {
5571
super(conf);
5672
//load the configuration from the classloader of the original conf.
5773
setClassLoader(conf.getClassLoader());
5874
if (!(conf instanceof OzoneConfiguration)) {
5975
loadDefaults();
76+
//here we load the REAL configuration.
77+
if (!justTheDefaults) {
78+
loadConfigFiles();
79+
}
6080
}
6181
}
6282

83+
public static OzoneConfiguration createWithDefaultsOnly() {
84+
return new OzoneConfiguration(true);
85+
}
86+
6387
private void loadDefaults() {
6488
try {
6589
//there could be multiple ozone-default-generated.xml files on the
@@ -74,7 +98,6 @@ private void loadDefaults() {
7498
} catch (IOException e) {
7599
e.printStackTrace();
76100
}
77-
addResource("ozone-site.xml");
78101
}
79102

80103
public List<Property> readPropertyFromXml(URL url) throws JAXBException {
@@ -316,4 +339,9 @@ public Properties getAllPropertiesByTag(String tag) {
316339
}
317340
return props;
318341
}
342+
343+
@Override
344+
public synchronized Properties getProps() {
345+
return super.getProps();
346+
}
319347
}
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
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.hdds.discovery;
19+
20+
import java.io.File;
21+
import java.io.FileOutputStream;
22+
import java.net.URL;
23+
import java.nio.channels.Channels;
24+
import java.nio.channels.ReadableByteChannel;
25+
26+
import org.apache.hadoop.hdds.conf.OzoneConfiguration;
27+
28+
import org.slf4j.Logger;
29+
import org.slf4j.LoggerFactory;
30+
31+
/**
32+
* Utility to download ozone configuration from SCM.
33+
*/
34+
public final class DiscoveryUtil {
35+
36+
private static final Logger LOG =
37+
LoggerFactory.getLogger(DiscoveryUtil.class);
38+
39+
public static final String OZONE_GLOBAL_XML = "ozone-global.xml";
40+
41+
private DiscoveryUtil() {
42+
}
43+
44+
/**
45+
* Download ozone-global.conf from SCM to the local HADOOP_CONF_DIR.
46+
*/
47+
public static boolean loadGlobalConfig(OzoneConfiguration conf) {
48+
String hadoopConfDir = System.getenv("HADOOP_CONF_DIR");
49+
if (hadoopConfDir == null || hadoopConfDir.isEmpty()) {
50+
LOG.warn(
51+
"HADOOP_CONF_DIR is not set, can't download ozone-global.xml from "
52+
+ "SCM.");
53+
return false;
54+
}
55+
if (conf.get("ozone.scm.names") == null) {
56+
LOG.warn("ozone.scm.names is not set. Can't download config from scm.");
57+
return false;
58+
}
59+
for (int i = 0; i < 60; i++) {
60+
for (String scmHost : conf.getStrings("ozone.scm.names")) {
61+
String configOrigin =
62+
String.format("http://%s:9876/discovery/config", scmHost);
63+
File destinationFile = new File(hadoopConfDir, OZONE_GLOBAL_XML);
64+
65+
try {
66+
LOG.info("Downloading {} to {}", configOrigin,
67+
destinationFile.getAbsolutePath());
68+
URL confUrl = new URL(configOrigin);
69+
ReadableByteChannel rbc = Channels.newChannel(confUrl.openStream());
70+
FileOutputStream fos =
71+
new FileOutputStream(
72+
destinationFile);
73+
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
74+
return true;
75+
} catch (Exception ex) {
76+
LOG.error("Can't download config from " + configOrigin, ex);
77+
}
78+
}
79+
LOG.warn(
80+
"Configuration download was unsuccessful. Let's wait 5 seconds and"
81+
+ " retry.");
82+
try {
83+
Thread.sleep(5000);
84+
} catch (InterruptedException e) {
85+
LOG.error("Polling the config file upload is interrupted", e);
86+
}
87+
}
88+
return false;
89+
}
90+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/**
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with this
4+
* work for additional information regarding copyright ownership. The ASF
5+
* licenses this file to you under the Apache License, Version 2.0 (the
6+
* "License"); you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,WITHOUT
13+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14+
* License for the specific language governing permissions and limitations under
15+
* the License.
16+
*/
17+
18+
package org.apache.hadoop.hdds.discovery;
19+
20+
/*
21+
* Discovery/config service related classes.
22+
*/

hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/HddsDatanodeService.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import org.apache.hadoop.hdds.cli.GenericCli;
2626
import org.apache.hadoop.hdds.cli.HddsVersionProvider;
2727
import org.apache.hadoop.hdds.conf.OzoneConfiguration;
28+
import org.apache.hadoop.hdds.discovery.DiscoveryUtil;
2829
import org.apache.hadoop.hdds.protocol.DatanodeDetails;
2930
import org.apache.hadoop.hdds.protocol.proto.SCMSecurityProtocolProtos.SCMGetCertResponseProto;
3031
import org.apache.hadoop.hdds.protocolPB.SCMSecurityProtocolClientSideTranslatorPB;
@@ -140,7 +141,12 @@ public Void call() throws Exception {
140141
StringUtils
141142
.startupShutdownMessage(HddsDatanodeService.class, args, LOG);
142143
}
143-
start(createOzoneConfiguration());
144+
OzoneConfiguration ozoneConfiguration = createOzoneConfiguration();
145+
if (DiscoveryUtil.loadGlobalConfig(ozoneConfiguration)) {
146+
//reload the configuration with the downloaded new configs.
147+
ozoneConfiguration = createOzoneConfiguration();
148+
}
149+
start(ozoneConfiguration);
144150
join();
145151
return null;
146152
}

hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/server/BaseHttpServer.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import javax.servlet.http.HttpServlet;
3434
import java.io.IOException;
3535
import java.net.InetSocketAddress;
36+
import java.util.Map;
3637
import java.util.Optional;
3738

3839
import static org.apache.hadoop.hdds.HddsUtils.getHostNameFromConfigKeys;
@@ -127,6 +128,18 @@ protected void addServlet(String servletName, String pathSpec,
127128
httpServer.addServlet(servletName, pathSpec, clazz);
128129
}
129130

131+
/**
132+
* Add a servlet to BaseHttpServer.
133+
*
134+
* @param servletName The name of the servlet
135+
* @param pathSpec The path spec for the servlet
136+
* @param clazz The servlet class
137+
*/
138+
protected void addInternalServlet(String servletName, String pathSpec,
139+
Class<? extends HttpServlet> clazz, Map<String, String> initParams) {
140+
httpServer.addInternalServlet(servletName, pathSpec, clazz, initParams);
141+
}
142+
130143
/**
131144
* Returns the WebAppContext associated with this HttpServer.
132145
*

hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/server/ServerUtils.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,17 @@ public static InetSocketAddress updateRPCListenAddress(
9696
rpcServer.getListenerAddress());
9797
}
9898

99-
99+
public static InetSocketAddress updateRPCListenPort(
100+
OzoneConfiguration conf, String rpcAddressKey,
101+
InetSocketAddress listenerAddress) {
102+
String originalValue = conf.get(rpcAddressKey);
103+
//remove existing port
104+
originalValue = originalValue.replaceAll(":.*", "");
105+
conf.set(rpcAddressKey,
106+
originalValue + ":" + listenerAddress.getPort());
107+
return new InetSocketAddress(originalValue,
108+
listenerAddress.getPort());
109+
}
100110
/**
101111
* After starting an server, updates configuration with the actual
102112
* listening address of that server. The listening address may be different

hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/server/TestServerUtils.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,14 @@
2323
import org.apache.hadoop.hdds.conf.OzoneConfiguration;
2424
import org.apache.hadoop.hdds.scm.ScmConfigKeys;
2525
import org.apache.hadoop.test.PathUtils;
26+
27+
import org.junit.Assert;
2628
import org.junit.Rule;
2729
import org.junit.Test;
2830
import org.junit.rules.ExpectedException;
2931

3032
import java.io.File;
33+
import java.net.InetSocketAddress;
3134

3235
import static org.junit.Assert.assertEquals;
3336
import static org.junit.Assert.assertFalse;
@@ -120,4 +123,18 @@ public void ozoneMetadataDirRejectsList() {
120123
ServerUtils.getOzoneMetaDirPath(conf);
121124
}
122125

126+
@Test
127+
public void updateRpcListenPort() {
128+
OzoneConfiguration conf = new OzoneConfiguration();
129+
130+
conf.set("test1", "localhost:0");
131+
ServerUtils.updateRPCListenPort(conf, "test1",
132+
new InetSocketAddress("0.0.0.0", 1234));
133+
Assert.assertEquals("localhost:1234", conf.get("test1"));
134+
135+
conf.set("test2", "localhost");
136+
ServerUtils.updateRPCListenPort(conf, "test2",
137+
new InetSocketAddress("0.0.0.0", 1234));
138+
Assert.assertEquals("localhost:1234", conf.get("test2"));
139+
}
123140
}

hadoop-hdds/pom.xml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,27 @@ https://maven.apache.org/xsd/maven-4.0.0.xsd">
191191
<version>${bouncycastle.version}</version>
192192
</dependency>
193193

194+
<dependency>
195+
<groupId>com.sun.xml.bind</groupId>
196+
<artifactId>jaxb-impl</artifactId>
197+
<version>2.3.0.1</version>
198+
</dependency>
199+
<dependency>
200+
<groupId>com.sun.xml.bind</groupId>
201+
<artifactId>jaxb-core</artifactId>
202+
<version>2.3.0.1</version>
203+
</dependency>
204+
<dependency>
205+
<groupId>javax.xml.bind</groupId>
206+
<artifactId>jaxb-api</artifactId>
207+
<version>2.3.0</version>
208+
</dependency>
209+
<dependency>
210+
<groupId>javax.activation</groupId>
211+
<artifactId>activation</artifactId>
212+
<version>1.1.1</version>
213+
</dependency>
214+
194215
<dependency>
195216
<groupId>org.junit.jupiter</groupId>
196217
<artifactId>junit-jupiter-api</artifactId>

hadoop-hdds/server-scm/pom.xml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,24 @@ https://maven.apache.org/xsd/maven-4.0.0.xsd">
5454
<artifactId>hadoop-hdds-docs</artifactId>
5555
</dependency>
5656

57+
<dependency>
58+
<groupId>com.sun.xml.bind</groupId>
59+
<artifactId>jaxb-impl</artifactId>
60+
</dependency>
61+
<dependency>
62+
<groupId>com.sun.xml.bind</groupId>
63+
<artifactId>jaxb-core</artifactId>
64+
</dependency>
65+
<dependency>
66+
<groupId>javax.xml.bind</groupId>
67+
<artifactId>jaxb-api</artifactId>
68+
</dependency>
69+
<dependency>
70+
<groupId>javax.activation</groupId>
71+
<artifactId>activation</artifactId>
72+
</dependency>
73+
74+
5775
<dependency>
5876
<groupId>org.apache.hadoop</groupId>
5977
<artifactId>hadoop-hdds-container-service</artifactId>
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
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.hdds.discovery;
19+
20+
import javax.servlet.ServletContext;
21+
import javax.ws.rs.GET;
22+
import javax.ws.rs.Path;
23+
24+
import java.util.Map.Entry;
25+
import java.util.Properties;
26+
27+
import org.apache.hadoop.hdds.conf.OzoneConfiguration;
28+
import org.apache.hadoop.hdds.scm.server.StorageContainerManagerHttpServer;
29+
30+
/**
31+
* JAXRS endpoint to publish current ozone configuration.
32+
*/
33+
@Path("/config")
34+
public class ConfigurationEndpoint {
35+
36+
private Properties defaults =
37+
OzoneConfiguration.createWithDefaultsOnly().getProps();
38+
39+
@javax.ws.rs.core.Context
40+
private ServletContext context;
41+
42+
/**
43+
* Returns with the non-default configuration.
44+
*/
45+
@GET
46+
public ConfigurationXml getConfiguration() {
47+
OzoneConfiguration conf = (OzoneConfiguration) context.getAttribute(
48+
StorageContainerManagerHttpServer.CONFIG_CONTEXT_ATTRIBUTE);
49+
ConfigurationXml configXml = new ConfigurationXml();
50+
for (Entry<Object, Object> entry : conf.getProps().entrySet()) {
51+
//return only the non-defaults
52+
if (defaults.get(entry.getKey()) != entry.getValue()) {
53+
configXml.addConfiguration(entry.getKey().toString(),
54+
entry.getValue().toString());
55+
}
56+
}
57+
return configXml;
58+
}
59+
60+
}

0 commit comments

Comments
 (0)