Skip to content

Commit

Permalink
GEODE-6811: be able to create GWR in management api. (apache#3687)
Browse files Browse the repository at this point in the history
* add createGWR methods in the gateway controllers
* add GatewaReceiverConfigValidator
* add MemberValidator to validate same element can't exists in multiple groups which have common member
* add ConfigurationManager.get method to replace ConfigurationValidator.exists method for more conflict validation
  • Loading branch information
jinmeiliao authored Jun 11, 2019
1 parent bdcdf0c commit 7b4870a
Show file tree
Hide file tree
Showing 33 changed files with 822 additions and 313 deletions.
1 change: 1 addition & 0 deletions geode-assembly/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,7 @@ dependencies {
}
distributedTestRuntime('org.codehaus.cargo:cargo-core-uberjar')
distributedTestRuntime('io.swagger:swagger-annotations')
distributedTestRuntime(project(':geode-wan'))


// geodeArchives is a direct reflection of what is contained in geode-dependencies.jar. To that
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/*
* 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.rest;

import static org.apache.geode.test.junit.assertions.ClusterManagementResultAssert.assertManagementResult;

import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Test;

import org.apache.geode.cache.configuration.GatewayReceiverConfig;
import org.apache.geode.examples.SimpleSecurityManager;
import org.apache.geode.management.api.ClusterManagementResult;
import org.apache.geode.management.api.ClusterManagementService;
import org.apache.geode.management.client.ClusterManagementServiceBuilder;
import org.apache.geode.test.dunit.rules.ClusterStartupRule;
import org.apache.geode.test.dunit.rules.MemberVM;

public class GatewayReceiverManagementDUnitTest {
@ClassRule
public static ClusterStartupRule cluster = new ClusterStartupRule();

private static MemberVM locator, server;
private static ClusterManagementService cms;
private GatewayReceiverConfig receiver;

@BeforeClass
public static void beforeClass() throws Exception {
locator = cluster.startLocatorVM(0,
l -> l.withSecurityManager(SimpleSecurityManager.class).withHttpService());
int locatorPort = locator.getPort();
server = cluster.startServerVM(1, s -> s.withConnectionToLocator(locatorPort)
.withProperty("groups", "group1")
.withCredential("cluster", "cluster"));
}

@Before
public void before() throws Exception {
receiver = new GatewayReceiverConfig();
}

@Test
public void withInsuffientCredential() throws Exception {
cms = ClusterManagementServiceBuilder.buildWithHostAddress()
.setHostAddress("localhost", locator.getHttpPort())
.setCredentials("test", "test").build();

assertManagementResult(cms.create(receiver)).failed()
.hasStatusCode(ClusterManagementResult.StatusCode.UNAUTHORIZED)
.containsStatusMessage("test not authorized for CLUSTER:MANAGE");
}

@Test
public void createGWR() throws Exception {
cms = ClusterManagementServiceBuilder.buildWithHostAddress()
.setHostAddress("localhost", locator.getHttpPort())
.setCredentials("cluster", "cluster").build();

receiver.setStartPort("5000");
receiver.setGroup("group1");
assertManagementResult(cms.create(receiver)).isSuccessful()
.containsStatusMessage("Successfully updated config for group1")
.hasMemberStatus().hasSize(1);

// try create another GWR on the same group
receiver.setStartPort("5001");
receiver.setGroup("group1");
assertManagementResult(cms.create(receiver)).failed()
.hasStatusCode(ClusterManagementResult.StatusCode.ENTITY_EXISTS)
.containsStatusMessage("Member(s) server-1 already has this element created");

// try create another GWR on another group but has no server
receiver.setStartPort("5002");
receiver.setGroup("group2");
assertManagementResult(cms.create(receiver)).isSuccessful()
.containsStatusMessage("Successfully updated config for group2")
.hasMemberStatus().hasSize(0);

// try create another GWR on another group but has a common member in another goup
receiver.setStartPort("5003");
receiver.setGroup(null);
assertManagementResult(cms.create(receiver)).failed()
.hasStatusCode(ClusterManagementResult.StatusCode.ENTITY_EXISTS)
.containsStatusMessage("Member(s) server-1 already has this element created");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,15 @@
package org.apache.geode.management.internal.configuration.realizers;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;

import org.apache.geode.cache.DataPolicy;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.RegionExistsException;
import org.apache.geode.cache.Scope;
import org.apache.geode.cache.configuration.RegionConfig;
import org.apache.geode.cache.configuration.RegionType;
Expand Down Expand Up @@ -62,8 +64,9 @@ public void create2ndTime() throws Exception {
RegionConfigValidator.setShortcutAttributes(config);
realizer.create(config, server.getCache());

// the 2nd time with same name and type will not throw an error
realizer.create(config, server.getCache());
// the 2nd time with same name and type will throw an error
assertThatThrownBy(() -> realizer.create(config, server.getCache()))
.isInstanceOf(RegionExistsException.class);
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,10 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.apache.commons.lang3.NotImplementedException;
import org.apache.commons.lang3.StringUtils;
Expand Down Expand Up @@ -59,20 +57,21 @@
import org.apache.geode.management.internal.configuration.mutators.RegionConfigManager;
import org.apache.geode.management.internal.configuration.validators.CacheElementValidator;
import org.apache.geode.management.internal.configuration.validators.ConfigurationValidator;
import org.apache.geode.management.internal.configuration.validators.GatewayReceiverConfigValidator;
import org.apache.geode.management.internal.configuration.validators.MemberValidator;
import org.apache.geode.management.internal.configuration.validators.RegionConfigValidator;
import org.apache.geode.management.internal.exceptions.EntityExistsException;
import org.apache.geode.management.internal.exceptions.EntityNotFoundException;

public class LocatorClusterManagementService implements ClusterManagementService {
private static final Logger logger = LogService.getLogger();
private InternalCache cache;
private ConfigurationPersistenceService persistenceService;
private Map<Class, ConfigurationManager<? extends CacheElement>> managers;
private Map<Class, ConfigurationValidator> validators;
private MemberValidator memberValidator;

public LocatorClusterManagementService(InternalCache cache,
ConfigurationPersistenceService persistenceService) {
this(cache, persistenceService, new HashMap(), new HashMap());
this(persistenceService, new HashMap(), new HashMap(), null);
// initialize the list of managers
managers.put(RegionConfig.class, new RegionConfigManager(cache));
managers.put(MemberConfig.class, new MemberConfigManager(cache));
Expand All @@ -82,15 +81,17 @@ public LocatorClusterManagementService(InternalCache cache,
// initialize the list of validators
validators.put(CacheElement.class, new CacheElementValidator());
validators.put(RegionConfig.class, new RegionConfigValidator(cache));
validators.put(GatewayReceiverConfig.class, new GatewayReceiverConfigValidator());
memberValidator = new MemberValidator(cache, persistenceService);
}

@VisibleForTesting
public LocatorClusterManagementService(InternalCache cache,
ConfigurationPersistenceService persistenceService, Map managers, Map validators) {
this.cache = cache;
public LocatorClusterManagementService(ConfigurationPersistenceService persistenceService,
Map managers, Map validators, MemberValidator memberValidator) {
this.persistenceService = persistenceService;
this.managers = managers;
this.validators = validators;
this.memberValidator = memberValidator;
}

@Override
Expand All @@ -106,19 +107,18 @@ public ClusterManagementResult create(CacheElement config) {
// first validate common attributes of all configuration object
validators.get(CacheElement.class).validate(CacheElementOperation.CREATE, config);


String group = config.getConfigGroup();
ConfigurationValidator validator = validators.get(config.getClass());
if (validator != null) {
validator.validate(CacheElementOperation.CREATE, config);
// exit early if config element already exists in cache config
CacheConfig currentPersistedConfig = persistenceService.getCacheConfig(group, true);
if (validator.exists(config.getId(), currentPersistedConfig)) {
throw new EntityExistsException("Cache element '" + config.getId() + "' already exists");
}
}

// check if this config already exists on all/some members of this group
memberValidator.validateCreate(config, configurationManager);

// execute function on all members
Set<DistributedMember> targetedMembers = findMembers(group);
Set<DistributedMember> targetedMembers = memberValidator.findMembers(group);

ClusterManagementResult result = new ClusterManagementResult();

Expand Down Expand Up @@ -174,31 +174,23 @@ public ClusterManagementResult delete(CacheElement config) {
validators.get(CacheElement.class).validate(CacheElementOperation.DELETE, config);

ConfigurationValidator validator = validators.get(config.getClass());
validator.validate(CacheElementOperation.DELETE, config);

List<String> relevantGroups = persistenceService.getGroups().stream().filter(g -> {
CacheConfig currentPersistedConfig = persistenceService.getCacheConfig(g);
if (currentPersistedConfig != null && validator != null) {
return validator.exists(config.getId(), currentPersistedConfig);
} else {
return false;
}
}).collect(Collectors.toList());
if (validator != null) {
validator.validate(CacheElementOperation.DELETE, config);
}

if (relevantGroups.isEmpty()) {
String[] groupsWithThisElement =
memberValidator.findGroupsWithThisElement(config, configurationManager);
if (groupsWithThisElement.length == 0) {
throw new EntityNotFoundException("Cache element '" + config.getId() + "' does not exist");
}

// execute function on all members
Set<DistributedMember> targetedMembers = new HashSet<>();
relevantGroups.forEach(g -> targetedMembers.addAll(findMembers(g)));

ClusterManagementResult result = new ClusterManagementResult();

List<CliFunctionResult> functionResults = executeAndGetFunctionResult(
new UpdateCacheFunction(),
Arrays.asList(config, CacheElementOperation.DELETE),
targetedMembers);
memberValidator.findMembers(groupsWithThisElement));
functionResults
.forEach(functionResult -> result.addMemberStatus(functionResult.getMemberIdOrName(),
functionResult.isSuccessful(),
Expand All @@ -213,7 +205,7 @@ public ClusterManagementResult delete(CacheElement config) {
// persist configuration in cache config
List<String> updatedGroups = new ArrayList<>();
List<String> failedGroups = new ArrayList<>();
for (String finalGroup : relevantGroups) {
for (String finalGroup : groupsWithThisElement) {
persistenceService.updateCacheConfig(finalGroup, cacheConfigForGroup -> {
try {
configurationManager.delete(config, cacheConfigForGroup);
Expand Down Expand Up @@ -338,17 +330,6 @@ public boolean isConnected() {
return true;
}

@VisibleForTesting
Set<DistributedMember> findMembers(String group) {
Stream<DistributedMember> memberStream =
cache.getDistributionManager().getNormalDistributionManagerIds()
.stream().map(DistributedMember.class::cast);
if (!"cluster".equals(group)) {
memberStream = memberStream.filter(m -> m.getGroups().contains(group));
}
return memberStream.collect(Collectors.toSet());
}

@VisibleForTesting
List<CliFunctionResult> executeAndGetFunctionResult(Function function, Object args,
Set<DistributedMember> targetMembers) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@
import org.apache.geode.management.internal.cli.GfshParseResult;
import org.apache.geode.management.internal.cli.functions.CliFunctionResult;
import org.apache.geode.management.internal.cli.functions.GatewayReceiverCreateFunction;
import org.apache.geode.management.internal.cli.functions.GatewayReceiverFunctionArgs;
import org.apache.geode.management.internal.cli.i18n.CliStrings;
import org.apache.geode.management.internal.cli.result.model.ResultModel;
import org.apache.geode.management.internal.security.ResourceOperation;
Expand Down Expand Up @@ -89,14 +88,11 @@ public ResultModel createGatewayReceiver(@CliOption(key = {CliStrings.GROUP, Cli
buildConfiguration(manualStart, startPort, endPort, bindAddress, maximumTimeBetweenPings,
socketBufferSize, gatewayTransportFilters, hostnameForSenders);

GatewayReceiverFunctionArgs gatewayReceiverFunctionArgs =
new GatewayReceiverFunctionArgs(configuration, ifNotExists);

Set<DistributedMember> membersToCreateGatewayReceiverOn = getMembers(onGroups, onMember);

List<CliFunctionResult> gatewayReceiverCreateResults =
executeAndGetFunctionResult(GatewayReceiverCreateFunction.INSTANCE,
gatewayReceiverFunctionArgs, membersToCreateGatewayReceiverOn);
new Object[] {configuration, ifNotExists}, membersToCreateGatewayReceiverOn);

ResultModel result = ResultModel.createMemberStatusResult(gatewayReceiverCreateResults);
result.setConfigObject(configuration);
Expand Down
Loading

0 comments on commit 7b4870a

Please sign in to comment.