blob: efd473ef3e4f6a9d827996e1eadea1bef9ad9a22 [file] [log] [blame]
/**
* 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.
*/
var App = require('app');
var numberUtils = require('utils/number_utils');
var ComponentDependency = Ember.Object.extend({
componentName: null,
compatibleComponents: [],
/**
* Find the first compatible component which belongs to a service that is installed
*/
chooseCompatible: function() {
var compatibleComponent = this.get('compatibleComponents').find(function(component) {
return App.Service.find().someProperty('serviceName', component.get('serviceName'))
});
return (compatibleComponent ? compatibleComponent : this.get('compatibleComponents')[0]).get('componentName');
}
});
/**
* This model loads all serviceComponents supported by the stack
* @type {*}
*/
App.StackServiceComponent = DS.Model.extend({
componentName: DS.attr('string'),
displayName: DS.attr('string'),
cardinality: DS.attr('string'),
customCommands: DS.attr('array'),
reassignAllowed: DS.attr('boolean'),
decommissionAllowed: DS.attr('boolean'),
hasBulkCommandsDefinition: DS.attr('boolean'),
bulkCommandsDisplayName: DS.attr('string'),
bulkCommandsMasterComponentName: DS.attr('string'),
dependencies: DS.attr('array'),
serviceName: DS.attr('string'),
componentCategory: DS.attr('string'),
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'),
serviceComponentId: DS.attr('number', {defaultValue: 1}), // this is used on Assign Master page for multiple masters
/**
* Minimum required count for installation.
*
* @property {Number} minToInstall
**/
minToInstall: function() {
return numberUtils.getCardinalityValue(this.get('cardinality'), false);
}.property('cardinality'),
/**
* Maximum required count for installation.
*
* @property {Number} maxToInstall
**/
maxToInstall: function() {
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); });
var missingComponents = dependencies.filter(function (dependency) {
return !installedComponents.some(function(each) {
return each.compatibleWith(App.StackServiceComponent.find(dependency.componentName));
});
}).mapProperty('componentName');
return missingComponents.map(function (missingComponentName) {
return ComponentDependency.create({
'componentName': missingComponentName,
'compatibleComponents': App.StackServiceComponent.find().filter(function (each) {
return each.compatibleWith(App.StackServiceComponent.find(missingComponentName));
})
});
});
},
/** @property {Boolean} isRequired - component required to install **/
isRequired: Em.computed.gt('minToInstall', 0),
/** @property {Boolean} isMultipleAllowed - component can be assigned for more than one host **/
isMultipleAllowed: Em.computed.gt('maxToInstall', 1),
/** @property {Boolean} isSlave **/
isSlave: Em.computed.equal('componentCategory', 'SLAVE'),
/** @property {Boolean} isRestartable - component supports restart action **/
isRestartable: Em.computed.not('isClient'),
/** @property {Boolean} isReassignable - component supports reassign action **/
isReassignable: function(){
return this.get('reassignAllowed');
}.property('reassignAllowed'),
/** @property {Boolean} isNonHDPComponent - component not belongs to HDP services **/
isNonHDPComponent: function() {
return ['METRICS_COLLECTOR', 'METRICS_MONITOR'].contains(this.get('componentName'));
}.property('componentName'),
/** @property {Boolean} isRollinRestartAllowed - component supports rolling restart action **/
isRollinRestartAllowed: function() {
return this.get('isSlave') || this.get('rollingRestartSupported');
}.property('componentName'),
/** @property {Boolean} isDecommissionAllowed - component supports decommission action **/
isDecommissionAllowed: function() {
return this.get('decommissionAllowed');
}.property('decommissionAllowed'),
/** @property {Boolean} isRefreshConfigsAllowed - component supports refresh configs action **/
isRefreshConfigsAllowed: Em.computed.existsIn('componentName', ['FLUME_HANDLER']),
/** @property {Boolean} isAddableToHost - component can be added on host details page **/
isAddableToHost: function() {
return this.get('isMasterAddableInstallerWizard')
|| ((this.get('isNotAddableOnlyInInstall') || this.get('isSlave') || this.get('isClient'))
&& (!this.get('isHAComponentOnly') || (App.get('isHaEnabled') && this.get('componentName') === 'JOURNALNODE')));
}.property('componentName'),
/** @property {Boolean} isDeletable - component supports delete action **/
isDeletable: function() {
var ignored = [];
return (this.get('isAddableToHost') && !ignored.contains(this.get('componentName'))) || (this.get('componentName') === 'MYSQL_SERVER');
}.property('componentName'),
/**
* @type {boolean}
*/
isInstallable: function() {
const notInstallable = App.get('currentStackName') === 'HDF' ? ['ACTIVITY_ANALYZER', 'ACTIVITY_EXPLORER'] : [];
return !notInstallable.contains(this.get('componentName'));
}.property('componentName'),
/** @property {Boolean} isShownOnInstallerAssignMasterPage - component visible on "Assign Masters" step of Install Wizard **/
// Note: Components that are not visible on Assign Master Page are not saved as part of host component recommendation/validation layout
isShownOnInstallerAssignMasterPage: function() {
var component = this.get('componentName');
var mastersNotShown = ['MYSQL_SERVER', 'POSTGRESQL_SERVER', 'HIVE_SERVER_INTERACTIVE'];
return this.get('isMaster') && this.get('isInstallable') && !mastersNotShown.contains(component);
}.property('isMaster','componentName', 'isInstallable'),
/** @property {Boolean} isShownOnInstallerSlaveClientPage - component visible on "Assign Slaves and Clients" step of Install Wizard**/
// Note: Components that are not visible on Assign Slaves and Clients Page are saved as part of host component recommendation/validation layout
isShownOnInstallerSlaveClientPage: function() {
var component = this.get('componentName');
var slavesNotShown = ['JOURNALNODE','ZKFC','APP_TIMELINE_SERVER'];
return this.get('isSlave') && !this.get('isRequiredOnAllHosts') && !slavesNotShown.contains(component);
}.property('isSlave','componentName', 'isRequiredOnAllHosts'),
/** @property {Boolean} isShownOnAddServiceAssignMasterPage - component visible on "Assign Masters" step of Add Service Wizard **/
// Note: Components that are not visible on Assign Master Page are not saved as part of host component recommendation/validation layout
isShownOnAddServiceAssignMasterPage: function() {
var isVisible = this.get('isShownOnInstallerAssignMasterPage');
if (App.get('isHaEnabled')) {
isVisible = isVisible && this.get('componentName') !== 'SECONDARY_NAMENODE';
}
return isVisible;
}.property('isShownOnInstallerAssignMasterPage','App.isHaEnabled'),
/** @property {Boolean} isMasterWithMultipleInstances **/
isMasterWithMultipleInstances: function() {
// @todo: safe removing JOURNALNODE from masters list
return (this.get('isMaster') && this.get('isMultipleAllowed')) || this.get('componentName') == 'JOURNALNODE';
}.property('componentName'),
/**
* Master component list that could be assigned for more than 1 host.
* Some components like NameNode and ResourceManager have range cardinality value, so they are excluded using isMasterAddableOnlyOnHA property
*
* @property {Boolean} isMasterAddableInstallerWizard
**/
isMasterAddableInstallerWizard: Em.computed.and('isMaster', 'isMultipleAllowed', '!isMasterAddableOnlyOnHA', '!isNotAddableOnlyInInstall'),
/**
* Master components with cardinality more than 1 (n+ or n-n) that could not be added in wizards
* New instances of these components are added in appropriate HA wizards
* @property {Boolean} isMasterAddableOnlyOnHA
*/
isMasterAddableOnlyOnHA: Em.computed.existsIn('componentName', ['NAMENODE', 'RESOURCEMANAGER', 'RANGER_ADMIN']),
/** @property {Boolean} isHAComponentOnly - Components that can be installed only if HA enabled **/
isHAComponentOnly: Em.computed.existsIn('componentName', ['ZKFC','JOURNALNODE']),
/** @property {Boolean} isRequiredOnAllHosts - Is It require to install the components on all hosts. used in step-6 wizard controller **/
isRequiredOnAllHosts: Em.computed.equal('minToInstall', Infinity),
/** @property {Number} defaultNoOfMasterHosts - default number of master hosts on Assign Master page: **/
defaultNoOfMasterHosts: function() {
if (this.get('isMasterAddableInstallerWizard')) {
return this.get('componentName') === 'ZOOKEEPER_SERVER' ? 3 : this.get('minToInstall');
}
}.property('componentName'),
/** @property {Boolean} coHostedComponents - components that are co-hosted with this component **/
coHostedComponents: function() {
var componentName = this.get('componentName');
var key, coHostedComponents = [];
for (key in App.StackServiceComponent.coHost) {
if (App.StackServiceComponent.coHost[key] === componentName) {
coHostedComponents.push(key)
}
}
return coHostedComponents;
}.property('componentName'),
/** @property {Boolean} isOtherComponentCoHosted - Is any other component co-hosted with this component **/
isOtherComponentCoHosted: Em.computed.bool('coHostedComponents.length'),
/** @property {Boolean} isCoHostedComponent - Is this component co-hosted with other component **/
isCoHostedComponent: function() {
var componentName = this.get('componentName');
return !!App.StackServiceComponent.coHost[componentName];
}.property('componentName'),
/** @property {Boolean} isNotAddableOnlyInInstall - is this component addable, except Install and Add Service Wizards **/
isNotAddableOnlyInInstall: Em.computed.existsIn('componentName', ['HIVE_METASTORE', 'HIVE_SERVER', 'RANGER_KMS_SERVER',
'OOZIE_SERVER', 'TIMELINE_READER', 'YARN_REGISTRY_DNS']),
/** @property {Boolean} isNotAllowedOnSingleNodeCluster - is this component allowed on single node **/
isNotAllowedOnSingleNodeCluster: Em.computed.existsIn('componentName', ['HAWQSTANDBY'])
});
App.StackServiceComponent.FIXTURES = [];
App.StackServiceComponent.coHost = {};