You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by di...@apache.org on 2016/01/11 20:15:39 UTC
[03/13] ambari git commit: AMBARI-12885: Dynamic stack extensions -
install and upgrade support for custom services (tthorpe via dili)
http://git-wip-us.apache.org/repos/asf/ambari/blob/647929db/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
index 6c56a85..ebf82eb 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
@@ -24,6 +24,24 @@ CREATE TABLE stack(
PRIMARY KEY (stack_id)
);
+CREATE TABLE extension(
+ extension_id BIGINT NOT NULL,
+ extension_name VARCHAR(255) NOT NULL,
+ extension_version VARCHAR(255) NOT NULL,
+ PRIMARY KEY (extension_id),
+ CONSTRAINT unq_extension UNIQUE(extension_name, extension_version)
+);
+
+CREATE TABLE extensionlink(
+ link_id BIGINT NOT NULL,
+ stack_id BIGINT NOT NULL,
+ extension_id BIGINT NOT NULL,
+ PRIMARY KEY (link_id),
+ FOREIGN KEY (stack_id) REFERENCES stack(stack_id),
+ FOREIGN KEY (extension_id) REFERENCES extension(extension_id),
+ CONSTRAINT unq_extension_link UNIQUE(stack_id, extension_id)
+);
+
CREATE TABLE clusters (
cluster_id BIGINT NOT NULL,
resource_id BIGINT NOT NULL,
@@ -104,10 +122,21 @@ CREATE TABLE cluster_version (
user_name VARCHAR(32),
PRIMARY KEY (id));
+CREATE TABLE cluster_extension_version (
+ id BIGINT NOT NULL,
+ repo_version_id BIGINT NOT NULL,
+ cluster_id BIGINT NOT NULL,
+ state VARCHAR(32) NOT NULL,
+ start_time BIGINT NOT NULL,
+ end_time BIGINT,
+ user_name VARCHAR(32),
+ PRIMARY KEY (id));
+
CREATE TABLE hostcomponentdesiredstate (
cluster_id BIGINT NOT NULL,
component_name VARCHAR(255) NOT NULL,
desired_stack_id BIGINT NOT NULL,
+ desired_extension_id BIGINT,
desired_state VARCHAR(255) NOT NULL,
host_id BIGINT NOT NULL,
service_name VARCHAR(255) NOT NULL,
@@ -124,6 +153,7 @@ CREATE TABLE hostcomponentstate (
component_name VARCHAR(255) NOT NULL,
version VARCHAR(32) NOT NULL DEFAULT 'UNKNOWN',
current_stack_id BIGINT NOT NULL,
+ current_extension_id BIGINT,
current_state VARCHAR(255) NOT NULL,
host_id BIGINT NOT NULL,
service_name VARCHAR(255) NOT NULL,
@@ -170,6 +200,13 @@ CREATE TABLE host_version (
state VARCHAR(32) NOT NULL,
PRIMARY KEY (id));
+CREATE TABLE host_extension_version (
+ id BIGINT NOT NULL,
+ repo_version_id BIGINT NOT NULL,
+ host_id BIGINT NOT NULL,
+ state VARCHAR(32) NOT NULL,
+ PRIMARY KEY (id));
+
CREATE TABLE servicecomponentdesiredstate (
component_name VARCHAR(255) NOT NULL,
cluster_id BIGINT NOT NULL,
@@ -550,7 +587,19 @@ CREATE TABLE repo_version (
version VARCHAR(255) NOT NULL,
display_name VARCHAR(128) NOT NULL,
repositories TEXT NOT NULL,
- PRIMARY KEY(repo_version_id)
+ PRIMARY KEY(repo_version_id),
+ FOREIGN KEY (stack_id) REFERENCES stack(stack_id)
+);
+
+CREATE TABLE extension_repo_version (
+ repo_version_id BIGINT NOT NULL,
+ extension_id BIGINT NOT NULL,
+ version VARCHAR(255) NOT NULL,
+ display_name VARCHAR(128) NOT NULL,
+ upgrade_package VARCHAR(255) NOT NULL,
+ repositories TEXT NOT NULL,
+ PRIMARY KEY repo_version_id),
+ FOREIGN KEY (extension_id) REFERENCES extension(extension_id)
);
CREATE TABLE widget (
@@ -676,6 +725,8 @@ ALTER TABLE clusterconfigmapping ADD CONSTRAINT clusterconfigmappingcluster_id F
ALTER TABLE clusterstate ADD CONSTRAINT FK_clusterstate_cluster_id FOREIGN KEY (cluster_id) REFERENCES clusters (cluster_id);
ALTER TABLE cluster_version ADD CONSTRAINT FK_cluster_version_cluster_id FOREIGN KEY (cluster_id) REFERENCES clusters (cluster_id);
ALTER TABLE cluster_version ADD CONSTRAINT FK_cluster_version_repovers_id FOREIGN KEY (repo_version_id) REFERENCES repo_version (repo_version_id);
+ALTER TABLE cluster_extension_version ADD CONSTRAINT FK_cluster_extension_version_cluster_id FOREIGN KEY (cluster_id) REFERENCES clusters (cluster_id);
+ALTER TABLE cluster_extension_version ADD CONSTRAINT FK_cluster_extension_version_repovers_id FOREIGN KEY (repo_version_id) REFERENCES extension_repo_version (repo_version_id);
ALTER TABLE hostcomponentdesiredstate ADD CONSTRAINT FK_hcdesiredstate_host_id FOREIGN KEY (host_id) REFERENCES hosts (host_id);
ALTER TABLE hostcomponentdesiredstate ADD CONSTRAINT hstcmpnntdesiredstatecmpnntnme FOREIGN KEY (component_name, cluster_id, service_name) REFERENCES servicecomponentdesiredstate (component_name, cluster_id, service_name);
ALTER TABLE hostcomponentstate ADD CONSTRAINT hstcomponentstatecomponentname FOREIGN KEY (component_name, cluster_id, service_name) REFERENCES servicecomponentdesiredstate (component_name, cluster_id, service_name);
@@ -683,6 +734,8 @@ ALTER TABLE hostcomponentstate ADD CONSTRAINT FK_hostcomponentstate_host_id FORE
ALTER TABLE hoststate ADD CONSTRAINT FK_hoststate_host_id FOREIGN KEY (host_id) REFERENCES hosts (host_id);
ALTER TABLE host_version ADD CONSTRAINT FK_host_version_host_id FOREIGN KEY (host_id) REFERENCES hosts (host_id);
ALTER TABLE host_version ADD CONSTRAINT FK_host_version_repovers_id FOREIGN KEY (repo_version_id) REFERENCES repo_version (repo_version_id);
+ALTER TABLE host_extension_version ADD CONSTRAINT FK_host_extension_version_host_id FOREIGN KEY (host_id) REFERENCES hosts (host_id);
+ALTER TABLE host_extension_version ADD CONSTRAINT FK_host_extension_version_repovers_id FOREIGN KEY (repo_version_id) REFERENCES extension_repo_version (repo_version_id);
ALTER TABLE servicecomponentdesiredstate ADD CONSTRAINT srvccmponentdesiredstatesrvcnm FOREIGN KEY (service_name, cluster_id) REFERENCES clusterservices (service_name, cluster_id);
ALTER TABLE servicedesiredstate ADD CONSTRAINT servicedesiredstateservicename FOREIGN KEY (service_name, cluster_id) REFERENCES clusterservices (service_name, cluster_id);
ALTER TABLE execution_command ADD CONSTRAINT FK_execution_command_task_id FOREIGN KEY (task_id) REFERENCES host_role_command (task_id);
@@ -746,11 +799,15 @@ ALTER TABLE clusterconfig ADD CONSTRAINT FK_clusterconfig_stack_id FOREIGN KEY (
ALTER TABLE serviceconfig ADD CONSTRAINT FK_serviceconfig_stack_id FOREIGN KEY (stack_id) REFERENCES stack(stack_id);
ALTER TABLE clusterstate ADD CONSTRAINT FK_cs_current_stack_id FOREIGN KEY (current_stack_id) REFERENCES stack(stack_id);
ALTER TABLE hostcomponentdesiredstate ADD CONSTRAINT FK_hcds_desired_stack_id FOREIGN KEY (desired_stack_id) REFERENCES stack(stack_id);
+ALTER TABLE hostcomponentdesiredstate ADD CONSTRAINT FK_hcds_desired_extension_id FOREIGN KEY (desired_extension_id) REFERENCES extension(extension_id);
ALTER TABLE hostcomponentstate ADD CONSTRAINT FK_hcs_current_stack_id FOREIGN KEY (current_stack_id) REFERENCES stack(stack_id);
+ALTER TABLE hostcomponentstate ADD CONSTRAINT FK_hcs_current_extension_id FOREIGN KEY (current_extension_id) REFERENCES extension(extension_id);
ALTER TABLE servicecomponentdesiredstate ADD CONSTRAINT FK_scds_desired_stack_id FOREIGN KEY (desired_stack_id) REFERENCES stack(stack_id);
ALTER TABLE servicedesiredstate ADD CONSTRAINT FK_sds_desired_stack_id FOREIGN KEY (desired_stack_id) REFERENCES stack(stack_id);
ALTER TABLE blueprint ADD CONSTRAINT FK_blueprint_stack_id FOREIGN KEY (stack_id) REFERENCES stack(stack_id);
ALTER TABLE repo_version ADD CONSTRAINT FK_repoversion_stack_id FOREIGN KEY (stack_id) REFERENCES stack(stack_id);
+ALTER TABLE extensionlink ADD CONSTRAINT FK_extensionlink_stack_id FOREIGN KEY (stack_id) REFERENCES stack(stack_id);
+ALTER TABLE extensionlink ADD CONSTRAINT FK_extensionlink_extension_id FOREIGN KEY (extension_id) REFERENCES extension(extension_id);
-- Kerberos
CREATE TABLE kerberos_principal (
@@ -984,10 +1041,16 @@ INSERT INTO ambari_sequences (sequence_name, sequence_value)
union all
select 'repo_version_id_seq', 0
union all
+ select 'extension_repo_version_id_seq', 0
+ union all
select 'cluster_version_id_seq', 0
union all
select 'host_version_id_seq', 0
union all
+ select 'cluster_extension_version_id_seq', 0
+ union all
+ select 'host_extension_version_id_seq', 0
+ union all
select 'service_config_id_seq', 1
union all
select 'upgrade_id_seq', 0
@@ -1002,6 +1065,10 @@ INSERT INTO ambari_sequences (sequence_name, sequence_value)
union all
select 'stack_id_seq', 0
union all
+ select 'extension_id_seq', 0
+ union all
+ select 'link_id_seq', 0
+ union all
select 'topology_host_info_id_seq', 0
union all
select 'topology_host_request_id_seq', 0
http://git-wip-us.apache.org/repos/asf/ambari/blob/647929db/ambari-server/src/main/resources/META-INF/persistence.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/META-INF/persistence.xml b/ambari-server/src/main/resources/META-INF/persistence.xml
index 3979bc0..1f85931 100644
--- a/ambari-server/src/main/resources/META-INF/persistence.xml
+++ b/ambari-server/src/main/resources/META-INF/persistence.xml
@@ -25,6 +25,7 @@
<class>org.apache.ambari.server.orm.entities.ClusterConfigEntity</class>
<class>org.apache.ambari.server.orm.entities.ClusterConfigMappingEntity</class>
<class>org.apache.ambari.server.orm.entities.ClusterEntity</class>
+ <class>org.apache.ambari.server.orm.entities.ClusterExtensionVersionEntity</class>
<class>org.apache.ambari.server.orm.entities.ClusterServiceEntity</class>
<class>org.apache.ambari.server.orm.entities.ClusterStateEntity</class>
<class>org.apache.ambari.server.orm.entities.ClusterVersionEntity</class>
@@ -32,11 +33,15 @@
<class>org.apache.ambari.server.orm.entities.ConfigGroupEntity</class>
<class>org.apache.ambari.server.orm.entities.ConfigGroupHostMappingEntity</class>
<class>org.apache.ambari.server.orm.entities.ExecutionCommandEntity</class>
+ <class>org.apache.ambari.server.orm.entities.ExtensionEntity</class>
+ <class>org.apache.ambari.server.orm.entities.ExtensionLinkEntity</class>
+ <class>org.apache.ambari.server.orm.entities.ExtensionRepositoryVersionEntity</class>
<class>org.apache.ambari.server.orm.entities.GroupEntity</class>
<class>org.apache.ambari.server.orm.entities.HostComponentDesiredStateEntity</class>
<class>org.apache.ambari.server.orm.entities.HostComponentStateEntity</class>
<class>org.apache.ambari.server.orm.entities.HostConfigMappingEntity</class>
<class>org.apache.ambari.server.orm.entities.HostEntity</class>
+ <class>org.apache.ambari.server.orm.entities.HostExtensionVersionEntity</class>
<class>org.apache.ambari.server.orm.entities.HostGroupComponentEntity</class>
<class>org.apache.ambari.server.orm.entities.HostGroupConfigEntity</class>
<class>org.apache.ambari.server.orm.entities.HostGroupEntity</class>
http://git-wip-us.apache.org/repos/asf/ambari/blob/647929db/ambari-server/src/main/resources/common-services/AMBARI_METRICS/0.1.0/metainfo.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/common-services/AMBARI_METRICS/0.1.0/metainfo.xml b/ambari-server/src/main/resources/common-services/AMBARI_METRICS/0.1.0/metainfo.xml
index 66d3f52..4c33dfd 100644
--- a/ambari-server/src/main/resources/common-services/AMBARI_METRICS/0.1.0/metainfo.xml
+++ b/ambari-server/src/main/resources/common-services/AMBARI_METRICS/0.1.0/metainfo.xml
@@ -31,6 +31,7 @@
<category>MASTER</category>
<cardinality>1</cardinality>
<versionAdvertised>false</versionAdvertised>
+ <setupHA>true</setupHA>
<timelineAppid>AMS-HBASE</timelineAppid>
<dependencies>
<dependency>
http://git-wip-us.apache.org/repos/asf/ambari/blob/647929db/ambari-server/src/main/resources/common-services/HBASE/0.96.0.2.0/metainfo.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/common-services/HBASE/0.96.0.2.0/metainfo.xml b/ambari-server/src/main/resources/common-services/HBASE/0.96.0.2.0/metainfo.xml
index 78aca3d..2d14e97 100644
--- a/ambari-server/src/main/resources/common-services/HBASE/0.96.0.2.0/metainfo.xml
+++ b/ambari-server/src/main/resources/common-services/HBASE/0.96.0.2.0/metainfo.xml
@@ -32,6 +32,7 @@
<category>MASTER</category>
<cardinality>1+</cardinality>
<versionAdvertised>true</versionAdvertised>
+ <setupHA>true</setupHA>
<timelineAppid>HBASE</timelineAppid>
<dependencies>
<dependency>
http://git-wip-us.apache.org/repos/asf/ambari/blob/647929db/ambari-server/src/main/resources/common-services/HDFS/2.1.0.2.0/metainfo.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/common-services/HDFS/2.1.0.2.0/metainfo.xml b/ambari-server/src/main/resources/common-services/HDFS/2.1.0.2.0/metainfo.xml
index b678e51..b1f6836 100644
--- a/ambari-server/src/main/resources/common-services/HDFS/2.1.0.2.0/metainfo.xml
+++ b/ambari-server/src/main/resources/common-services/HDFS/2.1.0.2.0/metainfo.xml
@@ -147,6 +147,7 @@
<!-- TODO: cardinality is conditional on HA topology -->
<cardinality>0+</cardinality>
<versionAdvertised>false</versionAdvertised>
+ <notValuable>true</notValuable>
<commandScript>
<script>scripts/zkfc_slave.py</script>
<scriptType>PYTHON</scriptType>
http://git-wip-us.apache.org/repos/asf/ambari/blob/647929db/ambari-server/src/main/resources/common-services/ZOOKEEPER/3.4.5.2.0/metainfo.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/common-services/ZOOKEEPER/3.4.5.2.0/metainfo.xml b/ambari-server/src/main/resources/common-services/ZOOKEEPER/3.4.5.2.0/metainfo.xml
index 4d14725..7486b98 100644
--- a/ambari-server/src/main/resources/common-services/ZOOKEEPER/3.4.5.2.0/metainfo.xml
+++ b/ambari-server/src/main/resources/common-services/ZOOKEEPER/3.4.5.2.0/metainfo.xml
@@ -31,6 +31,8 @@
<category>MASTER</category>
<cardinality>1+</cardinality>
<versionAdvertised>true</versionAdvertised>
+ <setupHA>true</setupHA>
+ <idealMinimum>3</idealMinimum>
<commandScript>
<script>scripts/zookeeper_server.py</script>
<scriptType>PYTHON</scriptType>
http://git-wip-us.apache.org/repos/asf/ambari/blob/647929db/ambari-server/src/main/resources/key_properties.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/key_properties.json b/ambari-server/src/main/resources/key_properties.json
index 46a6cf9..8665907 100644
--- a/ambari-server/src/main/resources/key_properties.json
+++ b/ambari-server/src/main/resources/key_properties.json
@@ -79,13 +79,58 @@
"StackService": "StackServiceComponents/service_name",
"StackServiceComponent": "StackServiceComponents/component_name"
},
- "StackServiceComponentDependency": {
+ "StackServiceComponentDependency": {
"Stack": "Dependencies/stack_name",
"StackVersion": "Dependencies/stack_version",
"StackService": "Dependencies/dependent_service_name",
"StackServiceComponent": "Dependencies/dependent_component_name",
"StackServiceComponentDependency": "Dependencies/component_name"
},
+ "ExtensionLink": {
+ "ExtensionLink": "ExtensionLink/link_id",
+ "Stack": "ExtensionLink/stack_name",
+ "StackVersion": "ExtensionLink/stack_version",
+ "Extension": "ExtensionLink/extension_name",
+ "ExtensionVersion": "ExtensionLink/extension_version"
+ },
+ "Extension": {
+ "Extension": "Extensions/extension_name"
+ },
+ "ExtensionVersion": {
+ "Extension": "Versions/extension_name",
+ "ExtensionVersion": "Versions/extension_version"
+ },
+ "ExtensionService": {
+ "Extension": "ExtensionServices/extension_name",
+ "ExtensionVersion": "ExtensionServices/extension_version",
+ "ExtensionService": "ExtensionServices/service_name"
+ },
+ "ExtensionConfiguration": {
+ "Extension": "ExtensionConfigurations/extension_name",
+ "ExtensionVersion": "ExtensionConfigurations/extension_version",
+ "ExtensionService": "ExtensionConfigurations/service_name",
+ "ExtensionConfiguration": "ExtensionConfigurations/property_name"
+ },
+ "ExtensionConfigurationDependency": {
+ "Extension": "ExtensionConfigurationDependency/extension_name",
+ "ExtensionVersion": "ExtensionConfigurationDependency/extension_version",
+ "ExtensionService": "ExtensionConfigurationDependency/service_name",
+ "ExtensionConfiguration": "ExtensionConfigurationDependency/property_name",
+ "ExtensionConfigurationDependency": "ExtensionConfigurationDependency/dependency_name"
+ },
+ "ExtensionServiceComponent": {
+ "Extension": "ExtensionServiceComponents/extension_name",
+ "ExtensionVersion": "ExtensionServiceComponents/extension_version",
+ "ExtensionService": "ExtensionServiceComponents/service_name",
+ "ExtensionServiceComponent": "ExtensionServiceComponents/component_name"
+ },
+ "ExtensionServiceComponentDependency": {
+ "Extension": "Dependencies/extension_name",
+ "ExtensionVersion": "Dependencies/extension_version",
+ "ExtensionService": "Dependencies/dependent_service_name",
+ "ExtensionServiceComponent": "Dependencies/dependent_component_name",
+ "ExtensionServiceComponentDependency": "Dependencies/component_name"
+ },
"DRFeed": {
"DRFeed": "Feed/name"
},
@@ -148,6 +193,11 @@
"StackVersion": "StackLevelConfigurations/stack_version",
"StackLevelConfiguration": "StackLevelConfigurations/property_name"
},
+ "ExtensionLevelConfiguration": {
+ "Extension": "ExtensionLevelConfigurations/extension_name",
+ "ExtensionVersion": "ExtensionLevelConfigurations/extension_version",
+ "ExtensionLevelConfiguration": "ExtensionLevelConfigurations/property_name"
+ },
"KerberosDescriptor": {
"KerberosDescriptor": "KerberosDescriptors/kerberos_descriptor_name"
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/647929db/ambari-server/src/main/resources/properties.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/properties.json b/ambari-server/src/main/resources/properties.json
index 4052ad2..d3c4b57 100644
--- a/ambari-server/src/main/resources/properties.json
+++ b/ambari-server/src/main/resources/properties.json
@@ -255,6 +255,87 @@
"auto_deploy/enabled",
"auto_deploy/location"
],
+ "ExtensionLink": [
+ "ExtensionLink/link_id",
+ "ExtensionLink/stack_name",
+ "ExtensionLink/stack_version",
+ "ExtensionLink/extension_name",
+ "ExtensionLink/extension_version",
+ "_"
+ ],
+ "Extension":[
+ "Extensions/extension_name",
+ "_"
+ ],
+ "ExtensionVersion":[
+ "Versions/extension_name",
+ "Versions/extension_version",
+ "Versions/min_upgrade_version",
+ "Versions/active",
+ "Versions/valid",
+ "Versions/extension-errors",
+ "Versions/parent_extension_version",
+ "Versions/config_types",
+ "Versions/upgrade_packs",
+ "_"
+ ],
+ "ExtensionService":[
+ "ExtensionServices/extension_name",
+ "ExtensionServices/extension_version",
+ "ExtensionServices/service_name",
+ "ExtensionServices/display_name",
+ "ExtensionServices/user_name",
+ "ExtensionServices/comments",
+ "ExtensionServices/service_version",
+ "ExtensionServices/config_types",
+ "ExtensionServices/service_check_supported",
+ "ExtensionServices/custom_commands",
+ "ExtensionServices/required_services",
+ "_"
+ ],
+ "ExtensionConfiguration":[
+ "ExtensionConfigurations/extension_name",
+ "ExtensionConfigurations/extension_version",
+ "ExtensionConfigurations/service_name",
+ "ExtensionConfigurations/property_name",
+ "ExtensionConfigurations/property_value",
+ "ExtensionConfigurations/property_value_attributes",
+ "ExtensionConfigurations/property_depends_on",
+ "ExtensionConfigurations/property_description",
+ "ExtensionConfigurations/property_display_name",
+ "ExtensionConfigurations/type",
+ "ExtensionConfigurations/final",
+ "ExtensionConfigurations/adding_forbidden",
+ "ExtensionConfigurations/do_not_extend",
+ "ExtensionConfigurations/property_type",
+ "_"
+ ],
+ "ExtensionServiceComponent":[
+ "ExtensionServiceComponents/extension_name",
+ "ExtensionServiceComponents/extension_version",
+ "ExtensionServiceComponents/service_name",
+ "ExtensionServiceComponents/component_name",
+ "ExtensionServiceComponents/display_name",
+ "ExtensionServiceComponents/component_category",
+ "ExtensionServiceComponents/is_client",
+ "ExtensionServiceComponents/is_master",
+ "ExtensionServiceComponents/cardinality",
+ "ExtensionServiceComponents/custom_commands",
+ "auto_deploy/enabled",
+ "auto_deploy/location",
+ "_"
+ ],
+ "ExtensionServiceComponentDependency" :[
+ "Dependencies/extension_name",
+ "Dependencies/extension_version",
+ "Dependencies/dependent_service_name",
+ "Dependencies/dependent_component_name",
+ "Dependencies/service_name",
+ "Dependencies/component_name",
+ "Dependencies/scope",
+ "auto_deploy/enabled",
+ "auto_deploy/location"
+ ],
"DRFeed":[
"Feed/name",
"Feed/description",
@@ -458,10 +539,32 @@
"StackConfigurationDependency/dependency_name",
"_"
],
- "KerberosDescriptor":[
- "KerberosDescriptors/kerberos_descriptor_name",
- "KerberosDescriptors/kerberos_descriptor_text",
- "_"
- ]
+ "ExtensionLevelConfiguration":[
+ "ExtensionLevelConfigurations/extension_name",
+ "ExtensionLevelConfigurations/extension_version",
+ "ExtensionLevelConfigurations/property_name",
+ "ExtensionLevelConfigurations/property_value",
+ "ExtensionLevelConfigurations/property_value_attributes",
+ "ExtensionLevelConfigurations/property_depends_on",
+ "ExtensionLevelConfigurations/property_description",
+ "ExtensionLevelConfigurations/type",
+ "ExtensionLevelConfigurations/final",
+ "ExtensionLevelConfigurations/property_type",
+ "_"
+ ],
+ "ExtensionConfigurationDependency":[
+ "ExtensionConfigurationDependency/extension_name",
+ "ExtensionConfigurationDependency/extension_version",
+ "ExtensionConfigurationDependency/service_name",
+ "ExtensionConfigurationDependency/property_name",
+ "ExtensionConfigurationDependency/dependency_type",
+ "ExtensionConfigurationDependency/dependency_name",
+ "_"
+ ],
+ "KerberosDescriptor":[
+ "KerberosDescriptors/kerberos_descriptor_name",
+ "KerberosDescriptors/kerberos_descriptor_text",
+ "_"
+ ]
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/647929db/ambari-server/src/main/resources/scripts/stack_layout_advisor.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/scripts/stack_layout_advisor.py b/ambari-server/src/main/resources/scripts/stack_layout_advisor.py
new file mode 100644
index 0000000..80c87f1
--- /dev/null
+++ b/ambari-server/src/main/resources/scripts/stack_layout_advisor.py
@@ -0,0 +1,147 @@
+#!/usr/bin/env ambari-python-wrap
+
+'''
+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.
+'''
+
+import json
+import os
+import sys
+import traceback
+
+RECOMMEND_COMPONENT_LAYOUT_ACTION = 'recommend-component-layout'
+VALIDATE_COMPONENT_LAYOUT_ACTION = 'validate-component-layout'
+
+ALL_ACTIONS = [RECOMMEND_COMPONENT_LAYOUT_ACTION,
+ VALIDATE_COMPONENT_LAYOUT_ACTION]
+USAGE = "Usage: <action> <hosts_file> <services_file>\nPossible actions are: {0}\n".format( str(ALL_ACTIONS) )
+
+SCRIPT_DIRECTORY = os.path.dirname(os.path.abspath(__file__))
+STACK_LAYOUT_ADVISOR_PATH_TEMPLATE = os.path.join(SCRIPT_DIRECTORY, '../stacks/stack_advisor.py')
+STACK_LAYOUT_ADVISOR_DEFAULT_IMPL_CLASS = 'DefaultStackLayoutAdvisor'
+STACK_LAYOUT_ADVISOR_IMPL_PATH_TEMPLATE = os.path.join(SCRIPT_DIRECTORY, './../stacks/stack_layout_advisor.py')
+STACK_LAYOUT_ADVISOR_IMPL_CLASS_TEMPLATE = '{0}{1}StackAdvisor'
+
+
+class StackAdvisorException(Exception):
+ pass
+
+def loadJson(path):
+ try:
+ with open(path, 'r') as f:
+ return json.load(f)
+ except Exception, err:
+ raise StackAdvisorException("File not found at: {0}".format(path))
+
+
+def dumpJson(json_object, dump_file):
+ try:
+ with open(dump_file, 'w') as out:
+ json.dump(json_object, out, indent=1)
+ except Exception, err:
+ raise StackAdvisorException("Can not write to file {0} : {1}".format(dump_file, str(err)))
+
+
+def main(argv=None):
+ args = argv[1:]
+
+ if len(args) < 3:
+ sys.stderr.write(USAGE)
+ sys.exit(2)
+ pass
+
+ action = args[0]
+ if action not in ALL_ACTIONS:
+ sys.stderr.write(USAGE)
+ sys.exit(2)
+ pass
+
+ hostsFile = args[1]
+ servicesFile = args[2]
+
+ # Parse hostsFile and servicesFile
+ hosts = loadJson(hostsFile)
+ services = loadJson(servicesFile)
+
+ # Instantiate StackAdvisor and call action related method
+ stackName = services["Versions"]["stack_name"]
+ stackVersion = services["Versions"]["stack_version"]
+ parentVersions = []
+ if "stack_hierarchy" in services["Versions"]:
+ parentVersions = services["Versions"]["stack_hierarchy"]["stack_versions"]
+
+ stackAdvisor = instantiateStackAdvisor(stackName, stackVersion, parentVersions)
+
+ # Perform action
+ actionDir = os.path.realpath(os.path.dirname(args[1]))
+ result = {}
+ result_file = "non_valid_result_file.json"
+
+ if action == RECOMMEND_COMPONENT_LAYOUT_ACTION:
+ result = stackAdvisor.recommendComponentLayout(services, hosts)
+ result_file = os.path.join(actionDir, "component-layout.json")
+ elif action == VALIDATE_COMPONENT_LAYOUT_ACTION:
+ result = stackAdvisor.validateComponentLayout(services, hosts)
+ result_file = os.path.join(actionDir, "component-layout-validation.json")
+
+ dumpJson(result, result_file)
+ pass
+
+
+def instantiateStackAdvisor(stackName, stackVersion, parentVersions):
+ """Instantiates StackAdvisor implementation for the specified Stack"""
+ import imp
+
+ with open(STACK_LAYOUT_ADVISOR_PATH_TEMPLATE, 'rb') as fp:
+ default_stack_advisor = imp.load_module('stack_layout_advisor', fp, STACK_LAYOUT_ADVISOR_PATH_TEMPLATE, ('.py', 'rb', imp.PY_SOURCE))
+ className = STACK_LAYOUT_ADVISOR_DEFAULT_IMPL_CLASS
+ stack_advisor = default_stack_advisor
+
+ #versions = [stackVersion]
+ #versions.extend(parentVersions)
+
+ #for version in reversed(versions):
+ # try:
+ # path = STACK_LAYOUT_ADVISOR_IMPL_PATH_TEMPLATE.format(stackName, version)
+
+ # with open(path, 'rb') as fp:
+ # stack_advisor = imp.load_module('stack_advisor_impl', fp, path, ('.py', 'rb', imp.PY_SOURCE))
+ # className = STACK_LAYOUT_ADVISOR_IMPL_CLASS_TEMPLATE.format(stackName, version.replace('.', ''))
+ # print "StackAdvisor implementation for stack {0}, version {1} was loaded".format(stackName, version)
+ # except Exception:
+ # print "StackAdvisor implementation for stack {0}, version {1} was not found".format(stackName, version)
+
+ try:
+ clazz = getattr(stack_advisor, className)
+ print "Returning " + className + " implementation"
+ return clazz()
+ except Exception, e:
+ print "Returning default implementation"
+ return default_stack_advisor.DefaultStackAdvisor()
+
+
+if __name__ == '__main__':
+ try:
+ main(sys.argv)
+ except StackAdvisorException as stack_exception:
+ traceback.print_exc()
+ print "Error occured in stack advisor.\nError details: {0}".format(str(stack_exception))
+ sys.exit(1)
+ except Exception as e:
+ traceback.print_exc()
+ print "Error occured in stack advisor.\nError details: {0}".format(str(e))
+ sys.exit(2)
http://git-wip-us.apache.org/repos/asf/ambari/blob/647929db/ambari-server/src/main/resources/stacks/HDP/2.3/services/HBASE/metainfo.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.3/services/HBASE/metainfo.xml b/ambari-server/src/main/resources/stacks/HDP/2.3/services/HBASE/metainfo.xml
index 90a31f5..5de9c7d 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.3/services/HBASE/metainfo.xml
+++ b/ambari-server/src/main/resources/stacks/HDP/2.3/services/HBASE/metainfo.xml
@@ -29,6 +29,7 @@
<category>SLAVE</category>
<cardinality>0+</cardinality>
<versionAdvertised>true</versionAdvertised>
+ <useCardinalityForLayout>true</useCardinalityForLayout>
<commandScript>
<script>scripts/phoenix_queryserver.py</script>
<scriptType>PYTHON</scriptType>
http://git-wip-us.apache.org/repos/asf/ambari/blob/647929db/ambari-server/src/main/resources/stacks/HDP/2.3/services/HDFS/metainfo.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.3/services/HDFS/metainfo.xml b/ambari-server/src/main/resources/stacks/HDP/2.3/services/HDFS/metainfo.xml
index ca69195..4d2a7a2 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.3/services/HDFS/metainfo.xml
+++ b/ambari-server/src/main/resources/stacks/HDP/2.3/services/HDFS/metainfo.xml
@@ -28,6 +28,7 @@
<displayName>NFSGateway</displayName>
<cardinality>0+</cardinality>
<versionAdvertised>false</versionAdvertised>
+ <useCardinalityForLayout>true</useCardinalityForLayout>
<category>SLAVE</category>
<commandScript>
<script>scripts/nfsgateway.py</script>
http://git-wip-us.apache.org/repos/asf/ambari/blob/647929db/ambari-server/src/main/resources/stacks/stack_advisor.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/stack_advisor.py b/ambari-server/src/main/resources/stacks/stack_advisor.py
index d993feb..d5ef10c 100644
--- a/ambari-server/src/main/resources/stacks/stack_advisor.py
+++ b/ambari-server/src/main/resources/stacks/stack_advisor.py
@@ -439,7 +439,7 @@ class DefaultStackAdvisor(StackAdvisor):
pass
def isComponentUsingCardinalityForLayout(self, componentName):
- return False
+ return self.getComponentAttribute(component, "use_cardinality_for_layout")
def createValidationResponse(self, services, validationItems):
"""Returns array of Validation objects about issues with hostnames components assigned to"""
@@ -607,9 +607,7 @@ class DefaultStackAdvisor(StackAdvisor):
return componentName in masters
def isComponentNotValuable(self, component):
- componentName = self.getComponentName(component)
- service = self.getNotValuableComponents()
- return componentName in service
+ return self.getComponentAttribute(component, "not_valuable")
def getMinComponentCount(self, component):
componentName = self.getComponentName(component)
@@ -643,9 +641,7 @@ class DefaultStackAdvisor(StackAdvisor):
return self.getComponentAttribute(component, "component_name")
def isComponentNotPreferableOnAmbariServerHost(self, component):
- componentName = self.getComponentName(component)
- service = self.getNotPreferableOnServerComponents()
- return componentName in service
+ return self.getComponentAttribute(component, "not_preferable_on_server_components")
def isHostSuitableForComponent(self, host, component):
return not (self.isComponentNotPreferableOnAmbariServerHost(component) and self.isLocalHost(host))
@@ -656,9 +652,6 @@ class DefaultStackAdvisor(StackAdvisor):
def getNotValuableComponents(self):
return []
- def getNotPreferableOnServerComponents(self):
- return []
-
def getCardinalitiesDict(self):
return {}
http://git-wip-us.apache.org/repos/asf/ambari/blob/647929db/ambari-server/src/main/resources/stacks/stack_layout_advisor.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/stack_layout_advisor.py b/ambari-server/src/main/resources/stacks/stack_layout_advisor.py
new file mode 100644
index 0000000..1f65d70
--- /dev/null
+++ b/ambari-server/src/main/resources/stacks/stack_layout_advisor.py
@@ -0,0 +1,449 @@
+#!/usr/bin/env ambari-python-wrap
+"""
+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.
+"""
+
+import socket
+import re
+
+class StackLayoutAdvisor(object):
+ """
+ Abstract class implemented by all stack layout advisors. Stack layout advisors advise on stack specific questions.
+
+ Currently stack layout advisors provide following abilities:
+ - Recommend where services should be installed in cluster
+ - Validate user selection of where services are installed on cluster
+
+ Each of the above methods is passed in parameters about services and hosts involved as described below.
+
+ @type services: dictionary
+ @param services: Dictionary containing all information about services selected by the user.
+ Example: {
+ "services": [
+ {
+ "StackServices": {
+ "service_name" : "HDFS",
+ "service_version" : "2.6.0.2.2",
+ },
+ "components" : [
+ {
+ "StackServiceComponents" : {
+ "cardinality" : "1+",
+ "component_category" : "SLAVE",
+ "component_name" : "DATANODE",
+ "display_name" : "DataNode",
+ "service_name" : "HDFS",
+ "hostnames" : []
+ },
+ "dependencies" : []
+ }, {
+ "StackServiceComponents" : {
+ "cardinality" : "1-2",
+ "component_category" : "MASTER",
+ "component_name" : "NAMENODE",
+ "display_name" : "NameNode",
+ "service_name" : "HDFS",
+ "hostnames" : []
+ },
+ "dependencies" : []
+ },
+ ...
+ ]
+ },
+ ...
+ ]
+ }
+ @type hosts: dictionary
+ @param hosts: Dictionary containing all information about hosts in this cluster
+ Example: {
+ "items": [
+ {
+ Hosts: {
+ "host_name": "c6401.ambari.apache.org",
+ "public_host_name" : "c6401.ambari.apache.org",
+ "ip": "192.168.1.101",
+ "cpu_count" : 1,
+ "disk_info" : [
+ {
+ "available" : "4564632",
+ "used" : "5230344",
+ "percent" : "54%",
+ "size" : "10319160",
+ "type" : "ext4",
+ "mountpoint" : "/"
+ },
+ {
+ "available" : "1832436",
+ "used" : "0",
+ "percent" : "0%",
+ "size" : "1832436",
+ "type" : "tmpfs",
+ "mountpoint" : "/dev/shm"
+ }
+ ],
+ "host_state" : "HEALTHY",
+ "os_arch" : "x86_64",
+ "os_type" : "centos6",
+ "total_mem" : 3664872
+ }
+ },
+ ...
+ ]
+ }
+
+ Each of the methods can either return recommendations or validations.
+
+ Recommendations are made in a Ambari Blueprints friendly format.
+ Validations are an array of validation objects.
+ """
+
+ def recommendComponentLayout(self, services, hosts):
+ """
+ Returns recommendation of which hosts various service components should be installed on.
+
+ This function takes as input all details about services being installed, and hosts
+ they are being installed into, to generate hostname assignments to various components
+ of each service.
+
+ @type services: dictionary
+ @param services: Dictionary containing all information about services selected by the user.
+ @type hosts: dictionary
+ @param hosts: Dictionary containing all information about hosts in this cluster
+ @rtype: dictionary
+ @return: Layout recommendation of service components on cluster hosts in Ambari Blueprints friendly format.
+ Example: {
+ "resources" : [
+ {
+ "hosts" : [
+ "c6402.ambari.apache.org",
+ "c6401.ambari.apache.org"
+ ],
+ "services" : [
+ "HDFS"
+ ],
+ "recommendations" : {
+ "blueprint" : {
+ "host_groups" : [
+ {
+ "name" : "host-group-2",
+ "components" : [
+ { "name" : "JOURNALNODE" },
+ { "name" : "ZKFC" },
+ { "name" : "DATANODE" },
+ { "name" : "SECONDARY_NAMENODE" }
+ ]
+ },
+ {
+ "name" : "host-group-1",
+ "components" : [
+ { "name" : "HDFS_CLIENT" },
+ { "name" : "NAMENODE" },
+ { "name" : "JOURNALNODE" },
+ { "name" : "ZKFC" },
+ { "name" : "DATANODE" }
+ ]
+ }
+ ]
+ },
+ "blueprint_cluster_binding" : {
+ "host_groups" : [
+ {
+ "name" : "host-group-1",
+ "hosts" : [ { "fqdn" : "c6401.ambari.apache.org" } ]
+ },
+ {
+ "name" : "host-group-2",
+ "hosts" : [ { "fqdn" : "c6402.ambari.apache.org" } ]
+ }
+ ]
+ }
+ }
+ }
+ ]
+ }
+ """
+ pass
+
+ def validateComponentLayout(self, services, hosts):
+ """
+ Returns array of Validation issues with service component layout on hosts
+
+ This function takes as input all details about services being installed along with
+ hosts the components are being installed on (hostnames property is populated for
+ each component).
+
+ @type services: dictionary
+ @param services: Dictionary containing information about services and host layout selected by the user.
+ @type hosts: dictionary
+ @param hosts: Dictionary containing all information about hosts in this cluster
+ @rtype: dictionary
+ @return: Dictionary containing array of validation items
+ Example: {
+ "items": [
+ {
+ "type" : "host-group",
+ "level" : "ERROR",
+ "message" : "NameNode and Secondary NameNode should not be hosted on the same machine",
+ "component-name" : "NAMENODE",
+ "host" : "c6401.ambari.apache.org"
+ },
+ ...
+ ]
+ }
+ """
+ pass
+
+
+
+
+
+
+class DefaultStackLayoutAdvisor(StackLayoutAdvisor):
+ """
+ Default stack layout advisor implementation.
+
+ This implementation is used when a stack-version, or its hierarchy does not
+ have an advisor. Stack-versions can extend this class to provide their own
+ implementation
+ """
+
+ def recommendComponentLayout(self, services, hosts):
+ """Returns Services object with hostnames array populated for components"""
+
+ stackName = services["Versions"]["stack_name"]
+ stackVersion = services["Versions"]["stack_version"]
+ hostsList = [host["Hosts"]["host_name"] for host in hosts["items"]]
+ servicesList = [service["StackServices"]["service_name"] for service in services["services"]]
+
+ layoutRecommendations = self.createComponentLayoutRecommendations(services, hosts)
+
+ recommendations = {
+ "Versions": {"stack_name": stackName, "stack_version": stackVersion},
+ "hosts": hostsList,
+ "services": servicesList,
+ "recommendations": layoutRecommendations
+ }
+
+ return recommendations
+
+ def createComponentLayoutRecommendations(self, services, hosts):
+
+ recommendations = {
+ "blueprint": {
+ "host_groups": [ ]
+ },
+ "blueprint_cluster_binding": {
+ "host_groups": [ ]
+ }
+ }
+
+ hostsList = [host["Hosts"]["host_name"] for host in hosts["items"]]
+
+ hostsComponentsMap = {}
+ for hostName in hostsList:
+ if hostName not in hostsComponentsMap:
+ hostsComponentsMap[hostName] = []
+
+ #extend 'hostsComponentsMap' with MASTER components
+ for service in services["services"]:
+ masterComponents = [component for component in service["components"] if self.isMasterComponent(component)]
+ for component in masterComponents:
+ componentName = component["StackServiceComponents"]["component_name"]
+
+ if self.isComponentHostsPopulated(component):
+ hostsForComponent = component["StackServiceComponents"]["hostnames"]
+ else:
+
+ if len(hostsList) > 1 and self.isMasterComponentWithMultipleInstances(component):
+ hostsCount = self.getMinComponentCount(component)
+ if hostsCount > 1: # get first 'hostsCount' available hosts
+ hostsForComponent = []
+ hostIndex = 0
+ while hostsCount > len(hostsForComponent) and hostIndex < len(hostsList):
+ currentHost = hostsList[hostIndex]
+ if self.isHostSuitableForComponent(currentHost, component):
+ hostsForComponent.append(currentHost)
+ hostIndex += 1
+ else:
+ hostsForComponent = [self.getHostForComponent(component, hostsList)]
+ else:
+ hostsForComponent = [self.getHostForComponent(component, hostsList)]
+
+ #extend 'hostsComponentsMap' with 'hostsForComponent'
+ for hostName in hostsForComponent:
+ hostsComponentsMap[hostName].append( { "name":componentName } )
+ #extend 'hostsComponentsMap' with Slave and Client Components
+ componentsListList = [service["components"] for service in services["services"]]
+ componentsList = [item for sublist in componentsListList for item in sublist]
+ usedHostsListList = [component["StackServiceComponents"]["hostnames"] for component in componentsList if not self.isComponentNotValuable(component)]
+ utilizedHosts = [item for sublist in usedHostsListList for item in sublist]
+ freeHosts = [hostName for hostName in hostsList if hostName not in utilizedHosts]
+
+ for service in services["services"]:
+ slaveClientComponents = [component for component in service["components"]
+ if self.isSlaveComponent(component) or self.isClientComponent(component)]
+ for component in slaveClientComponents:
+ componentName = component["StackServiceComponents"]["component_name"]
+
+ if component["StackServiceComponents"]["cardinality"] == "ALL":
+ hostsForComponent = hostsList
+ else:
+ componentIsPopulated = self.isComponentHostsPopulated(component)
+ if componentIsPopulated:
+ hostsForComponent = component["StackServiceComponents"]["hostnames"]
+ else:
+ hostsForComponent = []
+
+ if self.isSlaveComponent(component):
+ cardinality = str(component["StackServiceComponents"]["cardinality"])
+ if self.isComponentUsingCardinalityForLayout(component) and cardinality:
+ # cardinality types: 1+, 1-2, 1, ALL
+ if "+" in cardinality:
+ hostsMin = int(cardinality[:-1])
+ elif "-" in cardinality:
+ nums = cardinality.split("-")
+ hostsMin = int(nums[0])
+ else:
+ hostsMin = int(cardinality)
+ if hostsMin > len(hostsForComponent):
+ hostsForComponent.extend(freeHosts[0:hostsMin-len(hostsForComponent)])
+ else:
+ hostsForComponent.extend(freeHosts)
+ if not hostsForComponent: # hostsForComponent is empty
+ hostsForComponent = hostsList[-1:]
+ hostsForComponent = list(set(hostsForComponent)) # removing duplicates
+ elif self.isClientComponent(component) and not componentIsPopulated:
+ hostsForComponent = freeHosts[0:1]
+ if not hostsForComponent: # hostsForComponent is empty
+ hostsForComponent = hostsList[-1:]
+
+ #extend 'hostsComponentsMap' with 'hostsForComponent'
+ for hostName in hostsForComponent:
+ if hostName not in hostsComponentsMap:
+ hostsComponentsMap[hostName] = []
+ hostsComponentsMap[hostName].append( { "name": componentName } )
+
+ #prepare 'host-group's from 'hostsComponentsMap'
+ host_groups = recommendations["blueprint"]["host_groups"]
+ bindings = recommendations["blueprint_cluster_binding"]["host_groups"]
+ index = 0
+ for key in hostsComponentsMap.keys():
+ index += 1
+ host_group_name = "host-group-{0}".format(index)
+ host_groups.append( { "name": host_group_name, "components": hostsComponentsMap[key] } )
+ bindings.append( { "name": host_group_name, "hosts": [{ "fqdn": key }] } )
+
+ return recommendations
+ pass
+
+ def isComponentUsingCardinalityForLayout(self, componentName):
+ return self.getComponentAttribute(component, "use_cardinality_for_layout")
+
+ def createValidationResponse(self, services, validationItems):
+ """Returns array of Validation objects about issues with hostnames components assigned to"""
+ stackName = services["Versions"]["stack_name"]
+ stackVersion = services["Versions"]["stack_version"]
+
+ validations = {
+ "Versions": {"stack_name": stackName, "stack_version": stackVersion},
+ "items": validationItems
+ }
+
+ return validations
+
+ def validateComponentLayout(self, services, hosts):
+ """Returns array of Validation objects about issues with hostnames components assigned to"""
+ validationItems = self.getComponentLayoutValidations(services, hosts)
+ return self.createValidationResponse(services, validationItems)
+
+ def getComponentLayoutValidations(self, services, hosts):
+ return []
+
+ def getConfigurationClusterSummary(self, servicesList, hosts, components, services):
+ pass
+
+ # Recommendation helper methods
+ def isComponentHostsPopulated(self, component):
+ hostnames = self.getComponentAttribute(component, "hostnames")
+ if hostnames is not None:
+ return len(hostnames) > 0
+ return False
+
+ def isClientComponent(self, component):
+ return self.getComponentAttribute(component, "component_category") == 'CLIENT'
+
+ def isSlaveComponent(self, component):
+ return self.getComponentAttribute(component, "component_category") == 'SLAVE'
+
+ def isMasterComponent(self, component):
+ return self.getComponentAttribute(component, "is_master")
+
+ def getComponentAttribute(self, component, attribute):
+ serviceComponent = component.get("StackServiceComponents", None)
+ if serviceComponent is None:
+ return None
+ return serviceComponent.get(attribute, None)
+
+ def isLocalHost(self, hostName):
+ return socket.getfqdn(hostName) == socket.getfqdn()
+
+ def isMasterComponentWithMultipleInstances(self, component):
+ return self.getComponentAttribute(component, "setup_ha")
+
+ def isComponentNotValuable(self, component):
+ return self.getComponentAttribute(component, "not_valuable")
+
+ def getMinComponentCount(self, component):
+ min = self.getComponentAttribute(component, "ideal_minimum")
+ if min is not None:
+ return min
+ return 1
+
+ def getHostForComponent(self, component, hostsList):
+ componentName = self.getComponentName(component)
+ print(componentName)
+
+ if len(hostsList) != 1:
+ scheme = self.getComponentAttribute(component, "layout")
+ if scheme is not None:
+ print(scheme)
+ entry = scheme['else']
+ print(entry)
+ hostIndex = next((index for key, index in scheme.iteritems() if isinstance(key, ( int, long )) and len(hostsList) < key), scheme['else'])
+ else:
+ hostIndex = 0
+ for host in hostsList[hostIndex:]:
+ if self.isHostSuitableForComponent(host, component):
+ return host
+ return hostsList[0]
+
+ def getComponentName(self, component):
+ return self.getComponentAttribute(component, "component_name")
+
+ def isComponentNotPreferableOnAmbariServerHost(self, component):
+ return self.getComponentAttribute(component, "not_preferable_on_server_components")
+
+ def isHostSuitableForComponent(self, host, component):
+ return not (self.isComponentNotPreferableOnAmbariServerHost(component) and self.isLocalHost(host))
+
+ def getComponentHostNames(self, servicesDict, serviceName, componentName):
+ for service in servicesDict["services"]:
+ if service["StackServices"]["service_name"] == serviceName:
+ for component in service['components']:
+ if component["StackServiceComponents"]["component_name"] == componentName:
+ return component["StackServiceComponents"]["hostnames"]
+ pass
http://git-wip-us.apache.org/repos/asf/ambari/blob/647929db/ambari-server/src/test/java/org/apache/ambari/server/api/services/ExtensionsServiceTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/services/ExtensionsServiceTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/services/ExtensionsServiceTest.java
new file mode 100644
index 0000000..0989207
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/services/ExtensionsServiceTest.java
@@ -0,0 +1,215 @@
+/**
+ * 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 org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.services.parsers.RequestBodyParser;
+import org.apache.ambari.server.api.services.serializers.ResultSerializer;
+import org.easymock.EasyMock;
+import org.junit.Test;
+
+
+import javax.ws.rs.PathParam;
+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 java.lang.reflect.Method;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.List;
+
+
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.notNull;
+import static org.easymock.EasyMock.same;
+import static org.junit.Assert.assertEquals;
+
+/**
+* Unit tests for ExtensionsService.
+*/
+public class ExtensionsServiceTest extends BaseServiceTest {
+
+ @Override
+ public List<ServiceTestInvocation> getTestInvocations() throws Exception {
+ List<ServiceTestInvocation> listInvocations = new ArrayList<ServiceTestInvocation>();
+
+ // getExtension
+ ExtensionsService service = new TestExtensionsService("extensionName", null);
+ Method m = service.getClass().getMethod("getExtension", String.class, HttpHeaders.class, UriInfo.class, String.class);
+ Object[] args = new Object[] {null, getHttpHeaders(), getUriInfo(), "extensionName"};
+ listInvocations.add(new ServiceTestInvocation(Request.Type.GET, service, m, args, null));
+
+ //getExtensions
+ service = new TestExtensionsService(null, null);
+ m = service.getClass().getMethod("getExtensions", String.class, HttpHeaders.class, UriInfo.class);
+ args = new Object[] {null, getHttpHeaders(), getUriInfo()};
+ listInvocations.add(new ServiceTestInvocation(Request.Type.GET, service, m, args, null));
+
+ // getExtensionVersion
+ service = new TestExtensionsService("extensionName", "extensionVersion");
+ m = service.getClass().getMethod("getExtensionVersion", String.class, HttpHeaders.class, UriInfo.class, String.class, String.class);
+ args = new Object[] {null, getHttpHeaders(), getUriInfo(), "extensionName", "extensionVersion"};
+ listInvocations.add(new ServiceTestInvocation(Request.Type.GET, service, m, args, null));
+
+ // getExtensionVersions
+ service = new TestExtensionsService("extensionName", null);
+ m = service.getClass().getMethod("getExtensionVersions", String.class, HttpHeaders.class, UriInfo.class, String.class);
+ args = new Object[] {null, getHttpHeaders(), getUriInfo(), "extensionName"};
+ listInvocations.add(new ServiceTestInvocation(Request.Type.GET, service, m, args, null));
+
+ // getExtensionService
+ service = new TestExtensionsService("extensionName", null);
+ m = service.getClass().getMethod("getExtensionService", String.class, HttpHeaders.class, UriInfo.class, String.class,
+ String.class, String.class);
+ args = new Object[] {null, getHttpHeaders(), getUriInfo(), "extensionName", "extensionVersion", "service-name"};
+ listInvocations.add(new ServiceTestInvocation(Request.Type.GET, service, m, args, null));
+
+ // getExtensionServices
+ service = new TestExtensionsService("extensionName", null);
+ m = service.getClass().getMethod("getExtensionServices", String.class, HttpHeaders.class, UriInfo.class, String.class, String.class);
+ args = new Object[] {null, getHttpHeaders(), getUriInfo(), "extensionName", "extensionVersion"};
+ listInvocations.add(new ServiceTestInvocation(Request.Type.GET, service, m, args, null));
+
+ // getExtensionConfiguration
+ service = new TestExtensionsService("extensionName", "extensionVersion");
+ m = service.getClass().getMethod("getExtensionConfiguration", String.class, HttpHeaders.class, UriInfo.class,
+ String.class, String.class, String.class, String.class);
+ args = new Object[] {null, getHttpHeaders(), getUriInfo(), "extensionName", "extensionVersion", "service-name", "property-name"};
+ listInvocations.add(new ServiceTestInvocation(Request.Type.GET, service, m, args, null));
+
+ // getExtensionConfigurations
+ service = new TestExtensionsService("extensionName", null);
+ m = service.getClass().getMethod("getExtensionConfigurations", String.class, HttpHeaders.class, UriInfo.class,
+ String.class, String.class, String.class);
+ args = new Object[] {null, getHttpHeaders(), getUriInfo(), "extensionName", "extensionVersion", "service-name"};
+ listInvocations.add(new ServiceTestInvocation(Request.Type.GET, service, m, args, null));
+
+ // getServiceComponent
+ service = new TestExtensionsService("extensionName", "extensionVersion");
+ m = service.getClass().getMethod("getServiceComponent", String.class, HttpHeaders.class, UriInfo.class,
+ String.class, String.class, String.class, String.class);
+ args = new Object[] {null, getHttpHeaders(), getUriInfo(), "extensionName", "extensionVersion", "service-name", "component-name"};
+ listInvocations.add(new ServiceTestInvocation(Request.Type.GET, service, m, args, null));
+
+ // getServiceComponents
+ service = new TestExtensionsService("extensionName", "extensionVersion");
+ m = service.getClass().getMethod("getServiceComponents", String.class, HttpHeaders.class, UriInfo.class,
+ String.class, String.class, String.class);
+ args = new Object[] {null, getHttpHeaders(), getUriInfo(), "extensionName", "extensionVersion", "service-name"};
+ listInvocations.add(new ServiceTestInvocation(Request.Type.GET, service, m, args, null));
+
+ //get extension artifacts
+ service = new TestExtensionsService("extensionName", null);
+ m = service.getClass().getMethod("getExtensionArtifacts", String.class, HttpHeaders.class, UriInfo.class, String.class, String.class);
+ args = new Object[] {null, getHttpHeaders(), getUriInfo(), "extensionName", "extensionVersion"};
+ listInvocations.add(new ServiceTestInvocation(Request.Type.GET, service, m, args, null));
+
+ //get extension artifact
+ service = new TestExtensionsService("extensionName", null);
+ m = service.getClass().getMethod("getExtensionArtifact", String.class, HttpHeaders.class, UriInfo.class, String.class,
+ String.class, String.class);
+ args = new Object[] {null, getHttpHeaders(), getUriInfo(), "extensionName", "extensionVersion", "artifact-name"};
+ listInvocations.add(new ServiceTestInvocation(Request.Type.GET, service, m, args, null));
+
+ //get extension service artifacts
+ service = new TestExtensionsService("extensionName", "extensionVersion");
+ m = service.getClass().getMethod("getExtensionServiceArtifacts", String.class, HttpHeaders.class, UriInfo.class,
+ String.class, String.class, String.class);
+ args = new Object[] {null, getHttpHeaders(), getUriInfo(), "extensionName", "extensionVersion", "service-name"};
+ listInvocations.add(new ServiceTestInvocation(Request.Type.GET, service, m, args, null));
+
+ //get extension service artifact
+ service = new TestExtensionsService("extensionName", "extensionVersion");
+ m = service.getClass().getMethod("getExtensionServiceArtifact", String.class, HttpHeaders.class, UriInfo.class,
+ String.class, String.class, String.class, String.class);
+ args = new Object[] {null, getHttpHeaders(), getUriInfo(), "extensionName", "extensionVersion", "service-name", "artifact-name"};
+ listInvocations.add(new ServiceTestInvocation(Request.Type.GET, service, m, args, null));
+
+ return listInvocations;
+ }
+
+ private class TestExtensionsService extends ExtensionsService {
+
+ private String m_extensionId;
+ private String m_extensionVersion;
+
+ private TestExtensionsService(String extensionName, String extensionVersion) {
+ m_extensionId = extensionName;
+ m_extensionVersion = extensionVersion;
+ }
+
+ @Override
+ ResourceInstance createExtensionResource(String extensionName) {
+ assertEquals(m_extensionId, extensionName);
+ return getTestResource();
+ }
+
+ @Override
+ ResourceInstance createExtensionVersionResource(String extensionName, String extensionVersion) {
+ assertEquals(m_extensionId, extensionName);
+ assertEquals(m_extensionVersion, extensionVersion);
+ return getTestResource();
+ }
+
+ @Override
+ ResourceInstance createExtensionServiceResource(String extensionName,
+ String extensionVersion, String serviceName) {
+ return getTestResource();
+ }
+
+ @Override
+ ResourceInstance createExtensionConfigurationResource(String extensionName,
+ String extensionVersion, String serviceName, String propertyName) {
+ return getTestResource();
+ }
+
+ @Override
+ ResourceInstance createExtensionServiceComponentResource(String extensionName,
+ String extensionVersion, String serviceName, String componentName) {
+ return getTestResource();
+ }
+
+ @Override
+ ResourceInstance createExtensionArtifactsResource(String extensionName, String extensionVersion, String artifactName) {
+ return getTestResource();
+ }
+
+ @Override
+ ResourceInstance createExtensionServiceArtifactsResource(String extensionName, String extensionVersion, String serviceName, String artifactName) {
+ return getTestResource();
+ }
+
+ @Override
+ RequestFactory getRequestFactory() {
+ return getTestRequestFactory();
+ }
+
+ @Override
+ protected RequestBodyParser getBodyParser() {
+ return getTestBodyParser();
+ }
+
+ @Override
+ protected ResultSerializer getResultSerializer() {
+ return getTestResultSerializer();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/647929db/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ExtensionResourceProviderTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ExtensionResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ExtensionResourceProviderTest.java
new file mode 100644
index 0000000..8959e4d
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ExtensionResourceProviderTest.java
@@ -0,0 +1,91 @@
+/**
+ * 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 org.apache.ambari.server.controller.AmbariManagementController;
+import org.apache.ambari.server.controller.ExtensionRequest;
+import org.apache.ambari.server.controller.ExtensionResponse;
+import org.apache.ambari.server.controller.spi.Request;
+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 org.easymock.EasyMock;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+
+/**
+ * ExtensionResourceProvider Test
+ */
+public class ExtensionResourceProviderTest {
+ @Test
+ public void testGetResources() throws Exception {
+ Resource.Type type = Resource.Type.Extension;
+
+ AmbariManagementController managementController = createMock(AmbariManagementController.class);
+
+ Set<ExtensionResponse> allResponse = new HashSet<ExtensionResponse>();
+ allResponse.add(new ExtensionResponse("Extension1"));
+ allResponse.add(new ExtensionResponse("Extension2"));
+
+ // set expectations
+ expect(managementController.getExtensions(EasyMock.<Set<ExtensionRequest>>anyObject())).andReturn(allResponse).once();
+
+ // replay
+ replay(managementController);
+
+ ResourceProvider provider = AbstractControllerResourceProvider.getResourceProvider(
+ type,
+ PropertyHelper.getPropertyIds(type),
+ PropertyHelper.getKeyPropertyIds(type),
+ managementController);
+
+ Set<String> propertyIds = new HashSet<String>();
+
+ propertyIds.add(ExtensionResourceProvider.EXTENSION_NAME_PROPERTY_ID);
+
+ // create the request
+ Request request = PropertyHelper.getReadRequest(propertyIds);
+
+ // get all ... no predicate
+ Set<Resource> resources = provider.getResources(request, null);
+
+ Assert.assertEquals(2, resources.size());
+
+
+ Set<String> extensionNames = new HashSet<String>();
+ extensionNames.add("Extension1");
+ extensionNames.add("Extension2");
+
+ for (Resource resource : resources) {
+ String extensionName = (String) resource.getPropertyValue(ExtensionResourceProvider.EXTENSION_NAME_PROPERTY_ID);
+ Assert.assertTrue(extensionNames.contains(extensionName));
+ }
+
+ // verify
+ verify(managementController);
+ }
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/647929db/ambari-server/src/test/java/org/apache/ambari/server/stack/ComponentModuleTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/stack/ComponentModuleTest.java b/ambari-server/src/test/java/org/apache/ambari/server/stack/ComponentModuleTest.java
index 2f84f04..e80bf8b 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/stack/ComponentModuleTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/stack/ComponentModuleTest.java
@@ -394,7 +394,7 @@ public class ComponentModuleTest {
ComponentModule component = new ComponentModule(info);
ComponentModule parentComponent = new ComponentModule(parentInfo);
- component.resolve(parentComponent, Collections.<String, StackModule>emptyMap(), Collections.<String, ServiceModule>emptyMap());
+ component.resolve(parentComponent, Collections.<String, StackModule>emptyMap(), Collections.<String, ServiceModule>emptyMap(), Collections.<String, ExtensionModule>emptyMap());
return component;
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/647929db/ambari-server/src/test/java/org/apache/ambari/server/stack/ServiceModuleTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/stack/ServiceModuleTest.java b/ambari-server/src/test/java/org/apache/ambari/server/stack/ServiceModuleTest.java
index 92c1200..76a5bdf 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/stack/ServiceModuleTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/stack/ServiceModuleTest.java
@@ -1210,7 +1210,7 @@ public class ServiceModuleTest {
}
private void resolveService(ServiceModule service, ServiceModule parent) throws AmbariException {
- service.resolve(parent, Collections.<String, StackModule>emptyMap(), Collections.<String, ServiceModule>emptyMap());
+ service.resolve(parent, Collections.<String, StackModule>emptyMap(), Collections.<String, ServiceModule>emptyMap(), Collections.<String, ExtensionModule>emptyMap());
// during runtime this would be called by the Stack module when it's resolve completed
service.finalizeModule();
parent.finalizeModule();
http://git-wip-us.apache.org/repos/asf/ambari/blob/647929db/ambari-server/src/test/java/org/apache/ambari/server/stack/StackManagerCommonServicesTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/stack/StackManagerCommonServicesTest.java b/ambari-server/src/test/java/org/apache/ambari/server/stack/StackManagerCommonServicesTest.java
index 6f3cf78..3fc382e 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/stack/StackManagerCommonServicesTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/stack/StackManagerCommonServicesTest.java
@@ -35,6 +35,8 @@ import java.util.Map;
import org.apache.ambari.server.configuration.Configuration;
import org.apache.ambari.server.metadata.ActionMetadata;
+import org.apache.ambari.server.orm.dao.ExtensionDAO;
+import org.apache.ambari.server.orm.dao.ExtensionLinkDAO;
import org.apache.ambari.server.orm.dao.MetainfoDAO;
import org.apache.ambari.server.orm.dao.StackDAO;
import org.apache.ambari.server.orm.entities.StackEntity;
@@ -58,6 +60,8 @@ public class StackManagerCommonServicesTest {
private static StackManager stackManager;
private static MetainfoDAO metaInfoDao;
private static StackDAO stackDao;
+ private static ExtensionDAO extensionDao;
+ private static ExtensionLinkDAO linkDao;
private static ActionMetadata actionMetadata;
private static OsFamily osFamily;
@@ -72,14 +76,18 @@ public class StackManagerCommonServicesTest {
String commonServices = ClassLoader.getSystemClassLoader().getResource(
"common-services").getPath();
- return createTestStackManager(stack, commonServices);
+ String extensions = ClassLoader.getSystemClassLoader().getResource(
+ "extensions").getPath();
+ return createTestStackManager(stack, commonServices, extensions);
}
public static StackManager createTestStackManager(String stackRoot,
- String commonServicesRoot) throws Exception {
+ String commonServicesRoot, String extensionRoot) throws Exception {
// todo: dao , actionMetaData expectations
metaInfoDao = createNiceMock(MetainfoDAO.class);
stackDao = createNiceMock(StackDAO.class);
+ extensionDao = createNiceMock(ExtensionDAO.class);
+ linkDao = createNiceMock(ExtensionLinkDAO.class);
actionMetadata = createNiceMock(ActionMetadata.class);
Configuration config = createNiceMock(Configuration.class);
StackEntity stackEntity = createNiceMock(StackEntity.class);
@@ -96,8 +104,8 @@ public class StackManagerCommonServicesTest {
replay(metaInfoDao, actionMetadata);
- StackManager stackManager = new StackManager(new File(stackRoot), new File(
- commonServicesRoot), osFamily, metaInfoDao, actionMetadata, stackDao);
+ StackManager stackManager = new StackManager(new File(stackRoot), new File(commonServicesRoot),
+ new File(extensionRoot), osFamily, metaInfoDao, actionMetadata, stackDao, extensionDao, linkDao);
EasyMock.verify( config, stackDao );
http://git-wip-us.apache.org/repos/asf/ambari/blob/647929db/ambari-server/src/test/java/org/apache/ambari/server/stack/StackManagerExtensionTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/stack/StackManagerExtensionTest.java b/ambari-server/src/test/java/org/apache/ambari/server/stack/StackManagerExtensionTest.java
new file mode 100644
index 0000000..3ebe4f6
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/stack/StackManagerExtensionTest.java
@@ -0,0 +1,105 @@
+/**
+ * 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.stack;
+
+import static org.easymock.EasyMock.createNiceMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.File;
+import java.util.Map;
+
+import org.apache.ambari.server.metadata.ActionMetadata;
+import org.apache.ambari.server.orm.dao.ExtensionDAO;
+import org.apache.ambari.server.orm.dao.ExtensionLinkDAO;
+import org.apache.ambari.server.orm.dao.MetainfoDAO;
+import org.apache.ambari.server.orm.dao.StackDAO;
+import org.apache.ambari.server.orm.entities.StackEntity;
+import org.apache.ambari.server.state.ExtensionInfo;
+import org.apache.ambari.server.state.ServiceInfo;
+import org.apache.ambari.server.state.StackInfo;
+import org.apache.ambari.server.state.stack.OsFamily;
+import org.easymock.EasyMock;
+import org.junit.Test;
+
+/**
+ * StackManager extension unit tests.
+ */
+public class StackManagerExtensionTest {
+
+ @Test
+ public void testExtensions() throws Exception {
+ MetainfoDAO metaInfoDao = createNiceMock(MetainfoDAO.class);
+ StackDAO stackDao = createNiceMock(StackDAO.class);
+ ExtensionDAO extensionDao = createNiceMock(ExtensionDAO.class);
+ ExtensionLinkDAO linkDao = createNiceMock(ExtensionLinkDAO.class);
+ ActionMetadata actionMetadata = createNiceMock(ActionMetadata.class);
+ OsFamily osFamily = createNiceMock(OsFamily.class);
+ StackEntity stackEntity = createNiceMock(StackEntity.class);
+
+ expect(
+ stackDao.find(EasyMock.anyObject(String.class),
+ EasyMock.anyObject(String.class))).andReturn(stackEntity).atLeastOnce();
+
+ replay(actionMetadata, stackDao, metaInfoDao, osFamily);
+
+ String stacks = ClassLoader.getSystemClassLoader().getResource("stacks_with_extensions").getPath();
+ String common = ClassLoader.getSystemClassLoader().getResource("common-services").getPath();
+ String extensions = ClassLoader.getSystemClassLoader().getResource("extensions").getPath();
+
+ StackManager stackManager = new StackManager(new File(stacks),
+ new File(common), new File(extensions), osFamily, metaInfoDao, actionMetadata, stackDao, extensionDao, linkDao);
+
+ ExtensionInfo extension = stackManager.getExtension("EXT", "0.1");
+ assertNull("EXT 0.1's parent: " + extension.getParentExtensionVersion(), extension.getParentExtensionVersion());
+ assertNotNull(extension.getService("OOZIE2"));
+ ServiceInfo oozie = extension.getService("OOZIE2");
+ assertNotNull("Package dir is " + oozie.getServicePackageFolder(), oozie.getServicePackageFolder());
+ assertTrue("Package dir is " + oozie.getServicePackageFolder(), oozie.getServicePackageFolder().contains("extensions/EXT/0.1/services/OOZIE2/package"));
+ assertEquals(oozie.getVersion(), "3.2.0");
+
+ extension = stackManager.getExtension("EXT", "0.2");
+ assertNotNull("EXT 0.2's parent: " + extension.getParentExtensionVersion(), extension.getParentExtensionVersion());
+ assertEquals("EXT 0.2's parent: " + extension.getParentExtensionVersion(), "0.1", extension.getParentExtensionVersion());
+ assertNotNull(extension.getService("OOZIE2"));
+ oozie = extension.getService("OOZIE2");
+ assertNotNull("Package dir is " + oozie.getServicePackageFolder(), oozie.getServicePackageFolder());
+ assertTrue("Package dir is " + oozie.getServicePackageFolder(), oozie.getServicePackageFolder().contains("extensions/EXT/0.1/services/OOZIE2/package"));
+ assertEquals(oozie.getVersion(), "4.0.0");
+
+ StackInfo stack = stackManager.getStack("HDP", "0.2");
+ assertNotNull(stack.getService("OOZIE2"));
+ oozie = stack.getService("OOZIE2");
+ assertNotNull("Package dir is " + oozie.getServicePackageFolder(), oozie.getServicePackageFolder());
+ assertTrue("Package dir is " + oozie.getServicePackageFolder(), oozie.getServicePackageFolder().contains("extensions/EXT/0.1/services/OOZIE2/package"));
+ assertEquals(oozie.getVersion(), "4.0.0");
+
+ assertTrue("Extensions found: " + stack.getExtensions().size(), stack.getExtensions().size() == 1);
+ extension = stack.getExtensions().iterator().next();
+ assertEquals("Extension name: " + extension.getName(), extension.getName(), "EXT");
+ assertEquals("Extension version: " + extension.getVersion(), extension.getVersion(), "0.2");
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/647929db/ambari-server/src/test/java/org/apache/ambari/server/stack/StackManagerMiscTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/stack/StackManagerMiscTest.java b/ambari-server/src/test/java/org/apache/ambari/server/stack/StackManagerMiscTest.java
index dda1e7a..c925b38 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/stack/StackManagerMiscTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/stack/StackManagerMiscTest.java
@@ -31,6 +31,8 @@ import java.util.Collection;
import org.apache.ambari.server.AmbariException;
import org.apache.ambari.server.metadata.ActionMetadata;
+import org.apache.ambari.server.orm.dao.ExtensionDAO;
+import org.apache.ambari.server.orm.dao.ExtensionLinkDAO;
import org.apache.ambari.server.orm.dao.MetainfoDAO;
import org.apache.ambari.server.orm.dao.StackDAO;
import org.apache.ambari.server.orm.entities.StackEntity;
@@ -48,6 +50,8 @@ public class StackManagerMiscTest {
public void testCycleDetection() throws Exception {
MetainfoDAO metaInfoDao = createNiceMock(MetainfoDAO.class);
StackDAO stackDao = createNiceMock(StackDAO.class);
+ ExtensionDAO extensionDao = createNiceMock(ExtensionDAO.class);
+ ExtensionLinkDAO linkDao = createNiceMock(ExtensionLinkDAO.class);
ActionMetadata actionMetadata = createNiceMock(ActionMetadata.class);
OsFamily osFamily = createNiceMock(OsFamily.class);
StackEntity stackEntity = createNiceMock(StackEntity.class);
@@ -62,7 +66,7 @@ public class StackManagerMiscTest {
String stacksCycle1 = ClassLoader.getSystemClassLoader().getResource("stacks_with_cycle").getPath();
StackManager stackManager = new StackManager(new File(stacksCycle1),
- null, osFamily, metaInfoDao, actionMetadata, stackDao);
+ null, null, osFamily, metaInfoDao, actionMetadata, stackDao, extensionDao, linkDao);
fail("Expected exception due to cyclic stack");
} catch (AmbariException e) {
@@ -74,7 +78,7 @@ public class StackManagerMiscTest {
"stacks_with_cycle2").getPath();
StackManager stackManager = new StackManager(new File(stacksCycle2),
- null, osFamily, metaInfoDao, actionMetadata, stackDao);
+ null, null, osFamily, metaInfoDao, actionMetadata, stackDao, extensionDao, linkDao);
fail("Expected exception due to cyclic stack");
} catch (AmbariException e) {
@@ -91,6 +95,8 @@ public class StackManagerMiscTest {
public void testGetServiceInfoFromSingleStack() throws Exception {
MetainfoDAO metaInfoDao = createNiceMock(MetainfoDAO.class);
StackDAO stackDao = createNiceMock(StackDAO.class);
+ ExtensionDAO extensionDao = createNiceMock(ExtensionDAO.class);
+ ExtensionLinkDAO linkDao = createNiceMock(ExtensionLinkDAO.class);
ActionMetadata actionMetadata = createNiceMock(ActionMetadata.class);
OsFamily osFamily = createNiceMock(OsFamily.class);
StackEntity stackEntity = createNiceMock(StackEntity.class);
@@ -108,7 +114,7 @@ public class StackManagerMiscTest {
StackManager stackManager = new StackManager(new File(singleStack.replace(
StackManager.PATH_DELIMITER, File.separator)),
- null, osFamily, metaInfoDao, actionMetadata, stackDao);
+ null, null, osFamily, metaInfoDao, actionMetadata, stackDao, extensionDao, linkDao);
Collection<StackInfo> stacks = stackManager.getStacks();
http://git-wip-us.apache.org/repos/asf/ambari/blob/647929db/ambari-server/src/test/java/org/apache/ambari/server/stack/StackManagerTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/stack/StackManagerTest.java b/ambari-server/src/test/java/org/apache/ambari/server/stack/StackManagerTest.java
index b690a6f..133c9ff 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/stack/StackManagerTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/stack/StackManagerTest.java
@@ -31,6 +31,7 @@ import static org.junit.Assert.assertTrue;
import java.io.File;
import java.io.FileReader;
import java.lang.reflect.Type;
+import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
@@ -40,11 +41,14 @@ import java.util.Map;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
+
import org.apache.ambari.server.AmbariException;
import org.apache.ambari.server.Role;
import org.apache.ambari.server.RoleCommand;
import org.apache.ambari.server.configuration.Configuration;
import org.apache.ambari.server.metadata.ActionMetadata;
+import org.apache.ambari.server.orm.dao.ExtensionDAO;
+import org.apache.ambari.server.orm.dao.ExtensionLinkDAO;
import org.apache.ambari.server.orm.dao.MetainfoDAO;
import org.apache.ambari.server.orm.dao.StackDAO;
import org.apache.ambari.server.state.ClientConfigFileDefinition;
@@ -71,6 +75,8 @@ public class StackManagerTest {
private static ActionMetadata actionMetadata;
private static OsFamily osFamily;
private static StackDAO stackDao;
+ private static ExtensionDAO extensionDao;
+ private static ExtensionLinkDAO linkDao;
@BeforeClass
public static void initStack() throws Exception{
@@ -86,6 +92,8 @@ public class StackManagerTest {
// todo: dao , actionMetaData expectations
metaInfoDao = createNiceMock(MetainfoDAO.class);
stackDao = createNiceMock(StackDAO.class);
+ extensionDao = createNiceMock(ExtensionDAO.class);
+ linkDao = createNiceMock(ExtensionLinkDAO.class);
actionMetadata = createNiceMock(ActionMetadata.class);
Configuration config = createNiceMock(Configuration.class);
@@ -96,8 +104,8 @@ public class StackManagerTest {
osFamily = new OsFamily(config);
- StackManager stackManager = new StackManager(new File(stackRoot), null,
- osFamily, metaInfoDao, actionMetadata, stackDao);
+ StackManager stackManager = new StackManager(new File(stackRoot), null, null,
+ osFamily, metaInfoDao, actionMetadata, stackDao, extensionDao, linkDao);
verify(config, metaInfoDao, stackDao, actionMetadata);
@@ -269,7 +277,7 @@ public class StackManagerTest {
assertEquals("1.0", stack.getVersion());
Collection<ServiceInfo> services = stack.getServices();
- assertEquals(3, services.size());
+ assertEquals(4, services.size());
// hdfs service
assertEquals(6, stack.getService("HDFS").getComponents().size());
@@ -357,7 +365,7 @@ public class StackManagerTest {
StackInfo baseStack = stackManager.getStack("OTHER", "1.0");
StackInfo stack = stackManager.getStack("OTHER", "2.0");
- assertEquals(4, stack.getServices().size());
+ assertEquals(5, stack.getServices().size());
ServiceInfo service = stack.getService("SQOOP2");
ServiceInfo baseSqoopService = baseStack.getService("SQOOP2");
@@ -423,6 +431,19 @@ public class StackManagerTest {
}
@Test
+ public void testPackageInheritance() throws Exception{
+ StackInfo stack = stackManager.getStack("HDP", "2.0.7");
+ assertNotNull(stack.getService("HBASE"));
+ ServiceInfo hbase = stack.getService("HBASE");
+ assertNotNull("Package dir is " + hbase.getServicePackageFolder(), hbase.getServicePackageFolder());
+
+ stack = stackManager.getStack("HDP", "2.0.8");
+ assertNotNull(stack.getService("HBASE"));
+ hbase = stack.getService("HBASE");
+ assertNotNull("Package dir is " + hbase.getServicePackageFolder(), hbase.getServicePackageFolder());
+ }
+
+ @Test
public void testMonitoringServicePropertyInheritance() throws Exception{
StackInfo stack = stackManager.getStack("HDP", "2.0.8");
Collection<ServiceInfo> allServices = stack.getServices();
@@ -620,6 +641,9 @@ public class StackManagerTest {
ArrayList<String> hbaseMasterStartValues = (ArrayList<String>) generalDeps.get("HBASE_MASTER-START");
assertTrue(hbaseMasterStartValues.get(0).equals("ZOOKEEPER_SERVER-START"));
+ ServiceInfo service = stack.getService("PIG");
+ assertNotNull("PIG's roll command order is null", service.getRoleCommandOrder());
+
assertTrue(optionalNoGlusterfs.containsKey("NAMENODE-STOP"));
ArrayList<String> nameNodeStopValues = (ArrayList<String>) optionalNoGlusterfs.get("NAMENODE-STOP");
assertTrue(nameNodeStopValues.contains("JOBTRACKER-STOP"));
@@ -629,6 +653,7 @@ public class StackManagerTest {
ArrayList<String> customMasterStartValues = (ArrayList<String>) generalDeps.get("CUSTOM_MASTER-START");
assertTrue(customMasterStartValues.contains("ZOOKEEPER_SERVER-START"));
assertTrue(customMasterStartValues.contains("NAMENODE-START"));
+
}
@Test
@@ -644,9 +669,19 @@ public class StackManagerTest {
String stackRoot = ClassLoader.getSystemClassLoader().getResource("stacks").getPath().replace("test-classes","classes");
String commonServices = ClassLoader.getSystemClassLoader().getResource("common-services").getPath().replace("test-classes","classes");
+ File extensions = null;
+
+ try {
+ URL extensionsURL = ClassLoader.getSystemClassLoader().getResource("extensions");
+ if (extensionsURL != null)
+ extensions = new File(extensionsURL.getPath().replace("test-classes","classes"));
+ }
+ catch (Exception e) {}
MetainfoDAO metaInfoDao = createNiceMock(MetainfoDAO.class);
StackDAO stackDao = createNiceMock(StackDAO.class);
+ ExtensionDAO extensionDao = createNiceMock(ExtensionDAO.class);
+ ExtensionLinkDAO linkDao = createNiceMock(ExtensionLinkDAO.class);
ActionMetadata actionMetadata = createNiceMock(ActionMetadata.class);
Configuration config = createNiceMock(Configuration.class);
@@ -657,8 +692,8 @@ public class StackManagerTest {
OsFamily osFamily = new OsFamily(config);
- StackManager stackManager = new StackManager(new File(stackRoot), new File(commonServices),
- osFamily, metaInfoDao, actionMetadata, stackDao);
+ StackManager stackManager = new StackManager(new File(stackRoot), new File(commonServices), extensions,
+ osFamily, metaInfoDao, actionMetadata, stackDao, extensionDao, linkDao);
for (StackInfo stackInfo : stackManager.getStacks()) {
for (ServiceInfo serviceInfo : stackInfo.getServices()) {
http://git-wip-us.apache.org/repos/asf/ambari/blob/647929db/ambari-server/src/test/java/org/apache/ambari/server/stack/ThemeModuleTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/stack/ThemeModuleTest.java b/ambari-server/src/test/java/org/apache/ambari/server/stack/ThemeModuleTest.java
index f4b4b93..f4f45a7 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/stack/ThemeModuleTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/stack/ThemeModuleTest.java
@@ -36,7 +36,7 @@ public class ThemeModuleTest {
ThemeModule parentModule = new ThemeModule(parentThemeFile);
ThemeModule childModule = new ThemeModule(childThemeFile);
- childModule.resolve(parentModule, null, null);
+ childModule.resolve(parentModule, null, null, null);
Theme childTheme = childModule.getModuleInfo().getThemeMap().get(ThemeModule.THEME_KEY);
Theme parentTheme = parentModule.getModuleInfo().getThemeMap().get(ThemeModule.THEME_KEY);