AMBARI-21307 Feature for supporting LDAP configuration from the UI
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/30415a18 Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/30415a18 Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/30415a18 Branch: refs/heads/feature-branch-AMBARI-21307 Commit: 30415a18909f37a094e4adcc27ca5f2bf39e2fb1 Parents: 7e6036c Author: lpuskas <lpus...@apache.org> Authored: Wed Jul 5 14:20:18 2017 +0200 Committer: lpuskas <lpus...@apache.org> Committed: Fri Oct 27 11:57:59 2017 +0200 ---------------------------------------------------------------------- ambari-funtest/pom.xml | 67 ---- ambari-project/pom.xml | 52 +-- ambari-server/pom.xml | 83 +---- .../resources/ResourceInstanceFactoryImpl.java | 4 + .../AmbariConfigurationRequestSwagger.java | 47 +++ .../AmbariConfigurationResponseSwagger.java | 40 +++ .../services/AmbariConfigurationService.java | 193 +++++++++++ .../api/services/ldap/AmbariConfiguration.java | 87 +++++ .../api/services/ldap/LdapConfigOperation.java | 43 +++ .../services/ldap/LdapConfigurationRequest.java | 49 +++ .../services/ldap/LdapConfigurationService.java | 185 +++++++++++ .../api/services/ldap/LdapRequestInfo.java | 61 ++++ .../stackadvisor/StackAdvisorRequest.java | 12 + .../commands/StackAdvisorCommand.java | 54 +++ .../ambari/server/controller/AmbariServer.java | 3 +- .../server/controller/ControllerModule.java | 3 + .../controller/ResourceProviderFactory.java | 24 +- .../AbstractControllerResourceProvider.java | 2 + .../internal/AbstractProviderModule.java | 2 +- .../AmbariConfigurationResourceProvider.java | 328 +++++++++++++++++++ .../internal/DefaultProviderModule.java | 24 +- .../ambari/server/controller/spi/Resource.java | 5 +- .../ambari/server/events/AmbariEvent.java | 11 +- .../events/AmbariLdapConfigChangedEvent.java | 37 +++ .../apache/ambari/server/ldap/LdapModule.java | 82 +++++ .../ldap/domain/AmbariLdapConfigKeys.java | 83 +++++ .../ldap/domain/AmbariLdapConfiguration.java | 199 +++++++++++ .../domain/AmbariLdapConfigurationFactory.java | 34 ++ .../AmbariLdapConfigurationProvider.java | 120 +++++++ .../ldap/service/AmbariLdapException.java | 33 ++ .../server/ldap/service/AmbariLdapFacade.java | 140 ++++++++ .../server/ldap/service/AttributeDetector.java | 41 +++ .../service/LdapAttributeDetectionService.java | 40 +++ .../ldap/service/LdapConfigurationService.java | 60 ++++ .../service/LdapConnectionConfigService.java | 36 ++ .../ambari/server/ldap/service/LdapFacade.java | 58 ++++ .../DefaultLdapAttributeDetectionService.java | 200 +++++++++++ .../ads/DefaultLdapConfigurationService.java | 213 ++++++++++++ .../ads/DefaultLdapConnectionConfigService.java | 113 +++++++ .../ads/LdapConnectionTemplateFactory.java | 111 +++++++ .../ads/detectors/AttributeDetectorFactory.java | 75 +++++ .../ads/detectors/ChainedAttributeDetector.java | 73 +++++ .../ads/detectors/GroupMemberAttrDetector.java | 65 ++++ .../ads/detectors/GroupNameAttrDetector.java | 70 ++++ .../ads/detectors/GroupObjectClassDetector.java | 73 +++++ .../OccurrenceAndWeightBasedDetector.java | 143 ++++++++ .../detectors/UserGroupMemberAttrDetector.java | 64 ++++ .../ads/detectors/UserNameAttrDetector.java | 71 ++++ .../ads/detectors/UserObjectClassDetector.java | 69 ++++ .../server/orm/dao/AmbariConfigurationDAO.java | 89 +++++ .../apache/ambari/server/orm/dao/DaoUtils.java | 13 +- .../orm/entities/AmbariConfigurationEntity.java | 70 ++++ .../orm/entities/ConfigurationBaseEntity.java | 159 +++++++++ .../authorization/RoleAuthorization.java | 95 +++--- .../main/resources/Ambari-DDL-Derby-CREATE.sql | 21 ++ .../main/resources/Ambari-DDL-MySQL-CREATE.sql | 20 ++ .../main/resources/Ambari-DDL-Oracle-CREATE.sql | 20 ++ .../resources/Ambari-DDL-Postgres-CREATE.sql | 25 +- .../resources/Ambari-DDL-SQLAnywhere-CREATE.sql | 20 ++ .../resources/Ambari-DDL-SQLServer-CREATE.sql | 20 ++ .../src/main/resources/META-INF/persistence.xml | 2 + .../commands/StackAdvisorCommandTest.java | 212 ++++++++++++ .../server/checks/UpgradeCheckOrderTest.java | 3 +- ...AmbariConfigurationResourceProviderTest.java | 251 ++++++++++++++ .../StackAdvisorResourceProviderTest.java | 97 +++--- .../server/ldap/LdapModuleFunctionalTest.java | 149 +++++++++ .../TestAmbariLdapConfigurationFactory.java | 29 ++ .../ldap/service/AmbariLdapFacadeTest.java | 215 ++++++++++++ ...efaultLdapAttributeDetectionServiceTest.java | 188 +++++++++++ .../DefaultLdapConfigurationServiceTest.java | 221 +++++++++++++ .../detectors/GroupMemberAttrDetectorTest.java | 107 ++++++ .../notifications/DispatchFactoryTest.java | 3 +- .../server/orm/InMemoryDefaultTestModule.java | 2 + .../ambari/server/orm/JdbcPropertyTest.java | 5 +- ...uthenticationProviderForDNWithSpaceTest.java | 35 +- .../AmbariLdapAuthenticationProviderTest.java | 3 +- .../AmbariLocalUserProviderTest.java | 3 +- .../authorization/LdapServerPropertiesTest.java | 5 +- 78 files changed, 5409 insertions(+), 355 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/30415a18/ambari-funtest/pom.xml ---------------------------------------------------------------------- diff --git a/ambari-funtest/pom.xml b/ambari-funtest/pom.xml index bb2068d..6466af3 100644 --- a/ambari-funtest/pom.xml +++ b/ambari-funtest/pom.xml @@ -197,73 +197,6 @@ <artifactId>spring-ldap-core</artifactId> </dependency> <dependency> - <groupId>org.apache.directory.server</groupId> - <artifactId>apacheds-server-annotations</artifactId> - <scope>test</scope> - <exclusions> - <exclusion> - <groupId>net.sf.ehcache</groupId> - <artifactId>ehcache-core</artifactId> - </exclusion> - </exclusions> - </dependency> - <dependency> - <groupId>org.apache.directory.server</groupId> - <artifactId>apacheds-core-integ</artifactId> - <scope>test</scope> - <exclusions> - <exclusion> - <groupId>net.sf.ehcache</groupId> - <artifactId>ehcache-core</artifactId> - </exclusion> - </exclusions> - </dependency> - <dependency> - <groupId>org.apache.directory.server</groupId> - <artifactId>apacheds-server-integ</artifactId> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.apache.directory.server</groupId> - <artifactId>apacheds-jdbm</artifactId> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.apache.directory.server</groupId> - <artifactId>apacheds-kerberos-codec</artifactId> - <exclusions> - <exclusion> - <groupId>net.sf.ehcache</groupId> - <artifactId>ehcache-core</artifactId> - </exclusion> - </exclusions> - </dependency> - <dependency> - <groupId>org.apache.directory.server</groupId> - <artifactId>apacheds-core</artifactId> - <scope>test</scope> - <exclusions> - <exclusion> - <groupId>net.sf.ehcache</groupId> - <artifactId>ehcache-core</artifactId> - </exclusion> - </exclusions> - </dependency> - <dependency> - <groupId>org.apache.directory.server</groupId> - <artifactId>apacheds-protocol-ldap</artifactId> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.apache.directory.server</groupId> - <artifactId>kerberos-client</artifactId> - </dependency> - <dependency> - <groupId>org.apache.directory.shared</groupId> - <artifactId>shared-ldap</artifactId> - <scope>test</scope> - </dependency> - <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.20</version> http://git-wip-us.apache.org/repos/asf/ambari/blob/30415a18/ambari-project/pom.xml ---------------------------------------------------------------------- diff --git a/ambari-project/pom.xml b/ambari-project/pom.xml index 00ba1bc..f6e3bc7 100644 --- a/ambari-project/pom.xml +++ b/ambari-project/pom.xml @@ -31,6 +31,7 @@ <ambari.dir>${project.parent.basedir}</ambari.dir> <powermock.version>1.6.3</powermock.version> <jetty.version>8.1.19.v20160209</jetty.version> + <ldap-api.version>1.0.0</ldap-api.version> <checkstyle.version>6.19</checkstyle.version> <!-- last version that does not require Java 8 --> <swagger.version>1.5.10</swagger.version> <swagger.maven.plugin.version>3.1.4</swagger.maven.plugin.version> @@ -161,57 +162,6 @@ <version>2.0.4.RELEASE</version> </dependency> <dependency> - <groupId>org.apache.directory.server</groupId> - <artifactId>apacheds-server-annotations</artifactId> - <version>2.0.0-M19</version> - </dependency> - <dependency> - <groupId>org.apache.directory.server</groupId> - <artifactId>apacheds-core-integ</artifactId> - <version>2.0.0-M19</version> - </dependency> - <dependency> - <groupId>org.apache.directory.server</groupId> - <artifactId>apacheds-server-integ</artifactId> - <version>2.0.0-M19</version> - </dependency> - <dependency> - <groupId>org.apache.directory.server</groupId> - <artifactId>apacheds-jdbm</artifactId> - <version>2.0.0-M5</version> - </dependency> - <dependency> - <groupId>org.apache.directory.server</groupId> - <artifactId>apacheds-kerberos-codec</artifactId> - <version>2.0.0-M19</version> - </dependency> - <dependency> - <groupId>org.apache.directory.server</groupId> - <artifactId>apacheds-core</artifactId> - <version>2.0.0-M19</version> - </dependency> - <dependency> - <groupId>org.apache.directory.server</groupId> - <artifactId>kerberos-client</artifactId> - <version>2.0.0-M19</version> - </dependency> - <dependency> - <groupId>org.apache.directory.server</groupId> - <artifactId>apacheds-protocol-ldap</artifactId> - <version>2.0.0-M19</version> - <exclusions> - <exclusion> - <groupId>org.apache.directory.jdbm</groupId> - <artifactId>apacheds-jdbm1</artifactId> - </exclusion> - </exclusions> - </dependency> - <dependency> - <groupId>org.apache.directory.shared</groupId> - <artifactId>shared-ldap</artifactId> - <version>0.9.17</version> - </dependency> - <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>${slf4j.version}</version> http://git-wip-us.apache.org/repos/asf/ambari/blob/30415a18/ambari-server/pom.xml ---------------------------------------------------------------------- diff --git a/ambari-server/pom.xml b/ambari-server/pom.xml index e250da7..a86acf5 100644 --- a/ambari-server/pom.xml +++ b/ambari-server/pom.xml @@ -1225,73 +1225,6 @@ <artifactId>spring-ldap-core</artifactId> </dependency> <dependency> - <groupId>org.apache.directory.server</groupId> - <artifactId>apacheds-server-annotations</artifactId> - <scope>test</scope> - <exclusions> - <exclusion> - <groupId>net.sf.ehcache</groupId> - <artifactId>ehcache-core</artifactId> - </exclusion> - </exclusions> - </dependency> - <dependency> - <groupId>org.apache.directory.server</groupId> - <artifactId>apacheds-core-integ</artifactId> - <scope>test</scope> - <exclusions> - <exclusion> - <groupId>net.sf.ehcache</groupId> - <artifactId>ehcache-core</artifactId> - </exclusion> - </exclusions> - </dependency> - <dependency> - <groupId>org.apache.directory.server</groupId> - <artifactId>apacheds-server-integ</artifactId> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.apache.directory.server</groupId> - <artifactId>apacheds-jdbm</artifactId> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.apache.directory.server</groupId> - <artifactId>apacheds-kerberos-codec</artifactId> - <exclusions> - <exclusion> - <groupId>net.sf.ehcache</groupId> - <artifactId>ehcache-core</artifactId> - </exclusion> - </exclusions> - </dependency> - <dependency> - <groupId>org.apache.directory.server</groupId> - <artifactId>apacheds-core</artifactId> - <scope>test</scope> - <exclusions> - <exclusion> - <groupId>net.sf.ehcache</groupId> - <artifactId>ehcache-core</artifactId> - </exclusion> - </exclusions> - </dependency> - <dependency> - <groupId>org.apache.directory.server</groupId> - <artifactId>apacheds-protocol-ldap</artifactId> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.apache.directory.server</groupId> - <artifactId>kerberos-client</artifactId> - </dependency> - <dependency> - <groupId>org.apache.directory.shared</groupId> - <artifactId>shared-ldap</artifactId> - <scope>test</scope> - </dependency> - <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> </dependency> @@ -1622,6 +1555,12 @@ <groupId>org.apache.hadoop</groupId> <artifactId>hadoop-auth</artifactId> <version>${hadoop.version}</version> + <exclusions> + <exclusion> + <groupId>org.apache.directory.server</groupId> + <artifactId>apacheds-kerberos-codec</artifactId> + </exclusion> + </exclusions> </dependency> <dependency> <groupId>org.apache.hadoop</groupId> @@ -1689,6 +1628,16 @@ <version>4.2.2</version> </dependency> <dependency> + <groupId>org.apache.directory.server</groupId> + <artifactId>apacheds-all</artifactId> + <version>2.0.0-M24</version> + </dependency> + <dependency> + <groupId>org.apache.directory.server</groupId> + <artifactId>kerberos-client</artifactId> + <version>2.0.0-M24</version> + </dependency> + <dependency> <groupId>com.networknt</groupId> <artifactId>json-schema-validator</artifactId> <version>0.1.10</version> http://git-wip-us.apache.org/repos/asf/ambari/blob/30415a18/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java index d0d115d..f5fb6e9 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java @@ -471,6 +471,10 @@ public class ResourceInstanceFactoryImpl implements ResourceInstanceFactory { case RemoteCluster: resourceDefinition = new RemoteClusterResourceDefinition(); break; + case AmbariConfiguration: + resourceDefinition = new SimpleResourceDefinition(Resource.Type.AmbariConfiguration, "ambariconfiguration", "ambariconfigurations"); + + break; default: throw new IllegalArgumentException("Unsupported resource type: " + type); http://git-wip-us.apache.org/repos/asf/ambari/blob/30415a18/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariConfigurationRequestSwagger.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariConfigurationRequestSwagger.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariConfigurationRequestSwagger.java new file mode 100644 index 0000000..5e8094e --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariConfigurationRequestSwagger.java @@ -0,0 +1,47 @@ +/* + * Licensed 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.ambari.server.api.services; + +import java.util.Map; + +import org.apache.ambari.server.controller.ApiModel; + +import io.swagger.annotations.ApiModelProperty; + +/** + * Request data model for {@link org.apache.ambari.server.api.services.AmbariConfigurationService} + */ +public interface AmbariConfigurationRequestSwagger extends ApiModel { + + @ApiModelProperty(name = "AmbariConfiguration") + AmbariConfigurationRequestInfo getAmbariConfiguration(); + + interface AmbariConfigurationRequestInfo { + @ApiModelProperty + Long getId(); + + @ApiModelProperty + Map<String, Object> getData(); + + @ApiModelProperty + String getType(); + + @ApiModelProperty + Long getVersion(); + + @ApiModelProperty(name = "version_tag") + String getVersionTag(); + } + +} http://git-wip-us.apache.org/repos/asf/ambari/blob/30415a18/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariConfigurationResponseSwagger.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariConfigurationResponseSwagger.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariConfigurationResponseSwagger.java new file mode 100644 index 0000000..c55ac1d --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariConfigurationResponseSwagger.java @@ -0,0 +1,40 @@ +/* + * Licensed 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.ambari.server.api.services; + +import java.util.Map; + +import org.apache.ambari.server.controller.ApiModel; + +import io.swagger.annotations.ApiModelProperty; + +/** + * Response data model for {@link org.apache.ambari.server.api.services.AmbariConfigurationService} + */ +public interface AmbariConfigurationResponseSwagger extends ApiModel { + + @ApiModelProperty(name = "AmbariConfiguration") + AmbariConfigurationResponseInfo getAmbariConfigurationResponse(); + + interface AmbariConfigurationResponseInfo { + @ApiModelProperty + Long getId(); + + @ApiModelProperty + Map<String, Object> getData(); + + @ApiModelProperty + String getType(); + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/30415a18/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariConfigurationService.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariConfigurationService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariConfigurationService.java new file mode 100644 index 0000000..38ae766 --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariConfigurationService.java @@ -0,0 +1,193 @@ +/* + * Licensed 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.ambari.server.api.services; + +import java.util.Collections; + +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; + +import org.apache.ambari.server.controller.spi.Resource; +import org.apache.http.HttpStatus; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiImplicitParams; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; + +/** + * Rest endpoint for managing ambari configurations. Supports CRUD operations. + * Ambari configurations are resources that relate to the ambari server instance even before a cluster is provisioned. + * + * Ambari configuration resources may be shared with components and services in the cluster + * (by recommending them as default values) + * + * Eg. LDAP configuration is stored as ambariconfiguration. + * The request payload has the form: + * + * <pre> + * { + * "AmbariConfiguration": { + * "type": "ldap-configuration", + * "data": [ + * { + * "authentication.ldap.primaryUrl": "localhost:33389" + * "authentication.ldap.secondaryUrl": "localhost:333" + * "authentication.ldap.baseDn": "dc=ambari,dc=apache,dc=org" + * // ...... + * ] + * } + * </pre> + */ +@Path("/ambariconfigs/") +@Api(value = "Ambari Configurations", description = "Endpoint for Ambari configuration related operations") +public class AmbariConfigurationService extends BaseService { + + private static final String AMBARI_CONFIGURATION_REQUEST_TYPE = + "org.apache.ambari.server.api.services.AmbariConfigurationRequestSwagger"; + + /** + * Creates an ambari configuration resource. + * + * @param body the payload in json format + * @param headers http headers + * @param uri request uri information + * @return + */ + @POST + @Produces(MediaType.TEXT_PLAIN) + @ApiOperation(value = "Creates an ambari configuration resource", + nickname = "AmbariConfigurationService#createAmbariConfiguration") + @ApiImplicitParams({ + @ApiImplicitParam(dataType = AMBARI_CONFIGURATION_REQUEST_TYPE, paramType = PARAM_TYPE_BODY) + }) + @ApiResponses({ + @ApiResponse(code = HttpStatus.SC_CREATED, message = MSG_SUCCESSFUL_OPERATION), + @ApiResponse(code = HttpStatus.SC_ACCEPTED, message = MSG_REQUEST_ACCEPTED), + @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = MSG_INVALID_ARGUMENTS), + @ApiResponse(code = HttpStatus.SC_CONFLICT, message = MSG_RESOURCE_ALREADY_EXISTS), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = MSG_NOT_AUTHENTICATED), + @ApiResponse(code = HttpStatus.SC_FORBIDDEN, message = MSG_PERMISSION_DENIED), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = MSG_SERVER_ERROR), + }) + public Response createAmbariConfiguration(String body, @Context HttpHeaders headers, @Context UriInfo uri) { + return handleRequest(headers, body, uri, Request.Type.POST, createResource(Resource.Type.AmbariConfiguration, + Collections.EMPTY_MAP)); + } + + @GET + @Produces(MediaType.TEXT_PLAIN) + @ApiOperation(value = "Retrieve all ambari configuration resources", + nickname = "AmbariConfigurationService#getAmbariConfigurations", + notes = "Returns all Ambari configurations.", + response = AmbariConfigurationResponseSwagger.class, + responseContainer = RESPONSE_CONTAINER_LIST) + @ApiImplicitParams({ + @ApiImplicitParam(name = QUERY_FIELDS, value = QUERY_FILTER_DESCRIPTION, + defaultValue = "AmbariConfiguration/data, AmbariConfiguration/id, AmbariConfiguration/type", + dataType = DATA_TYPE_STRING, paramType = PARAM_TYPE_QUERY), + @ApiImplicitParam(name = QUERY_SORT, value = QUERY_SORT_DESCRIPTION, + defaultValue = "AmbariConfiguration/id", + dataType = DATA_TYPE_STRING, paramType = PARAM_TYPE_QUERY), + @ApiImplicitParam(name = QUERY_PAGE_SIZE, value = QUERY_PAGE_SIZE_DESCRIPTION, defaultValue = DEFAULT_PAGE_SIZE, dataType = DATA_TYPE_INT, paramType = PARAM_TYPE_QUERY), + @ApiImplicitParam(name = QUERY_FROM, value = QUERY_FROM_DESCRIPTION, defaultValue = DEFAULT_FROM, dataType = DATA_TYPE_STRING, paramType = PARAM_TYPE_QUERY), + @ApiImplicitParam(name = QUERY_TO, value = QUERY_TO_DESCRIPTION, dataType = DATA_TYPE_STRING, paramType = PARAM_TYPE_QUERY) + }) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.SC_OK, message = MSG_SUCCESSFUL_OPERATION), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = MSG_SERVER_ERROR) + }) + public Response getAmbariConfigurations(String body, @Context HttpHeaders headers, @Context UriInfo uri) { + return handleRequest(headers, body, uri, Request.Type.GET, createResource(Resource.Type.AmbariConfiguration, + Collections.EMPTY_MAP)); + } + + @GET + @Path("{configurationId}") + @Produces(MediaType.TEXT_PLAIN) + @ApiOperation(value = "Retrieve the details of an ambari configuration resource", + nickname = "AmbariConfigurationService#getAmbariConfiguration", + response = AmbariConfigurationResponseSwagger.class) + @ApiImplicitParams({ + @ApiImplicitParam(name = QUERY_FIELDS, value = QUERY_FILTER_DESCRIPTION, defaultValue = "AmbariConfiguration/*", + dataType = DATA_TYPE_STRING, paramType = PARAM_TYPE_QUERY) + }) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.SC_OK, message = MSG_SUCCESSFUL_OPERATION), + @ApiResponse(code = HttpStatus.SC_NOT_FOUND, message = MSG_RESOURCE_NOT_FOUND), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = MSG_SERVER_ERROR) + }) + public Response getAmbariConfiguration(String body, @Context HttpHeaders headers, @Context UriInfo uri, + @PathParam("configurationId") String configurationId) { + return handleRequest(headers, body, uri, Request.Type.GET, createResource(Resource.Type.AmbariConfiguration, + Collections.singletonMap(Resource.Type.AmbariConfiguration, configurationId))); + } + + @PUT + @Path("{configurationId}") + @Produces(MediaType.TEXT_PLAIN) + @ApiOperation(value = "Updates ambari configuration resources ", + nickname = "AmbariConfigurationService#updateAmbariConfiguration") + @ApiImplicitParams({ + @ApiImplicitParam(dataType = AMBARI_CONFIGURATION_REQUEST_TYPE, paramType = PARAM_TYPE_BODY), + @ApiImplicitParam(name = QUERY_FIELDS, value = QUERY_FILTER_DESCRIPTION, defaultValue = "AmbariConfiguration/*", + dataType = DATA_TYPE_STRING, paramType = PARAM_TYPE_QUERY) + }) + @ApiResponses({ + @ApiResponse(code = HttpStatus.SC_OK, message = MSG_SUCCESSFUL_OPERATION), + @ApiResponse(code = HttpStatus.SC_ACCEPTED, message = MSG_REQUEST_ACCEPTED), + @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = MSG_INVALID_ARGUMENTS), + @ApiResponse(code = HttpStatus.SC_NOT_FOUND, message = MSG_RESOURCE_NOT_FOUND), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = MSG_NOT_AUTHENTICATED), + @ApiResponse(code = HttpStatus.SC_FORBIDDEN, message = MSG_PERMISSION_DENIED), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = MSG_SERVER_ERROR), + }) + public Response updateAmbariConfiguration(String body, @Context HttpHeaders headers, @Context UriInfo uri, + @PathParam("configurationId") String configurationId) { + return handleRequest(headers, body, uri, Request.Type.PUT, createResource(Resource.Type.AmbariConfiguration, + Collections.singletonMap(Resource.Type.AmbariConfiguration, configurationId))); + } + + @DELETE + @Path("{configurationId}") + @Produces(MediaType.TEXT_PLAIN) + @ApiOperation(value = "Deletes an ambari configuration resource", + nickname = "AmbariConfigurationService#deleteAmbariConfiguration") + @ApiResponses({ + @ApiResponse(code = HttpStatus.SC_OK, message = MSG_SUCCESSFUL_OPERATION), + @ApiResponse(code = HttpStatus.SC_NOT_FOUND, message = MSG_RESOURCE_NOT_FOUND), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = MSG_NOT_AUTHENTICATED), + @ApiResponse(code = HttpStatus.SC_FORBIDDEN, message = MSG_PERMISSION_DENIED), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = MSG_SERVER_ERROR), + }) + public Response deleteAmbariConfiguration(String body, @Context HttpHeaders headers, @Context UriInfo uri, + @PathParam("configurationId") String configurationId) { + return handleRequest(headers, body, uri, Request.Type.DELETE, createResource(Resource.Type.AmbariConfiguration, + Collections.singletonMap(Resource.Type.AmbariConfiguration, configurationId))); + } + +} http://git-wip-us.apache.org/repos/asf/ambari/blob/30415a18/ambari-server/src/main/java/org/apache/ambari/server/api/services/ldap/AmbariConfiguration.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ldap/AmbariConfiguration.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ldap/AmbariConfiguration.java new file mode 100644 index 0000000..b5cc921 --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ldap/AmbariConfiguration.java @@ -0,0 +1,87 @@ +/* + * Licensed 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.ambari.server.api.services.ldap; + +import java.util.Collections; +import java.util.Map; +import java.util.Set; + +/** + * Domain POJO representing generic ambari configuration data. + */ +public class AmbariConfiguration { + + /** + * The type of the configuration, eg.: ldap-configuration + */ + private String type; + + /** + * Version tag + */ + private String versionTag; + + /** + * Version number + */ + private Integer version; + + /** + * Created timestamp + */ + private long createdTs; + + private Set<Map<String, Object>> data = Collections.emptySet(); + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public Set<Map<String, Object>> getData() { + return data; + } + + public void setData(Set<Map<String, Object>> data) { + this.data = data; + } + + public String getVersionTag() { + return versionTag; + } + + public void setVersionTag(String versionTag) { + this.versionTag = versionTag; + } + + public Integer getVersion() { + return version; + } + + public void setVersion(Integer version) { + this.version = version; + } + + public long getCreatedTs() { + return createdTs; + } + + public void setCreatedTs(long createdTs) { + this.createdTs = createdTs; + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/30415a18/ambari-server/src/main/java/org/apache/ambari/server/api/services/ldap/LdapConfigOperation.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ldap/LdapConfigOperation.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ldap/LdapConfigOperation.java new file mode 100644 index 0000000..478d4ff --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ldap/LdapConfigOperation.java @@ -0,0 +1,43 @@ +/* + * Licensed 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.ambari.server.api.services.ldap; + +/** + * Enumeration for supported operations related to LDAP configuration. + */ +public enum LdapConfigOperation { + TEST_CONNECTION("test-connection"), + TEST_ATTRIBUTES("test-attributes"), + DETECT_ATTRIBUTES("detect-attributes"); + + private String actionStr; + + LdapConfigOperation(String actionStr) { + this.actionStr = actionStr; + } + + public static LdapConfigOperation fromAction(String action) { + for (LdapConfigOperation val : LdapConfigOperation.values()) { + if (val.action().equals(action)) { + return val; + } + } + throw new IllegalStateException("Action [ " + action + " ] is not supported"); + } + + public String action() { + return this.actionStr; + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/30415a18/ambari-server/src/main/java/org/apache/ambari/server/api/services/ldap/LdapConfigurationRequest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ldap/LdapConfigurationRequest.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ldap/LdapConfigurationRequest.java new file mode 100644 index 0000000..2e478c4 --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ldap/LdapConfigurationRequest.java @@ -0,0 +1,49 @@ +/* + * Licensed 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.ambari.server.api.services.ldap; + + +import com.google.gson.annotations.SerializedName; + +/** + * Request object wrapping information for LDAP configuration related request calls. + */ +public class LdapConfigurationRequest { + + @SerializedName("AmbariConfiguration") + private AmbariConfiguration ambariConfiguration; + + @SerializedName("RequestInfo") + private LdapRequestInfo requestInfo; + + public LdapConfigurationRequest() { + } + + public AmbariConfiguration getAmbariConfiguration() { + return ambariConfiguration; + } + + public void setAmbariConfiguration(AmbariConfiguration ambariConfiguration) { + this.ambariConfiguration = ambariConfiguration; + } + + public LdapRequestInfo getRequestInfo() { + return requestInfo; + } + + public void setRequestInfo(LdapRequestInfo requestInfo) { + this.requestInfo = requestInfo; + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/30415a18/ambari-server/src/main/java/org/apache/ambari/server/api/services/ldap/LdapConfigurationService.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ldap/LdapConfigurationService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ldap/LdapConfigurationService.java new file mode 100644 index 0000000..13f8835 --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ldap/LdapConfigurationService.java @@ -0,0 +1,185 @@ +/* + * Licensed 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. + */ + +/* + * Licensed 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.ambari.server.api.services.ldap; + +import java.util.Set; + +import javax.inject.Inject; +import javax.ws.rs.Consumes; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.apache.ambari.annotations.ApiIgnore; +import org.apache.ambari.server.StaticallyInject; +import org.apache.ambari.server.api.services.AmbariConfigurationService; +import org.apache.ambari.server.api.services.Result; +import org.apache.ambari.server.api.services.ResultImpl; +import org.apache.ambari.server.api.services.ResultStatus; +import org.apache.ambari.server.controller.internal.ResourceImpl; +import org.apache.ambari.server.controller.spi.Resource; +import org.apache.ambari.server.ldap.domain.AmbariLdapConfiguration; +import org.apache.ambari.server.ldap.domain.AmbariLdapConfigurationFactory; +import org.apache.ambari.server.ldap.service.LdapFacade; +import org.apache.ambari.server.security.authorization.AuthorizationException; +import org.apache.ambari.server.security.authorization.AuthorizationHelper; +import org.apache.ambari.server.security.authorization.ResourceType; +import org.apache.ambari.server.security.authorization.RoleAuthorization; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.security.core.Authentication; + +import com.google.common.collect.Sets; + +/** + * Endpoint designated to LDAP specific operations. + */ +@StaticallyInject +@Path("/ldapconfigs/") +public class LdapConfigurationService extends AmbariConfigurationService { + + private static final Logger LOGGER = LoggerFactory.getLogger(LdapConfigurationService.class); + + @Inject + private static LdapFacade ldapFacade; + + @Inject + private static AmbariLdapConfigurationFactory ambariLdapConfigurationFactory; + + + @POST + @ApiIgnore // until documented + @Path("/validate") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Response validateConfiguration(LdapConfigurationRequest ldapConfigurationRequest) { + + // check if the user is authorized to perform the operation + authorize(); + + Set<String> groups = Sets.newHashSet(); + Object responseEntity = null; + + Result result = new ResultImpl(new ResultStatus(ResultStatus.STATUS.OK)); + try { + + validateRequest(ldapConfigurationRequest); + + AmbariLdapConfiguration ambariLdapConfiguration = ambariLdapConfigurationFactory.createLdapConfiguration( + ldapConfigurationRequest.getAmbariConfiguration().getData().iterator().next()); + + LdapConfigOperation action = LdapConfigOperation.fromAction(ldapConfigurationRequest.getRequestInfo().getAction()); + switch (action) { + + case TEST_CONNECTION: + + LOGGER.info("Testing connection to the LDAP server ..."); + ldapFacade.checkConnection(ambariLdapConfiguration); + + break; + case TEST_ATTRIBUTES: + + LOGGER.info("Testing LDAP attributes ...."); + groups = ldapFacade.checkLdapAttributes(ldapConfigurationRequest.getRequestInfo().getParameters(), ambariLdapConfiguration); + responseEntity = groups; + + break; + case DETECT_ATTRIBUTES: + + LOGGER.info("Detecting LDAP attributes ..."); + ambariLdapConfiguration = ldapFacade.detectAttributes(ambariLdapConfiguration); + responseEntity = ambariLdapConfiguration; + + break; + default: + LOGGER.warn("No action provided ..."); + throw new IllegalArgumentException("No request action provided"); + } + + } catch (Exception e) { + result.setResultStatus(new ResultStatus(ResultStatus.STATUS.SERVER_ERROR, e)); + responseEntity = e.getMessage(); + } + + return Response.status(result.getStatus().getStatusCode()).entity(responseEntity).build(); + } + + private void setResult(Set<String> groups, Result result) { + Resource resource = new ResourceImpl(Resource.Type.AmbariConfiguration); + resource.setProperty("groups", groups); + result.getResultTree().addChild(resource, "payload"); + } + + private void validateRequest(LdapConfigurationRequest ldapConfigurationRequest) { + String errMsg; + + if (null == ldapConfigurationRequest) { + errMsg = "No ldap configuraiton request provided"; + LOGGER.error(errMsg); + throw new IllegalArgumentException(errMsg); + } + + if (null == ldapConfigurationRequest.getRequestInfo()) { + errMsg = String.format("No request information provided. Request: [%s]", ldapConfigurationRequest); + LOGGER.error(errMsg); + throw new IllegalArgumentException(errMsg); + } + + if (null == ldapConfigurationRequest.getAmbariConfiguration() + || ldapConfigurationRequest.getAmbariConfiguration().getData().size() != 1) { + errMsg = String.format("No / Invalid configuration data provided. Request: [%s]", ldapConfigurationRequest); + LOGGER.error(errMsg); + throw new IllegalArgumentException(errMsg); + } + } + + private void authorize() { + try { + Authentication authentication = AuthorizationHelper.getAuthentication(); + + if (authentication == null || !authentication.isAuthenticated()) { + throw new AuthorizationException("Authentication data is not available, authorization to perform the requested operation is not granted"); + } + + if (!AuthorizationHelper.isAuthorized(authentication, ResourceType.AMBARI, null, requiredAuthorizations())) { + throw new AuthorizationException("The authenticated user does not have the appropriate authorizations to create the requested resource(s)"); + } + } catch (AuthorizationException e) { + LOGGER.error("Unauthorized operation.", e); + throw new IllegalArgumentException("User is not authorized to perform the operation", e); + } + + } + + private Set<RoleAuthorization> requiredAuthorizations() { + return Sets.newHashSet(RoleAuthorization.AMBARI_MANAGE_CONFIGURATION); + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/30415a18/ambari-server/src/main/java/org/apache/ambari/server/api/services/ldap/LdapRequestInfo.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ldap/LdapRequestInfo.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ldap/LdapRequestInfo.java new file mode 100644 index 0000000..eeecfee --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ldap/LdapRequestInfo.java @@ -0,0 +1,61 @@ +/* + * Licensed 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.ambari.server.api.services.ldap; + +import java.util.Map; + +import org.apache.ambari.server.controller.RequestPostRequest; + +/** + * Bean holding LDAP request specific request information. + */ +public class LdapRequestInfo implements RequestPostRequest.RequestInfo { + + // no-arg costructor facilitating JSON serialization + public LdapRequestInfo() { + } + + private String action; + + private Map<String, Object> parameters; + + @Override + public String getAction() { + return action; + } + + public void setAction(String action) { + this.action = action; + } + + public void setParameters(Map<String, Object> parameters) { + this.parameters = parameters; + } + + @Override + public String getCommand() { + return null; + } + + @Override + public RequestPostRequest.OperationLevel getOperationLevel() { + return null; + } + + @Override + public Map<String, Object> getParameters() { + return parameters; + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/30415a18/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorRequest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorRequest.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorRequest.java index 3a2b488..cd26c56 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorRequest.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorRequest.java @@ -31,6 +31,8 @@ import org.apache.ambari.server.api.services.stackadvisor.recommendations.Recomm import org.apache.ambari.server.state.ChangedConfigInfo; import org.apache.commons.lang.StringUtils; +import com.google.common.base.Preconditions; + /** * Stack advisor request. */ @@ -48,6 +50,7 @@ public class StackAdvisorRequest { private List<ChangedConfigInfo> changedConfigurations = new LinkedList<>(); private Set<RecommendationResponse.ConfigGroup> configGroups; private Map<String, String> userContext = new HashMap<>(); + private Map<String, Object> ldapConfig = new HashMap<>(); public String getStackName() { return stackName; @@ -93,6 +96,8 @@ public class StackAdvisorRequest { return configurations; } + public Map<String, Object> getLdapConfig() { return ldapConfig; } + public List<ChangedConfigInfo> getChangedConfigurations() { return changedConfigurations; } @@ -189,6 +194,13 @@ public class StackAdvisorRequest { return this; } + public StackAdvisorRequestBuilder withLdapConfig(Map<String, Object> ldapConfig) { + Preconditions.checkNotNull(ldapConfig); + this.instance.ldapConfig = ldapConfig; + return this; + } + + public StackAdvisorRequest build() { return this.instance; } http://git-wip-us.apache.org/repos/asf/ambari/blob/30415a18/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/StackAdvisorCommand.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/StackAdvisorCommand.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/StackAdvisorCommand.java index 356754d..2dc45de 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/StackAdvisorCommand.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/StackAdvisorCommand.java @@ -84,6 +84,7 @@ public abstract class StackAdvisorCommand<T extends StackAdvisorResponse> extend + ",services/configurations/dependencies/StackConfigurationDependency/dependency_name" + ",services/configurations/dependencies/StackConfigurationDependency/dependency_type,services/configurations/StackConfigurations/type" + "&services/StackServices/service_name.in(%s)"; + private static final String GET_LDAP_CONFIG_URI = "/api/v1/configurations?AmbariConfiguration/type=ldap&fields=AmbariConfiguration/*"; private static final String SERVICES_PROPERTY = "services"; private static final String SERVICES_COMPONENTS_PROPERTY = "components"; private static final String CONFIG_GROUPS_PROPERTY = "config-groups"; @@ -95,6 +96,7 @@ public abstract class StackAdvisorCommand<T extends StackAdvisorResponse> extend private static final String CHANGED_CONFIGURATIONS_PROPERTY = "changed-configurations"; private static final String USER_CONTEXT_PROPERTY = "user-context"; private static final String AMBARI_SERVER_CONFIGURATIONS_PROPERTY = "ambari-server-properties"; + protected static final String LDAP_CONFIGURATION_PROPERTY = "ldap-configuration"; private File recommendationsDir; private String recommendationsArtifactsLifetime; @@ -160,6 +162,7 @@ public abstract class StackAdvisorCommand<T extends StackAdvisorResponse> extend populateConfigurations(root, request); populateConfigGroups(root, request); populateAmbariServerInfo(root); + populateLdapConfiguration(root); data.servicesJSON = mapper.writeValueAsString(root); } catch (Exception e) { // should not happen @@ -171,6 +174,52 @@ public abstract class StackAdvisorCommand<T extends StackAdvisorResponse> extend return data; } + /** + * Retrieves the LDAP configuration if exists and adds it to services.json + * @param root The JSON document that will become service.json when passed to the stack advisor engine + * @throws StackAdvisorException + * @throws IOException + */ + protected void populateLdapConfiguration(ObjectNode root) throws StackAdvisorException, IOException { + Response response = handleRequest(null, null, new LocalUriInfo(GET_LDAP_CONFIG_URI), Request.Type.GET, + createConfigResource()); + + if (response.getStatus() != Status.OK.getStatusCode()) { + String message = String.format( + "Error occured during retrieving ldap configuration, status=%s, response=%s", + response.getStatus(), (String) response.getEntity()); + LOG.warn(message); + throw new StackAdvisorException(message); + } + + String ldapConfigJSON = (String) response.getEntity(); + if (LOG.isDebugEnabled()) { + LOG.debug("LDAP configuration: {}", ldapConfigJSON); + } + + JsonNode ldapConfigRoot = mapper.readTree(ldapConfigJSON); + ArrayNode ldapConfigs = ((ArrayNode)ldapConfigRoot.get("items")); + int numConfigs = ldapConfigs.size(); + // Zero or one config may exist + switch (numConfigs) { + case 0: + LOG.debug("No LDAP config is stored in the DB"); + break; + case 1: + ArrayNode ldapConfigData = (ArrayNode)ldapConfigs.get(0).get("AmbariConfiguration").get("data"); + if (ldapConfigData.size() == 0) { + throw new StackAdvisorException("No configuration data for LDAP configuration."); + } + if (ldapConfigData.size() > 1) { + throw new StackAdvisorException("Ambigous configuration data for LDAP configuration."); + } + root.put(LDAP_CONFIGURATION_PROPERTY, ldapConfigData.get(0)); + break; + default: + throw new StackAdvisorException(String.format("Multiple (%s) LDAP configs are found in the DB.", numConfigs)); + } + } + protected void populateAmbariServerInfo(ObjectNode root) throws StackAdvisorException { Map<String, String> serverProperties = metaInfo.getAmbariServerProperties(); @@ -437,6 +486,11 @@ public abstract class StackAdvisorCommand<T extends StackAdvisorResponse> extend return createResource(Resource.Type.Host, mapIds); } + protected ResourceInstance createConfigResource() { + return createResource(Resource.Type.AmbariConfiguration, new HashMap<>()); + } + + private ResourceInstance createStackVersionResource(String stackName, String stackVersion) { Map<Resource.Type, String> mapIds = new HashMap<>(); mapIds.put(Resource.Type.Stack, stackName); http://git-wip-us.apache.org/repos/asf/ambari/blob/30415a18/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java index 8988be0..6ceed4a 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java @@ -77,6 +77,7 @@ import org.apache.ambari.server.controller.internal.ViewPermissionResourceProvid import org.apache.ambari.server.controller.metrics.ThreadPoolEnabledPropertyProvider; import org.apache.ambari.server.controller.utilities.KerberosChecker; import org.apache.ambari.server.controller.utilities.KerberosIdentityCleaner; +import org.apache.ambari.server.ldap.LdapModule; import org.apache.ambari.server.metrics.system.MetricsService; import org.apache.ambari.server.orm.GuiceJpaInitializer; import org.apache.ambari.server.orm.PersistenceType; @@ -1061,7 +1062,7 @@ public class AmbariServer { public static void main(String[] args) throws Exception { logStartup(); - Injector injector = Guice.createInjector(new ControllerModule(), new AuditLoggerModule()); + Injector injector = Guice.createInjector(new ControllerModule(), new AuditLoggerModule(), new LdapModule()); AmbariServer server = null; try { http://git-wip-us.apache.org/repos/asf/ambari/blob/30415a18/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java index dc97871..1425e1b 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java @@ -63,6 +63,7 @@ import org.apache.ambari.server.configuration.Configuration; import org.apache.ambari.server.configuration.Configuration.ConnectionPoolType; import org.apache.ambari.server.configuration.Configuration.DatabaseType; import org.apache.ambari.server.controller.internal.AlertTargetResourceProvider; +import org.apache.ambari.server.controller.internal.AmbariConfigurationResourceProvider; import org.apache.ambari.server.controller.internal.ClusterStackVersionResourceProvider; import org.apache.ambari.server.controller.internal.ComponentResourceProvider; import org.apache.ambari.server.controller.internal.CredentialResourceProvider; @@ -470,6 +471,7 @@ public class ControllerModule extends AbstractModule { .implement(ResourceProvider.class, Names.named("credential"), CredentialResourceProvider.class) .implement(ResourceProvider.class, Names.named("kerberosDescriptor"), KerberosDescriptorResourceProvider.class) .implement(ResourceProvider.class, Names.named("upgrade"), UpgradeResourceProvider.class) + .implement(ResourceProvider.class, Names.named("ambariConfiguration"), AmbariConfigurationResourceProvider.class) .implement(ResourceProvider.class, Names.named("clusterStackVersion"), ClusterStackVersionResourceProvider.class) .implement(ResourceProvider.class, Names.named("alertTarget"), AlertTargetResourceProvider.class) .implement(ResourceProvider.class, Names.named("viewInstance"), ViewInstanceResourceProvider.class) @@ -508,6 +510,7 @@ public class ControllerModule extends AbstractModule { install(new FactoryModuleBuilder().implement(CollectionPersisterService.class, CsvFilePersisterService.class).build(CollectionPersisterServiceFactory.class)); install(new FactoryModuleBuilder().build(ConfigureClusterTaskFactory.class)); + } /** http://git-wip-us.apache.org/repos/asf/ambari/blob/30415a18/ambari-server/src/main/java/org/apache/ambari/server/controller/ResourceProviderFactory.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/ResourceProviderFactory.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/ResourceProviderFactory.java index a198775..711ae10 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/ResourceProviderFactory.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/ResourceProviderFactory.java @@ -22,6 +22,8 @@ package org.apache.ambari.server.controller; import java.util.Map; import java.util.Set; +import javax.inject.Named; + import org.apache.ambari.server.controller.internal.AlertTargetResourceProvider; import org.apache.ambari.server.controller.internal.ClusterStackVersionResourceProvider; import org.apache.ambari.server.controller.internal.UpgradeResourceProvider; @@ -30,18 +32,15 @@ import org.apache.ambari.server.controller.spi.Resource; import org.apache.ambari.server.controller.spi.Resource.Type; import org.apache.ambari.server.controller.spi.ResourceProvider; -import com.google.inject.name.Named; public interface ResourceProviderFactory { @Named("host") - ResourceProvider getHostResourceProvider(Set<String> propertyIds, - Map<Type, String> keyPropertyIds, - AmbariManagementController managementController); + ResourceProvider getHostResourceProvider(Set<String> propertyIds, Map<Type, String> keyPropertyIds, + AmbariManagementController managementController); @Named("hostComponent") - ResourceProvider getHostComponentResourceProvider(Set<String> propertyIds, - Map<Type, String> keyPropertyIds, - AmbariManagementController managementController); + ResourceProvider getHostComponentResourceProvider(Set<String> propertyIds, Map<Type, String> keyPropertyIds, + AmbariManagementController managementController); @Named("service") ResourceProvider getServiceResourceProvider(AmbariManagementController managementController); @@ -50,9 +49,8 @@ public interface ResourceProviderFactory { ResourceProvider getComponentResourceProvider(AmbariManagementController managementController); @Named("member") - ResourceProvider getMemberResourceProvider(Set<String> propertyIds, - Map<Type, String> keyPropertyIds, - AmbariManagementController managementController); + ResourceProvider getMemberResourceProvider(Set<String> propertyIds, Map<Type, String> keyPropertyIds, + AmbariManagementController managementController); @Named("hostKerberosIdentity") ResourceProvider getHostKerberosIdentityResourceProvider(AmbariManagementController managementController); @@ -64,13 +62,15 @@ public interface ResourceProviderFactory { ResourceProvider getRepositoryVersionResourceProvider(); @Named("kerberosDescriptor") - ResourceProvider getKerberosDescriptorResourceProvider(AmbariManagementController managementController, - Set<String> propertyIds, + ResourceProvider getKerberosDescriptorResourceProvider(AmbariManagementController managementController, Set<String> propertyIds, Map<Resource.Type, String> keyPropertyIds); @Named("upgrade") UpgradeResourceProvider getUpgradeResourceProvider(AmbariManagementController managementController); + @Named("ambariConfiguration") + ResourceProvider getAmbariConfigurationResourceProvider(); + @Named("clusterStackVersion") ClusterStackVersionResourceProvider getClusterStackVersionResourceProvider(AmbariManagementController managementController); http://git-wip-us.apache.org/repos/asf/ambari/blob/30415a18/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java index a98ad46..1dc0841 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java @@ -254,6 +254,8 @@ public abstract class AbstractControllerResourceProvider extends AbstractAuthori return new ClusterKerberosDescriptorResourceProvider(managementController); case LoggingQuery: return new LoggingResourceProvider(propertyIds, keyPropertyIds, managementController); + case AmbariConfiguration: + return resourceProviderFactory.getAmbariConfigurationResourceProvider(); case AlertTarget: return resourceProviderFactory.getAlertTargetResourceProvider(); case ViewInstance: http://git-wip-us.apache.org/repos/asf/ambari/blob/30415a18/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractProviderModule.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractProviderModule.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractProviderModule.java index 1cd2d10..1501a01 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractProviderModule.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractProviderModule.java @@ -224,7 +224,7 @@ public abstract class AbstractProviderModule implements ProviderModule, * are going to work unless refactoring is complete. */ @Inject - AmbariManagementController managementController; + protected AmbariManagementController managementController; @Inject TimelineMetricCacheProvider metricCacheProvider; http://git-wip-us.apache.org/repos/asf/ambari/blob/30415a18/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AmbariConfigurationResourceProvider.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AmbariConfigurationResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AmbariConfigurationResourceProvider.java new file mode 100644 index 0000000..4f4cc70 --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AmbariConfigurationResourceProvider.java @@ -0,0 +1,328 @@ +/* + * Licensed 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.ambari.server.controller.internal; + +import java.util.Calendar; +import java.util.Collections; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.inject.Inject; + +import org.apache.ambari.server.AmbariException; +import org.apache.ambari.server.controller.spi.NoSuchParentResourceException; +import org.apache.ambari.server.controller.spi.NoSuchResourceException; +import org.apache.ambari.server.controller.spi.Predicate; +import org.apache.ambari.server.controller.spi.Request; +import org.apache.ambari.server.controller.spi.RequestStatus; +import org.apache.ambari.server.controller.spi.Resource; +import org.apache.ambari.server.controller.spi.ResourceAlreadyExistsException; +import org.apache.ambari.server.controller.spi.SystemException; +import org.apache.ambari.server.controller.spi.UnsupportedPropertyException; +import org.apache.ambari.server.controller.utilities.PredicateHelper; +import org.apache.ambari.server.events.AmbariEvent; +import org.apache.ambari.server.events.AmbariLdapConfigChangedEvent; +import org.apache.ambari.server.events.publishers.AmbariEventPublisher; +import org.apache.ambari.server.orm.dao.AmbariConfigurationDAO; +import org.apache.ambari.server.orm.entities.AmbariConfigurationEntity; +import org.apache.ambari.server.orm.entities.ConfigurationBaseEntity; +import org.apache.ambari.server.security.authorization.RoleAuthorization; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.collect.Sets; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.inject.assistedinject.AssistedInject; + +/** + * Resource provider for AmbariConfiguration resources. + */ +public class AmbariConfigurationResourceProvider extends AbstractAuthorizedResourceProvider { + + private static final Logger LOGGER = LoggerFactory.getLogger(AmbariConfigurationResourceProvider.class); + private static final String DEFAULT_VERSION_TAG = "Default version"; + private static final Integer DEFAULT_VERSION = 1; + + /** + * Resource property id constants. + */ + public enum ResourcePropertyId { + + ID("AmbariConfiguration/id"), + TYPE("AmbariConfiguration/type"), + VERSION("AmbariConfiguration/version"), + VERSION_TAG("AmbariConfiguration/version_tag"), + DATA("AmbariConfiguration/data"); + + private String propertyId; + + ResourcePropertyId(String propertyId) { + this.propertyId = propertyId; + } + + String getPropertyId() { + return this.propertyId; + } + + public static ResourcePropertyId fromString(String propertyIdStr) { + ResourcePropertyId propertyIdFromStr = null; + + for (ResourcePropertyId id : ResourcePropertyId.values()) { + if (id.getPropertyId().equals(propertyIdStr)) { + propertyIdFromStr = id; + break; + } + } + + if (propertyIdFromStr == null) { + throw new IllegalArgumentException("Unsupported property type: " + propertyIdStr); + } + + return propertyIdFromStr; + + } + } + + private static Set<String> PROPERTIES = Sets.newHashSet( + ResourcePropertyId.ID.getPropertyId(), + ResourcePropertyId.TYPE.getPropertyId(), + ResourcePropertyId.VERSION.getPropertyId(), + ResourcePropertyId.VERSION_TAG.getPropertyId(), + ResourcePropertyId.DATA.getPropertyId()); + + private static Map<Resource.Type, String> PK_PROPERTY_MAP = Collections.unmodifiableMap( + new HashMap<Resource.Type, String>() {{ + put(Resource.Type.AmbariConfiguration, ResourcePropertyId.ID.getPropertyId()); + }} + ); + + + @Inject + private AmbariConfigurationDAO ambariConfigurationDAO; + + @Inject + private AmbariEventPublisher publisher; + + + private Gson gson; + + @AssistedInject + public AmbariConfigurationResourceProvider() { + super(PROPERTIES, PK_PROPERTY_MAP); + setRequiredCreateAuthorizations(EnumSet.of(RoleAuthorization.AMBARI_MANAGE_CONFIGURATION)); + setRequiredDeleteAuthorizations(EnumSet.of(RoleAuthorization.AMBARI_MANAGE_CONFIGURATION)); + + gson = new GsonBuilder().create(); + } + + @Override + protected Set<String> getPKPropertyIds() { + return Sets.newHashSet(ResourcePropertyId.ID.getPropertyId()); + } + + @Override + public RequestStatus createResourcesAuthorized(Request request) throws SystemException, UnsupportedPropertyException, + ResourceAlreadyExistsException, NoSuchParentResourceException { + + LOGGER.info("Creating new ambari configuration resource ..."); + AmbariConfigurationEntity ambariConfigurationEntity = null; + try { + ambariConfigurationEntity = getEntityFromRequest(request); + } catch (AmbariException e) { + throw new NoSuchParentResourceException(e.getMessage()); + } + + LOGGER.info("Persisting new ambari configuration: {} ", ambariConfigurationEntity); + + try { + ambariConfigurationDAO.create(ambariConfigurationEntity); + } catch (Exception e) { + LOGGER.error("Failed to create resource", e); + throw new ResourceAlreadyExistsException(e.getMessage()); + } + + // todo filter by configuration type + // notify subscribers about the configuration changes + publisher.publish(new AmbariLdapConfigChangedEvent(AmbariEvent.AmbariEventType.LDAP_CONFIG_CHANGED, + ambariConfigurationEntity.getId())); + + return getRequestStatus(null); + } + + + @Override + protected Set<Resource> getResourcesAuthorized(Request request, Predicate predicate) throws SystemException, + UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException { + Set<Resource> resources = Sets.newHashSet(); + + // retrieves allconfigurations, filtering is done at a higher level + List<AmbariConfigurationEntity> ambariConfigurationEntities = ambariConfigurationDAO.findAll(); + for (AmbariConfigurationEntity ambariConfigurationEntity : ambariConfigurationEntities) { + try { + resources.add(toResource(ambariConfigurationEntity, getPropertyIds())); + } catch (AmbariException e) { + LOGGER.error("Error while retrieving ambari configuration", e); + } + } + return resources; + } + + @Override + protected RequestStatus deleteResourcesAuthorized(Request request, Predicate predicate) throws SystemException, + UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException { + + Long idFromRequest = Long.valueOf((String) PredicateHelper.getProperties(predicate).get(ResourcePropertyId.ID.getPropertyId())); + + if (null == idFromRequest) { + LOGGER.debug("No resource id provided in the request"); + } else { + LOGGER.debug("Deleting amari configuration with id: {}", idFromRequest); + try { + ambariConfigurationDAO.removeByPK(idFromRequest); + } catch (IllegalStateException e) { + throw new NoSuchResourceException(e.getMessage()); + } + + } + + // notify subscribers about the configuration changes + publisher.publish(new AmbariLdapConfigChangedEvent(AmbariEvent.AmbariEventType.LDAP_CONFIG_CHANGED, idFromRequest)); + + + return getRequestStatus(null); + + } + + @Override + protected RequestStatus updateResourcesAuthorized(Request request, Predicate predicate) throws SystemException, + UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException { + Long idFromRequest = Long.valueOf((String) PredicateHelper.getProperties(predicate).get(ResourcePropertyId.ID.getPropertyId())); + + AmbariConfigurationEntity persistedEntity = ambariConfigurationDAO.findByPK(idFromRequest); + if (persistedEntity == null) { + String errorMsg = String.format("Entity with primary key [ %s ] not found in the database.", idFromRequest); + LOGGER.error(errorMsg); + throw new NoSuchResourceException(errorMsg); + } + + try { + + AmbariConfigurationEntity entityFromRequest = getEntityFromRequest(request); + persistedEntity.getConfigurationBaseEntity().setVersionTag(entityFromRequest.getConfigurationBaseEntity().getVersionTag()); + persistedEntity.getConfigurationBaseEntity().setVersion(entityFromRequest.getConfigurationBaseEntity().getVersion()); + persistedEntity.getConfigurationBaseEntity().setType(entityFromRequest.getConfigurationBaseEntity().getType()); + persistedEntity.getConfigurationBaseEntity().setConfigurationData(entityFromRequest.getConfigurationBaseEntity().getConfigurationData()); + persistedEntity.getConfigurationBaseEntity().setConfigurationAttributes(entityFromRequest.getConfigurationBaseEntity().getConfigurationAttributes()); + + + ambariConfigurationDAO.update(persistedEntity); + } catch (AmbariException e) { + throw new NoSuchParentResourceException(e.getMessage()); + } + + publisher.publish(new AmbariLdapConfigChangedEvent(AmbariEvent.AmbariEventType.LDAP_CONFIG_CHANGED, + persistedEntity.getId())); + + + return getRequestStatus(null); + + } + + private Resource toResource(AmbariConfigurationEntity entity, Set<String> requestedIds) throws AmbariException { + + if (null == entity) { + throw new IllegalArgumentException("Null entity can't be transformed into a resource"); + } + + if (null == entity.getConfigurationBaseEntity()) { + throw new IllegalArgumentException("Invalid configuration entity can't be transformed into a resource"); + } + Resource resource = new ResourceImpl(Resource.Type.AmbariConfiguration); + Set<Map<String, String>> configurationSet = gson.fromJson(entity.getConfigurationBaseEntity().getConfigurationData(), Set.class); + + setResourceProperty(resource, ResourcePropertyId.ID.getPropertyId(), entity.getId(), requestedIds); + setResourceProperty(resource, ResourcePropertyId.TYPE.getPropertyId(), entity.getConfigurationBaseEntity().getType(), requestedIds); + setResourceProperty(resource, ResourcePropertyId.DATA.getPropertyId(), configurationSet, requestedIds); + setResourceProperty(resource, ResourcePropertyId.VERSION.getPropertyId(), entity.getConfigurationBaseEntity().getVersion(), requestedIds); + setResourceProperty(resource, ResourcePropertyId.VERSION_TAG.getPropertyId(), entity.getConfigurationBaseEntity().getVersionTag(), requestedIds); + + return resource; + } + + private AmbariConfigurationEntity getEntityFromRequest(Request request) throws AmbariException { + + AmbariConfigurationEntity ambariConfigurationEntity = new AmbariConfigurationEntity(); + ambariConfigurationEntity.setConfigurationBaseEntity(new ConfigurationBaseEntity()); + + // set of resource properties (eache entry in the set belongs to a different resource) + Set<Map<String, Object>> resourcePropertiesSet = request.getProperties(); + + if (resourcePropertiesSet.size() != 1) { + throw new AmbariException("There must be only one resource specified in the request"); + } + + // the configuration type must be set + if (getValueFromResourceProperties(ResourcePropertyId.TYPE, resourcePropertiesSet.iterator().next()) == null) { + throw new AmbariException("The configuration type must be set"); + } + + + for (ResourcePropertyId resourcePropertyId : ResourcePropertyId.values()) { + Object requestValue = getValueFromResourceProperties(resourcePropertyId, resourcePropertiesSet.iterator().next()); + + switch (resourcePropertyId) { + case DATA: + if (requestValue == null) { + throw new IllegalArgumentException("No configuration data is provided in the request"); + } + ambariConfigurationEntity.getConfigurationBaseEntity().setConfigurationData(gson.toJson(requestValue)); + break; + case TYPE: + ambariConfigurationEntity.getConfigurationBaseEntity().setType((String) requestValue); + break; + case VERSION: + Integer version = (requestValue == null) ? DEFAULT_VERSION : Integer.valueOf((String) requestValue); + ambariConfigurationEntity.getConfigurationBaseEntity().setVersion((version)); + break; + case VERSION_TAG: + String versionTag = requestValue == null ? DEFAULT_VERSION_TAG : (String) requestValue; + ambariConfigurationEntity.getConfigurationBaseEntity().setVersionTag(versionTag); + break; + default: + LOGGER.debug("Ignored property in the request: {}", resourcePropertyId); + break; + } + } + ambariConfigurationEntity.getConfigurationBaseEntity().setCreateTimestamp(Calendar.getInstance().getTimeInMillis()); + return ambariConfigurationEntity; + + } + + private Object getValueFromResourceProperties(ResourcePropertyId resourcePropertyIdEnum, Map<String, Object> resourceProperties) { + LOGGER.debug("Locating resource property [{}] in the resource properties map ...", resourcePropertyIdEnum); + Object requestValue = null; + + if (resourceProperties.containsKey(resourcePropertyIdEnum.getPropertyId())) { + requestValue = resourceProperties.get(resourcePropertyIdEnum.getPropertyId()); + LOGGER.debug("Found resource property {} in the resource properties map, value: {}", resourcePropertyIdEnum, requestValue); + } + return requestValue; + } + +} http://git-wip-us.apache.org/repos/asf/ambari/blob/30415a18/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/DefaultProviderModule.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/DefaultProviderModule.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/DefaultProviderModule.java index 43779a3..c3758b3 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/DefaultProviderModule.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/DefaultProviderModule.java @@ -21,20 +21,18 @@ package org.apache.ambari.server.controller.internal; import java.util.Map; import java.util.Set; -import org.apache.ambari.server.controller.AmbariManagementController; -import org.apache.ambari.server.controller.AmbariServer; import org.apache.ambari.server.controller.spi.Resource; import org.apache.ambari.server.controller.spi.ResourceProvider; import org.apache.ambari.server.controller.utilities.PropertyHelper; - -import com.google.inject.Inject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * The default provider module implementation. */ public class DefaultProviderModule extends AbstractProviderModule { - @Inject - private AmbariManagementController managementController; + + private static final Logger LOGGER = LoggerFactory.getLogger(DefaultProviderModule.class); // ----- Constructors ------------------------------------------------------ @@ -42,9 +40,7 @@ public class DefaultProviderModule extends AbstractProviderModule { * Create a default provider module. */ public DefaultProviderModule() { - if (managementController == null) { - managementController = AmbariServer.getController(); - } + super(); } @@ -52,8 +48,10 @@ public class DefaultProviderModule extends AbstractProviderModule { @Override protected ResourceProvider createResourceProvider(Resource.Type type) { - Set<String> propertyIds = PropertyHelper.getPropertyIds(type); - Map<Resource.Type,String> keyPropertyIds = PropertyHelper.getKeyPropertyIds(type); + + LOGGER.debug("Creating resource provider for the type: {}", type); + Set<String> propertyIds = PropertyHelper.getPropertyIds(type); + Map<Resource.Type, String> keyPropertyIds = PropertyHelper.getKeyPropertyIds(type); switch (type.getInternalType()) { case Workflow: @@ -118,10 +116,10 @@ public class DefaultProviderModule extends AbstractProviderModule { return new ArtifactResourceProvider(managementController); case RemoteCluster: return new RemoteClusterResourceProvider(); - default: + LOGGER.debug("Delegating creation of resource provider for: {} to the AbstractControllerResourceProvider", type.getInternalType()); return AbstractControllerResourceProvider.getResourceProvider(type, propertyIds, - keyPropertyIds, managementController); + keyPropertyIds, managementController); } } } http://git-wip-us.apache.org/repos/asf/ambari/blob/30415a18/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java index 362b4e6..7835373 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java @@ -160,7 +160,8 @@ public interface Resource { VersionDefinition, ClusterKerberosDescriptor, LoggingQuery, - RemoteCluster; + RemoteCluster, + AmbariConfiguration; /** * Get the {@link Type} that corresponds to this InternalType. @@ -282,6 +283,8 @@ public interface Resource { public static final Type ClusterKerberosDescriptor = InternalType.ClusterKerberosDescriptor.getType(); public static final Type LoggingQuery = InternalType.LoggingQuery.getType(); public static final Type RemoteCluster = InternalType.RemoteCluster.getType(); + public static final Type AmbariConfiguration = InternalType.AmbariConfiguration.getType(); + /** * The type name. http://git-wip-us.apache.org/repos/asf/ambari/blob/30415a18/ambari-server/src/main/java/org/apache/ambari/server/events/AmbariEvent.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/AmbariEvent.java b/ambari-server/src/main/java/org/apache/ambari/server/events/AmbariEvent.java index 9a5ee79..0f9ff52 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/events/AmbariEvent.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/events/AmbariEvent.java @@ -140,7 +140,13 @@ public abstract class AmbariEvent { /** * Local user has been created. */ - USER_CREATED; + USER_CREATED, + + /** + * LDAP config changed event; + */ + LDAP_CONFIG_CHANGED; + } /** @@ -151,8 +157,7 @@ public abstract class AmbariEvent { /** * Constructor. * - * @param eventType - * the type of event (not {@code null}). + * @param eventType the type of event (not {@code null}). */ public AmbariEvent(AmbariEventType eventType) { m_eventType = eventType; http://git-wip-us.apache.org/repos/asf/ambari/blob/30415a18/ambari-server/src/main/java/org/apache/ambari/server/events/AmbariLdapConfigChangedEvent.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/AmbariLdapConfigChangedEvent.java b/ambari-server/src/main/java/org/apache/ambari/server/events/AmbariLdapConfigChangedEvent.java new file mode 100644 index 0000000..48799d7 --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/events/AmbariLdapConfigChangedEvent.java @@ -0,0 +1,37 @@ +/* + * Licensed 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.ambari.server.events; + +/** + * Event signaling the creation or changing of an LDAP configuration entry. + */ +public class AmbariLdapConfigChangedEvent extends AmbariEvent { + + private Long configurationId; + + /** + * Constructor. + * + * @param eventType the type of event (not {@code null}). + */ + public AmbariLdapConfigChangedEvent(AmbariEventType eventType, Long configurationId) { + super(eventType); + this.configurationId = configurationId; + } + + public Long getConfigurationId() { + return configurationId; + } +}