| /* |
| * 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); |
| } |
| } |