You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by am...@apache.org on 2018/01/10 11:00:14 UTC
[ambari] 13/15: AMBARI-22449. Improved service/component dependency
support (amagyar)
This is an automated email from the ASF dual-hosted git repository.
amagyar pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/ambari.git
commit ebf3630e5759d39bdc9e4ea0dd3b97217b5248b2
Author: Attila Magyar <am...@hortonworks.com>
AuthorDate: Fri Jan 5 08:53:59 2018 +0100
AMBARI-22449. Improved service/component dependency support (amagyar)
---
.../controller/StackServiceComponentResponse.java | 10 ++++++
.../StackServiceComponentResourceProvider.java | 9 ++++-
.../apache/ambari/server/state/ComponentInfo.java | 15 ++++++++
.../common-services/HDFS/2.1.0.2.0/metainfo.xml | 1 +
.../common-services/HDFS/3.0.0.3.0/metainfo.xml | 1 +
ambari-web/app/controllers/main/host/details.js | 8 ++---
.../app/controllers/wizard/step8_controller.js | 8 +++--
ambari-web/app/mappers/stack_service_mapper.js | 1 +
ambari-web/app/models/stack_service_component.js | 33 +++++++++++++++++
.../test/controllers/main/host/details_test.js | 23 +++++++++---
ambari-web/test/controllers/wizard/step8_test.js | 41 ++++++++++++----------
11 files changed, 117 insertions(+), 33 deletions(-)
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/StackServiceComponentResponse.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/StackServiceComponentResponse.java
index 75fac6e..8797f03 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/StackServiceComponentResponse.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/StackServiceComponentResponse.java
@@ -118,6 +118,11 @@ public class StackServiceComponentResponse {
private String reassignAllowed;
/**
+ * @see ComponentInfo#componentType
+ */
+ private String componentType;
+
+ /**
* Constructor.
*
* @param component
@@ -139,6 +144,7 @@ public class StackServiceComponentResponse {
bulkCommandMasterComponentName = getBulkCommandsMasterComponentName(component);
reassignAllowed = component.getReassignAllowed();
rollingRestartSupported = component.getRollingRestartSupported();
+ componentType = component.getComponentType();
// the custom command names defined for this component
List<CustomCommandDefinition> definitions = component.getCustomCommands();
@@ -511,6 +517,10 @@ public class StackServiceComponentResponse {
return bulkCommandMasterComponentName == null ? "":bulkCommandMasterComponentName;
}
+ public String getComponentType() {
+ return componentType;
+ }
+
/**
* Interface to help correct Swagger documentation generation
*/
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StackServiceComponentResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StackServiceComponentResourceProvider.java
index a221248..933dcb7 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StackServiceComponentResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StackServiceComponentResourceProvider.java
@@ -104,6 +104,10 @@ public class StackServiceComponentResourceProvider extends
private static final String AUTO_DEPLOY_LOCATION_ID = PropertyHelper.getPropertyId(
"auto_deploy", "location");
+ private static final String COMPONENT_TYPE = PropertyHelper.getPropertyId(
+ "StackServiceComponents", "component_type");
+
+
/**
* The key property ids for a StackServiceComponent resource.
*/
@@ -137,7 +141,8 @@ public class StackServiceComponentResourceProvider extends
RECOVERY_ENABLED,
ROLLING_RESTART_SUPPORTED,
AUTO_DEPLOY_ENABLED_ID,
- AUTO_DEPLOY_LOCATION_ID);
+ AUTO_DEPLOY_LOCATION_ID,
+ COMPONENT_TYPE);
protected StackServiceComponentResourceProvider(AmbariManagementController managementController) {
super(Type.StackServiceComponent, propertyIds, keyPropertyIds, managementController);
@@ -225,6 +230,8 @@ public class StackServiceComponentResourceProvider extends
setResourceProperty(resource, ROLLING_RESTART_SUPPORTED, response.isRollingRestartSupported(), requestedIds);
+ setResourceProperty(resource, COMPONENT_TYPE, response.getComponentType(), requestedIds);
+
AutoDeployInfo autoDeployInfo = response.getAutoDeploy();
if (autoDeployInfo != null) {
setResourceProperty(resource, AUTO_DEPLOY_ENABLED_ID,
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/ComponentInfo.java b/ambari-server/src/main/java/org/apache/ambari/server/state/ComponentInfo.java
index d361a29..a4bac56 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/ComponentInfo.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/ComponentInfo.java
@@ -145,6 +145,12 @@ public class ComponentInfo {
@XmlElement(name="customFolder")
private String customFolder;
+ /**
+ * Optional component type like HCFS_CLIENT.
+ * HCFS_CLIENT indicates compatibility with HDFS_CLIENT
+ */
+ private String componentType;
+
public ComponentInfo() {
}
@@ -173,6 +179,7 @@ public class ComponentInfo {
reassignAllowed = prototype.reassignAllowed;
customFolder = prototype.customFolder;
rollingRestartSupported = prototype.rollingRestartSupported;
+ componentType = prototype.componentType;
}
public String getName() {
@@ -435,6 +442,14 @@ public class ComponentInfo {
this.customFolder = customFolder;
}
+ public String getComponentType() {
+ return componentType;
+ }
+
+ public void setComponentType(String componentType) {
+ this.componentType = componentType;
+ }
+
@Override
public boolean equals(Object o) {
if (this == o) return true;
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 6bbb583..71e487c 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
@@ -157,6 +157,7 @@
<name>HDFS_CLIENT</name>
<displayName>HDFS Client</displayName>
<category>CLIENT</category>
+ <componentType>HCFS_CLIENT</componentType>
<cardinality>1+</cardinality>
<versionAdvertised>true</versionAdvertised>
<commandScript>
diff --git a/ambari-server/src/main/resources/common-services/HDFS/3.0.0.3.0/metainfo.xml b/ambari-server/src/main/resources/common-services/HDFS/3.0.0.3.0/metainfo.xml
index 0c629f3..c1dd4af 100644
--- a/ambari-server/src/main/resources/common-services/HDFS/3.0.0.3.0/metainfo.xml
+++ b/ambari-server/src/main/resources/common-services/HDFS/3.0.0.3.0/metainfo.xml
@@ -157,6 +157,7 @@
<name>HDFS_CLIENT</name>
<displayName>HDFS Client</displayName>
<category>CLIENT</category>
+ <componentType>HCFS_CLIENT</componentType>
<cardinality>1+</cardinality>
<versionAdvertised>true</versionAdvertised>
<commandScript>
diff --git a/ambari-web/app/controllers/main/host/details.js b/ambari-web/app/controllers/main/host/details.js
index e52eec0..9e05f2a 100644
--- a/ambari-web/app/controllers/main/host/details.js
+++ b/ambari-web/app/controllers/main/host/details.js
@@ -3005,9 +3005,6 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
opt = opt || {};
opt.scope = opt.scope || '*';
var installedComponents;
- var dependencies = App.StackServiceComponent.find(componentName).get('dependencies');
- dependencies = opt.scope === '*' ? dependencies : dependencies.filterProperty('scope', opt.scope);
- if (dependencies.length == 0) return [];
switch (opt.scope) {
case 'host':
Em.assert("You should pass at least `hostName` or `installedComponents` to options.", opt.hostName || opt.installedComponents);
@@ -3018,9 +3015,8 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
installedComponents = opt.installedComponents || App.HostComponent.find().mapProperty('componentName').uniq();
break;
}
- return dependencies.filter(function (dependency) {
- return !installedComponents.contains(dependency.componentName);
- }).mapProperty('componentName');
+ var component = App.StackServiceComponent.find(componentName);
+ return component.missingDependencies(installedComponents, opt);
},
/**
diff --git a/ambari-web/app/controllers/wizard/step8_controller.js b/ambari-web/app/controllers/wizard/step8_controller.js
index bd3c36f..2d9f4d2 100644
--- a/ambari-web/app/controllers/wizard/step8_controller.js
+++ b/ambari-web/app/controllers/wizard/step8_controller.js
@@ -1181,13 +1181,15 @@ App.WizardStep8Controller = Em.Controller.extend(App.AddSecurityConfigs, App.wiz
},
getClientsMap: function (flag) {
- var clientNames = App.StackServiceComponent.find().filterProperty('isClient').mapProperty('componentName'),
+ var clients = App.StackServiceComponent.find().filterProperty('isClient'),
clientsMap = {},
dependedComponents = flag ? App.StackServiceComponent.find().filterProperty(flag) : App.StackServiceComponent.find();
- clientNames.forEach(function (clientName) {
+ clients.forEach(function (client) {
+ var clientName = client.get('componentName');
clientsMap[clientName] = Em.A([]);
dependedComponents.forEach(function (component) {
- if (component.get('dependencies').mapProperty('componentName').contains(clientName)) clientsMap[clientName].push(component.get('componentName'));
+ if (component.dependsOn(client))
+ clientsMap[clientName].push(component.get('componentName'));
});
if (!clientsMap[clientName].length) delete clientsMap[clientName];
});
diff --git a/ambari-web/app/mappers/stack_service_mapper.js b/ambari-web/app/mappers/stack_service_mapper.js
index 368a182..9b55a05 100644
--- a/ambari-web/app/mappers/stack_service_mapper.js
+++ b/ambari-web/app/mappers/stack_service_mapper.js
@@ -64,6 +64,7 @@ App.stackServiceMapper = App.QuickDataMapper.create({
rolling_restart_supported: 'rolling_restart_supported',
is_master: 'is_master',
is_client: 'is_client',
+ component_type: 'component_type',
stack_name: 'stack_name',
stack_version: 'stack_version',
stack_service_id: 'service_name',
diff --git a/ambari-web/app/models/stack_service_component.js b/ambari-web/app/models/stack_service_component.js
index 27aa8aa..d4e3446 100644
--- a/ambari-web/app/models/stack_service_component.js
+++ b/ambari-web/app/models/stack_service_component.js
@@ -38,6 +38,7 @@ App.StackServiceComponent = DS.Model.extend({
rollingRestartSupported: DS.attr('boolean'),
isMaster: DS.attr('boolean'),
isClient: DS.attr('boolean'),
+ componentType: DS.attr('string'),
stackName: DS.attr('string'),
stackVersion: DS.attr('string'),
stackService: DS.belongsTo('App.StackService'),
@@ -61,6 +62,38 @@ App.StackServiceComponent = DS.Model.extend({
return numberUtils.getCardinalityValue(this.get('cardinality'), true);
}.property('cardinality'),
+ /**
+ * Check if the given component is compatible with this one. Having the same name or componentType indicates compatibility.
+ **/
+ dependsOn: function(aStackServiceComponent, opt) {
+ return this.get('dependencies').some(function(each) {
+ return aStackServiceComponent.compatibleWith(App.StackServiceComponent.find(each.componentName));
+ });
+ },
+
+ compatibleWith: function(aStackServiceComponent) {
+ return this.get('componentName') === aStackServiceComponent.get('componentName')
+ || (this.get('componentType') && this.get('componentType') === aStackServiceComponent.get('componentType'));
+ },
+
+ /**
+ * Collect dependencies which are required by this component but not installed.
+ * A compatible installed component (e.g.: componentType=HCFS_CLIENT) is not considered as a missing dependency.
+ **/
+ missingDependencies: function(installedComponents, opt) {
+ opt = opt || {};
+ opt.scope = opt.scope || '*';
+ var dependencies = this.get('dependencies');
+ dependencies = opt.scope === '*' ? dependencies : dependencies.filterProperty('scope', opt.scope);
+ if (dependencies.length == 0) return [];
+ installedComponents = installedComponents.map(function(each) { return App.StackServiceComponent.find(each); });
+ return dependencies.filter(function (dependency) {
+ return !installedComponents.some(function(each) {
+ return each.compatibleWith(App.StackServiceComponent.find(dependency.componentName));
+ });
+ }).mapProperty('componentName');
+ },
+
/** @property {Boolean} isRequired - component required to install **/
isRequired: Em.computed.gt('minToInstall', 0),
diff --git a/ambari-web/test/controllers/main/host/details_test.js b/ambari-web/test/controllers/main/host/details_test.js
index f9df36d..e9490fb 100644
--- a/ambari-web/test/controllers/main/host/details_test.js
+++ b/ambari-web/test/controllers/main/host/details_test.js
@@ -3566,30 +3566,43 @@ describe('App.MainHostDetailsController', function () {
it("no dependencies", function () {
var opt = {scope: '*'};
- this.mock.returns(Em.Object.create({
- dependencies: []
+ this.mock.withArgs('C1').returns(App.StackServiceComponent.createRecord({
+ 'dependencies': []
}));
expect(controller.checkComponentDependencies('C1', opt)).to.be.empty;
});
it("dependecies already installed", function () {
var opt = {scope: '*', installedComponents: ['C2']};
- this.mock.returns(Em.Object.create({
+ this.mock.withArgs('C1').returns(App.StackServiceComponent.createRecord({
dependencies: [{componentName: 'C2'}]
}));
+ this.mock.withArgs('C2').returns(App.StackServiceComponent.createRecord({ componentName: 'C2' }));
expect(controller.checkComponentDependencies('C1', opt)).to.be.empty;
});
it("dependecies should be added", function () {
var opt = {scope: '*', installedComponents: ['C2']};
- this.mock.returns(Em.Object.create({
+ this.mock.withArgs('C1').returns(App.StackServiceComponent.createRecord({
dependencies: [{componentName: 'C3'}]
}));
+ this.mock.withArgs('C2').returns(App.StackServiceComponent.createRecord({ componentName: 'C2' }));
+ this.mock.withArgs('C3').returns(App.StackServiceComponent.createRecord({ componentName: 'C3' }));
expect(controller.checkComponentDependencies('C1', opt)).to.eql(['C3']);
});
+ it("dependecies already installed by component type", function () {
+ var opt = {scope: '*', installedComponents: ['C3']};
+ this.mock.withArgs('C1').returns(App.StackServiceComponent.createRecord({
+ dependencies: [{componentName: 'C2'}]
+ }));
+ this.mock.withArgs('C2').returns(App.StackServiceComponent.createRecord({ componentName: 'C2', componentType: 'HCFS_CLIENT' }));
+ this.mock.withArgs('C3').returns(App.StackServiceComponent.createRecord({ componentName: 'C3', componentType: 'HCFS_CLIENT' }));
+ expect(controller.checkComponentDependencies('C1', opt)).to.be.empty;
+ });
it("scope is host", function () {
var opt = {scope: 'host', hostName: 'host1'};
- this.mock.returns(Em.Object.create({
+ this.mock.withArgs('C1').returns(App.StackServiceComponent.createRecord({
dependencies: [{componentName: 'C3', scope: 'host'}]
}));
+ this.mock.withArgs('C3').returns(App.StackServiceComponent.createRecord({ componentName: 'C3' }));
expect(controller.checkComponentDependencies('C1', opt)).to.eql(['C3']);
});
});
diff --git a/ambari-web/test/controllers/wizard/step8_test.js b/ambari-web/test/controllers/wizard/step8_test.js
index 2a52598..22bcf96 100644
--- a/ambari-web/test/controllers/wizard/step8_test.js
+++ b/ambari-web/test/controllers/wizard/step8_test.js
@@ -2086,8 +2086,9 @@ describe('App.WizardStep8Controller', function () {
];
before(function () {
- sinon.stub(App.StackServiceComponent, 'find').returns([
- Em.Object.create({
+ var mock = sinon.stub(App.StackServiceComponent, 'find');
+ var components = [
+ App.StackServiceComponent.createRecord({
componentName: 'c0',
isMaster: true,
dependencies: [
@@ -2105,7 +2106,7 @@ describe('App.WizardStep8Controller', function () {
}
]
}),
- Em.Object.create({
+ App.StackServiceComponent.createRecord({
componentName: 'c1',
isMaster: true,
dependencies: [
@@ -2123,7 +2124,7 @@ describe('App.WizardStep8Controller', function () {
}
]
}),
- Em.Object.create({
+ App.StackServiceComponent.createRecord({
componentName: 'c2',
isMaster: true,
dependencies: [
@@ -2141,14 +2142,14 @@ describe('App.WizardStep8Controller', function () {
}
]
}),
- Em.Object.create({
+ App.StackServiceComponent.createRecord({
componentName: 'c3',
isMaster: true,
dependencies: []
}),
- Em.Object.create({
+ App.StackServiceComponent.createRecord({
componentName: 'c4',
- isSlave: true,
+ componentCategory: 'SLAVE',
dependencies: [
{
componentName: 'c1'
@@ -2164,9 +2165,9 @@ describe('App.WizardStep8Controller', function () {
}
]
}),
- Em.Object.create({
+ App.StackServiceComponent.createRecord({
componentName: 'c5',
- isSlave: true,
+ componentCategory: 'SLAVE',
dependencies: [
{
componentName: 'c4'
@@ -2182,9 +2183,9 @@ describe('App.WizardStep8Controller', function () {
}
]
}),
- Em.Object.create({
+ App.StackServiceComponent.createRecord({
componentName: 'c6',
- isSlave: true,
+ componentCategory: 'SLAVE',
dependencies: [
{
componentName: 'c1'
@@ -2200,12 +2201,12 @@ describe('App.WizardStep8Controller', function () {
}
]
}),
- Em.Object.create({
+ App.StackServiceComponent.createRecord({
componentName: 'c7',
- isSlave: true,
+ componentCategory: 'SLAVE',
dependencies: []
}),
- Em.Object.create({
+ App.StackServiceComponent.createRecord({
componentName: 'c8',
isClient: true,
dependencies: [
@@ -2223,7 +2224,7 @@ describe('App.WizardStep8Controller', function () {
}
]
}),
- Em.Object.create({
+ App.StackServiceComponent.createRecord({
componentName: 'c9',
isClient: true,
dependencies: [
@@ -2241,7 +2242,7 @@ describe('App.WizardStep8Controller', function () {
}
]
}),
- Em.Object.create({
+ App.StackServiceComponent.createRecord({
componentName: 'c10',
isClient: true,
dependencies: [
@@ -2259,12 +2260,16 @@ describe('App.WizardStep8Controller', function () {
}
]
}),
- Em.Object.create({
+ App.StackServiceComponent.createRecord({
componentName: 'c11',
isClient: true,
dependencies: []
})
- ]);
+ ];
+ components.forEach(function(component) {
+ mock.withArgs(component.get('componentName')).returns(component);
+ });
+ mock.returns(components);
});
after(function () {
--
To stop receiving notification emails like this one, please contact
"commits@ambari.apache.org" <co...@ambari.apache.org>.