ambari-web/app/models/stack_service.js (439 lines of code) (raw):

/** * 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 stringUtils = require('utils/string_utils'); require('utils/helper'); require('models/configs/objects/service_config_category'); var Dependency = Ember.Object.extend({ name: Ember.computed('service', function() { return this.get('service.serviceName'); }), displayName: Ember.computed('service', function() { return this.get('service.displayNameOnSelectServicePage'); }), compatibleServices: function(services) { return services.filterProperty('serviceName', this.get('name')); }, isMissing: function(selectedServices) { return Em.isEmpty(this.compatibleServices(selectedServices)); } }); var HcfsDependency = Dependency.extend({ displayName: Ember.computed(function() { return Em.I18n.t('installer.step4.hcfs.displayName'); }), compatibleServices: function(services) { return services.filterProperty("isDFS", true); } }); Dependency.reopenClass({ fromService: function(service) { return service.get('isDFS') ? HcfsDependency.create({service: service}) : Dependency.create({service: service}); } }); var MissingDependency = Ember.Object.extend({ hasMultipleOptions: Ember.computed('compatibleServices', function() { return this.get('compatibleServices').length > 1; }), selectFirstCompatible: function() { this.get('compatibleServices')[0].set('isSelected', true); }, displayOptions: Ember.computed('compatibleServices', function() { return this.get('compatibleServices').mapProperty('serviceName').join(', '); }) }); App.FileSystem = Ember.ObjectProxy.extend({ content: null, services: [], //special case for HDFS and OZONE. They can be selected together shouldAllSelectionBeCleared: function () { const dfsNames = this.get('services').mapProperty('serviceName'); const coExistingDfs = ['HDFS', 'OZONE'], selectedServices = this.get('services').filterProperty('isSelected'); for (let i = 0; i < selectedServices.length; i++) { if (!coExistingDfs.includes(selectedServices[i].get('serviceName'))) { return true; } } return !(dfsNames.includes('HDFS') && dfsNames.includes('OZONE') && coExistingDfs.includes(this.get('content.serviceName'))); }, isSelected: function(key, aBoolean) { if (arguments.length > 1) { if (this.shouldAllSelectionBeCleared()) { this.clearAllSelection(); } this.get('content').set('isSelected', aBoolean); } return this.get('content.isSelected'); }.property('content.isSelected', 'services.@each.isSelected'), clearAllSelection: function() { this.get('services').setEach('isSelected', false); } }); /** * This model loads all services supported by the stack * The model maps to the http://hostname:8080/api/v1/stacks/HDP/versions/${versionNumber}/services?fields=StackServices/*,serviceComponents/* * @type {*} */ App.StackService = DS.Model.extend({ serviceName: DS.attr('string'), serviceType: DS.attr('string'), displayName: DS.attr('string'), comments: DS.attr('string'), configTypes: DS.attr('object'), serviceVersion: DS.attr('string'), serviceCheckSupported: DS.attr('boolean'), supportDeleteViaUi: DS.attr('boolean'), stackName: DS.attr('string'), stackVersion: DS.attr('string'), selection: DS.attr('string'), isMandatory: DS.attr('boolean', {defaultValue: false}), isSelected: DS.attr('boolean', {defaultValue: true}), isInstalled: DS.attr('boolean', {defaultValue: false}), isInstallable: DS.attr('boolean', {defaultValue: true}), isServiceWithWidgets: DS.attr('boolean', {defaultValue: false}), stack: DS.belongsTo('App.Stack'), serviceComponents: DS.hasMany('App.StackServiceComponent'), configs: DS.attr('array'), requiredServices: DS.attr('array', {defaultValue: []}), isDisabled: function () { return this.get('isInstalled') || (this.get('isMandatory') && !App.get('router.clusterInstallCompleted')); }.property('isMandatory', 'isInstalled', 'App.router.clusterInstallCompleted'), /** * @type {String[]} */ configTypeList: function() { var configTypes = Object.keys(this.get('configTypes') || {}); //Falcon has dependency on oozie-site but oozie-site advanced/custom section should not be shown on Falcon page if (this.get('serviceName') === 'FALCON') { configTypes = configTypes.without('oozie-site'); } return configTypes; }.property('configTypes'), /** * contains array of serviceNames that have configs that * depends on configs from current service * @type {String[]} */ dependentServiceNames: DS.attr('array', {defaultValue: []}), dependencies: function(availableServices) { var result = []; this.get('requiredServices').forEach(function(serviceName) { var service = availableServices.findProperty('serviceName', serviceName); if (service) { result.push(Dependency.fromService(service)); } }); return result; }, /** * Add dependencies which are not already included in selectedServices to the given missingDependencies collection */ collectMissingDependencies: function(selectedServices, availableServices, missingDependencies) { this._missingDependencies(selectedServices, availableServices).forEach(function (dependency) { this._addMissingDependency(dependency, availableServices, missingDependencies); }.bind(this)); }, _missingDependencies: function(selectedServices, availableServices) { return this.dependencies(availableServices).filter(function(dependency) { return dependency.isMissing(selectedServices); }); }, _addMissingDependency: function(dependency, availableServices, missingDependencies) { if(!missingDependencies.someProperty('serviceName', dependency.get('name'))) { missingDependencies.push(MissingDependency.create({ serviceName: dependency.get('name'), displayName: dependency.get('displayName'), compatibleServices: dependency.compatibleServices(availableServices) })); } }, // Is the service a distributed filesystem isDFS: function () { return this.get('serviceType') === 'HCFS' || ['HDFS', 'GLUSTERFS', 'OZONE'].contains(this.get('serviceName')); }.property('serviceName', 'serviceType'), // Primary DFS. used if there is more than one DFS in a stack. // Only one service in the stack should be tagged as primary DFS. isPrimaryDFS: Em.computed.equal('serviceName', 'HDFS'), configTypesRendered: function () { var configTypes = this.get('configTypes'); var renderedConfigTypes = $.extend(true, {}, configTypes); if (this.get('serviceName') == 'FALCON') { delete renderedConfigTypes['oozie-site']; } return renderedConfigTypes }.property('serviceName', 'configTypes'), displayNameOnSelectServicePage: function () { var displayName = this.get('displayName'); var services = this.get('coSelectedServices').slice(); var serviceDisplayNames = services.map(function (item) { return App.format.role(item, true); }, this); if (!!serviceDisplayNames.length) { serviceDisplayNames.unshift(displayName); displayName = serviceDisplayNames.join(" + "); } return displayName; }.property('coSelectedServices', 'serviceName'), isHiddenOnSelectServicePage: function () { return !this.get('isInstallable') || this.get('doNotShowAndInstall'); }.property('isInstallable', 'doNotShowAndInstall'), doNotShowAndInstall: function () { var skipServices = []; if(!App.supports.installGanglia) { skipServices.push('GANGLIA'); } return skipServices.contains(this.get('serviceName')); }.property('serviceName'), // Is the service required for monitoring of other hadoop ecosystem services isMonitoringService: Em.computed.existsIn('serviceName', ['GANGLIA']), // Is the service required for reporting host metrics isHostMetricsService: Em.computed.existsIn('serviceName', ['GANGLIA', 'AMBARI_METRICS']), // Is the service required for reporting hadoop service metrics isServiceMetricsService: Em.computed.existsIn('serviceName', ['GANGLIA']), coSelectedServices: function () { var coSelectedServices = App.StackService.coSelected[this.get('serviceName')]; if (!!coSelectedServices) { return coSelectedServices; } else { return []; } }.property('serviceName'), hasClient: Em.computed.someBy('serviceComponents', 'isClient', true), hasMaster: Em.computed.someBy('serviceComponents', 'isMaster', true), hasSlave: Em.computed.someBy('serviceComponents', 'isSlave', true), hasNonMastersWithCustomAssignment: function () { var serviceComponents = this.get('serviceComponents'); return serviceComponents.rejectProperty('isMaster').rejectProperty('cardinality', 'ALL').length > 0; }.property('serviceName'), isClientOnlyService: Em.computed.everyBy('serviceComponents', 'isClient', true), isNoConfigTypes: function () { var configTypes = this.get('configTypes'); return !(configTypes && !!Object.keys(configTypes).length); }.property('configTypes'), customReviewHandler: function () { return App.StackService.reviewPageHandlers[this.get('serviceName')]; }.property('serviceName'), hasHeatmapSection: Em.computed.existsIn('serviceName', ['HDFS', 'YARN', 'HBASE']), /** * configCategories are fetched from App.StackService.configCategories. * Also configCategories that does not match any serviceComponent of a service and not included in the permissible default pattern are omitted */ configCategories: function () { var configCategories = []; var configTypes = this.get('configTypes'); var serviceComponents = this.get('serviceComponents'); if (configTypes && Object.keys(configTypes).length) { var pattern = ["General", "ResourceType", "CapacityScheduler", "ContainerExecutor", "Registry", "FaultTolerance", "Isolation", "Performance", "HIVE_SERVER2", "KDC", "Kadmin","^Advanced", "Env$", "^Custom", "Falcon - Oozie integration", "FalconStartupSite", "FalconRuntimeSite", "MetricCollector", "Settings$", "AdvancedHawqCheck", "LogsearchAdminJson"]; configCategories = App.StackService.configCategories.call(this).filter(function (_configCategory) { var serviceComponentName = _configCategory.get('name'); var isServiceComponent = serviceComponents.someProperty('componentName', serviceComponentName); if (isServiceComponent) return isServiceComponent; var result = false; pattern.forEach(function (_pattern) { var regex = new RegExp(_pattern); if (regex.test(serviceComponentName)) result = true; }); return result; }); } return configCategories; }.property('serviceName', 'configTypes', 'serviceComponents'), /** * Compare specified version with current service version * @param {string} version [description] * @return {number} 0 - equal, -1 - less, +1 - more @see stringUtils#compareVersions */ compareCurrentVersion: function(version) { var toMinor = this.get('serviceVersion').split('.').slice(0, 2).join('.'); return stringUtils.compareVersions(toMinor, version); } }); App.StackService.FIXTURES = []; App.StackService.displayOrder = [ 'HDFS', 'GLUSTERFS', 'YARN', 'MAPREDUCE2', 'TEZ', 'GANGLIA', 'HIVE', 'HAWQ', 'PXF', 'HBASE', 'PIG', 'SQOOP', 'OOZIE', 'ZOOKEEPER', 'FALCON', 'STORM', 'FLUME', 'ACCUMULO', 'AMBARI_INFRA_SOLR', 'AMBARI_METRICS', 'ATLAS', 'KAFKA', 'KNOX', 'LOGSEARCH', 'RANGER', 'RANGER_KMS', 'SMARTSENSE', 'SPARK', 'SPARK2', 'ZEPPELIN' ]; App.StackService.componentsOrderForService = { 'HAWQ': ['HAWQMASTER', 'HAWQSTANDBY'] }; //@TODO: Write unit test for no two keys in the object should have any intersecting elements in their values App.StackService.coSelected = {}; App.StackService.reviewPageHandlers = { 'HIVE': { 'Database': 'loadHiveDbValue' }, 'OOZIE': { 'Database': 'loadOozieDbValue' } }; App.StackService.configCategories = function () { var serviceConfigCategories = []; switch (this.get('serviceName')) { case 'HDFS': serviceConfigCategories.pushObject(App.ServiceConfigCategory.create({ name: 'NAMENODE', displayName: 'NameNode', showHost: true})); if (!App.get('isHaEnabled')) { serviceConfigCategories.pushObject(App.ServiceConfigCategory.create({ name: 'SECONDARY_NAMENODE', displayName: 'Secondary NameNode', showHost: true})); } serviceConfigCategories.pushObjects([ App.ServiceConfigCategory.create({ name: 'DATANODE', displayName: 'DataNode', showHost: true}), App.ServiceConfigCategory.create({ name: 'General', displayName: 'General'}), App.ServiceConfigCategory.create({ name: 'NFS_GATEWAY', displayName: 'NFS Gateway', showHost: true}) ]); break; case 'GLUSTERFS': serviceConfigCategories.pushObjects([ App.ServiceConfigCategory.create({ name: 'General', displayName: 'General'}) ]); break; case 'YARN': serviceConfigCategories.pushObjects([ App.ServiceConfigCategory.create({ name: 'RESOURCEMANAGER', displayName: 'Resource Manager', showHost: true}), App.ServiceConfigCategory.create({ name: 'NODEMANAGER', displayName: 'Node Manager', showHost: true}), App.ServiceConfigCategory.create({ name: 'APP_TIMELINE_SERVER', displayName: 'Application Timeline Server', showHost: true}), App.ServiceConfigCategory.create({ name: 'General', displayName: 'General'}), App.ServiceConfigCategory.create({ name: 'ResourceTypes', displayName: 'Resource Types'}), App.ServiceConfigCategory.create({ name: 'FaultTolerance', displayName: 'Fault Tolerance'}), App.ServiceConfigCategory.create({ name: 'Isolation', displayName: 'Isolation'}), App.ServiceConfigCategory.create({ name: 'CapacityScheduler', displayName: 'Scheduler', siteFileName: 'capacity-scheduler.xml'}), App.ServiceConfigCategory.create({ name: 'ContainerExecutor', displayName: 'Container Executor', siteFileName: 'container-executor.xml'}), App.ServiceConfigCategory.create({ name: 'Registry', displayName: 'Registry'}) ]); break; case 'MAPREDUCE2': serviceConfigCategories.pushObjects([ App.ServiceConfigCategory.create({ name: 'HISTORYSERVER', displayName: 'History Server', showHost: true}), App.ServiceConfigCategory.create({ name: 'General', displayName: 'General'}) ]); break; case 'HIVE': serviceConfigCategories.pushObjects([ App.ServiceConfigCategory.create({ name: 'HIVE_METASTORE', displayName: 'Hive Metastore', showHost: true}), App.ServiceConfigCategory.create({ name: 'WEBHCAT_SERVER', displayName: 'WebHCat Server', showHost: true}), App.ServiceConfigCategory.create({ name: 'General', displayName: 'General'}), App.ServiceConfigCategory.create({ name: 'Performance', displayName: 'Performance'}), App.ServiceConfigCategory.create({ name: 'HIVE_SERVER2', displayName: 'Hive Server2'}), App.ServiceConfigCategory.create({ name: 'HIVE_CLIENT', displayName: 'Hive Client'}) ]); break; case 'HBASE': serviceConfigCategories.pushObjects([ App.ServiceConfigCategory.create({ name: 'HBASE_MASTER', displayName: 'HBase Master', showHost: true}), App.ServiceConfigCategory.create({ name: 'HBASE_REGIONSERVER', displayName: 'RegionServer', showHost: true}), App.ServiceConfigCategory.create({ name: 'General', displayName: 'General'}) ]); break; case 'ZOOKEEPER': serviceConfigCategories.pushObjects([ App.ServiceConfigCategory.create({ name: 'ZOOKEEPER_SERVER', displayName: 'ZooKeeper Server', showHost: true}) ]); break; case 'OOZIE': serviceConfigCategories.pushObjects([ App.ServiceConfigCategory.create({ name: 'OOZIE_SERVER', displayName: 'Oozie Server', showHost: true}), App.ServiceConfigCategory.create({ name: 'Falcon - Oozie integration', displayName: 'Falcon - Oozie integration'}) ]); break; case 'FALCON': serviceConfigCategories.pushObjects([ App.ServiceConfigCategory.create({ name: 'FALCON_SERVER', displayName: 'Falcon Server', showHost: true}), App.ServiceConfigCategory.create({ name: 'Falcon - Oozie integration', displayName: 'Falcon - Oozie integration'}), App.ServiceConfigCategory.create({ name: 'FalconStartupSite', displayName: 'Falcon startup.properties'}), App.ServiceConfigCategory.create({ name: 'FalconRuntimeSite', displayName: 'Falcon runtime.properties'}), App.ServiceConfigCategory.create({ name: 'General', displayName: 'General'}) ]); break; case 'STORM': serviceConfigCategories.pushObjects([ App.ServiceConfigCategory.create({ name: 'NIMBUS', displayName: 'Nimbus', showHost: true}), App.ServiceConfigCategory.create({ name: 'SUPERVISOR', displayName: 'Supervisor', showHost: true}), App.ServiceConfigCategory.create({ name: 'STORM_UI_SERVER', displayName: 'Storm UI Server', showHost: true}), App.ServiceConfigCategory.create({ name: 'STORM_REST_API', displayName: 'Storm REST API Server', showHost: true}), App.ServiceConfigCategory.create({ name: 'DRPC_SERVER', displayName: 'DRPC Server', showHost: true}), App.ServiceConfigCategory.create({ name: 'General', displayName: 'General'}) ]); break; case 'TEZ': serviceConfigCategories.pushObjects([ App.ServiceConfigCategory.create({ name: 'General', displayName: 'General'}) ]); break; case 'FLUME': serviceConfigCategories.pushObjects([ App.ServiceConfigCategory.create({ name: 'FLUME_HANDLER', displayName: 'flume.conf', siteFileName: 'flume-conf', canAddProperty: false}) ]); break; case 'KNOX': serviceConfigCategories.pushObjects([ App.ServiceConfigCategory.create({ name: 'KNOX_GATEWAY', displayName: 'Knox Gateway', showHost: true}) ]); break; case 'KAFKA': serviceConfigCategories.pushObjects([ App.ServiceConfigCategory.create({ name: 'KAFKA_BROKER', displayName: 'Kafka Broker', showHost: true}) ]); break; case 'KERBEROS': serviceConfigCategories.pushObjects([ App.ServiceConfigCategory.create({ name: 'KDC', displayName: 'KDC'}), App.ServiceConfigCategory.create({ name: 'Kadmin', displayName: 'Kadmin'}), App.ServiceConfigCategory.create({ name: 'General', displayName: 'General'}) ]); break; case 'AMBARI_METRICS': serviceConfigCategories.pushObjects([ App.ServiceConfigCategory.create({ name: 'General', displayName: 'General'}), App.ServiceConfigCategory.create({ name: 'MetricCollector', displayName: 'Metric Collector'}) ]); break; case 'RANGER': serviceConfigCategories.pushObjects([ App.ServiceConfigCategory.create({ name: 'RANGER_ADMIN', displayName: 'Admin Settings', showHost: true}), App.ServiceConfigCategory.create({ name: 'DBSettings', displayName: 'DB Settings'}), App.ServiceConfigCategory.create({ name: 'RangerSettings', displayName: 'Ranger Settings'}), App.ServiceConfigCategory.create({ name: 'UnixAuthenticationSettings', displayName: 'Unix Authentication Settings'}), App.ServiceConfigCategory.create({ name: 'ADSettings', displayName: 'AD Settings'}), App.ServiceConfigCategory.create({ name: 'LDAPSettings', displayName: 'LDAP Settings'}), App.ServiceConfigCategory.create({ name: 'KnoxSSOSettings', displayName: 'Knox SSO Settings'}) ]); break; case 'ACCUMULO': serviceConfigCategories.pushObjects([ App.ServiceConfigCategory.create({ name: 'General', displayName: 'General'}) ]); break; case 'PIG': break; case 'SQOOP': break; case 'HAWQ': serviceConfigCategories.pushObjects([ App.ServiceConfigCategory.create({ name: 'General', displayName: 'General'}), App.ServiceConfigCategory.create({ name: 'AdvancedHawqCheck', displayName: 'Advanced HAWQ Check'}) ]); break; case 'LOGSEARCH': serviceConfigCategories.pushObjects([ App.ServiceConfigCategory.create({ name: 'LogsearchAdminJson', displayName: 'Advanced logsearch-admin-json'}) ]); break; default: serviceConfigCategories.pushObjects([ App.ServiceConfigCategory.create({ name: 'General', displayName: 'General'}) ]); } serviceConfigCategories.pushObject(App.ServiceConfigCategory.create({ name: 'Advanced', displayName: 'Advanced'})); var configTypes = this.get('configTypeList'); // Add Advanced section for every configType to all the services configTypes.forEach(function (type) { serviceConfigCategories.pushObject(App.ServiceConfigCategory.create({ name: 'Advanced ' + type, displayName: Em.I18n.t('common.advanced') + " " + type, canAddProperty: false })); }, this); // Add custom section for every configType to all the services configTypes.forEach(function (type) { if (Em.getWithDefault(this.get('configTypes')[type] || {}, 'supports.adding_forbidden', 'true') === 'false') { serviceConfigCategories.pushObject(App.ServiceConfigCategory.create({ name: 'Custom ' + type, displayName: Em.I18n.t('common.custom') + " " + type, siteFileName: type + '.xml', canAddProperty: true })); } }, this); return serviceConfigCategories; };