blob: 91602e1d3b3e2263babf124cba66d44421b17e49 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.registry;
import org.apache.commons.lang.StringUtils;
import org.apache.hadoop.security.UserGroupInformation;
import org.apache.hadoop.registry.client.api.RegistryConstants;
import org.apache.hadoop.registry.client.binding.RegistryUtils;
import org.apache.hadoop.registry.client.binding.RegistryTypeUtils;
import org.apache.hadoop.registry.client.types.AddressTypes;
import org.apache.hadoop.registry.client.types.Endpoint;
import org.apache.hadoop.registry.client.types.ProtocolTypes;
import org.apache.hadoop.registry.client.types.ServiceRecord;
import org.apache.hadoop.registry.client.types.yarn.YarnRegistryAttributes;
import org.apache.hadoop.registry.secure.AbstractSecureRegistryTest;
import org.apache.zookeeper.common.PathUtils;
import org.junit.Assert;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.security.auth.Subject;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;
import java.io.File;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.List;
import java.util.Map;
import static org.apache.hadoop.registry.client.binding.RegistryTypeUtils.*;
/**
* This is a set of static methods to aid testing the registry operations.
* The methods can be imported statically —or the class used as a base
* class for tests.
*/
public class RegistryTestHelper extends Assert {
public static final String SC_HADOOP = "org-apache-hadoop";
public static final String USER = "devteam/";
public static final String NAME = "hdfs";
public static final String API_WEBHDFS = "classpath:org.apache.hadoop.namenode.webhdfs";
public static final String API_HDFS = "classpath:org.apache.hadoop.namenode.dfs";
public static final String USERPATH = RegistryConstants.PATH_USERS + USER;
public static final String PARENT_PATH = USERPATH + SC_HADOOP + "/";
public static final String ENTRY_PATH = PARENT_PATH + NAME;
public static final String NNIPC = "uuid:423C2B93-C927-4050-AEC6-6540E6646437";
public static final String IPC2 = "uuid:0663501D-5AD3-4F7E-9419-52F5D6636FCF";
private static final Logger LOG =
LoggerFactory.getLogger(RegistryTestHelper.class);
private static final RegistryUtils.ServiceRecordMarshal recordMarshal =
new RegistryUtils.ServiceRecordMarshal();
public static final String HTTP_API = "http://";
/**
* Assert the path is valid by ZK rules
* @param path path to check
*/
public static void assertValidZKPath(String path) {
try {
PathUtils.validatePath(path);
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException("Invalid Path " + path + ": " + e, e);
}
}
/**
* Assert that a string is not empty (null or "")
* @param message message to raise if the string is empty
* @param check string to check
*/
public static void assertNotEmpty(String message, String check) {
if (StringUtils.isEmpty(check)) {
fail(message);
}
}
/**
* Assert that a string is empty (null or "")
* @param check string to check
*/
public static void assertNotEmpty(String check) {
if (StringUtils.isEmpty(check)) {
fail("Empty string");
}
}
/**
* Log the details of a login context
* @param name name to assert that the user is logged in as
* @param loginContext the login context
*/
public static void logLoginDetails(String name,
LoginContext loginContext) {
assertNotNull("Null login context", loginContext);
Subject subject = loginContext.getSubject();
LOG.info("Logged in as {}:\n {}", name, subject);
}
/**
* Set the JVM property to enable Kerberos debugging
*/
public static void enableKerberosDebugging() {
System.setProperty(AbstractSecureRegistryTest.SUN_SECURITY_KRB5_DEBUG,
"true");
}
/**
* Set the JVM property to enable Kerberos debugging
*/
public static void disableKerberosDebugging() {
System.setProperty(AbstractSecureRegistryTest.SUN_SECURITY_KRB5_DEBUG,
"false");
}
/**
* General code to validate bits of a component/service entry built iwth
* {@link #addSampleEndpoints(ServiceRecord, String)}
* @param record instance to check
*/
public static void validateEntry(ServiceRecord record) {
assertNotNull("null service record", record);
List<Endpoint> endpoints = record.external;
assertEquals(2, endpoints.size());
Endpoint webhdfs = findEndpoint(record, API_WEBHDFS, true, 1, 1);
assertEquals(API_WEBHDFS, webhdfs.api);
assertEquals(AddressTypes.ADDRESS_URI, webhdfs.addressType);
assertEquals(ProtocolTypes.PROTOCOL_REST, webhdfs.protocolType);
List<Map<String, String>> addressList = webhdfs.addresses;
Map<String, String> url = addressList.get(0);
String addr = url.get("uri");
assertTrue(addr.contains("http"));
assertTrue(addr.contains(":8020"));
Endpoint nnipc = findEndpoint(record, NNIPC, false, 1,2);
assertEquals("wrong protocol in " + nnipc, ProtocolTypes.PROTOCOL_THRIFT,
nnipc.protocolType);
Endpoint ipc2 = findEndpoint(record, IPC2, false, 1,2);
assertNotNull(ipc2);
Endpoint web = findEndpoint(record, HTTP_API, true, 1, 1);
assertEquals(1, web.addresses.size());
assertEquals(1, web.addresses.get(0).size());
}
/**
* Assert that an endpoint matches the criteria
* @param endpoint endpoint to examine
* @param addressType expected address type
* @param protocolType expected protocol type
* @param api API
*/
public static void assertMatches(Endpoint endpoint,
String addressType,
String protocolType,
String api) {
assertNotNull(endpoint);
assertEquals(addressType, endpoint.addressType);
assertEquals(protocolType, endpoint.protocolType);
assertEquals(api, endpoint.api);
}
/**
* Assert the records match.
* @param source record that was written
* @param resolved the one that resolved.
*/
public static void assertMatches(ServiceRecord source, ServiceRecord resolved) {
assertNotNull("Null source record ", source);
assertNotNull("Null resolved record ", resolved);
assertEquals(source.description, resolved.description);
Map<String, String> srcAttrs = source.attributes();
Map<String, String> resolvedAttrs = resolved.attributes();
String sourceAsString = source.toString();
String resolvedAsString = resolved.toString();
assertEquals("Wrong count of attrs in \n" + sourceAsString
+ "\nfrom\n" + resolvedAsString,
srcAttrs.size(),
resolvedAttrs.size());
for (Map.Entry<String, String> entry : srcAttrs.entrySet()) {
String attr = entry.getKey();
assertEquals("attribute "+ attr, entry.getValue(), resolved.get(attr));
}
assertEquals("wrong external endpoint count",
source.external.size(), resolved.external.size());
assertEquals("wrong external endpoint count",
source.internal.size(), resolved.internal.size());
}
/**
* Find an endpoint in a record or fail,
* @param record record
* @param api API
* @param external external?
* @param addressElements expected # of address elements?
* @param addressTupleSize expected size of a type
* @return the endpoint.
*/
public static Endpoint findEndpoint(ServiceRecord record,
String api, boolean external, int addressElements, int addressTupleSize) {
Endpoint epr = external ? record.getExternalEndpoint(api)
: record.getInternalEndpoint(api);
if (epr != null) {
assertEquals("wrong # of addresses",
addressElements, epr.addresses.size());
assertEquals("wrong # of elements in an address tuple",
addressTupleSize, epr.addresses.get(0).size());
return epr;
}
List<Endpoint> endpoints = external ? record.external : record.internal;
StringBuilder builder = new StringBuilder();
for (Endpoint endpoint : endpoints) {
builder.append("\"").append(endpoint).append("\" ");
}
fail("Did not find " + api + " in endpoints " + builder);
// never reached; here to keep the compiler happy
return null;
}
/**
* Log a record
* @param name record name
* @param record details
* @throws IOException only if something bizarre goes wrong marshalling
* a record.
*/
public static void logRecord(String name, ServiceRecord record) throws
IOException {
LOG.info(" {} = \n{}\n", name, recordMarshal.toJson(record));
}
/**
* Create a service entry with the sample endpoints
* @param persistence persistence policy
* @return the record
* @throws IOException on a failure
*/
public static ServiceRecord buildExampleServiceEntry(String persistence) throws
IOException,
URISyntaxException {
ServiceRecord record = new ServiceRecord();
record.set(YarnRegistryAttributes.YARN_ID, "example-0001");
record.set(YarnRegistryAttributes.YARN_PERSISTENCE, persistence);
addSampleEndpoints(record, "namenode");
return record;
}
/**
* Add some endpoints
* @param entry entry
*/
public static void addSampleEndpoints(ServiceRecord entry, String hostname)
throws URISyntaxException {
assertNotNull(hostname);
entry.addExternalEndpoint(webEndpoint(HTTP_API,
new URI("http", hostname + ":80", "/")));
entry.addExternalEndpoint(
restEndpoint(API_WEBHDFS,
new URI("http", hostname + ":8020", "/")));
Endpoint endpoint = ipcEndpoint(API_HDFS, null);
endpoint.addresses.add(RegistryTypeUtils.hostnamePortPair(hostname, 8030));
entry.addInternalEndpoint(endpoint);
InetSocketAddress localhost = new InetSocketAddress("localhost", 8050);
entry.addInternalEndpoint(
inetAddrEndpoint(NNIPC, ProtocolTypes.PROTOCOL_THRIFT, "localhost",
8050));
entry.addInternalEndpoint(
RegistryTypeUtils.ipcEndpoint(
IPC2, localhost));
}
/**
* Describe the stage in the process with a box around it -so as
* to highlight it in test logs
* @param log log to use
* @param text text
* @param args logger args
*/
public static void describe(Logger log, String text, Object...args) {
log.info("\n=======================================");
log.info(text, args);
log.info("=======================================\n");
}
/**
* log out from a context if non-null ... exceptions are caught and logged
* @param login login context
* @return null, always
*/
public static LoginContext logout(LoginContext login) {
try {
if (login != null) {
LOG.debug("Logging out login context {}", login.toString());
login.logout();
}
} catch (LoginException e) {
LOG.warn("Exception logging out: {}", e, e);
}
return null;
}
/**
* Login via a UGI. Requres UGI to have been set up
* @param user username
* @param keytab keytab to list
* @return the UGI
* @throws IOException
*/
public static UserGroupInformation loginUGI(String user, File keytab) throws
IOException {
LOG.info("Logging in as {} from {}", user, keytab);
return UserGroupInformation.loginUserFromKeytabAndReturnUGI(user,
keytab.getAbsolutePath());
}
public static ServiceRecord createRecord(String persistence) {
return createRecord("01", persistence, "description");
}
public static ServiceRecord createRecord(String id, String persistence,
String description) {
ServiceRecord serviceRecord = new ServiceRecord();
serviceRecord.set(YarnRegistryAttributes.YARN_ID, id);
serviceRecord.description = description;
serviceRecord.set(YarnRegistryAttributes.YARN_PERSISTENCE, persistence);
return serviceRecord;
}
public static ServiceRecord createRecord(String id, String persistence,
String description, String data) {
return createRecord(id, persistence, description);
}
}