You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by al...@apache.org on 2016/06/20 21:34:48 UTC
[6/6] ambari git commit: AMBARI-12885. Dynamic stack extensions -
install and upgrade support for custom services (Tim Thorpe via alejandro)
AMBARI-12885. Dynamic stack extensions - install and upgrade support for custom services (Tim Thorpe via alejandro)
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/300a7e21
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/300a7e21
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/300a7e21
Branch: refs/heads/trunk
Commit: 300a7e21d109ef731af65dc8652e057065081bb2
Parents: 31dfc56
Author: Alejandro Fernandez <af...@hortonworks.com>
Authored: Mon Jun 20 12:19:40 2016 -0700
Committer: Alejandro Fernandez <af...@hortonworks.com>
Committed: Mon Jun 20 14:36:26 2016 -0700
----------------------------------------------------------------------
ambari-server/conf/unix/ambari.properties | 1 +
ambari-server/src/main/assemblies/server.xml | 4 +
.../ExtensionLinkResourceDefinition.java | 58 ++
.../resources/ExtensionResourceDefinition.java | 59 ++
.../ExtensionVersionResourceDefinition.java | 54 ++
.../resources/ResourceInstanceFactoryImpl.java | 12 +
.../server/api/services/AmbariMetaInfo.java | 42 +-
.../api/services/ExtensionLinksService.java | 101 ++++
.../server/api/services/ExtensionsService.java | 127 +++++
.../server/api/services/StacksService.java | 23 +
.../server/configuration/Configuration.java | 9 +
.../controller/AmbariManagementController.java | 49 +-
.../AmbariManagementControllerImpl.java | 270 ++++++++++
.../server/controller/ExtensionLinkRequest.java | 86 +++
.../controller/ExtensionLinkResponse.java | 124 +++++
.../server/controller/ExtensionRequest.java | 43 ++
.../server/controller/ExtensionResponse.java | 61 +++
.../controller/ExtensionVersionRequest.java | 44 ++
.../controller/ExtensionVersionResponse.java | 101 ++++
.../AbstractControllerResourceProvider.java | 6 +
.../server/controller/internal/Extension.java | 282 ++++++++++
.../internal/ExtensionLinkResourceProvider.java | 241 +++++++++
.../internal/ExtensionResourceProvider.java | 121 +++++
.../ExtensionVersionResourceProvider.java | 131 +++++
.../ambari/server/controller/spi/Resource.java | 6 +
.../ambari/server/orm/dao/ExtensionDAO.java | 168 ++++++
.../ambari/server/orm/dao/ExtensionLinkDAO.java | 240 +++++++++
.../server/orm/entities/ExtensionEntity.java | 156 ++++++
.../orm/entities/ExtensionLinkEntity.java | 139 +++++
.../apache/ambari/server/stack/BaseModule.java | 4 +-
.../server/stack/CommonServiceDirectory.java | 7 +-
.../ambari/server/stack/ComponentModule.java | 3 +-
.../server/stack/ConfigurationModule.java | 3 +-
.../ambari/server/stack/ExtensionDirectory.java | 196 +++++++
.../ambari/server/stack/ExtensionHelper.java | 167 ++++++
.../ambari/server/stack/ExtensionModule.java | 540 +++++++++++++++++++
.../server/stack/ModuleFileUnmarshaller.java | 4 +
.../stack/QuickLinksConfigurationModule.java | 2 +-
.../ambari/server/stack/ServiceDirectory.java | 114 +++-
.../ambari/server/stack/ServiceModule.java | 57 +-
.../server/stack/StackDefinitionModule.java | 3 +-
.../ambari/server/stack/StackDirectory.java | 32 --
.../ambari/server/stack/StackManager.java | 223 +++++++-
.../server/stack/StackManagerFactory.java | 3 +
.../apache/ambari/server/stack/StackModule.java | 211 +++++++-
.../server/stack/StackServiceDirectory.java | 6 +-
.../apache/ambari/server/stack/ThemeModule.java | 3 +-
.../apache/ambari/server/state/ExtensionId.java | 160 ++++++
.../ambari/server/state/ExtensionInfo.java | 208 +++++++
.../apache/ambari/server/state/ServiceInfo.java | 11 +
.../apache/ambari/server/state/StackInfo.java | 29 +
.../state/stack/ExtensionMetainfoXml.java | 204 +++++++
.../server/state/stack/ServiceMetainfoXml.java | 4 +
.../server/upgrade/UpgradeCatalog240.java | 53 +-
.../main/resources/Ambari-DDL-Derby-CREATE.sql | 26 +-
.../main/resources/Ambari-DDL-MySQL-CREATE.sql | 24 +-
.../main/resources/Ambari-DDL-Oracle-CREATE.sql | 24 +-
.../resources/Ambari-DDL-Postgres-CREATE.sql | 24 +-
.../Ambari-DDL-Postgres-EMBEDDED-CREATE.sql | 26 +-
.../resources/Ambari-DDL-SQLAnywhere-CREATE.sql | 24 +-
.../resources/Ambari-DDL-SQLServer-CREATE.sql | 24 +-
.../src/main/resources/META-INF/persistence.xml | 2 +
.../src/main/resources/extensions/README.txt | 31 ++
.../src/main/resources/key_properties.json | 16 +-
.../src/main/resources/properties.json | 30 +-
.../api/services/ExtensionsServiceTest.java | 119 ++++
.../internal/ExtensionResourceProviderTest.java | 91 ++++
.../server/stack/ComponentModuleTest.java | 2 +-
.../QuickLinksConfigurationModuleTest.java | 4 +-
.../ambari/server/stack/ServiceModuleTest.java | 2 +-
.../stack/StackManagerCommonServicesTest.java | 32 +-
.../server/stack/StackManagerExtensionTest.java | 131 +++++
.../server/stack/StackManagerMiscTest.java | 47 +-
.../ambari/server/stack/StackManagerTest.java | 123 ++++-
.../ambari/server/stack/ThemeModuleTest.java | 2 +-
.../server/upgrade/UpgradeCatalog240Test.java | 43 +-
.../resources/extensions/EXT/0.1/metainfo.xml | 30 ++
.../OOZIE2/configuration/oozie2-site.xml | 245 +++++++++
.../EXT/0.1/services/OOZIE2/metainfo.xml | 110 ++++
.../0.1/services/OOZIE2/package/dummy-script.py | 20 +
.../EXT/0.1/services/PIG2/metainfo.xml | 26 +
.../resources/extensions/EXT/0.2/metainfo.xml | 31 ++
.../EXT/0.2/services/OOZIE2/metainfo.xml | 110 ++++
.../stacks/OTHER/1.0/services/PIG2/metainfo.xml | 30 ++
.../stacks_with_extensions/HDP/0.1/metainfo.xml | 22 +
.../HDP/0.1/repos/repoinfo.xml | 57 ++
.../HDP/0.1/services/HDFS/metainfo.xml | 46 ++
.../HDP/0.1/services/MAPREDUCE/metainfo.xml | 23 +
.../HDP/0.1/services/PIG/metainfo.xml | 26 +
.../stacks_with_extensions/HDP/0.2/metainfo.xml | 22 +
.../HDP/0.2/repos/repoinfo.xml | 57 ++
.../HDP/0.2/services/HBASE/metainfo.xml | 26 +
.../0.2/services/HDFS/configuration/global.xml | 145 +++++
.../services/HDFS/configuration/hadoop-env.xml | 223 ++++++++
.../services/HDFS/configuration/hbase-site.xml | 137 +++++
.../services/HDFS/configuration/hdfs-log4j.xml | 199 +++++++
.../services/HDFS/configuration/hdfs-site.xml | 396 ++++++++++++++
.../HDP/0.2/services/HDFS/metainfo.xml | 30 ++
.../0.2/services/HDFS/package/dummy-script.py | 20 +
.../HDP/0.2/services/HIVE/metainfo.xml | 26 +
.../HDP/0.2/services/MAPREDUCE/metainfo.xml | 23 +
.../HDP/0.2/services/ZOOKEEPER/metainfo.xml | 26 +
102 files changed, 7755 insertions(+), 203 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/ambari/blob/300a7e21/ambari-server/conf/unix/ambari.properties
----------------------------------------------------------------------
diff --git a/ambari-server/conf/unix/ambari.properties b/ambari-server/conf/unix/ambari.properties
index a88a025..abd72ad 100644
--- a/ambari-server/conf/unix/ambari.properties
+++ b/ambari-server/conf/unix/ambari.properties
@@ -43,6 +43,7 @@ jce.download.supported=true
metadata.path=$ROOT/var/lib/ambari-server/resources/stacks
common.services.path=$ROOT/var/lib/ambari-server/resources/common-services
+extensions.path=/var/lib/ambari-server/resources/extensions
server.version.file=$ROOT/var/lib/ambari-server/resources/version
webapp.dir=$ROOT/usr/lib/ambari-server/web
pid.dir=$ROOT/var/run/ambari-server
http://git-wip-us.apache.org/repos/asf/ambari/blob/300a7e21/ambari-server/src/main/assemblies/server.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/assemblies/server.xml b/ambari-server/src/main/assemblies/server.xml
index 1560d8d..2439e17 100644
--- a/ambari-server/src/main/assemblies/server.xml
+++ b/ambari-server/src/main/assemblies/server.xml
@@ -155,6 +155,10 @@
<outputDirectory>/var/lib/ambari-server/resources/stacks/${stack.distribution}</outputDirectory>
</fileSet>
<fileSet>
+ <directory>src/main/resources/extensions</directory>
+ <outputDirectory>/var/lib/ambari-server/resources/extensions</outputDirectory>
+ </fileSet>
+ <fileSet>
<directory>src/main/python/ambari_server</directory>
<outputDirectory>/usr/lib/python2.6/site-packages/ambari_server</outputDirectory>
</fileSet>
http://git-wip-us.apache.org/repos/asf/ambari/blob/300a7e21/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ExtensionLinkResourceDefinition.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ExtensionLinkResourceDefinition.java b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ExtensionLinkResourceDefinition.java
new file mode 100644
index 0000000..f03f4f7
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ExtensionLinkResourceDefinition.java
@@ -0,0 +1,58 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.api.resources;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.controller.spi.Resource.Type;
+
+/**
+ * An extension version is like a stack version but it contains custom services. Linking an extension
+ * version to the current stack version allows the cluster to install the custom services contained in
+ * the extension version.
+ */
+public class ExtensionLinkResourceDefinition extends BaseResourceDefinition {
+
+ public ExtensionLinkResourceDefinition(Type resourceType) {
+ super(Resource.Type.ExtensionLink);
+ }
+
+ public ExtensionLinkResourceDefinition() {
+ super(Resource.Type.ExtensionLink);
+ }
+
+ @Override
+ public String getPluralName() {
+ return "links";
+ }
+
+ @Override
+ public String getSingularName() {
+ return "link";
+ }
+
+ @Override
+ public Set<SubResourceDefinition> getSubResourceDefinitions() {
+ Set<SubResourceDefinition> setChildren = new HashSet<SubResourceDefinition>();
+ return setChildren;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/300a7e21/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ExtensionResourceDefinition.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ExtensionResourceDefinition.java b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ExtensionResourceDefinition.java
new file mode 100644
index 0000000..bad78b9
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ExtensionResourceDefinition.java
@@ -0,0 +1,59 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.api.resources;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.controller.spi.Resource.Type;
+
+/**
+ * An extension version is like a stack version but it contains custom services. Linking an extension
+ * version to the current stack version allows the cluster to install the custom services contained in
+ * the extension version.
+ */
+public class ExtensionResourceDefinition extends BaseResourceDefinition {
+
+ public ExtensionResourceDefinition(Type resourceType) {
+ super(Resource.Type.Extension);
+ }
+
+ public ExtensionResourceDefinition() {
+ super(Resource.Type.Extension);
+ }
+
+ @Override
+ public String getPluralName() {
+ return "extensions";
+ }
+
+ @Override
+ public String getSingularName() {
+ return "extension";
+ }
+
+ @Override
+ public Set<SubResourceDefinition> getSubResourceDefinitions() {
+ Set<SubResourceDefinition> setChildren = new HashSet<SubResourceDefinition>();
+ setChildren.add(new SubResourceDefinition(Resource.Type.ExtensionVersion));
+ return setChildren;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/300a7e21/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ExtensionVersionResourceDefinition.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ExtensionVersionResourceDefinition.java b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ExtensionVersionResourceDefinition.java
new file mode 100644
index 0000000..824640a
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ExtensionVersionResourceDefinition.java
@@ -0,0 +1,54 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.api.resources;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.ambari.server.controller.spi.Resource;
+
+/**
+ * An extension version is like a stack version but it contains custom services. Linking an extension
+ * version to the current stack version allows the cluster to install the custom services contained in
+ * the extension version.
+ */
+public class ExtensionVersionResourceDefinition extends BaseResourceDefinition {
+
+ public ExtensionVersionResourceDefinition() {
+ super(Resource.Type.ExtensionVersion);
+ }
+
+ @Override
+ public String getPluralName() {
+ return "versions";
+ }
+
+ @Override
+ public String getSingularName() {
+ return "version";
+ }
+
+ @Override
+ public Set<SubResourceDefinition> getSubResourceDefinitions() {
+
+ Set<SubResourceDefinition> children = new HashSet<SubResourceDefinition>();
+
+ return children;
+ }
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/300a7e21/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 cf7c391..a2aeffa 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
@@ -187,6 +187,18 @@ public class ResourceInstanceFactoryImpl implements ResourceInstanceFactory {
resourceDefinition = new StackConfigurationDependencyResourceDefinition();
break;
+ case Extension:
+ resourceDefinition = new ExtensionResourceDefinition();
+ break;
+
+ case ExtensionVersion:
+ resourceDefinition = new ExtensionVersionResourceDefinition();
+ break;
+
+ case ExtensionLink:
+ resourceDefinition = new ExtensionLinkResourceDefinition();
+ break;
+
case OperatingSystem:
resourceDefinition = new OperatingSystemResourceDefinition();
break;
http://git-wip-us.apache.org/repos/asf/ambari/blob/300a7e21/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java
index f0928cf..92d47df 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java
@@ -63,6 +63,7 @@ import org.apache.ambari.server.state.Cluster;
import org.apache.ambari.server.state.Clusters;
import org.apache.ambari.server.state.ComponentInfo;
import org.apache.ambari.server.state.DependencyInfo;
+import org.apache.ambari.server.state.ExtensionInfo;
import org.apache.ambari.server.state.OperatingSystemInfo;
import org.apache.ambari.server.state.PropertyInfo;
import org.apache.ambari.server.state.RepositoryInfo;
@@ -108,12 +109,12 @@ public class AmbariMetaInfo {
public static final String SERVICE_ADVISOR_FILE_NAME = "service_advisor.py";
/**
- * The filename name for a Kerberos descriptor file at either the stack or service level
+ * The filename for a Kerberos descriptor file at either the stack or service level
*/
public static final String KERBEROS_DESCRIPTOR_FILE_NAME = "kerberos.json";
/**
- * The filename name for a Widgets descriptor file at either the stack or service level
+ * The filename for a Widgets descriptor file at either the stack or service level
*/
public static final String WIDGETS_DESCRIPTOR_FILE_NAME = "widgets.json";
@@ -156,6 +157,7 @@ public class AmbariMetaInfo {
private File stackRoot;
private File commonServicesRoot;
+ private File extensionsRoot;
private File serverVersionFile;
private File customActionRoot;
private Map<String, VersionDefinitionXml> versionDefinitions = null;
@@ -237,6 +239,11 @@ public class AmbariMetaInfo {
commonServicesRoot = new File(commonServicesPath);
}
+ String extensionsPath = conf.getExtensionsPath();
+ if (extensionsPath != null && !extensionsPath.isEmpty()) {
+ extensionsRoot = new File(extensionsPath);
+ }
+
String serverVersionFilePath = conf.getServerVersionFilePath();
serverVersionFile = new File(serverVersionFilePath);
@@ -255,7 +262,7 @@ public class AmbariMetaInfo {
readServerVersion();
- stackManager = stackManagerFactory.create(stackRoot, commonServicesRoot,
+ stackManager = stackManagerFactory.create(stackRoot, commonServicesRoot, extensionsRoot,
osFamily, false);
getCustomActionDefinitions(customActionRoot);
@@ -629,6 +636,30 @@ public class AmbariMetaInfo {
return parents;
}
+ public Collection<ExtensionInfo> getExtensions() {
+ return stackManager.getExtensions();
+ }
+
+ public Collection<ExtensionInfo> getExtensions(String extensionName) throws AmbariException {
+ Collection<ExtensionInfo> extensions = stackManager.getExtensions(extensionName);
+
+ if (extensions.isEmpty()) {
+ throw new StackAccessException("extensionName=" + extensionName);
+ }
+
+ return extensions;
+ }
+
+ public ExtensionInfo getExtension(String extensionName, String version) throws AmbariException {
+ ExtensionInfo result = stackManager.getExtension(extensionName, version);
+
+ if (result == null) {
+ throw new StackAccessException("Extension " + extensionName + " " + version + " is not found in Ambari metainfo");
+ }
+
+ return result;
+ }
+
public Set<PropertyInfo> getServiceProperties(String stackName, String version, String serviceName)
throws AmbariException {
@@ -700,7 +731,6 @@ public class AmbariMetaInfo {
return propertyResult;
}
-
/**
* Lists operatingsystems supported by stack
*/
@@ -862,6 +892,10 @@ public class AmbariMetaInfo {
return stackRoot;
}
+ public File getExtensionsRoot() {
+ return extensionsRoot;
+ }
+
/**
* Return metrics for a stack service.
*/
http://git-wip-us.apache.org/repos/asf/ambari/blob/300a7e21/ambari-server/src/main/java/org/apache/ambari/server/api/services/ExtensionLinksService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ExtensionLinksService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ExtensionLinksService.java
new file mode 100644
index 0000000..4bacfbf
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ExtensionLinksService.java
@@ -0,0 +1,101 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.api.services;
+
+import java.util.HashMap;
+import java.util.Map;
+
+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.Response;
+import javax.ws.rs.core.UriInfo;
+
+import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.controller.spi.Resource;
+
+/**
+ * Service for extension link management.
+ *
+ * An extension version is like a stack version but it contains custom services. Linking an extension
+ * version to the current stack version allows the cluster to install the custom services contained in
+ * the extension version.
+ */
+@Path("/links/")
+public class ExtensionLinksService extends BaseService {
+
+ @GET
+ @Produces("text/plain")
+ public Response getExtensionLinks(String body, @Context HttpHeaders headers, @Context UriInfo ui) {
+
+ return handleRequest(headers, body, ui, Request.Type.GET, createExtensionLinkResource(null));
+ }
+
+ @GET
+ @Path("{linkId}")
+ @Produces("text/plain")
+ public Response getExtensionLink(String body, @Context HttpHeaders headers,
+ @Context UriInfo ui, @PathParam("linkId") String linkId) {
+
+ return handleRequest(headers, body, ui, Request.Type.GET, createExtensionLinkResource(linkId));
+ }
+
+ @POST
+ @Produces("text/plain")
+ public Response createExtensionLink(String body, @Context HttpHeaders headers, @Context UriInfo ui) {
+ return handleRequest(headers, body, ui, Request.Type.POST, createExtensionLinkResource(null));
+ }
+
+ @DELETE
+ @Path("{linkId}")
+ @Produces("text/plain")
+ public Response deleteExtensionLink(@Context HttpHeaders headers, @Context UriInfo ui,
+ @PathParam("linkId") String linkId) {
+
+ return handleRequest(headers, null, ui, Request.Type.DELETE, createExtensionLinkResource(linkId));
+ }
+
+ @PUT
+ @Produces("text/plain")
+ public Response updateExtensionLink(String body, @Context HttpHeaders headers, @Context UriInfo ui) {
+ return handleRequest(headers, body, ui, Request.Type.PUT, createExtensionLinkResource(null));
+ }
+
+ @PUT
+ @Path("{linkId}")
+ @Produces("text/plain")
+ public Response updateExtensionLink(String body, @Context HttpHeaders headers, @Context UriInfo ui,
+ @PathParam("linkId") String linkId) {
+
+ return handleRequest(headers, body, ui, Request.Type.PUT, createExtensionLinkResource(linkId));
+ }
+
+ ResourceInstance createExtensionLinkResource(String linkId) {
+ Map<Resource.Type, String> mapIds = new HashMap<Resource.Type, String>();
+ mapIds.put(Resource.Type.ExtensionLink, linkId);
+ return createResource(Resource.Type.ExtensionLink, mapIds);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/300a7e21/ambari-server/src/main/java/org/apache/ambari/server/api/services/ExtensionsService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ExtensionsService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ExtensionsService.java
new file mode 100644
index 0000000..176c259
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ExtensionsService.java
@@ -0,0 +1,127 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.api.services;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.ws.rs.GET;
+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.Response;
+import javax.ws.rs.core.UriInfo;
+
+import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.controller.spi.Resource;
+
+/**
+ * Service for extensions management.
+ *
+ * An extension version is like a stack version but it contains custom services. Linking an extension
+ * version to the current stack version allows the cluster to install the custom services contained in
+ * the extension version.
+ */
+@Path("/extensions/")
+public class ExtensionsService extends BaseService {
+
+ @GET
+ @Produces("text/plain")
+ public Response getExtensions(String body, @Context HttpHeaders headers, @Context UriInfo ui) {
+
+ return handleRequest(headers, body, ui, Request.Type.GET,
+ createExtensionResource(null));
+ }
+
+ @GET
+ @Path("{extensionName}")
+ @Produces("text/plain")
+ public Response getExtension(String body, @Context HttpHeaders headers,
+ @Context UriInfo ui,
+ @PathParam("extensionName") String extensionName) {
+
+ return handleRequest(headers, body, ui, Request.Type.GET,
+ createExtensionResource(extensionName));
+ }
+
+ @GET
+ @Path("{extensionName}/versions")
+ @Produces("text/plain")
+ public Response getExtensionVersions(String body,
+ @Context HttpHeaders headers,
+ @Context UriInfo ui, @PathParam("extensionName") String extensionName) {
+
+ return handleRequest(headers, body, ui, Request.Type.GET,
+ createExtensionVersionResource(extensionName, null));
+ }
+
+ @GET
+ @Path("{extensionName}/versions/{extensionVersion}")
+ @Produces("text/plain")
+ public Response getExtensionVersion(String body,
+ @Context HttpHeaders headers,
+ @Context UriInfo ui, @PathParam("extensionName") String extensionName,
+ @PathParam("extensionVersion") String extensionVersion) {
+
+ return handleRequest(headers, body, ui, Request.Type.GET,
+ createExtensionVersionResource(extensionName, extensionVersion));
+ }
+
+ @GET
+ @Path("{extensionName}/versions/{extensionVersion}/links")
+ @Produces("text/plain")
+ public Response getExtensionVersionLinks(String body,
+ @Context HttpHeaders headers,
+ @Context UriInfo ui, @PathParam("extensionName") String extensionName,
+ @PathParam("extensionVersion") String extensionVersion) {
+
+ return handleRequest(headers, body, ui, Request.Type.GET,
+ createExtensionLinkResource(null, null, extensionName, extensionVersion));
+ }
+
+ ResourceInstance createExtensionVersionResource(String extensionName,
+ String extensionVersion) {
+ Map<Resource.Type, String> mapIds = new HashMap<Resource.Type, String>();
+ mapIds.put(Resource.Type.Extension, extensionName);
+ mapIds.put(Resource.Type.ExtensionVersion, extensionVersion);
+
+ return createResource(Resource.Type.ExtensionVersion, mapIds);
+ }
+
+ ResourceInstance createExtensionLinkResource(String stackName, String stackVersion,
+ String extensionName, String extensionVersion) {
+ Map<Resource.Type, String> mapIds = new HashMap<Resource.Type, String>();
+ mapIds.put(Resource.Type.Stack, stackName);
+ mapIds.put(Resource.Type.StackVersion, stackVersion);
+ mapIds.put(Resource.Type.Extension, extensionName);
+ mapIds.put(Resource.Type.ExtensionVersion, extensionVersion);
+
+ return createResource(Resource.Type.ExtensionLink, mapIds);
+ }
+
+ ResourceInstance createExtensionResource(String extensionName) {
+
+ return createResource(Resource.Type.Extension,
+ Collections.singletonMap(Resource.Type.Extension, extensionName));
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/300a7e21/ambari-server/src/main/java/org/apache/ambari/server/api/services/StacksService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/StacksService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/StacksService.java
index 557ce98..2c85e01 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/StacksService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/StacksService.java
@@ -83,6 +83,18 @@ public class StacksService extends BaseService {
}
@GET
+ @Path("{stackName}/versions/{stackVersion}/links")
+ @Produces("text/plain")
+ public Response getStackVersionLinks(String body,
+ @Context HttpHeaders headers,
+ @Context UriInfo ui, @PathParam("stackName") String stackName,
+ @PathParam("stackVersion") String stackVersion) {
+
+ return handleRequest(headers, body, ui, Request.Type.GET,
+ createExtensionLinkResource(stackName, stackVersion, null, null));
+ }
+
+ @GET
@Path("{stackName}/versions/{stackVersion}/configurations")
@Produces("text/plain")
public Response getStackLevelConfigurations(String body, @Context HttpHeaders headers,
@@ -491,6 +503,17 @@ public class StacksService extends BaseService {
return createResource(Resource.Type.QuickLink, mapIds);
}
+ ResourceInstance createExtensionLinkResource(String stackName, String stackVersion,
+ String extensionName, String extensionVersion) {
+ Map<Resource.Type, String> mapIds = new HashMap<Resource.Type, String>();
+ mapIds.put(Resource.Type.Stack, stackName);
+ mapIds.put(Resource.Type.StackVersion, stackVersion);
+ mapIds.put(Resource.Type.Extension, extensionName);
+ mapIds.put(Resource.Type.ExtensionVersion, extensionVersion);
+
+ return createResource(Resource.Type.ExtensionLink, mapIds);
+ }
+
ResourceInstance createStackResource(String stackName) {
return createResource(Resource.Type.Stack,
http://git-wip-us.apache.org/repos/asf/ambari/blob/300a7e21/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java b/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
index 2b7fca0..d736303 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
@@ -137,6 +137,7 @@ public class Configuration {
public static final String RESOURCES_DIR_KEY = "resources.dir";
public static final String METADATA_DIR_PATH = "metadata.path";
public static final String COMMON_SERVICES_DIR_PATH = "common.services.path";
+ public static final String EXTENSIONS_DIR_PATH = "extensions.path";
public static final String MPACKS_STAGING_DIR_PATH = "mpacks.staging.path";
public static final String SERVER_VERSION_FILE = "server.version.file";
public static final String SERVER_VERSION_KEY = "version";
@@ -1479,6 +1480,14 @@ public class Configuration {
}
/**
+ * Gets ambari extensions-path
+ * @return String
+ */
+ public String getExtensionsPath() {
+ return properties.getProperty(EXTENSIONS_DIR_PATH);
+ }
+
+ /**
* Gets ambari management packs staging directory
* @return String
*/
http://git-wip-us.apache.org/repos/asf/ambari/blob/300a7e21/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementController.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementController.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementController.java
index b488af3..947a9f4 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementController.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementController.java
@@ -34,6 +34,7 @@ import org.apache.ambari.server.controller.metrics.timeline.cache.TimelineMetric
import org.apache.ambari.server.events.AmbariEvent;
import org.apache.ambari.server.events.publishers.AmbariEventPublisher;
import org.apache.ambari.server.metadata.RoleCommandOrder;
+import org.apache.ambari.server.orm.entities.ExtensionLinkEntity;
import org.apache.ambari.server.scheduler.ExecutionScheduleManager;
import org.apache.ambari.server.security.authorization.AuthorizationException;
import org.apache.ambari.server.security.encryption.CredentialStoreService;
@@ -356,6 +357,52 @@ public interface AmbariManagementController {
RequestStatusResponse updateStacks() throws AmbariException;
/**
+ * Create a link between an extension and a stack
+ *
+ * @throws AmbariException if we fail to link the extension to the stack
+ */
+ public void createExtensionLink(ExtensionLinkRequest request) throws AmbariException;
+
+ /**
+ * Update a link between an extension and a stack
+ *
+ * @throws AmbariException if we fail to link the extension to the stack
+ */
+ public void updateExtensionLink(ExtensionLinkRequest request) throws AmbariException;
+
+ /**
+ * Update a link between an extension and a stack
+ *
+ * @throws AmbariException if we fail to link the extension to the stack
+ */
+ public void updateExtensionLink(ExtensionLinkEntity linkEntity) throws AmbariException;
+
+ /**
+ * Delete a link between an extension and a stack
+ *
+ * @throws AmbariException if we fail to unlink the extension from the stack
+ */
+ public void deleteExtensionLink(ExtensionLinkRequest request) throws AmbariException;
+
+ /**
+ * Get supported extensions.
+ *
+ * @param requests the extensions
+ * @return a set of extensions responses
+ * @throws AmbariException if the resources cannot be read
+ */
+ public Set<ExtensionResponse> getExtensions(Set<ExtensionRequest> requests) throws AmbariException;
+
+ /**
+ * Get supported extension versions.
+ *
+ * @param requests the extension versions
+ * @return a set of extension versions responses
+ * @throws AmbariException if the resources cannot be read
+ */
+ public Set<ExtensionVersionResponse> getExtensionVersions(Set<ExtensionVersionRequest> requests) throws AmbariException;
+
+ /**
* Get supported stacks versions.
*
* @param requests the stacks versions
@@ -366,7 +413,6 @@ public interface AmbariManagementController {
*/
Set<StackVersionResponse> getStackVersions(Set<StackVersionRequest> requests) throws AmbariException;
-
/**
* Get repositories by stack name, version and operating system.
*
@@ -431,7 +477,6 @@ public interface AmbariManagementController {
*/
Set<StackServiceComponentResponse> getStackComponents(Set<StackServiceComponentRequest> requests) throws AmbariException;
-
/**
* Get operating systems by stack name, version.
*
http://git-wip-us.apache.org/repos/asf/ambari/blob/300a7e21/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
index b5c6fc2..7dbb1ad 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
@@ -65,6 +65,8 @@ import java.util.TreeMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
+import javax.persistence.RollbackException;
+
import org.apache.ambari.server.AmbariException;
import org.apache.ambari.server.ClusterNotFoundException;
import org.apache.ambari.server.DuplicateResourceException;
@@ -102,14 +104,20 @@ import org.apache.ambari.server.metadata.ActionMetadata;
import org.apache.ambari.server.metadata.RoleCommandOrder;
import org.apache.ambari.server.orm.dao.ClusterDAO;
import org.apache.ambari.server.orm.dao.ClusterVersionDAO;
+import org.apache.ambari.server.orm.dao.ExtensionDAO;
+import org.apache.ambari.server.orm.dao.ExtensionLinkDAO;
import org.apache.ambari.server.orm.dao.RepositoryVersionDAO;
+import org.apache.ambari.server.orm.dao.StackDAO;
import org.apache.ambari.server.orm.dao.WidgetDAO;
import org.apache.ambari.server.orm.dao.WidgetLayoutDAO;
import org.apache.ambari.server.orm.entities.ClusterEntity;
import org.apache.ambari.server.orm.entities.ClusterVersionEntity;
+import org.apache.ambari.server.orm.entities.ExtensionEntity;
+import org.apache.ambari.server.orm.entities.ExtensionLinkEntity;
import org.apache.ambari.server.orm.entities.OperatingSystemEntity;
import org.apache.ambari.server.orm.entities.RepositoryEntity;
import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
+import org.apache.ambari.server.orm.entities.StackEntity;
import org.apache.ambari.server.orm.entities.WidgetEntity;
import org.apache.ambari.server.orm.entities.WidgetLayoutEntity;
import org.apache.ambari.server.orm.entities.WidgetLayoutUserWidgetEntity;
@@ -129,6 +137,8 @@ import org.apache.ambari.server.security.ldap.LdapBatchDto;
import org.apache.ambari.server.security.ldap.LdapSyncDto;
import org.apache.ambari.server.serveraction.kerberos.KerberosInvalidConfigurationException;
import org.apache.ambari.server.serveraction.kerberos.KerberosOperationException;
+import org.apache.ambari.server.stack.ExtensionHelper;
+import org.apache.ambari.server.stack.StackManager;
import org.apache.ambari.server.stageplanner.RoleGraph;
import org.apache.ambari.server.stageplanner.RoleGraphFactory;
import org.apache.ambari.server.state.Cluster;
@@ -139,6 +149,7 @@ import org.apache.ambari.server.state.Config;
import org.apache.ambari.server.state.ConfigFactory;
import org.apache.ambari.server.state.ConfigHelper;
import org.apache.ambari.server.state.DesiredConfig;
+import org.apache.ambari.server.state.ExtensionInfo;
import org.apache.ambari.server.state.Host;
import org.apache.ambari.server.state.HostComponentAdminState;
import org.apache.ambari.server.state.HostState;
@@ -166,6 +177,7 @@ import org.apache.ambari.server.state.configgroup.ConfigGroupFactory;
import org.apache.ambari.server.state.repository.VersionDefinitionXml;
import org.apache.ambari.server.state.scheduler.RequestExecutionFactory;
import org.apache.ambari.server.state.stack.RepositoryXml;
+import org.apache.ambari.server.state.stack.ServiceMetainfoXml;
import org.apache.ambari.server.state.stack.WidgetLayout;
import org.apache.ambari.server.state.stack.WidgetLayoutInfo;
import org.apache.ambari.server.state.svccomphost.ServiceComponentHostInstallEvent;
@@ -271,6 +283,13 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
private MaintenanceStateHelper maintenanceStateHelper;
+ @Inject
+ private ExtensionLinkDAO linkDAO;
+ @Inject
+ private ExtensionDAO extensionDAO;
+ @Inject
+ private StackDAO stackDAO;
+
/**
* The KerberosHelper to help setup for enabling for disabling Kerberos
*/
@@ -3783,6 +3802,94 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
}
@Override
+ public Set<ExtensionResponse> getExtensions(Set<ExtensionRequest> requests)
+ throws AmbariException {
+ Set<ExtensionResponse> response = new HashSet<ExtensionResponse>();
+ for (ExtensionRequest request : requests) {
+ try {
+ response.addAll(getExtensions(request));
+ } catch (StackAccessException e) {
+ if (requests.size() == 1) {
+ // only throw exception if 1 request.
+ // there will be > 1 request in case of OR predicate
+ throw e;
+ }
+ }
+ }
+ return response;
+
+ }
+
+
+ private Set<ExtensionResponse> getExtensions(ExtensionRequest request)
+ throws AmbariException {
+ Set<ExtensionResponse> response;
+
+ String extensionName = request.getExtensionName();
+
+ if (extensionName != null) {
+ // this will throw an exception if the extension doesn't exist
+ ambariMetaInfo.getExtensions(extensionName);
+ response = Collections.singleton(new ExtensionResponse(extensionName));
+ } else {
+ Collection<ExtensionInfo> supportedExtensions = ambariMetaInfo.getExtensions();
+ response = new HashSet<ExtensionResponse>();
+ for (ExtensionInfo extension: supportedExtensions) {
+ response.add(new ExtensionResponse(extension.getName()));
+ }
+ }
+ return response;
+ }
+
+ @Override
+ public Set<ExtensionVersionResponse> getExtensionVersions(
+ Set<ExtensionVersionRequest> requests) throws AmbariException {
+ Set<ExtensionVersionResponse> response = new HashSet<ExtensionVersionResponse>();
+ for (ExtensionVersionRequest request : requests) {
+ String extensionName = request.getExtensionName();
+ try {
+ Set<ExtensionVersionResponse> stackVersions = getExtensionVersions(request);
+ for (ExtensionVersionResponse stackVersionResponse : stackVersions) {
+ stackVersionResponse.setExtensionName(extensionName);
+ }
+ response.addAll(stackVersions);
+ } catch (StackAccessException e) {
+ if (requests.size() == 1) {
+ // only throw exception if 1 request.
+ // there will be > 1 request in case of OR predicate
+ throw e;
+ }
+ }
+ }
+
+ return response;
+ }
+
+ private Set<ExtensionVersionResponse> getExtensionVersions(ExtensionVersionRequest request) throws AmbariException {
+ Set<ExtensionVersionResponse> response;
+
+ String extensionName = request.getExtensionName();
+ String extensionVersion = request.getExtensionVersion();
+
+ if (extensionVersion != null) {
+ ExtensionInfo extensionInfo = ambariMetaInfo.getExtension(extensionName, extensionVersion);
+ response = Collections.singleton(extensionInfo.convertToResponse());
+ } else {
+ try {
+ Collection<ExtensionInfo> extensionInfos = ambariMetaInfo.getExtensions(extensionName);
+ response = new HashSet<ExtensionVersionResponse>();
+ for (ExtensionInfo extensionInfo: extensionInfos) {
+ response.add(extensionInfo.convertToResponse());
+ }
+ } catch (StackAccessException e) {
+ response = Collections.emptySet();
+ }
+ }
+
+ return response;
+ }
+
+ @Override
public Set<RepositoryResponse> getRepositories(Set<RepositoryRequest> requests)
throws AmbariException {
Set<RepositoryResponse> response = new HashSet<RepositoryResponse>();
@@ -4848,4 +4955,167 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
}
}
}
+
+ /**
+ * This method will delete a link between an extension version and a stack version (Extension Link).
+ *
+ * An extension version is like a stack version but it contains custom services. Linking an extension
+ * version to the current stack version allows the cluster to install the custom services contained in
+ * the extension version.
+ */
+ @Override
+ public void deleteExtensionLink(ExtensionLinkRequest request) throws AmbariException {
+ if (request.getLinkId() == null) {
+ throw new IllegalArgumentException("Link ID should be provided");
+ }
+ ExtensionLinkEntity linkEntity = null;
+ try {
+ linkEntity = linkDAO.findById(new Long(request.getLinkId()));
+ } catch (RollbackException e) {
+ throw new AmbariException("Unable to find extension link"
+ + ", linkId=" + request.getLinkId(), e);
+ }
+
+ StackInfo stackInfo = ambariMetaInfo.getStack(linkEntity.getStack().getStackName(), linkEntity.getStack().getStackVersion());
+
+ if (stackInfo == null)
+ throw new StackAccessException("stackName=" + linkEntity.getStack().getStackName() + ", stackVersion=" + linkEntity.getStack().getStackVersion());
+
+ ExtensionInfo extensionInfo = ambariMetaInfo.getExtension(linkEntity.getExtension().getExtensionName(), linkEntity.getExtension().getExtensionVersion());
+
+ if (extensionInfo == null)
+ throw new StackAccessException("extensionName=" + linkEntity.getExtension().getExtensionName() + ", extensionVersion=" + linkEntity.getExtension().getExtensionVersion());
+
+ ExtensionHelper.validateDeleteLink(getClusters(), stackInfo, extensionInfo);
+ ambariMetaInfo.getStackManager().unlinkStackAndExtension(stackInfo, extensionInfo);
+
+ try {
+ linkDAO.remove(linkEntity);
+ } catch (RollbackException e) {
+ throw new AmbariException("Unable to delete extension link"
+ + ", linkId=" + request.getLinkId()
+ + ", stackName=" + request.getStackName()
+ + ", stackVersion=" + request.getStackVersion()
+ + ", extensionName=" + request.getExtensionName()
+ + ", extensionVersion=" + request.getExtensionVersion(), e);
+ }
+ }
+
+ /**
+ * This method will create a link between an extension version and a stack version (Extension Link).
+ *
+ * An extension version is like a stack version but it contains custom services. Linking an extension
+ * version to the current stack version allows the cluster to install the custom services contained in
+ * the extension version.
+ */
+ @Override
+ public void createExtensionLink(ExtensionLinkRequest request) throws AmbariException {
+ validateCreateExtensionLinkRequest(request);
+
+ StackInfo stackInfo = ambariMetaInfo.getStack(request.getStackName(), request.getStackVersion());
+
+ if (stackInfo == null)
+ throw new StackAccessException("stackName=" + request.getStackName() + ", stackVersion=" + request.getStackVersion());
+
+ ExtensionInfo extensionInfo = ambariMetaInfo.getExtension(request.getExtensionName(), request.getExtensionVersion());
+
+ if (extensionInfo == null)
+ throw new StackAccessException("extensionName=" + request.getExtensionName() + ", extensionVersion=" + request.getExtensionVersion());
+
+ ExtensionHelper.validateCreateLink(stackInfo, extensionInfo);
+ ExtensionLinkEntity linkEntity = createExtensionLinkEntity(request);
+ ambariMetaInfo.getStackManager().linkStackToExtension(stackInfo, extensionInfo);
+
+ try {
+ linkDAO.create(linkEntity);
+ linkEntity = linkDAO.merge(linkEntity);
+ } catch (RollbackException e) {
+ String message = "Unable to create extension link";
+ LOG.debug(message, e);
+ String errorMessage = message
+ + ", stackName=" + request.getStackName()
+ + ", stackVersion=" + request.getStackVersion()
+ + ", extensionName=" + request.getExtensionName()
+ + ", extensionVersion=" + request.getExtensionVersion();
+ LOG.warn(errorMessage);
+ throw new AmbariException(errorMessage, e);
+ }
+ }
+
+ /**
+ * This method will update a link between an extension version and a stack version (Extension Link).
+ * Updating will only force ambari server to reread the stack and extension directories.
+ *
+ * An extension version is like a stack version but it contains custom services. Linking an extension
+ * version to the current stack version allows the cluster to install the custom services contained in
+ * the extension version.
+ */
+ @Override
+ public void updateExtensionLink(ExtensionLinkRequest request) throws AmbariException {
+ if (request.getLinkId() == null) {
+ throw new AmbariException("Link ID should be provided");
+ }
+ ExtensionLinkEntity linkEntity = null;
+ try {
+ linkEntity = linkDAO.findById(new Long(request.getLinkId()));
+ } catch (RollbackException e) {
+ throw new AmbariException("Unable to find extension link"
+ + ", linkId=" + request.getLinkId(), e);
+ }
+ updateExtensionLink(linkEntity);
+ }
+
+ /**
+ * This method will update a link between an extension version and a stack version (Extension Link).
+ * Updating will only force ambari server to reread the stack and extension directories.
+ *
+ * An extension version is like a stack version but it contains custom services. Linking an extension
+ * version to the current stack version allows the cluster to install the custom services contained in
+ * the extension version.
+ */
+ @Override
+ public void updateExtensionLink(ExtensionLinkEntity linkEntity) throws AmbariException {
+ StackInfo stackInfo = ambariMetaInfo.getStack(linkEntity.getStack().getStackName(), linkEntity.getStack().getStackVersion());
+
+ if (stackInfo == null)
+ throw new StackAccessException("stackName=" + linkEntity.getStack().getStackName() + ", stackVersion=" + linkEntity.getStack().getStackVersion());
+
+ ExtensionInfo extensionInfo = ambariMetaInfo.getExtension(linkEntity.getExtension().getExtensionName(), linkEntity.getExtension().getExtensionVersion());
+
+ if (extensionInfo == null)
+ throw new StackAccessException("extensionName=" + linkEntity.getExtension().getExtensionName() + ", extensionVersion=" + linkEntity.getExtension().getExtensionVersion());
+
+ ambariMetaInfo.getStackManager().linkStackToExtension(stackInfo, extensionInfo);
+ }
+
+ private void validateCreateExtensionLinkRequest(ExtensionLinkRequest request) throws AmbariException {
+ if (request.getStackName() == null
+ || request.getStackVersion() == null
+ || request.getExtensionName() == null
+ || request.getExtensionVersion() == null) {
+
+ throw new IllegalArgumentException("Stack name, stack version, extension name and extension version should be provided");
+ }
+
+ ExtensionLinkEntity entity = linkDAO.findByStackAndExtension(request.getStackName(), request.getStackVersion(),
+ request.getExtensionName(), request.getExtensionVersion());
+
+ if (entity != null) {
+ throw new AmbariException("The stack and extension are already linked"
+ + ", stackName=" + request.getStackName()
+ + ", stackVersion=" + request.getStackVersion()
+ + ", extensionName=" + request.getExtensionName()
+ + ", extensionVersion=" + request.getExtensionVersion());
+ }
+ }
+
+ private ExtensionLinkEntity createExtensionLinkEntity(ExtensionLinkRequest request) throws AmbariException {
+ StackEntity stack = stackDAO.find(request.getStackName(), request.getStackVersion());
+ ExtensionEntity extension = extensionDAO.find(request.getExtensionName(), request.getExtensionVersion());
+
+ ExtensionLinkEntity linkEntity = new ExtensionLinkEntity();
+ linkEntity.setStack(stack);
+ linkEntity.setExtension(extension);
+ return linkEntity;
+ }
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/300a7e21/ambari-server/src/main/java/org/apache/ambari/server/controller/ExtensionLinkRequest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/ExtensionLinkRequest.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/ExtensionLinkRequest.java
new file mode 100644
index 0000000..2c61de0
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/ExtensionLinkRequest.java
@@ -0,0 +1,86 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.controller;
+
+/**
+ * An extension version is like a stack version but it contains custom services. Linking an extension
+ * version to the current stack version allows the cluster to install the custom services contained in
+ * the extension version.
+ */
+public class ExtensionLinkRequest {
+
+ private String linkId;
+
+ private String stackName;
+
+ private String stackVersion;
+
+ private String extensionName;
+
+ private String extensionVersion;
+
+ public ExtensionLinkRequest(String linkId, String stackName, String stackVersion, String extensionName, String extensionVersion) {
+ this.setLinkId(linkId);
+ this.setStackName(stackName);
+ this.setStackVersion(stackVersion);
+ this.setExtensionName(extensionName);
+ this.setExtensionVersion(extensionVersion);
+ }
+
+ public String getLinkId() {
+ return linkId;
+ }
+
+ public void setLinkId(String linkId) {
+ this.linkId = linkId;
+ }
+
+ public String getStackName() {
+ return stackName;
+ }
+
+ public void setStackName(String stackName) {
+ this.stackName = stackName;
+ }
+
+ public String getStackVersion() {
+ return stackVersion;
+ }
+
+ public void setStackVersion(String stackVersion) {
+ this.stackVersion = stackVersion;
+ }
+
+ public String getExtensionName() {
+ return extensionName;
+ }
+
+ public void setExtensionName(String extensionName) {
+ this.extensionName = extensionName;
+ }
+
+ public String getExtensionVersion() {
+ return extensionVersion;
+ }
+
+ public void setExtensionVersion(String extensionVersion) {
+ this.extensionVersion = extensionVersion;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/300a7e21/ambari-server/src/main/java/org/apache/ambari/server/controller/ExtensionLinkResponse.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/ExtensionLinkResponse.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/ExtensionLinkResponse.java
new file mode 100644
index 0000000..df262b8
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/ExtensionLinkResponse.java
@@ -0,0 +1,124 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.controller;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.ambari.server.stack.Validable;
+
+/**
+ * An extension version is like a stack version but it contains custom services. Linking an extension
+ * version to the current stack version allows the cluster to install the custom services contained in
+ * the extension version.
+ */
+public class ExtensionLinkResponse implements Validable {
+
+ private String linkId;
+
+ private String stackName;
+
+ private String stackVersion;
+
+ private String extensionName;
+
+ private String extensionVersion;
+
+ private boolean valid;
+
+ private Set<String> errorSet = new HashSet<String>();
+
+ public ExtensionLinkResponse(String linkId, String stackName, String stackVersion, String extensionName,
+ String extensionVersion, boolean valid, Collection errorSet) {
+
+ setLinkId(linkId);
+ setStackName(stackName);
+ setStackVersion(stackVersion);
+ setExtensionName(extensionName);
+ setExtensionVersion(extensionVersion);
+ setValid(valid);
+ addErrors(errorSet);
+ }
+
+ public String getLinkId() {
+ return linkId;
+ }
+
+ public void setLinkId(String linkId) {
+ this.linkId = linkId;
+ }
+
+ public String getStackName() {
+ return stackName;
+ }
+
+ public void setStackName(String stackName) {
+ this.stackName = stackName;
+ }
+
+ public String getStackVersion() {
+ return stackVersion;
+ }
+
+ public void setStackVersion(String stackVersion) {
+ this.stackVersion = stackVersion;
+ }
+
+ public String getExtensionName() {
+ return extensionName;
+ }
+
+ public void setExtensionName(String extensionName) {
+ this.extensionName = extensionName;
+ }
+
+ public String getExtensionVersion() {
+ return extensionVersion;
+ }
+
+ public void setExtensionVersion(String extensionVersion) {
+ this.extensionVersion = extensionVersion;
+ }
+
+ @Override
+ public boolean isValid() {
+ return valid;
+ }
+
+ @Override
+ public void setValid(boolean valid) {
+ this.valid = valid;
+ }
+
+ @Override
+ public void addError(String error) {
+ errorSet.add(error);
+ }
+
+ @Override
+ public Collection<String> getErrors() {
+ return errorSet;
+ }
+
+ @Override
+ public void addErrors(Collection<String> errors) {
+ this.errorSet.addAll(errors);
+ }
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/300a7e21/ambari-server/src/main/java/org/apache/ambari/server/controller/ExtensionRequest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/ExtensionRequest.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/ExtensionRequest.java
new file mode 100644
index 0000000..f825c7b
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/ExtensionRequest.java
@@ -0,0 +1,43 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.controller;
+
+/**
+ * An extension version is like a stack version but it contains custom services. Linking an extension
+ * version to the current stack version allows the cluster to install the custom services contained in
+ * the extension version.
+ */
+public class ExtensionRequest {
+
+ public ExtensionRequest(String extensionName) {
+ this.setExtensionName(extensionName);
+
+ }
+
+ public String getExtensionName() {
+ return extensionName;
+ }
+
+ public void setExtensionName(String extensionName) {
+ this.extensionName = extensionName;
+ }
+
+ private String extensionName;
+
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/300a7e21/ambari-server/src/main/java/org/apache/ambari/server/controller/ExtensionResponse.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/ExtensionResponse.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/ExtensionResponse.java
new file mode 100644
index 0000000..50ab439
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/ExtensionResponse.java
@@ -0,0 +1,61 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.controller;
+
+/**
+ * An extension version is like a stack version but it contains custom services. Linking an extension
+ * version to the current stack version allows the cluster to install the custom services contained in
+ * the extension version.
+ */
+public class ExtensionResponse {
+
+ private String extensionName;
+
+ public ExtensionResponse(String extensionName) {
+ setExtensionName(extensionName);
+ }
+
+ public String getExtensionName() {
+ return extensionName;
+ }
+
+ public void setExtensionName(String extensionName) {
+ this.extensionName = extensionName;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 1;
+ result = 31 + getExtensionName().hashCode();
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof ExtensionResponse)) {
+ return false;
+ }
+ if (this == obj) {
+ return true;
+ }
+ ExtensionResponse extensionResponse = (ExtensionResponse) obj;
+ return getExtensionName().equals(extensionResponse.getExtensionName());
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/300a7e21/ambari-server/src/main/java/org/apache/ambari/server/controller/ExtensionVersionRequest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/ExtensionVersionRequest.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/ExtensionVersionRequest.java
new file mode 100644
index 0000000..32228f7
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/ExtensionVersionRequest.java
@@ -0,0 +1,44 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.ambari.server.controller;
+
+/**
+ * An extension version is like a stack version but it contains custom services. Linking an extension
+ * version to the current stack version allows the cluster to install the custom services contained in
+ * the extension version.
+ */
+public class ExtensionVersionRequest extends ExtensionRequest {
+
+ public ExtensionVersionRequest(String extensionName, String extensionVersion) {
+ super(extensionName);
+ setExtensionVersion(extensionVersion);
+ }
+
+ public String getExtensionVersion() {
+ return extensionVersion;
+ }
+
+ public void setExtensionVersion(String extensionVersion) {
+ this.extensionVersion = extensionVersion;
+ }
+
+ private String extensionVersion;
+
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/300a7e21/ambari-server/src/main/java/org/apache/ambari/server/controller/ExtensionVersionResponse.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/ExtensionVersionResponse.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/ExtensionVersionResponse.java
new file mode 100644
index 0000000..bf2db5c
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/ExtensionVersionResponse.java
@@ -0,0 +1,101 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.controller;
+
+import java.io.File;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.ambari.server.stack.Validable;
+
+/**
+ * An extension version is like a stack version but it contains custom services. Linking an extension
+ * version to the current stack version allows the cluster to install the custom services contained in
+ * the extension version.
+ */
+public class ExtensionVersionResponse implements Validable{
+
+ private String extensionName;
+ private String extensionVersion;
+ private boolean valid;
+ private String parentVersion;
+
+ public ExtensionVersionResponse(String extensionVersion, String parentVersion,
+ boolean valid, Collection errorSet) {
+ setExtensionVersion(extensionVersion);
+ setParentVersion(parentVersion);
+ setValid(valid);
+ addErrors(errorSet);
+ }
+
+ @Override
+ public boolean isValid() {
+ return valid;
+ }
+
+ @Override
+ public void setValid(boolean valid) {
+ this.valid = valid;
+ }
+
+ private Set<String> errorSet = new HashSet<String>();
+
+ @Override
+ public void addError(String error) {
+ errorSet.add(error);
+ }
+
+ @Override
+ public Collection<String> getErrors() {
+ return errorSet;
+ }
+
+ @Override
+ public void addErrors(Collection<String> errors) {
+ this.errorSet.addAll(errors);
+ }
+
+
+ public String getExtensionName() {
+ return extensionName;
+ }
+
+ public void setExtensionName(String extensionName) {
+ this.extensionName = extensionName;
+ }
+
+ public String getExtensionVersion() {
+ return extensionVersion;
+ }
+
+ public void setExtensionVersion(String extensionVersion) {
+ this.extensionVersion = extensionVersion;
+ }
+
+ public String getParentVersion() {
+ return parentVersion;
+ }
+
+ public void setParentVersion(String parentVersion) {
+ this.parentVersion = parentVersion;
+ }
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/300a7e21/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 3721113..b26814a 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
@@ -173,6 +173,12 @@ public abstract class AbstractControllerResourceProvider extends AbstractAuthori
return new StackConfigurationDependencyResourceProvider(propertyIds, keyPropertyIds, managementController);
case StackLevelConfiguration:
return new StackLevelConfigurationResourceProvider(propertyIds, keyPropertyIds, managementController);
+ case ExtensionLink:
+ return new ExtensionLinkResourceProvider(propertyIds, keyPropertyIds, managementController);
+ case Extension:
+ return new ExtensionResourceProvider(propertyIds, keyPropertyIds, managementController);
+ case ExtensionVersion:
+ return new ExtensionVersionResourceProvider(propertyIds, keyPropertyIds, managementController);
case RootService:
return new RootServiceResourceProvider(propertyIds, keyPropertyIds, managementController);
case RootServiceComponent:
http://git-wip-us.apache.org/repos/asf/ambari/blob/300a7e21/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/Extension.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/Extension.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/Extension.java
new file mode 100644
index 0000000..682adb8
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/Extension.java
@@ -0,0 +1,282 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.controller.internal;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.controller.AmbariManagementController;
+import org.apache.ambari.server.orm.entities.ExtensionEntity;
+import org.apache.ambari.server.state.AutoDeployInfo;
+import org.apache.ambari.server.state.ComponentInfo;
+import org.apache.ambari.server.state.DependencyInfo;
+import org.apache.ambari.server.state.PropertyInfo;
+import org.apache.ambari.server.topology.Cardinality;
+import org.apache.ambari.server.topology.Configuration;
+
+/**
+ * Encapsulates extension information.
+ *
+ * An extension version is like a stack version but it contains custom services. Linking an extension
+ * version to the current stack version allows the cluster to install the custom services contained in
+ * the extension version.
+ */
+public class Extension {
+ /**
+ * Extension name
+ */
+ private String name;
+
+ /**
+ * Extension version
+ */
+ private String version;
+
+ /**
+ * Map of service name to components
+ */
+ private Map<String, Collection<String>> serviceComponents =
+ new HashMap<String, Collection<String>>();
+
+ /**
+ * Map of component to service
+ */
+ private Map<String, String> componentService = new HashMap<String, String>();
+
+ /**
+ * Map of component to dependencies
+ */
+ private Map<String, Collection<DependencyInfo>> dependencies =
+ new HashMap<String, Collection<DependencyInfo>>();
+
+ /**
+ * Map of dependency to conditional service
+ */
+ private Map<DependencyInfo, String> dependencyConditionalServiceMap =
+ new HashMap<DependencyInfo, String>();
+
+ /**
+ * Map of database component name to configuration property which indicates whether
+ * the database in to be managed or if it is an external non-managed instance.
+ * If the value of the config property starts with 'New', the database is determined
+ * to be managed, otherwise it is non-managed.
+ */
+ private Map<String, String> dbDependencyInfo = new HashMap<String, String>();
+
+ /**
+ * Map of component to required cardinality
+ */
+ private Map<String, String> cardinalityRequirements = new HashMap<String, String>();
+
+ /**
+ * Map of component to auto-deploy information
+ */
+ private Map<String, AutoDeployInfo> componentAutoDeployInfo =
+ new HashMap<String, AutoDeployInfo>();
+
+ /**
+ * Ambari Management Controller, used to obtain Extension definitions
+ */
+ private final AmbariManagementController controller;
+
+
+ /**
+ * Constructor.
+ *
+ * @param extension
+ * the extension (not {@code null}).
+ * @param ambariManagementController
+ * the management controller (not {@code null}).
+ * @throws AmbariException
+ */
+ public Extension(ExtensionEntity extension, AmbariManagementController ambariManagementController) throws AmbariException {
+ this(extension.getExtensionName(), extension.getExtensionVersion(), ambariManagementController);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param name extension name
+ * @param version extension version
+ *
+ * @throws AmbariException an exception occurred getting extension information
+ * for the specified name and version
+ */
+ //todo: don't pass management controller in constructor
+ public Extension(String name, String version, AmbariManagementController controller) throws AmbariException {
+ this.name = name;
+ this.version = version;
+ this.controller = controller;
+ }
+
+ /**
+ * Obtain extension name.
+ *
+ * @return extension name
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Obtain extension version.
+ *
+ * @return extension version
+ */
+ public String getVersion() {
+ return version;
+ }
+
+
+ Map<DependencyInfo, String> getDependencyConditionalServiceMap() {
+ return dependencyConditionalServiceMap;
+ }
+
+ /**
+ * Get services contained in the extension.
+ *
+ * @return collection of all services for the extension
+ */
+ public Collection<String> getServices() {
+ return serviceComponents.keySet();
+ }
+
+ /**
+ * Get components contained in the extension for the specified service.
+ *
+ * @param service service name
+ *
+ * @return collection of component names for the specified service
+ */
+ public Collection<String> getComponents(String service) {
+ return serviceComponents.get(service);
+ }
+
+ /**
+ * Get all service components
+ *
+ * @return map of service to associated components
+ */
+ public Map<String, Collection<String>> getComponents() {
+ Map<String, Collection<String>> serviceComponents = new HashMap<String, Collection<String>>();
+ for (String service : getServices()) {
+ Collection<String> components = new HashSet<String>();
+ components.addAll(getComponents(service));
+ serviceComponents.put(service, components);
+ }
+ return serviceComponents;
+ }
+
+ /**
+ * Get info for the specified component.
+ *
+ * @param component component name
+ *
+ * @return component information for the requested component
+ * or null if the component doesn't exist in the extension
+ */
+ public ComponentInfo getComponentInfo(String component) {
+ ComponentInfo componentInfo = null;
+ String service = getServiceForComponent(component);
+ if (service != null) {
+ try {
+ componentInfo = controller.getAmbariMetaInfo().getComponent(
+ getName(), getVersion(), service, component);
+ } catch (AmbariException e) {
+ // just return null if component doesn't exist
+ }
+ }
+ return componentInfo;
+ }
+
+ /**
+ * Get the service for the specified component.
+ *
+ * @param component component name
+ *
+ * @return service name that contains tha specified component
+ */
+ public String getServiceForComponent(String component) {
+ return componentService.get(component);
+ }
+
+ /**
+ * Get the names of the services which contains the specified components.
+ *
+ * @param components collection of components
+ *
+ * @return collection of services which contain the specified components
+ */
+ public Collection<String> getServicesForComponents(Collection<String> components) {
+ Set<String> services = new HashSet<String>();
+ for (String component : components) {
+ services.add(getServiceForComponent(component));
+ }
+
+ return services;
+ }
+
+ /**
+ * Return the dependencies specified for the given component.
+ *
+ * @param component component to get dependency information for
+ *
+ * @return collection of dependency information for the specified component
+ */
+ //todo: full dependency graph
+ public Collection<DependencyInfo> getDependenciesForComponent(String component) {
+ return dependencies.containsKey(component) ? dependencies.get(component) :
+ Collections.<DependencyInfo>emptySet();
+ }
+
+ /**
+ * Get the service, if any, that a component dependency is conditional on.
+ *
+ * @param dependency dependency to get conditional service for
+ *
+ * @return conditional service for provided component or null if dependency
+ * is not conditional on a service
+ */
+ public String getConditionalServiceForDependency(DependencyInfo dependency) {
+ return dependencyConditionalServiceMap.get(dependency);
+ }
+
+ public String getExternalComponentConfig(String component) {
+ return dbDependencyInfo.get(component);
+ }
+
+ /**
+ * Obtain the required cardinality for the specified component.
+ */
+ public Cardinality getCardinality(String component) {
+ return new Cardinality(cardinalityRequirements.get(component));
+ }
+
+ /**
+ * Obtain auto-deploy information for the specified component.
+ */
+ public AutoDeployInfo getAutoDeployInfo(String component) {
+ return componentAutoDeployInfo.get(component);
+ }
+}