diff options
author | Alex Rudyy <orudyy@apache.org> | 2013-05-03 11:41:21 +0000 |
---|---|---|
committer | Alex Rudyy <orudyy@apache.org> | 2013-05-03 11:41:21 +0000 |
commit | 1197200b540692c3980ae305107ee3d8d1b37b8d (patch) | |
tree | d3e9a435c8ead7f37cbd4720ee8a3f9a59126e24 | |
parent | b162949c9fd2b4d2ac6ea455ed538eec5b1909fb (diff) | |
download | qpid-python-1197200b540692c3980ae305107ee3d8d1b37b8d.tar.gz |
QPID-4802: In management mode set state to ERRORED for failing to activate authentication providers, group providers and acl providers in order to allow editing of attributes preventing normal
merged from trunk r1478731
git-svn-id: https://svn.apache.org/repos/asf/qpid/branches/0.22@1478737 13f79535-47bb-0310-9956-ffa450edef68
19 files changed, 620 insertions, 62 deletions
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/AccessControlProvider.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/AccessControlProvider.js index fd8a3ecb0e..9d9343623b 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/AccessControlProvider.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/AccessControlProvider.js @@ -100,6 +100,7 @@ define(["dojo/_base/xhr", this.controller = controller; this.name = query(".name", node)[0]; this.type = query(".type", node)[0]; + this.state = query(".state", node)[0]; this.query = "rest/accesscontrolprovider/"+encodeURIComponent(groupProviderObj.name); var that = this; @@ -125,6 +126,7 @@ define(["dojo/_base/xhr", { this.name.innerHTML = this.accessControlProviderData[ "name" ]; this.type.innerHTML = this.accessControlProviderData[ "type" ]; + this.state.innerHTML = this.accessControlProviderData[ "state" ]; }; return AccessControlProvider; diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/AuthenticationProvider.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/AuthenticationProvider.js index b7c0554158..4778671bda 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/AuthenticationProvider.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/AuthenticationProvider.js @@ -115,11 +115,9 @@ define(["dojo/_base/xhr", this.controller = controller; this.name = query(".name", node)[0]; this.type = query(".type", node)[0]; + this.state = query(".state", node)[0]; this.authenticationProvider = authenticationProvider; - /*this.state = dom.byId("state"); - this.durable = dom.byId("durable"); - this.lifetimePolicy = dom.byId("lifetimePolicy"); - */ + this.query = "rest/authenticationprovider/" + encodeURIComponent(authProviderObj.name); var that = this; @@ -155,10 +153,7 @@ define(["dojo/_base/xhr", this.authenticationProvider.name = this.authProviderData[ "name" ] this.name.innerHTML = this.authProviderData[ "name" ]; this.type.innerHTML = this.authProviderData[ "type" ]; - /* this.state.innerHTML = this.brokerData[ "state" ]; - this.durable.innerHTML = this.brokerData[ "durable" ]; - this.lifetimePolicy.innerHTML = this.brokerData[ "lifetimePolicy" ]; -*/ + this.state.innerHTML = this.authProviderData[ "state" ]; }; AuthProviderUpdater.prototype.update = function() diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Broker.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Broker.js index 230f148d4c..9074c1b43c 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Broker.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Broker.js @@ -576,14 +576,15 @@ define(["dojo/_base/xhr", that.authenticationProvidersGrid = new UpdatableStore(that.brokerData.authenticationproviders, query(".broker-authentication-providers")[0], - [ { name: "Name", field: "name", width: "100%"}, - { name: "Type", field: "type", width: "300px"}, - { name: "User Management", field: "type", width: "200px", + [ { name: "Name", field: "name", width: "30%"}, + { name: "State", field: "state", width: "20%"}, + { name: "Type", field: "type", width: "20%"}, + { name: "User Management", field: "type", width: "20%", formatter: function(val){ return "<input type='radio' disabled='disabled' "+(util.isProviderManagingUsers(val)?"checked='checked'": "")+" />"; } }, - { name: "Default", field: "name", width: "100px", + { name: "Default", field: "name", width: "10%", formatter: function(val){ return "<input type='radio' disabled='disabled' "+(val == that.brokerData.defaultAuthenticationProvider ? "checked='checked'": "")+" />"; } @@ -637,8 +638,9 @@ define(["dojo/_base/xhr", }, gridProperties, EnhancedGrid); that.groupProvidersGrid = new UpdatableStore(that.brokerData.groupproviders, query(".broker-group-providers")[0], - [ { name: "Name", field: "name", width: "50%"}, - { name: "Type", field: "type", width: "50%"} + [ { name: "Name", field: "name", width: "40%"}, + { name: "State", field: "state", width: "30%"}, + { name: "Type", field: "type", width: "30%"} ], function(obj) { connect.connect(obj.grid, "onRowDblClick", obj.grid, function(evt){ @@ -651,8 +653,9 @@ define(["dojo/_base/xhr", var aclData = that.brokerData.accesscontrolproviders ? that.brokerData.accesscontrolproviders :[]; that.accessControlProvidersGrid = new UpdatableStore(aclData, query(".broker-access-control-providers")[0], - [ { name: "Name", field: "name", width: "60%"}, - { name: "Type", field: "type", width: "40%"} + [ { name: "Name", field: "name", width: "40%"}, + { name: "State", field: "state", width: "30%"}, + { name: "Type", field: "type", width: "30%"} ], function(obj) { connect.connect(obj.grid, "onRowDblClick", obj.grid, function(evt){ diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/GroupProvider.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/GroupProvider.js index 98e01773ef..9dde224982 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/GroupProvider.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/GroupProvider.js @@ -106,6 +106,7 @@ define(["dojo/_base/xhr", this.controller = controller; this.name = query(".name", node)[0]; this.type = query(".type", node)[0]; + this.state = query(".state", node)[0]; this.query = "rest/groupprovider/"+encodeURIComponent(groupProviderObj.name); this.typeUI ={"GroupFile": "FileGroupManager"}; var that = this; @@ -134,6 +135,7 @@ define(["dojo/_base/xhr", { this.name.innerHTML = this.groupProviderData[ "name" ]; this.type.innerHTML = this.groupProviderData[ "type" ]; + this.state.innerHTML = this.groupProviderData[ "state" ]; }; GroupProviderUpdater.prototype.update = function() diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Port.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Port.js index d1ba4043c2..5d6ce6727b 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Port.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Port.js @@ -128,6 +128,7 @@ define(["dojo/dom", } storeNodes(["nameValue", + "stateValue", "portValue", "authenticationProviderValue", "protocolsValue", @@ -169,6 +170,7 @@ define(["dojo/dom", } this.nameValue.innerHTML = this.keyStoreData[ "name" ]; + this.stateValue.innerHTML = this.keyStoreData[ "state" ]; this.portValue.innerHTML = this.keyStoreData[ "port" ]; this.authenticationProviderValue.innerHTML = this.keyStoreData[ "authenticationProvider" ] ? this.keyStoreData[ "authenticationProvider" ] : ""; this.protocolsValue.innerHTML = printArray( "protocols", this.keyStoreData); diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/showAccessControlProvider.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/showAccessControlProvider.html index 399425a7de..d017683225 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/showAccessControlProvider.html +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/showAccessControlProvider.html @@ -23,6 +23,8 @@ <br/> <span style="">Type:</span><span class="type" style="position:absolute; left:6em"></span> <br/> + <span style="">State:</span><span class="state" style="position:absolute; left:6em"></span> + <br/> <div class="providerDetails"></div> <div class="dijitDialogPaneActionBar"> <input class="deleteAccessControlProviderButton" type="button" value="Delete Access Control provider" label="Delete Access Control Provider" dojoType="dijit.form.Button" /> diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/showAuthProvider.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/showAuthProvider.html index bea5db2829..5e876fdc1f 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/showAuthProvider.html +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/showAuthProvider.html @@ -23,6 +23,8 @@ <br/> <span style="">Type:</span><span class="type" style="position:absolute; left:6em"></span> <br/> + <span style="">State:</span><span class="state" style="position:absolute; left:6em"></span> + <br/> <button data-dojo-type="dijit.form.Button" class="editAuthenticationProviderButton">Edit</button> <button data-dojo-type="dijit.form.Button" class="deleteAuthenticationProviderButton">Delete</button> </div>
\ No newline at end of file diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/showGroupProvider.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/showGroupProvider.html index 332c7f5eaa..5ab5573b40 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/showGroupProvider.html +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/showGroupProvider.html @@ -23,6 +23,8 @@ <br/> <span style="">Type:</span><span class="type" style="position:absolute; left:6em"></span> <br/> + <span style="">State:</span><span class="state" style="position:absolute; left:6em"></span> + <br/> <div class="providerDetails"></div> <div class="dijitDialogPaneActionBar"> <input class="deleteGroupProviderButton" type="button" value="Delete Group provider" label="Delete Group Provider" dojoType="dijit.form.Button" /> diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/showPort.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/showPort.html index f297f2d751..4f460b85c1 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/showPort.html +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/showPort.html @@ -18,14 +18,23 @@ - under the License. - --> -<div class="port"> +<div> <div class="portContainer"> - <div class="formLabel-labelCell" style="float:left; width: 250px;">Name:</div> - <div class="nameValue" style="float:left;"></div><br/> + <div class="name" style="clear:both"> + <div class="formLabel-labelCell" style="float:left; width: 250px;">Name:</div> + <div class="nameValue" style="float:left;"></div><br/> + </div> + + <div class="state" style="clear:both"> + <div class="formLabel-labelCell" style="float:left; width: 250px;">State:</div> + <div class="stateValue" style="float:left;"></div><br/> + </div> - <div class="formLabel-labelCell" style="float:left; width: 250px;">Port Number:</div> - <div class="portValue" style="float:left;"></div><br/> + <div class="port" style="clear:both"> + <div class="formLabel-labelCell" style="float:left; width: 250px;">Port Number:</div> + <div class="portValue" style="float:left;"></div><br/> + </div> <div class="authenticationProvider" style="clear:both"> <div class="formLabel-labelCell" style="float:left; width: 250px;">Authentication Provider:</div> diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/store/ManagementModeStoreHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/store/ManagementModeStoreHandler.java index abf1537ef7..d08deee29b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/store/ManagementModeStoreHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/store/ManagementModeStoreHandler.java @@ -13,6 +13,8 @@ import org.apache.qpid.server.configuration.ConfigurationEntry; import org.apache.qpid.server.configuration.ConfigurationEntryStore; import org.apache.qpid.server.configuration.IllegalConfigurationException; import org.apache.qpid.server.model.AccessControlProvider; +import org.apache.qpid.server.model.AuthenticationProvider; +import org.apache.qpid.server.model.GroupProvider; import org.apache.qpid.server.model.Port; import org.apache.qpid.server.model.Protocol; import org.apache.qpid.server.model.State; @@ -27,9 +29,12 @@ public class ManagementModeStoreHandler implements ConfigurationEntryStore private static final String PORT_TYPE = Port.class.getSimpleName(); private static final String VIRTUAL_HOST_TYPE = VirtualHost.class.getSimpleName(); private static final String ACCESS_CONTROL_PROVIDER_TYPE = AccessControlProvider.class.getSimpleName(); + private static final String GROUP_PROVIDER_TYPE = GroupProvider.class.getSimpleName(); + private static final String AUTHENTICATION_PROVIDER_TYPE = AuthenticationProvider.class.getSimpleName(); private static final String ATTRIBUTE_STATE = VirtualHost.STATE; private static final Object MANAGEMENT_MODE_AUTH_PROVIDER = "mm-auth"; + private final ConfigurationEntryStore _store; private final Map<UUID, ConfigurationEntry> _cliEntries; private final Map<UUID, Object> _quiescedEntries; @@ -255,11 +260,7 @@ public class ManagementModeStoreHandler implements ConfigurationEntryStore { quiesce = true; } - else if (ACCESS_CONTROL_PROVIDER_TYPE.equals(entryType)) - { - quiesce = true; - } - else if (PORT_TYPE.equalsIgnoreCase(entryType)) + else if (PORT_TYPE.equals(entryType)) { if (attributes == null) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AbstractAdapter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AbstractAdapter.java index 51fd3a5c78..a8c3f54530 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AbstractAdapter.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AbstractAdapter.java @@ -351,15 +351,7 @@ abstract class AbstractAdapter implements ConfiguredObject protected void changeAttributes(final Map<String, Object> attributes) { - if (attributes.containsKey(ID)) - { - UUID id = getId(); - Object idAttributeValue = attributes.get(ID); - if (idAttributeValue != null && !idAttributeValue.equals(id)) - { - throw new IllegalConfigurationException("Cannot change existing configured object id"); - } - } + validateChangeAttributes(attributes); Collection<String> names = getAttributeNames(); for (String name : names) { @@ -375,6 +367,19 @@ abstract class AbstractAdapter implements ConfiguredObject } } + protected void validateChangeAttributes(final Map<String, Object> attributes) + { + if (attributes.containsKey(ID)) + { + UUID id = getId(); + Object idAttributeValue = attributes.get(ID); + if (idAttributeValue != null && !idAttributeValue.equals(id.toString())) + { + throw new IllegalConfigurationException("Cannot change existing configured object id"); + } + } + } + protected void authoriseSetDesiredState(State currentState, State desiredState) throws AccessControlException { // allowed by default diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AccessControlProviderAdapter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AccessControlProviderAdapter.java index 75b80eb56c..a6fe191523 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AccessControlProviderAdapter.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AccessControlProviderAdapter.java @@ -29,6 +29,7 @@ import java.util.Map; import java.util.UUID; import java.util.concurrent.atomic.AtomicReference; +import org.apache.log4j.Logger; import org.apache.qpid.server.model.AccessControlProvider; import org.apache.qpid.server.model.Broker; import org.apache.qpid.server.model.ConfiguredObject; @@ -43,6 +44,8 @@ import org.apache.qpid.server.util.MapValueConverter; public class AccessControlProviderAdapter extends AbstractAdapter implements AccessControlProvider { + private static final Logger LOGGER = Logger.getLogger(AccessControlProviderAdapter.class); + protected AccessControl _accessControl; protected final Broker _broker; @@ -217,8 +220,23 @@ public class AccessControlProviderAdapter extends AbstractAdapter implements Acc { if ((state == State.INITIALISING || state == State.QUIESCED) && _state.compareAndSet(state, State.ACTIVE)) { - _accessControl.open(); - return true; + try + { + _accessControl.open(); + return true; + } + catch(RuntimeException e) + { + _state.compareAndSet(State.ACTIVE, State.ERRORED); + if (_broker.isManagementMode()) + { + LOGGER.warn("Failed to activate ACL provider: " + getName(), e); + } + else + { + throw e; + } + } } else { @@ -235,7 +253,6 @@ public class AccessControlProviderAdapter extends AbstractAdapter implements Acc return false; } - return false; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AuthenticationProviderAdapter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AuthenticationProviderAdapter.java index 24f4757a18..5c4c8a53cd 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AuthenticationProviderAdapter.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AuthenticationProviderAdapter.java @@ -30,6 +30,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.UUID; +import java.util.concurrent.atomic.AtomicReference; import javax.security.auth.login.AccountNotFoundException; @@ -58,6 +59,7 @@ import org.apache.qpid.server.security.auth.database.PrincipalDatabase; import org.apache.qpid.server.security.auth.manager.AuthenticationManager; import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager; import org.apache.qpid.server.security.SecurityManager; +import org.apache.qpid.server.util.MapValueConverter; public abstract class AuthenticationProviderAdapter<T extends AuthenticationManager> extends AbstractAdapter implements AuthenticationProvider { @@ -68,6 +70,7 @@ public abstract class AuthenticationProviderAdapter<T extends AuthenticationMana protected Collection<String> _supportedAttributes; protected Map<String, AuthenticationManagerFactory> _factories; + private AtomicReference<State> _state; private AuthenticationProviderAdapter(UUID id, Broker broker, final T authManager, Map<String, Object> attributes, Collection<String> attributeNames) { @@ -76,6 +79,9 @@ public abstract class AuthenticationProviderAdapter<T extends AuthenticationMana _broker = broker; _supportedAttributes = createSupportedAttributes(attributeNames); _factories = getAuthenticationManagerFactories(); + + State state = MapValueConverter.getEnumAttribute(State.class, STATE, attributes, State.INITIALISING); + _state = new AtomicReference<State>(state); addParent(Broker.class, broker); // set attributes now after all attribute names are known @@ -117,7 +123,7 @@ public abstract class AuthenticationProviderAdapter<T extends AuthenticationMana @Override public State getActualState() { - return null; + return _state.get(); } @Override @@ -191,7 +197,7 @@ public abstract class AuthenticationProviderAdapter<T extends AuthenticationMana } else if(STATE.equals(name)) { - return State.ACTIVE; // TODO + return getActualState(); } else if(TIME_TO_LIVE.equals(name)) { @@ -214,6 +220,7 @@ public abstract class AuthenticationProviderAdapter<T extends AuthenticationMana public boolean setState(State currentState, State desiredState) throws IllegalStateTransitionException, AccessControlException { + State state = _state.get(); if(desiredState == State.DELETED) { String providerName = getName(); @@ -227,20 +234,66 @@ public abstract class AuthenticationProviderAdapter<T extends AuthenticationMana throw new IntegrityViolationException("Authentication provider '" + providerName + "' is set on port " + port.getName()); } } - _authManager.close(); - _authManager.onDelete(); - return true; + + if ((state == State.INITIALISING || state == State.ACTIVE || state == State.STOPPED || state == State.QUIESCED || state == State.ERRORED) + && _state.compareAndSet(state, State.DELETED)) + { + _authManager.close(); + _authManager.onDelete(); + return true; + } + else + { + throw new IllegalStateException("Cannot delete authentication provider in state: " + state); + } } else if(desiredState == State.ACTIVE) { - _authManager.initialise(); - return true; + if ((state == State.INITIALISING || state == State.QUIESCED || state == State.STOPPED) && _state.compareAndSet(state, State.ACTIVE)) + { + try + { + _authManager.initialise(); + return true; + } + catch(RuntimeException e) + { + _state.compareAndSet(State.ACTIVE, State.ERRORED); + if (_broker.isManagementMode()) + { + LOGGER.warn("Failed to activate authentication provider: " + getName(), e); + } + else + { + throw e; + } + } + } + else + { + throw new IllegalStateException("Cannot activate authentication provider in state: " + state); + } + } + else if (desiredState == State.QUIESCED) + { + if (state == State.INITIALISING && _state.compareAndSet(state, State.QUIESCED)) + { + return true; + } } else if(desiredState == State.STOPPED) { - _authManager.close(); - return true; + if (_state.compareAndSet(state, State.STOPPED)) + { + _authManager.close(); + return true; + } + else + { + throw new IllegalStateException("Cannot stop authentication provider in state: " + state); + } } + return false; } @@ -256,11 +309,11 @@ public abstract class AuthenticationProviderAdapter<T extends AuthenticationMana Map<String, Object> effectiveAttributes = super.generateEffectiveAttributes(attributes); AuthenticationManager manager = validateAttributes(effectiveAttributes); manager.initialise(); - _authManager = (T)manager; - String type = (String)effectiveAttributes.get(AuthenticationManagerFactory.ATTRIBUTE_TYPE); - AuthenticationManagerFactory managerFactory = _factories.get(type); - _supportedAttributes = createSupportedAttributes(managerFactory.getAttributeNames()); super.changeAttributes(attributes); + _authManager = (T)manager; + + // if provider was previously in ERRORED state then set its state to ACTIVE + _state.compareAndSet(State.ERRORED, State.ACTIVE); } private Map<String, AuthenticationManagerFactory> getAuthenticationManagerFactories() @@ -287,6 +340,8 @@ public abstract class AuthenticationProviderAdapter<T extends AuthenticationMana protected AuthenticationManager validateAttributes(Map<String, Object> attributes) { + super.validateChangeAttributes(attributes); + String newName = (String)attributes.get(NAME); String currentName = getName(); if (!currentName.equals(newName)) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/GroupProviderAdapter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/GroupProviderAdapter.java index a0e5bdb0e8..3bf62dc96b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/GroupProviderAdapter.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/GroupProviderAdapter.java @@ -28,7 +28,9 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.UUID; +import java.util.concurrent.atomic.AtomicReference; +import org.apache.log4j.Logger; import org.apache.qpid.server.model.Broker; import org.apache.qpid.server.model.ConfiguredObject; import org.apache.qpid.server.model.Group; @@ -43,13 +45,17 @@ import org.apache.qpid.server.configuration.updater.TaskExecutor; import org.apache.qpid.server.security.access.Operation; import org.apache.qpid.server.security.group.GroupManager; import org.apache.qpid.server.security.SecurityManager; +import org.apache.qpid.server.util.MapValueConverter; public class GroupProviderAdapter extends AbstractAdapter implements GroupProvider { + private static Logger LOGGER = Logger.getLogger(GroupProviderAdapter.class); + private final GroupManager _groupManager; private final Broker _broker; private Collection<String> _supportedAttributes; + private AtomicReference<State> _state; public GroupProviderAdapter(UUID id, Broker broker, GroupManager groupManager, Map<String, Object> attributes, Collection<String> attributeNames) { @@ -62,6 +68,8 @@ public class GroupProviderAdapter extends AbstractAdapter implements _groupManager = groupManager; _broker = broker; _supportedAttributes = createSupportedAttributes(attributeNames); + State state = MapValueConverter.getEnumAttribute(State.class, STATE, attributes, State.INITIALISING); + _state = new AtomicReference<State>(state); addParent(Broker.class, broker); // set attributes now after all attribute names are known @@ -104,7 +112,7 @@ public class GroupProviderAdapter extends AbstractAdapter implements @Override public State getActualState() { - return null; + return _state.get(); } @Override @@ -180,7 +188,7 @@ public class GroupProviderAdapter extends AbstractAdapter implements } else if (STATE.equals(name)) { - return State.ACTIVE; // TODO + return getActualState(); } else if (TIME_TO_LIVE.equals(name)) { @@ -252,21 +260,67 @@ public class GroupProviderAdapter extends AbstractAdapter implements @Override protected boolean setState(State currentState, State desiredState) { + State state = _state.get(); if (desiredState == State.ACTIVE) { - _groupManager.open(); - return true; + if ((state == State.INITIALISING || state == State.QUIESCED || state == State.STOPPED) + && _state.compareAndSet(state, State.ACTIVE)) + { + try + { + _groupManager.open(); + return true; + } + catch(RuntimeException e) + { + _state.compareAndSet(State.ACTIVE, State.ERRORED); + if (_broker.isManagementMode()) + { + LOGGER.warn("Failed to activate group provider: " + getName(), e); + } + else + { + throw e; + } + } + } + else + { + throw new IllegalStateException("Cannot activate group provider in state: " + state); + } } else if (desiredState == State.STOPPED) { - _groupManager.close(); - return true; + if (_state.compareAndSet(state, State.STOPPED)) + { + _groupManager.close(); + return true; + } + else + { + throw new IllegalStateException("Cannot stop group provider in state: " + state); + } } else if (desiredState == State.DELETED) { - _groupManager.close(); - _groupManager.onDelete(); - return true; + if ((state == State.INITIALISING || state == State.ACTIVE || state == State.STOPPED || state == State.QUIESCED || state == State.ERRORED) + && _state.compareAndSet(state, State.DELETED)) + { + _groupManager.close(); + _groupManager.onDelete(); + return true; + } + else + { + throw new IllegalStateException("Cannot delete group provider in state: " + state); + } + } + else if (desiredState == State.QUIESCED) + { + if (state == State.INITIALISING && _state.compareAndSet(state, State.QUIESCED)) + { + return true; + } } return false; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/PortAdapter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/PortAdapter.java index 388427678e..de6ae06b94 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/PortAdapter.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/PortAdapter.java @@ -309,7 +309,7 @@ public class PortAdapter extends AbstractAdapter implements Port State state = _state.get(); if (desiredState == State.DELETED) { - if (state == State.INITIALISING || state == State.ACTIVE || state == State.STOPPED || state == State.QUIESCED) + if (state == State.INITIALISING || state == State.ACTIVE || state == State.STOPPED || state == State.QUIESCED || state == State.ERRORED) { return _state.compareAndSet(state, State.DELETED); } @@ -328,7 +328,7 @@ public class PortAdapter extends AbstractAdapter implements Port } catch(RuntimeException e) { - _state.compareAndSet(State.ACTIVE, state); + _state.compareAndSet(State.ACTIVE, State.ERRORED); throw e; } return true; diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/model/ConfiguredObjectStateTransitionTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/model/ConfiguredObjectStateTransitionTest.java new file mode 100644 index 0000000000..40f98b3b09 --- /dev/null +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/model/ConfiguredObjectStateTransitionTest.java @@ -0,0 +1,245 @@ +package org.apache.qpid.server.model; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.io.File; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import org.apache.qpid.server.BrokerOptions; +import org.apache.qpid.server.configuration.ConfigurationEntry; +import org.apache.qpid.server.configuration.ConfigurationEntryStore; +import org.apache.qpid.server.configuration.ConfiguredObjectRecoverer; +import org.apache.qpid.server.configuration.RecovererProvider; +import org.apache.qpid.server.configuration.startup.DefaultRecovererProvider; +import org.apache.qpid.server.configuration.updater.TaskExecutor; +import org.apache.qpid.server.security.auth.manager.AnonymousAuthenticationManagerFactory; +import org.apache.qpid.server.security.group.FileGroupManagerFactory; +import org.apache.qpid.server.stats.StatisticsGatherer; +import org.apache.qpid.server.util.BrokerTestHelper; +import org.apache.qpid.test.utils.QpidTestCase; + +public class ConfiguredObjectStateTransitionTest extends QpidTestCase +{ + private Broker _broker; + private RecovererProvider _recovererProvider; + private ConfigurationEntryStore _store; + private File _resourceToDelete; + + @Override + public void setUp() throws Exception + { + super.setUp(); + BrokerTestHelper.setUp(); + + _broker = BrokerTestHelper.createBrokerMock(); + StatisticsGatherer statisticsGatherer = mock(StatisticsGatherer.class); + TaskExecutor executor = mock(TaskExecutor.class); + when(executor.isTaskExecutorThread()).thenReturn(true); + when(_broker.getTaskExecutor()).thenReturn(executor); + + _recovererProvider = new DefaultRecovererProvider(statisticsGatherer, _broker.getVirtualHostRegistry(), + _broker.getLogRecorder(), _broker.getRootMessageLogger(), executor, new BrokerOptions()); + + _store = mock(ConfigurationEntryStore.class); + + _resourceToDelete = new File(TMP_FOLDER, getTestName()); + } + + @Override + public void tearDown() throws Exception + { + try + { + BrokerTestHelper.tearDown(); + if (_resourceToDelete.exists()) + { + _resourceToDelete.delete(); + } + } + finally + { + super.tearDown(); + } + } + + public void testGroupProviderValidStateTransitions() throws Exception + { + ConfigurationEntry providerEntry = getGroupProviderConfigurationEntry(); + ConfiguredObject provider = createConfiguredObject(providerEntry); + provider.setDesiredState(State.INITIALISING, State.QUIESCED); + assertValidStateTransition(provider, State.QUIESCED, State.STOPPED); + + provider = createConfiguredObject(providerEntry); + assertValidStateTransition(provider, State.INITIALISING, State.DELETED); + + providerEntry = getGroupProviderConfigurationEntry(); + provider = createConfiguredObject(providerEntry); + provider.setDesiredState(State.INITIALISING, State.QUIESCED); + assertValidStateTransition(provider, State.QUIESCED, State.DELETED); + + providerEntry = getGroupProviderConfigurationEntry(); + provider = createConfiguredObject(providerEntry); + provider.setDesiredState(State.INITIALISING, State.ACTIVE); + assertValidStateTransition(provider, State.ACTIVE, State.DELETED); + } + + public void testGroupProviderInvalidStateTransitions() throws Exception + { + ConfigurationEntry providerEntry = getGroupProviderConfigurationEntry(); + assertAllInvalidStateTransitions(providerEntry); + } + + public void testAuthenticationProviderValidStateTransitions() + { + ConfigurationEntry providerEntry = getAuthenticationProviderConfigurationEntry(); + assertAllValidStateTransitions(providerEntry); + } + + public void testAuthenticationProviderInvalidStateTransitions() + { + ConfigurationEntry providerEntry = getAuthenticationProviderConfigurationEntry(); + assertAllInvalidStateTransitions(providerEntry); + } + + public void testPortValidStateTransitions() + { + ConfigurationEntry providerEntry = getPortConfigurationEntry(); + assertAllValidStateTransitions(providerEntry); + } + + public void testPortInvalidStateTransitions() + { + ConfigurationEntry providerEntry = getPortConfigurationEntry(); + assertAllInvalidStateTransitions(providerEntry); + } + + private void assertAllInvalidStateTransitions(ConfigurationEntry providerEntry) + { + ConfiguredObject provider = createConfiguredObject(providerEntry); + assertInvalidStateTransition(provider, State.INITIALISING, State.REPLICA); + + provider.setDesiredState(State.INITIALISING, State.QUIESCED); + assertInvalidStateTransition(provider, State.QUIESCED, State.INITIALISING); + + provider.setDesiredState(State.QUIESCED, State.ACTIVE); + assertInvalidStateTransition(provider, State.ACTIVE, State.INITIALISING); + + provider.setDesiredState(State.ACTIVE, State.DELETED); + assertInvalidStateTransition(provider, State.DELETED, State.INITIALISING); + assertInvalidStateTransition(provider, State.DELETED, State.QUIESCED); + assertInvalidStateTransition(provider, State.DELETED, State.ACTIVE); + assertInvalidStateTransition(provider, State.DELETED, State.REPLICA); + assertInvalidStateTransition(provider, State.DELETED, State.ERRORED); + } + + private void assertAllValidStateTransitions(ConfigurationEntry providerEntry) + { + ConfiguredObject provider = createConfiguredObject(providerEntry); + assertNormalStateTransition(provider); + + provider = createConfiguredObject(providerEntry); + provider.setDesiredState(State.INITIALISING, State.QUIESCED); + assertValidStateTransition(provider, State.QUIESCED, State.STOPPED); + + provider = createConfiguredObject(providerEntry); + assertValidStateTransition(provider, State.INITIALISING, State.DELETED); + + provider = createConfiguredObject(providerEntry); + provider.setDesiredState(State.INITIALISING, State.QUIESCED); + assertValidStateTransition(provider, State.QUIESCED, State.DELETED); + + provider = createConfiguredObject(providerEntry); + provider.setDesiredState(State.INITIALISING, State.ACTIVE); + assertValidStateTransition(provider, State.ACTIVE, State.DELETED); + } + + private void assertInvalidStateTransition(ConfiguredObject object, State initialState, State... invalidStates) + { + assertEquals("Unepxceted state", initialState, object.getActualState()); + for (State state : invalidStates) + { + try + { + object.setDesiredState(initialState, state); + } + catch (IllegalStateException e) + { + // expected + } + assertEquals("Transition from state " + initialState + " into state " + state + " did occur", initialState, + object.getActualState()); + } + } + + private void assertValidStateTransition(ConfiguredObject object, State initialState, State... validStateSequence) + { + assertEquals("Unexpected state", initialState, object.getActualState()); + State currentState = initialState; + for (State state : validStateSequence) + { + object.setDesiredState(currentState, state); + assertEquals("Transition from state " + currentState + " into state " + state + " did not occur", state, + object.getActualState()); + currentState = state; + } + } + + private void assertNormalStateTransition(ConfiguredObject object) + { + assertValidStateTransition(object, State.INITIALISING, State.QUIESCED, State.ACTIVE, State.STOPPED, State.DELETED); + } + + private ConfiguredObject createConfiguredObject(ConfigurationEntry entry) + { + @SuppressWarnings("unchecked") + ConfiguredObjectRecoverer<ConfiguredObject> recoverer = + (ConfiguredObjectRecoverer<ConfiguredObject>)_recovererProvider.getRecoverer(entry.getType()); + return recoverer.create(_recovererProvider, entry, _broker); + } + + private ConfigurationEntry createConfigurationEntry(String type, Map<String, Object> attributes, ConfigurationEntryStore store) + { + return new ConfigurationEntry(UUID.randomUUID(), type, attributes, Collections.<UUID>emptySet(), store); + } + + private ConfigurationEntry getAuthenticationProviderConfigurationEntry() + { + Map<String, Object> attributes = new HashMap<String, Object>(); + attributes.put(AuthenticationProvider.NAME, getTestName()); + attributes.put(AuthenticationProvider.TYPE, AnonymousAuthenticationManagerFactory.PROVIDER_TYPE); + return createConfigurationEntry(AuthenticationProvider.class.getSimpleName(), attributes , _store); + } + + private ConfigurationEntry getGroupProviderConfigurationEntry() throws Exception + { + Map<String, Object> attributes = new HashMap<String, Object>(); + attributes.put(GroupProvider.NAME, getTestName()); + attributes.put(GroupProvider.TYPE, FileGroupManagerFactory.GROUP_FILE_PROVIDER_TYPE); + attributes.put(FileGroupManagerFactory.PATH, _resourceToDelete.getAbsolutePath()); + if (!_resourceToDelete.exists()) + { + _resourceToDelete.createNewFile(); + } + return createConfigurationEntry(GroupProvider.class.getSimpleName(), attributes , _store); + } + + private ConfigurationEntry getPortConfigurationEntry() + { + ConfigurationEntry authProviderEntry = getAuthenticationProviderConfigurationEntry(); + AuthenticationProvider authProvider = (AuthenticationProvider)createConfiguredObject(authProviderEntry); + + Map<String, Object> attributes = new HashMap<String, Object>(); + attributes.put(Port.NAME, getTestName()); + attributes.put(Port.PROTOCOLS, Collections.<Protocol>singleton(Protocol.HTTP)); + attributes.put(Port.AUTHENTICATION_PROVIDER, authProvider.getName()); + attributes.put(Port.PORT, 0); + + when(_broker.findAuthenticationProviderByName(authProvider.getName())).thenReturn(authProvider); + return createConfigurationEntry(Port.class.getSimpleName(), attributes , _store); + } + +} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/AccessControlProviderRestTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/AccessControlProviderRestTest.java index 861b246d54..312443cfa7 100644 --- a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/AccessControlProviderRestTest.java +++ b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/AccessControlProviderRestTest.java @@ -25,10 +25,13 @@ import java.io.IOException; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.UUID; import org.apache.commons.configuration.ConfigurationException; +import org.apache.qpid.server.BrokerOptions; import org.apache.qpid.server.management.plugin.HttpManagement; import org.apache.qpid.server.model.AccessControlProvider; +import org.apache.qpid.server.model.State; import org.apache.qpid.server.security.access.FileAccessControlProviderConstants; import org.apache.qpid.test.utils.TestBrokerConfiguration; import org.apache.qpid.test.utils.TestFileUtils; @@ -230,6 +233,34 @@ public class AccessControlProviderRestTest extends QpidRestTestCase assertCanAccessManagementInterface(accessControlProviderName2, true); } + public void testRemovalOfAccessControlProviderInErrorStateUsingManagementMode() throws Exception + { + stopBroker(); + + File file = new File(TMP_FOLDER, getTestName()); + if (file.exists()) + { + file.delete(); + } + assertFalse("ACL file should not exist", file.exists()); + UUID id = getBrokerConfiguration().addAclFileConfiguration(file.getAbsolutePath()); + getBrokerConfiguration().setSaved(false); + startBroker(0, true); + + getRestTestHelper().setUsernameAndPassword(BrokerOptions.MANAGEMENT_MODE_USER_NAME, MANAGEMENT_MODE_PASSWORD); + + Map<String, Object> acl = getRestTestHelper().getJsonAsSingletonList("/rest/accesscontrolprovider/" + TestBrokerConfiguration.ENTRY_NAME_ACL_FILE); + assertEquals("Unexpected id", id.toString(), acl.get(AccessControlProvider.ID)); + assertEquals("Unexpected path", file.getAbsolutePath() , acl.get(FileAccessControlProviderConstants.PATH)); + assertEquals("Unexpected state", State.ERRORED.name() , acl.get(AccessControlProvider.STATE)); + + int status = getRestTestHelper().submitRequest("/rest/accesscontrolprovider/" + TestBrokerConfiguration.ENTRY_NAME_ACL_FILE, "DELETE", null); + assertEquals("ACL was not deleted", 200, status); + + List<Map<String, Object>> acls = getRestTestHelper().getJsonAsList("/rest/accesscontrolprovider/" + TestBrokerConfiguration.ENTRY_NAME_ACL_FILE); + assertEquals("ACL exists", 0, acls.size()); + } + private void assertCanAccessManagementInterface(String accessControlProviderName, boolean canAccess) throws Exception { int expected = canAccess ? 200 : 403; diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/AuthenticationProviderRestTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/AuthenticationProviderRestTest.java index 4ff0db8bc3..bb01d1facf 100644 --- a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/AuthenticationProviderRestTest.java +++ b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/AuthenticationProviderRestTest.java @@ -26,6 +26,7 @@ import java.util.List; import java.util.Map; import java.util.UUID; +import org.apache.qpid.server.BrokerOptions; import org.apache.qpid.server.model.AuthenticationProvider; import org.apache.qpid.server.model.LifetimePolicy; import org.apache.qpid.server.model.Port; @@ -156,6 +157,103 @@ public class AuthenticationProviderRestTest extends QpidRestTestCase assertEquals("Unexpected number of providers", 0, providerDetails.size()); } + public void testRemovalOfAuthenticationProviderInErrorStateUsingManagementMode() throws Exception + { + stopBroker(); + + File file = new File(TMP_FOLDER, getTestName()); + if (file.exists()) + { + file.delete(); + } + assertFalse("Group file should not exist", file.exists()); + + TestBrokerConfiguration config = getBrokerConfiguration(); + + String providerName = getTestName(); + Map<String, Object> attributes = new HashMap<String, Object>(); + attributes.put(AuthenticationProvider.TYPE, PlainPasswordFileAuthenticationManagerFactory.PROVIDER_TYPE); + attributes.put(AuthenticationProvider.NAME, providerName); + attributes.put(PlainPasswordFileAuthenticationManagerFactory.ATTRIBUTE_PATH, file.getAbsoluteFile()); + + UUID id = config.addAuthenticationProviderConfiguration(attributes); + config.setSaved(false); + startBroker(0, true); + + getRestTestHelper().setUsernameAndPassword(BrokerOptions.MANAGEMENT_MODE_USER_NAME, MANAGEMENT_MODE_PASSWORD); + + Map<String, Object> provider = getRestTestHelper().getJsonAsSingletonList("/rest/authenticationprovider/" + providerName); + assertEquals("Unexpected id", id.toString(), provider.get(AuthenticationProvider.ID)); + assertEquals("Unexpected name", providerName, provider.get(AuthenticationProvider.NAME)); + assertEquals("Unexpected path", file.getAbsolutePath() , provider.get(PlainPasswordFileAuthenticationManagerFactory.ATTRIBUTE_PATH)); + assertEquals("Unexpected state", State.ERRORED.name() , provider.get(AuthenticationProvider.STATE)); + + int status = getRestTestHelper().submitRequest("/rest/authenticationprovider/" + providerName, "DELETE", null); + assertEquals("ACL was not deleted", 200, status); + + List<Map<String, Object>> providers = getRestTestHelper().getJsonAsList("/rest/authenticationprovider/" + providerName); + assertEquals("Provider exists", 0, providers.size()); + } + + public void testUpdateOfAuthenticationProviderInErrorStateUsingManagementMode() throws Exception + { + stopBroker(); + + File file = new File(TMP_FOLDER, getTestName()); + if (file.exists()) + { + file.delete(); + } + assertFalse("Group file should not exist", file.exists()); + + TestBrokerConfiguration config = getBrokerConfiguration(); + + String providerName = getTestName(); + Map<String, Object> attributes = new HashMap<String, Object>(); + attributes.put(AuthenticationProvider.TYPE, PlainPasswordFileAuthenticationManagerFactory.PROVIDER_TYPE); + attributes.put(AuthenticationProvider.NAME, providerName); + attributes.put(PlainPasswordFileAuthenticationManagerFactory.ATTRIBUTE_PATH, file.getAbsoluteFile()); + + UUID id = config.addAuthenticationProviderConfiguration(attributes); + config.setSaved(false); + startBroker(0, true); + + getRestTestHelper().setUsernameAndPassword(BrokerOptions.MANAGEMENT_MODE_USER_NAME, MANAGEMENT_MODE_PASSWORD); + + Map<String, Object> provider = getRestTestHelper().getJsonAsSingletonList("/rest/authenticationprovider/" + providerName); + assertEquals("Unexpected id", id.toString(), provider.get(AuthenticationProvider.ID)); + assertEquals("Unexpected name", providerName, provider.get(AuthenticationProvider.NAME)); + assertEquals("Unexpected path", file.getAbsolutePath() , provider.get(PlainPasswordFileAuthenticationManagerFactory.ATTRIBUTE_PATH)); + assertEquals("Unexpected state", State.ERRORED.name() , provider.get(AuthenticationProvider.STATE)); + + File principalDatabase = null; + try + { + principalDatabase = getRestTestHelper().createTemporaryPasswdFile(new String[]{"admin2", "guest2", "test2"}); + attributes = new HashMap<String, Object>(); + attributes.put(AuthenticationProvider.NAME, providerName); + attributes.put(AuthenticationProvider.ID, id); + attributes.put(AuthenticationProvider.TYPE, PlainPasswordFileAuthenticationManagerFactory.PROVIDER_TYPE); + attributes.put(PlainPasswordFileAuthenticationManagerFactory.ATTRIBUTE_PATH, principalDatabase.getAbsolutePath()); + + int status = getRestTestHelper().submitRequest("/rest/authenticationprovider/" + providerName, "PUT", attributes); + assertEquals("ACL was not deleted", 200, status); + + provider = getRestTestHelper().getJsonAsSingletonList("/rest/authenticationprovider/" + providerName); + assertEquals("Unexpected id", id.toString(), provider.get(AuthenticationProvider.ID)); + assertEquals("Unexpected name", providerName, provider.get(AuthenticationProvider.NAME)); + assertEquals("Unexpected path", principalDatabase.getAbsolutePath() , provider.get(PlainPasswordFileAuthenticationManagerFactory.ATTRIBUTE_PATH)); + assertEquals("Unexpected state", State.ACTIVE.name() , provider.get(AuthenticationProvider.STATE)); + } + finally + { + if (principalDatabase != null) + { + principalDatabase.delete(); + } + } + } + public void testCreateAndDeletePasswordAuthenticationProviderWithNonExistingFile() throws Exception { stopBroker(); diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/GroupProviderRestTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/GroupProviderRestTest.java index ef8e12a929..d09d5a8d02 100644 --- a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/GroupProviderRestTest.java +++ b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/GroupProviderRestTest.java @@ -26,7 +26,9 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Properties; +import java.util.UUID; +import org.apache.qpid.server.BrokerOptions; import org.apache.qpid.server.model.Group; import org.apache.qpid.server.model.GroupProvider; import org.apache.qpid.server.model.LifetimePolicy; @@ -285,6 +287,37 @@ public class GroupProviderRestTest extends QpidRestTestCase } } + public void testRemovalOfGroupProviderInErrorStateUsingManagementMode() throws Exception + { + stopBroker(); + + File file = new File(TMP_FOLDER, getTestName()); + if (file.exists()) + { + file.delete(); + } + assertFalse("Group file should not exist", file.exists()); + + TestBrokerConfiguration config = getBrokerConfiguration(); + config.removeObjectConfiguration(TestBrokerConfiguration.ENTRY_NAME_GROUP_FILE); + UUID id = config.addGroupFileConfiguration(file.getAbsolutePath()); + config.setSaved(false); + startBroker(0, true); + + getRestTestHelper().setUsernameAndPassword(BrokerOptions.MANAGEMENT_MODE_USER_NAME, MANAGEMENT_MODE_PASSWORD); + + Map<String, Object> groupProvider = getRestTestHelper().getJsonAsSingletonList("/rest/groupprovider/" + TestBrokerConfiguration.ENTRY_NAME_GROUP_FILE); + assertEquals("Unexpected id", id.toString(), groupProvider.get(GroupProvider.ID)); + assertEquals("Unexpected path", file.getAbsolutePath() , groupProvider.get(FileGroupManagerFactory.PATH)); + assertEquals("Unexpected state", State.ERRORED.name() , groupProvider.get(GroupProvider.STATE)); + + int status = getRestTestHelper().submitRequest("/rest/groupprovider/" + TestBrokerConfiguration.ENTRY_NAME_GROUP_FILE, "DELETE", null); + assertEquals("ACL was not deleted", 200, status); + + List<Map<String, Object>> providers = getRestTestHelper().getJsonAsList("/rest/groupprovider/" + TestBrokerConfiguration.ENTRY_NAME_GROUP_FILE); + assertEquals("Provider exists", 0, providers.size()); + } + private void assertProvider(String name, String type, Map<String, Object> provider) { Asserts.assertAttributesPresent(provider, GroupProvider.AVAILABLE_ATTRIBUTES, |