/*
* RHQ Management Platform
* Copyright (C) 2005-2010 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package org.rhq.enterprise.server.configuration;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.jetbrains.annotations.NotNull;
import org.testng.annotations.Test;
import org.rhq.core.clientapi.agent.PluginContainerException;
import org.rhq.core.clientapi.agent.discovery.DiscoveryAgentService;
import org.rhq.core.clientapi.agent.discovery.InvalidPluginConfigurationClientException;
import org.rhq.core.clientapi.server.discovery.InventoryReport;
import org.rhq.core.domain.authz.Permission;
import org.rhq.core.domain.configuration.Configuration;
import org.rhq.core.domain.configuration.ConfigurationUpdateStatus;
import org.rhq.core.domain.discovery.AvailabilityReport;
import org.rhq.core.domain.discovery.MergeResourceResponse;
import org.rhq.core.domain.discovery.PlatformSyncInfo;
import org.rhq.core.domain.discovery.ResourceSyncInfo;
import org.rhq.core.domain.resource.Resource;
import org.rhq.core.domain.resource.ResourceType;
import org.rhq.enterprise.server.authz.PermissionException;
import org.rhq.enterprise.server.test.LargeGroupTestBase;
import org.rhq.enterprise.server.test.TestServerCommunicationsService;
import org.rhq.enterprise.server.util.SessionTestHelper;
@Test
public class LargeGroupPluginConfigurationTest extends LargeGroupTestBase {
private LargeGroupEnvironment env;
private CountDownLatch latch;
@Override
protected void setupMockAgentServices(TestServerCommunicationsService agentServiceContainer) {
TestServices testServices = new TestServices();
agentServiceContainer.discoveryService = testServices;
}
/**
* Create a large group of 1000+ resources.
*/
@Override
protected void beforeMethod() throws Exception {
super.beforeMethod();
env = createLargeGroupWithNormalUserRoleAccess(1010, Permission.MODIFY_RESOURCE);
SessionTestHelper.simulateLogin(env.normalSubject);
}
/**
* Remove the group and all its members.
*/
@Override
protected void afterMethod() throws Exception {
tearDownLargeGroupWithNormalUserRoleAccess(env);
SessionTestHelper.simulateLogout(env.normalSubject);
super.afterMethod();
}
public void testGroupPluginConfigurationUpdate() throws Exception {
// all of our platform's children are members of the group we are testing with
int memberCount = env.platformResource.getChildResources().size();
// we don't have any updates yet, but when we created the resources, they had a default plugin config already set.
// let's see that we can obtain those plugin configs for all resources in the group
Map<Integer, Configuration> existingMap;
System.out.println("Getting plugin config for group [#members=" + memberCount + "]");
long start = System.currentTimeMillis();
existingMap = configurationManager.getPluginConfigurationsForCompatibleGroup(env.normalSubject,
env.compatibleGroup.getId());
long duration = System.currentTimeMillis() - start;
System.out.println("Took [" + duration + "]ms to get plugin config for group [#members=" + memberCount + "]");
assert existingMap.size() == memberCount : "did not get back the amount of configs [" + existingMap.size()
+ "] we expected [" + memberCount + "]";
for (Map.Entry<Integer, Configuration> entry : existingMap.entrySet()) {
Integer resourceId = entry.getKey();
Configuration config = entry.getValue();
assert PC_PROP1_VALUE.equals(config.getSimpleValue(PC_PROP1_NAME, null)) : "bad plugin config for "
+ resourceId + "=" + config.toString(true);
assert resourceId.toString().equals(config.getSimpleValue(PC_PROP2_NAME, null)) : "bad plugin config for "
+ resourceId + "=" + config.toString(true);
// create new plugin configuration settings for this resource, we will update the group members to these new configs
config.getSimple(PC_PROP2_NAME).setStringValue("UPDATE" + resourceId);
}
// update our group with the new plugin configs
System.out.println("Scheduling a group plugin update.");
latch = new CountDownLatch(memberCount); // our TestService will count this down
int groupUpdateId = configurationManager.scheduleGroupPluginConfigurationUpdate(env.normalSubject,
env.compatibleGroup.getId(), existingMap);
// group plugin configuration update has been kicked off, wait for the mock agents to each complete their update
System.out.print("Waiting for mock agents");
assert latch.await(5, TimeUnit.MINUTES) : "agents should not have taken this long";
System.out.println(" Mock agents are done.");
// wait for group update to get out of the INPROGRESS state (it will eventually get to SUCCESS), but don't wait indefinitely
// this shouldn't take too long - just have to wait for the all the DB commits to complete
System.out.print("Waiting for group plugin config update to be finished...");
ConfigurationUpdateStatus status = getGroupPluginConfigurationStatus(env.compatibleGroup.getId());
boolean inprogress = (status == ConfigurationUpdateStatus.INPROGRESS);
for (int i = 0; i < 20 && inprogress; i++) {
Thread.sleep(3000);
status = getGroupPluginConfigurationStatus(env.compatibleGroup.getId());
inprogress = (status == ConfigurationUpdateStatus.INPROGRESS);
}
assert !inprogress : "group plugin configuration update is still inprogress - this is taking too long";
System.out.println(" Done. Status=" + ((status != null) ? status.name() : "????null????"));
assert status == ConfigurationUpdateStatus.SUCCESS : "should have finished in the success status";
// now see if our group plugin configuration update affected all of our resources by getting the group plugin config
System.out.println("Getting updated plugin config for group [#members=" + memberCount + "]");
start = System.currentTimeMillis();
existingMap = configurationManager.getPluginConfigurationsForCompatibleGroup(env.normalSubject,
env.compatibleGroup.getId());
duration = System.currentTimeMillis() - start;
System.out.println("Took [" + duration + "]ms to get updated plugin config for group [#members=" + memberCount
+ "]");
assert existingMap.size() == memberCount : "did not get back the amount of configs [" + existingMap.size()
+ "] we expected [" + memberCount + "]";
for (Map.Entry<Integer, Configuration> entry : existingMap.entrySet()) {
Integer resourceId = entry.getKey();
Configuration config = entry.getValue();
assert PC_PROP1_VALUE.equals(config.getSimpleValue(PC_PROP1_NAME, null)) : "bad plugin config for "
+ resourceId + "=" + config.toString(true);
assert ("UPDATE" + resourceId.toString()).equals(config.getSimpleValue(PC_PROP2_NAME, null)) : "bad plugin config for "
+ resourceId + "=" + config.toString(true);
}
// now test our authz - unauthorized user should bomb out
System.out.println("Attempting unauthz access");
SessionTestHelper.simulateLogin(env.unauthzSubject);
start = System.currentTimeMillis();
try {
configurationManager.getPluginConfigurationsForCompatibleGroup(env.unauthzSubject,
env.compatibleGroup.getId());
assert false : "should have failed - unauthz user not allowed to get plugin configuration";
} catch (PermissionException expected) {
} finally {
duration = System.currentTimeMillis() - start;
SessionTestHelper.simulateLogout(env.unauthzSubject);
}
System.out.println("Took [" + duration + "]ms to attempt unauthz access");
return;
}
/**
* This class mocks out the remote agent. It will receive calls to, for example,
* update plugin configurations.
*/
private class TestServices implements DiscoveryAgentService {
@Override
public void updatePluginConfiguration(int resourceId, Configuration newPluginConfiguration)
throws InvalidPluginConfigurationClientException, PluginContainerException {
latch.countDown();
long latchCount = latch.getCount();
System.out.print(((latchCount % 100) != 0) ? "." : String.valueOf(latchCount));
}
@Override
public AvailabilityReport executeAvailabilityScanImmediately(boolean changedOnlyReport) {
return null;
}
@Override
public AvailabilityReport getCurrentAvailability(Resource resource, boolean changesOnly) {
return null;
}
@NotNull
@Override
public InventoryReport executeServerScanImmediately() throws PluginContainerException {
return null;
}
@NotNull
@Override
public InventoryReport executeServiceScanImmediately() throws PluginContainerException {
return null;
}
@Override
public boolean executeServiceScanDeferred() {
return true;
}
@Override
public void executeServiceScanDeferred(int resourceId) {
}
@Override
public Resource getPlatform() {
return null;
}
@Override
public MergeResourceResponse manuallyAddResource(ResourceType resourceType, int parentResourceId,
Configuration pluginConfiguration, int creatorSubjectId) throws InvalidPluginConfigurationClientException,
PluginContainerException {
return null;
}
@Override
public void uninventoryResource(int resourceId) {
}
@Override
public void disableServiceScans(int serverResourceId) {
}
@Override
public void enableServiceScans(int serverResourceId, Configuration config) {
}
@Override
public void requestFullAvailabilityReport() {
return;
}
@Override
public void synchronizePlatform(PlatformSyncInfo syncInfo) {
}
@Override
public void synchronizeServer(int resourceId, Collection<ResourceSyncInfo> toplevelServerSyncInfo) {
}
}
}