blob: 37018f0d705b2d615b60887532e2703d0f423dc8 [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.geode.management.internal.api;
import java.net.InetSocketAddress;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import javax.net.ssl.SSLContext;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.logging.log4j.Logger;
import org.apache.geode.annotations.Immutable;
import org.apache.geode.cache.GemFireCache;
import org.apache.geode.cache.client.ClientCache;
import org.apache.geode.cache.execute.FunctionException;
import org.apache.geode.cache.execute.FunctionService;
import org.apache.geode.cache.execute.ResultCollector;
import org.apache.geode.distributed.internal.DistributionConfig;
import org.apache.geode.distributed.internal.membership.InternalDistributedMember;
import org.apache.geode.distributed.internal.tcpserver.TcpClient;
import org.apache.geode.internal.admin.SSLConfig;
import org.apache.geode.internal.cache.GemFireCacheImpl;
import org.apache.geode.internal.logging.LogService;
import org.apache.geode.internal.net.SSLConfigurationFactory;
import org.apache.geode.internal.security.SecurableCommunicationChannel;
import org.apache.geode.management.api.ClusterManagementService;
import org.apache.geode.management.builder.ClusterManagementServiceBuilder;
import org.apache.geode.management.internal.PlainClusterManagementServiceBuilder;
import org.apache.geode.management.internal.SSLUtil;
import org.apache.geode.management.internal.cli.functions.GetMemberInformationFunction;
import org.apache.geode.management.internal.configuration.messages.ClusterManagementServiceInfo;
import org.apache.geode.management.internal.configuration.messages.ClusterManagementServiceInfoRequest;
import org.apache.geode.management.runtime.MemberInformation;
import org.apache.geode.security.AuthInitialize;
public class GeodeClusterManagementServiceBuilder implements
ClusterManagementServiceBuilder.GeodeBuilder {
@Immutable
private static final GetMemberInformationFunction MEMBER_INFORMATION_FUNCTION =
new GetMemberInformationFunction();
private static final Logger logger = LogService.getLogger();
private GemFireCache cache;
private PlainClusterManagementServiceBuilder javaBuilder =
new PlainClusterManagementServiceBuilder();
public GeodeClusterManagementServiceBuilder setCredentials(String username,
String password) {
javaBuilder.setCredentials(username, password);
return this;
}
public GeodeClusterManagementServiceBuilder setCache(GemFireCache cache) {
GemFireCacheImpl cacheImpl = (GemFireCacheImpl) cache;
if (cacheImpl.isServer()) {
setServerCache(cacheImpl);
} else if (cacheImpl.isClient()) {
setClientCache(cacheImpl);
} else {
throw new IllegalArgumentException("Need a cache instance in order to build the service.");
}
this.cache = cache;
return this;
}
public ClusterManagementService build() {
if (cache == null) {
throw new IllegalArgumentException("Need a cache instance in order to build the service.");
}
return javaBuilder.build();
}
private void setServerCache(GemFireCacheImpl cache) {
Set<InternalDistributedMember> locatorsWithClusterConfig =
cache.getDistributionManager().getAllHostedLocatorsWithSharedConfiguration()
.keySet();
ClusterManagementServiceInfo cmsInfo =
getClusterManagementServiceInfo(locatorsWithClusterConfig);
configureBuilder(cache.getSystem().getConfig(), cmsInfo);
}
private void setClientCache(ClientCache clientCache) {
List<InetSocketAddress> locators = clientCache.getDefaultPool().getLocators();
if (locators.size() == 0) {
throw new IllegalStateException(
"the client needs to have a client pool connected with a locator.");
}
DistributionConfig config = ((GemFireCacheImpl) clientCache).getSystem().getConfig();
TcpClient client = new TcpClient(config);
ClusterManagementServiceInfo cmsInfo = null;
for (InetSocketAddress locator : locators) {
try {
cmsInfo =
(ClusterManagementServiceInfo) client.requestToServer(locator,
new ClusterManagementServiceInfoRequest(), 1000, true);
// do not try anymore if we found one that has cms running
if (cmsInfo.isRunning()) {
break;
}
} catch (Exception e) {
logger.warn(
"unable to discover the ClusterManagementService on locator " + locator.toString());
}
}
// if cmsInfo is still null at this point, i.e. we failed to retrieve the cms information from
// any locator
if (cmsInfo == null || !cmsInfo.isRunning()) {
throw new IllegalStateException(
"Unable to discover a locator that has ClusterManagementService running.");
}
configureBuilder(config, cmsInfo);
}
private void configureBuilder(DistributionConfig config,
ClusterManagementServiceInfo cmsInfo) {
javaBuilder.setHostAddress(cmsInfo.getHostName(), cmsInfo.getHttpPort());
// if user didn't pass in a username and the locator requires credentials, use the credentials
// user used to create the client cache
if (cmsInfo.isSecured() && javaBuilder.getUsername() == null) {
Properties securityProps = config.getSecurityProps();
String username = securityProps.getProperty(AuthInitialize.SECURITY_USERNAME);
String password = securityProps.getProperty(AuthInitialize.SECURITY_PASSWORD);
if (StringUtils.isBlank(username)) {
String message = String.format("You will need to set the buildWithHostAddress username and "
+ "password or specify security-username and security-password in the properties when "
+ "starting this geode server/client.");
throw new IllegalStateException(message);
}
javaBuilder.setCredentials(username, password);
}
if (cmsInfo.isSSL()) {
SSLConfig sslConfig = SSLConfigurationFactory.getSSLConfigForComponent(
config, SecurableCommunicationChannel.WEB);
if (!sslConfig.useDefaultSSLContext() && sslConfig.getTruststore() == null) {
throw new IllegalStateException(
"This server/client needs to have ssl-truststore or ssl-use-default-context specified in order to use cluster management service.");
}
SSLContext sslContext = SSLUtil.createAndConfigureSSLContext(sslConfig, false);
javaBuilder.setSslContext(sslContext);
javaBuilder.setHostnameVerifier(new NoopHostnameVerifier());
}
}
private ClusterManagementServiceInfo getClusterManagementServiceInfo(
Set<InternalDistributedMember> locators) {
ClusterManagementServiceInfo info = new ClusterManagementServiceInfo();
MemberInformation memberInfo = null;
for (InternalDistributedMember locator : locators) {
try {
ResultCollector resultCollector =
FunctionService.onMember(locator).execute(MEMBER_INFORMATION_FUNCTION);
List<MemberInformation> memberInformations =
(List<MemberInformation>) resultCollector.getResult();
// Is this even possible?
if (memberInformations.isEmpty()) {
continue;
}
memberInfo = memberInformations.get(0);
break;
} catch (FunctionException e) {
logger.warn("Unable to execute GetMemberInformationFunction on " + locator.getId());
}
}
if (memberInfo == null) {
throw new IllegalStateException("Unable to determine ClusterManagementService endpoint");
}
info.setHostName(getHostName(memberInfo));
info.setHttpPort(memberInfo.getHttpServicePort());
info.setSSL(memberInfo.isWebSSL());
info.setSecured(memberInfo.isSecured());
return info;
}
private String getHostName(MemberInformation memberInformation) {
String host;
if (StringUtils.isNotBlank(memberInformation.getHttpServiceBindAddress())) {
host = memberInformation.getHttpServiceBindAddress();
} else if (StringUtils.isNotBlank(memberInformation.getServerBindAddress())) {
host = memberInformation.getServerBindAddress();
} else {
host = memberInformation.getHost();
}
return host;
}
}