blob: 1278eba102cd0a8e0f16a7ab8652d7c674381bf1 [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.cli.commands;
import static org.apache.geode.distributed.ConfigurationProperties.STATISTIC_SAMPLING_ENABLED;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.TreeSet;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.Logger;
import org.springframework.shell.core.annotation.CliCommand;
import org.springframework.shell.core.annotation.CliOption;
import org.apache.geode.cache.execute.ResultCollector;
import org.apache.geode.distributed.DistributedMember;
import org.apache.geode.distributed.internal.InternalConfigurationPersistenceService;
import org.apache.geode.internal.cache.xmlcache.CacheXml;
import org.apache.geode.logging.internal.log4j.LogLevel;
import org.apache.geode.logging.internal.log4j.api.LogService;
import org.apache.geode.management.cli.CliMetaData;
import org.apache.geode.management.cli.ConverterHint;
import org.apache.geode.management.cli.GfshCommand;
import org.apache.geode.management.internal.cli.AbstractCliAroundInterceptor;
import org.apache.geode.management.internal.cli.CliUtil;
import org.apache.geode.management.internal.cli.GfshParseResult;
import org.apache.geode.management.internal.cli.functions.AlterRuntimeConfigFunction;
import org.apache.geode.management.internal.cli.functions.CliFunctionResult;
import org.apache.geode.management.internal.cli.i18n.CliStrings;
import org.apache.geode.management.internal.cli.remote.CommandExecutor;
import org.apache.geode.management.internal.cli.result.model.InfoResultModel;
import org.apache.geode.management.internal.cli.result.model.ResultModel;
import org.apache.geode.management.internal.configuration.domain.XmlEntity;
import org.apache.geode.management.internal.security.ResourceOperation;
import org.apache.geode.security.ResourcePermission;
public class AlterRuntimeConfigCommand extends GfshCommand {
private final AlterRuntimeConfigFunction alterRunTimeConfigFunction =
new AlterRuntimeConfigFunction();
private static final Logger logger = LogService.getLogger();
@CliCommand(value = {CliStrings.ALTER_RUNTIME_CONFIG},
help = CliStrings.ALTER_RUNTIME_CONFIG__HELP)
@CliMetaData(relatedTopic = {CliStrings.TOPIC_GEODE_CONFIG},
interceptor = "org.apache.geode.management.internal.cli.commands.AlterRuntimeConfigCommand$AlterRuntimeInterceptor")
@ResourceOperation(resource = ResourcePermission.Resource.CLUSTER,
operation = ResourcePermission.Operation.MANAGE)
public ResultModel alterRuntimeConfig(
@CliOption(key = {CliStrings.MEMBER, CliStrings.MEMBERS},
optionContext = ConverterHint.ALL_MEMBER_IDNAME,
help = CliStrings.ALTER_RUNTIME_CONFIG__MEMBER__HELP) String[] memberNameOrId,
@CliOption(key = {CliStrings.GROUP, CliStrings.GROUPS},
optionContext = ConverterHint.MEMBERGROUP,
help = CliStrings.ALTER_RUNTIME_CONFIG__MEMBER__HELP) String[] group,
@CliOption(key = {CliStrings.ALTER_RUNTIME_CONFIG__ARCHIVE__DISK__SPACE__LIMIT},
help = CliStrings.ALTER_RUNTIME_CONFIG__ARCHIVE__DISK__SPACE__LIMIT__HELP) Integer archiveDiskSpaceLimit,
@CliOption(key = {CliStrings.ALTER_RUNTIME_CONFIG__ARCHIVE__FILE__SIZE__LIMIT},
help = CliStrings.ALTER_RUNTIME_CONFIG__ARCHIVE__FILE__SIZE__LIMIT__HELP) Integer archiveFileSizeLimit,
@CliOption(key = {CliStrings.ALTER_RUNTIME_CONFIG__LOG__DISK__SPACE__LIMIT},
help = CliStrings.ALTER_RUNTIME_CONFIG__LOG__DISK__SPACE__LIMIT__HELP) Integer logDiskSpaceLimit,
@CliOption(key = {CliStrings.ALTER_RUNTIME_CONFIG__LOG__FILE__SIZE__LIMIT},
help = CliStrings.ALTER_RUNTIME_CONFIG__LOG__FILE__SIZE__LIMIT__HELP) Integer logFileSizeLimit,
@CliOption(key = {CliStrings.ALTER_RUNTIME_CONFIG__LOG__LEVEL},
optionContext = ConverterHint.LOG_LEVEL,
help = CliStrings.ALTER_RUNTIME_CONFIG__LOG__LEVEL__HELP) String logLevel,
@CliOption(key = {CliStrings.ALTER_RUNTIME_CONFIG__STATISTIC__ARCHIVE__FILE},
help = CliStrings.ALTER_RUNTIME_CONFIG__STATISTIC__ARCHIVE__FILE__HELP) String statisticArchiveFile,
@CliOption(key = {CliStrings.ALTER_RUNTIME_CONFIG__STATISTIC__SAMPLE__RATE},
help = CliStrings.ALTER_RUNTIME_CONFIG__STATISTIC__SAMPLE__RATE__HELP) Integer statisticSampleRate,
@CliOption(key = {CliStrings.ALTER_RUNTIME_CONFIG__STATISTIC__SAMPLING__ENABLED},
help = CliStrings.ALTER_RUNTIME_CONFIG__STATISTIC__SAMPLING__ENABLED__HELP) Boolean statisticSamplingEnabled,
@CliOption(key = {CliStrings.ALTER_RUNTIME_CONFIG__COPY__ON__READ},
specifiedDefaultValue = "false",
help = CliStrings.ALTER_RUNTIME_CONFIG__COPY__ON__READ__HELP) Boolean setCopyOnRead,
@CliOption(key = {CliStrings.ALTER_RUNTIME_CONFIG__LOCK__LEASE},
help = CliStrings.ALTER_RUNTIME_CONFIG__LOCK__LEASE__HELP) Integer lockLease,
@CliOption(key = {CliStrings.ALTER_RUNTIME_CONFIG__LOCK__TIMEOUT},
help = CliStrings.ALTER_RUNTIME_CONFIG__LOCK__TIMEOUT__HELP) Integer lockTimeout,
@CliOption(key = {CliStrings.ALTER_RUNTIME_CONFIG__MESSAGE__SYNC__INTERVAL},
help = CliStrings.ALTER_RUNTIME_CONFIG__MESSAGE__SYNC__INTERVAL__HELP) Integer messageSyncInterval,
@CliOption(key = {CliStrings.ALTER_RUNTIME_CONFIG__SEARCH__TIMEOUT},
help = CliStrings.ALTER_RUNTIME_CONFIG__SEARCH__TIMEOUT__HELP) Integer searchTimeout) {
Map<String, String> runTimeDistributionConfigAttributes = new HashMap<>();
Map<String, String> rumTimeCacheAttributes = new HashMap<>();
Set<DistributedMember> targetMembers = findMembers(group, memberNameOrId);
if (targetMembers.isEmpty()) {
return ResultModel.createError(CliStrings.NO_MEMBERS_FOUND_MESSAGE);
}
if (archiveDiskSpaceLimit != null) {
runTimeDistributionConfigAttributes.put(
CliStrings.ALTER_RUNTIME_CONFIG__ARCHIVE__DISK__SPACE__LIMIT,
archiveDiskSpaceLimit.toString());
}
if (archiveFileSizeLimit != null) {
runTimeDistributionConfigAttributes.put(
CliStrings.ALTER_RUNTIME_CONFIG__ARCHIVE__FILE__SIZE__LIMIT,
archiveFileSizeLimit.toString());
}
if (logDiskSpaceLimit != null) {
runTimeDistributionConfigAttributes.put(
CliStrings.ALTER_RUNTIME_CONFIG__LOG__DISK__SPACE__LIMIT, logDiskSpaceLimit.toString());
}
if (logFileSizeLimit != null) {
runTimeDistributionConfigAttributes.put(
CliStrings.ALTER_RUNTIME_CONFIG__LOG__FILE__SIZE__LIMIT, logFileSizeLimit.toString());
}
if (logLevel != null && !logLevel.isEmpty()) {
runTimeDistributionConfigAttributes.put(CliStrings.ALTER_RUNTIME_CONFIG__LOG__LEVEL,
logLevel);
}
if (statisticArchiveFile != null && !statisticArchiveFile.isEmpty()) {
runTimeDistributionConfigAttributes
.put(CliStrings.ALTER_RUNTIME_CONFIG__STATISTIC__ARCHIVE__FILE, statisticArchiveFile);
}
if (statisticSampleRate != null) {
runTimeDistributionConfigAttributes.put(
CliStrings.ALTER_RUNTIME_CONFIG__STATISTIC__SAMPLE__RATE, statisticSampleRate.toString());
}
if (statisticSamplingEnabled != null) {
runTimeDistributionConfigAttributes.put(STATISTIC_SAMPLING_ENABLED,
statisticSamplingEnabled.toString());
}
// Attributes that are set on the cache.
if (setCopyOnRead != null) {
rumTimeCacheAttributes.put(CliStrings.ALTER_RUNTIME_CONFIG__COPY__ON__READ,
setCopyOnRead.toString());
}
if (lockLease != null && lockLease > 0 && lockLease < Integer.MAX_VALUE) {
rumTimeCacheAttributes.put(CliStrings.ALTER_RUNTIME_CONFIG__LOCK__LEASE,
lockLease.toString());
}
if (lockTimeout != null && lockTimeout > 0 && lockTimeout < Integer.MAX_VALUE) {
rumTimeCacheAttributes.put(CliStrings.ALTER_RUNTIME_CONFIG__LOCK__TIMEOUT,
lockTimeout.toString());
}
if (messageSyncInterval != null && messageSyncInterval > 0
&& messageSyncInterval < Integer.MAX_VALUE) {
rumTimeCacheAttributes.put(CliStrings.ALTER_RUNTIME_CONFIG__MESSAGE__SYNC__INTERVAL,
messageSyncInterval.toString());
}
if (searchTimeout != null && searchTimeout > 0 && searchTimeout < Integer.MAX_VALUE) {
rumTimeCacheAttributes.put(CliStrings.ALTER_RUNTIME_CONFIG__SEARCH__TIMEOUT,
searchTimeout.toString());
}
if (runTimeDistributionConfigAttributes.isEmpty() && rumTimeCacheAttributes.isEmpty()) {
return ResultModel.createError(CliStrings.ALTER_RUNTIME_CONFIG__RELEVANT__OPTION__MESSAGE);
}
Map<String, String> allRunTimeAttributes = new HashMap<>();
allRunTimeAttributes.putAll(runTimeDistributionConfigAttributes);
allRunTimeAttributes.putAll(rumTimeCacheAttributes);
ResultCollector<?, ?> rc =
CliUtil.executeFunction(alterRunTimeConfigFunction, allRunTimeAttributes, targetMembers);
List<CliFunctionResult> results = CliFunctionResult.cleanResults((List<?>) rc.getResult());
Set<String> successfulMembers = new TreeSet<>();
Set<String> errorMessages = new TreeSet<>();
for (CliFunctionResult result : results) {
if (result.getThrowable() != null) {
logger.info("Function failed: " + result.getThrowable());
errorMessages.add(result.getThrowable().getMessage());
} else {
successfulMembers.add(result.getMemberIdOrName());
}
}
final String lineSeparator = System.getProperty("line.separator");
if (!successfulMembers.isEmpty()) {
StringBuilder successMessageBuilder = new StringBuilder();
successMessageBuilder.append(CliStrings.ALTER_RUNTIME_CONFIG__SUCCESS__MESSAGE);
successMessageBuilder.append(lineSeparator);
for (String member : successfulMembers) {
successMessageBuilder.append(member);
successMessageBuilder.append(lineSeparator);
}
Properties properties = new Properties();
properties.putAll(runTimeDistributionConfigAttributes);
ResultModel result = new ResultModel();
InfoResultModel successInfo = result.addInfo("success");
successInfo.addLine(successMessageBuilder.toString());
// Set the Cache attributes to be modified
final XmlEntity xmlEntity = XmlEntity.builder().withType(CacheXml.CACHE)
.withAttributes(rumTimeCacheAttributes).build();
InternalConfigurationPersistenceService cps = getConfigurationPersistenceService();
if (cps == null) {
successInfo.addLine(CommandExecutor.SERVICE_NOT_RUNNING_CHANGE_NOT_PERSISTED);
} else {
cps.modifyXmlAndProperties(properties, xmlEntity, group);
}
return result;
} else {
StringBuilder errorMessageBuilder = new StringBuilder();
errorMessageBuilder.append("Following errors occurred while altering runtime config");
errorMessageBuilder.append(lineSeparator);
for (String errorMessage : errorMessages) {
errorMessageBuilder.append(errorMessage);
errorMessageBuilder.append(lineSeparator);
}
return ResultModel.createError(errorMessageBuilder.toString());
}
}
public static class AlterRuntimeInterceptor extends AbstractCliAroundInterceptor {
@Override
public ResultModel preExecution(GfshParseResult parseResult) {
// validate log level
String logLevel = parseResult.getParamValueAsString("log-level");
if (StringUtils.isNotBlank(logLevel) && (LogLevel.getLevel(logLevel) == null)) {
return ResultModel.createError("Invalid log level: " + logLevel);
}
return ResultModel.createInfo("");
}
}
}