AMBARI-13263. Create a Ranger theme with Ranger Admin. (jaimin)
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/61540bbb Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/61540bbb Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/61540bbb Branch: refs/heads/branch-dev-patch-upgrade Commit: 61540bbb54d023b52ce7e59fee81a067a1cbdcc8 Parents: 2b34016 Author: Jaimin Jetly <[email protected]> Authored: Mon Sep 28 20:22:26 2015 -0700 Committer: Jaimin Jetly <[email protected]> Committed: Mon Sep 28 20:23:52 2015 -0700 ---------------------------------------------------------------------- .../server/state/ValueAttributesInfo.java | 16 + .../server/state/theme/ConfigCondition.java | 87 +++++ .../server/state/theme/ConfigPlacement.java | 26 ++ .../ambari/server/state/theme/Subsection.java | 28 ++ .../ambari/server/state/theme/Widget.java | 23 +- .../0.4.0/configuration/admin-properties.xml | 12 + .../RANGER/0.4.0/configuration/ranger-env.xml | 3 +- .../RANGER/configuration/admin-properties.xml | 58 +++ .../RANGER/configuration/ranger-env.xml | 21 +- .../stacks/HDP/2.3/services/RANGER/metainfo.xml | 7 + .../HDP/2.3/services/RANGER/themes/theme.json | 294 +++++++++++++++ ambari-web/app/app.js | 2 + .../controllers/main/service/info/configs.js | 9 +- .../app/controllers/wizard/step7_controller.js | 2 +- ambari-web/app/data/HDP2.2/site_properties.js | 13 +- ambari-web/app/data/HDP2.3/site_properties.js | 44 +-- ambari-web/app/mappers/configs/themes_mapper.js | 84 ++++- ambari-web/app/models.js | 1 + .../app/models/configs/config_condition.js | 60 +++ ambari-web/app/models/configs/section.js | 6 +- .../app/models/configs/stack_config_property.js | 10 + ambari-web/app/models/configs/sub_section.js | 21 +- .../configs/service_config_layout_tab.hbs | 10 +- .../widgets/test_db_connection_widget.hbs | 35 ++ ambari-web/app/utils/config.js | 43 ++- ambari-web/app/views.js | 1 + .../configs/service_config_layout_tab_view.js | 24 +- .../configs/widgets/config_widget_view.js | 50 +++ .../widgets/password_config_widget_view.js | 1 + .../widgets/test_db_connection_widget_view.js | 364 +++++++++++++++++++ .../test/mappers/configs/themes_mapper_test.js | 2 + ambari-web/test/models/configs/section_test.js | 12 +- 32 files changed, 1278 insertions(+), 91 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/61540bbb/ambari-server/src/main/java/org/apache/ambari/server/state/ValueAttributesInfo.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/ValueAttributesInfo.java b/ambari-server/src/main/java/org/apache/ambari/server/state/ValueAttributesInfo.java index e8cd074..3f7f756 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/state/ValueAttributesInfo.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/state/ValueAttributesInfo.java @@ -43,6 +43,10 @@ public class ValueAttributesInfo { @JsonProperty("empty_value_valid") private Boolean emptyValueValid; + @XmlElement(name = "ui-only-property") + @JsonProperty("ui_only_property") + private Boolean uiOnlyProperty; + @XmlElement(name = "read-only") @JsonProperty("read_only") private Boolean readOnly; @@ -194,6 +198,14 @@ public class ValueAttributesInfo { this.showPropertyName = isPropertyNameVisible; } + public Boolean getUiOnlyProperty() { + return uiOnlyProperty; + } + + public void setUiOnlyProperty(Boolean isUiOnlyProperty) { + this.uiOnlyProperty = isUiOnlyProperty; + } + @Override public boolean equals(Object o) { if (this == o) return true; @@ -216,6 +228,8 @@ public class ValueAttributesInfo { return false; if (showPropertyName != null ? !showPropertyName.equals(that.showPropertyName) : that.showPropertyName != null) return false; + if (uiOnlyProperty != null ? !uiOnlyProperty.equals(that.uiOnlyProperty) : that.uiOnlyProperty != null) + return false; if (maximum != null ? !maximum.equals(that.maximum) : that.maximum != null) return false; if (minimum != null ? !minimum.equals(that.minimum) : that.minimum != null) return false; if (selectionCardinality != null ? !selectionCardinality.equals(that.selectionCardinality) : that.selectionCardinality != null) @@ -245,6 +259,7 @@ public class ValueAttributesInfo { result = 31 * result + (editableOnlyAtInstall != null ? editableOnlyAtInstall.hashCode() : 0); result = 31 * result + (overridable != null ? overridable.hashCode() : 0); result = 31 * result + (showPropertyName != null ? showPropertyName.hashCode() : 0); + result = 31 * result + (uiOnlyProperty != null ? uiOnlyProperty.hashCode() : 0); return result; } @@ -263,6 +278,7 @@ public class ValueAttributesInfo { ", editableOnlyAtInstall='" + editableOnlyAtInstall + '\'' + ", overridable='" + overridable + '\'' + ", showPropertyName='" + showPropertyName + '\'' + + ", uiOnlyProperty='" + uiOnlyProperty + '\'' + ", incrementStep='" + incrementStep + '\'' + ", entriesEditable=" + entriesEditable + ", selectionCardinality='" + selectionCardinality + '\'' + http://git-wip-us.apache.org/repos/asf/ambari/blob/61540bbb/ambari-server/src/main/java/org/apache/ambari/server/state/theme/ConfigCondition.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/theme/ConfigCondition.java b/ambari-server/src/main/java/org/apache/ambari/server/state/theme/ConfigCondition.java new file mode 100644 index 0000000..2d98660 --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/state/theme/ConfigCondition.java @@ -0,0 +1,87 @@ +/** + * 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 + * <p/> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p/> + * 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.state.theme; + +import org.apache.ambari.server.state.ValueAttributesInfo; +import org.codehaus.jackson.annotate.JsonIgnoreProperties; +import org.codehaus.jackson.annotate.JsonProperty; +import org.codehaus.jackson.map.annotate.JsonSerialize; + +import java.util.List; + +@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public class ConfigCondition { + @JsonProperty("configs") + private List<String> configs; + @JsonProperty("if") + private String ifLabel; + @JsonProperty("then") + private ConfigConditionResult then; + @JsonProperty("else") + private ConfigConditionResult elseLabel; + + public List<String> getConfigs() { + return configs; + } + + public void setConfigs(List<String> configs) { + this.configs = configs; + } + + public String getIfLabel() { + return ifLabel; + } + + public void setIfLabel(String ifLabel) { + this.ifLabel = ifLabel; + } + + public ConfigConditionResult getThen() { + return then; + } + + public void setThen(ConfigConditionResult then) { + this.then = then; + } + + public ConfigConditionResult getElseLabel() { + return elseLabel; + } + + public void setElseLabel(ConfigConditionResult elseLabel) { + this.elseLabel = elseLabel; + } + + @JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL) + @JsonIgnoreProperties(ignoreUnknown = true) + public class ConfigConditionResult { + @JsonProperty("property_value_attributes") + private ValueAttributesInfo propertyValueAttributes; + + public ValueAttributesInfo getPropertyValueAttributes() { + return propertyValueAttributes; + } + + public void setPropertyValueAttributes(ValueAttributesInfo propertyValueAttributes) { + this.propertyValueAttributes = propertyValueAttributes; + } + } + +} http://git-wip-us.apache.org/repos/asf/ambari/blob/61540bbb/ambari-server/src/main/java/org/apache/ambari/server/state/theme/ConfigPlacement.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/theme/ConfigPlacement.java b/ambari-server/src/main/java/org/apache/ambari/server/state/theme/ConfigPlacement.java index c20cd8e..56d2ea2 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/state/theme/ConfigPlacement.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/state/theme/ConfigPlacement.java @@ -18,10 +18,13 @@ package org.apache.ambari.server.state.theme; +import org.apache.ambari.server.state.ValueAttributesInfo; import org.codehaus.jackson.annotate.JsonIgnoreProperties; import org.codehaus.jackson.annotate.JsonProperty; import org.codehaus.jackson.map.annotate.JsonSerialize; +import java.util.List; + @JsonSerialize(include= JsonSerialize.Inclusion.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) public class ConfigPlacement { @@ -30,6 +33,13 @@ public class ConfigPlacement { @JsonProperty("subsection-name") private String subsectionName; + @JsonProperty("property_value_attributes") + private ValueAttributesInfo propertyValueAttributes; + + @JsonProperty("depends-on") + private List<ConfigCondition> dependsOn; + + public String getConfig() { return config; } @@ -46,6 +56,22 @@ public class ConfigPlacement { this.subsectionName = subsectionName; } + public ValueAttributesInfo getPropertyValueAttributes() { + return propertyValueAttributes; + } + + public void setPropertyValueAttributes(ValueAttributesInfo propertyValueAttributes) { + this.propertyValueAttributes = propertyValueAttributes; + } + + public List<ConfigCondition> getDependsOn() { + return dependsOn; + } + + public void setDependsOn(List<ConfigCondition> dependsOn) { + this.dependsOn = dependsOn; + } + public boolean isRemoved() { return subsectionName == null; } http://git-wip-us.apache.org/repos/asf/ambari/blob/61540bbb/ambari-server/src/main/java/org/apache/ambari/server/state/theme/Subsection.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/theme/Subsection.java b/ambari-server/src/main/java/org/apache/ambari/server/state/theme/Subsection.java index b86b51f..0397545 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/state/theme/Subsection.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/state/theme/Subsection.java @@ -23,6 +23,8 @@ import org.codehaus.jackson.annotate.JsonIgnoreProperties; import org.codehaus.jackson.annotate.JsonProperty; import org.codehaus.jackson.map.annotate.JsonSerialize; +import java.util.List; + @JsonSerialize(include= JsonSerialize.Inclusion.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) @@ -41,6 +43,10 @@ public class Subsection { private String columnIndex; @JsonProperty("border") private String border; + @JsonProperty("left-vertical-splitter") + private Boolean leftVerticalSplitter; + @JsonProperty("depends-on") + private List<ConfigCondition> dependsOn; public String getRowIndex() { @@ -99,6 +105,22 @@ public class Subsection { this.border = border; } + public Boolean getLeftVerticalSplitter() { + return leftVerticalSplitter; + } + + public void setLeftVerticalSplitter(Boolean leftVerticalSplitter) { + this.leftVerticalSplitter = leftVerticalSplitter; + } + + public List<ConfigCondition> getDependsOn() { + return dependsOn; + } + + public void setDependsOn(List<ConfigCondition> dependsOn) { + this.dependsOn = dependsOn; + } + public boolean isRemoved() { return rowIndex == null && rowSpan == null && columnIndex == null && columnSpan == null; } @@ -122,5 +144,11 @@ public class Subsection { if (border == null) { border = parent.border; } + if (leftVerticalSplitter == null) { + leftVerticalSplitter = parent.leftVerticalSplitter; + } + if (dependsOn == null) { + dependsOn = parent.dependsOn; + } } } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/61540bbb/ambari-server/src/main/java/org/apache/ambari/server/state/theme/Widget.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/theme/Widget.java b/ambari-server/src/main/java/org/apache/ambari/server/state/theme/Widget.java index 7b1e09c..c8176ee 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/state/theme/Widget.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/state/theme/Widget.java @@ -24,6 +24,7 @@ import org.codehaus.jackson.annotate.JsonProperty; import org.codehaus.jackson.map.annotate.JsonSerialize; import java.util.List; +import java.util.Map; @JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL) @@ -33,6 +34,10 @@ public class Widget{ private String type; @JsonProperty("units") private List<Unit> units; + @JsonProperty("required-properties") + private Map<String,String> requiredProperties; + @JsonProperty("display-name") + private String displayName; public String getType() { return type; @@ -49,4 +54,20 @@ public class Widget{ public void setUnits(List<Unit> units) { this.units = units; } -} \ No newline at end of file + + public Map<String, String> getRequiredProperties() { + return requiredProperties; + } + + public void setRequiredProperties(Map<String, String> requiredProperties) { + this.requiredProperties = requiredProperties; + } + + public String getDisplayName() { + return displayName; + } + + public void setDisplayName(String displayName) { + this.displayName = displayName; + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/61540bbb/ambari-server/src/main/resources/common-services/RANGER/0.4.0/configuration/admin-properties.xml ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/resources/common-services/RANGER/0.4.0/configuration/admin-properties.xml b/ambari-server/src/main/resources/common-services/RANGER/0.4.0/configuration/admin-properties.xml index 936c332..c7e3ff9 100644 --- a/ambari-server/src/main/resources/common-services/RANGER/0.4.0/configuration/admin-properties.xml +++ b/ambari-server/src/main/resources/common-services/RANGER/0.4.0/configuration/admin-properties.xml @@ -28,6 +28,18 @@ <description>The database type to be used (mysql/oracle)</description> <value-attributes> <overridable>false</overridable> + <type>value-list</type> + <entries> + <entry> + <value>MYSQL</value> + <label>MYSQL</label> + </entry> + <entry> + <value>ORACLE</value> + <label>ORACLE</label> + </entry> + </entries> + <selection-cardinality>1</selection-cardinality> </value-attributes> </property> http://git-wip-us.apache.org/repos/asf/ambari/blob/61540bbb/ambari-server/src/main/resources/common-services/RANGER/0.4.0/configuration/ranger-env.xml ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/resources/common-services/RANGER/0.4.0/configuration/ranger-env.xml b/ambari-server/src/main/resources/common-services/RANGER/0.4.0/configuration/ranger-env.xml index 95c3b50..97c2b9f 100644 --- a/ambari-server/src/main/resources/common-services/RANGER/0.4.0/configuration/ranger-env.xml +++ b/ambari-server/src/main/resources/common-services/RANGER/0.4.0/configuration/ranger-env.xml @@ -58,6 +58,7 @@ <name>ranger_admin_username</name> <value>amb_ranger_admin</value> <property-type>TEXT</property-type> + <display-name>Ranger Admin username for Ambari</display-name> <description>This is the ambari user created for creating repositories and policies in Ranger Admin for each plugin</description> </property> @@ -102,6 +103,6 @@ <name>ranger_pid_dir</name> <value>/var/run/ranger</value> <description></description> - </property> + </property> </configuration> http://git-wip-us.apache.org/repos/asf/ambari/blob/61540bbb/ambari-server/src/main/resources/stacks/HDP/2.3/services/RANGER/configuration/admin-properties.xml ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/resources/stacks/HDP/2.3/services/RANGER/configuration/admin-properties.xml b/ambari-server/src/main/resources/stacks/HDP/2.3/services/RANGER/configuration/admin-properties.xml index 114c3ab..5d7f7ce 100644 --- a/ambari-server/src/main/resources/stacks/HDP/2.3/services/RANGER/configuration/admin-properties.xml +++ b/ambari-server/src/main/resources/stacks/HDP/2.3/services/RANGER/configuration/admin-properties.xml @@ -22,6 +22,64 @@ <configuration supports_final="false"> <property> + <name>DB_FLAVOR</name> + <value>MYSQL</value> + <display-name>DB FLAVOR</display-name> + <description>The database type to be used (mysql/oracle)</description> + <value-attributes> + <overridable>false</overridable> + <type>value-list</type> + <entries> + <entry> + <value>MYSQL</value> + <label>MYSQL</label> + </entry> + <entry> + <value>ORACLE</value> + <label>ORACLE</label> + </entry> + <entry> + <value>POSTGRES</value> + <label>POSTGRES</label> + </entry> + <entry> + <value>MSSQL</value> + <label>MSSQL</label> + </entry> + <entry> + <value>SQLA</value> + <label>SQL Anywhere</label> + </entry> + </entries> + <selection-cardinality>1</selection-cardinality> + </value-attributes> + </property> + + <property> + <name>db_root_user</name> + <value>root</value> + <display-name>Ranger DB root user</display-name> + <description>Database admin user</description> + <value-attributes> + <overridable>false</overridable> + <visible>false</visible> + </value-attributes> + </property> + + <property require-input="true"> + <name>db_root_password</name> + <value></value> + <property-type>PASSWORD</property-type> + <display-name>Ranger DB root password</display-name> + <description>Database password for the database admin user-id</description> + <value-attributes> + <overridable>false</overridable> + <visible>false</visible> + </value-attributes> + </property> + + + <property> <name>policymgr_http_enabled</name> <deleted>true</deleted> </property> http://git-wip-us.apache.org/repos/asf/ambari/blob/61540bbb/ambari-server/src/main/resources/stacks/HDP/2.3/services/RANGER/configuration/ranger-env.xml ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/resources/stacks/HDP/2.3/services/RANGER/configuration/ranger-env.xml b/ambari-server/src/main/resources/stacks/HDP/2.3/services/RANGER/configuration/ranger-env.xml index 8308865..7f3e6e0 100644 --- a/ambari-server/src/main/resources/stacks/HDP/2.3/services/RANGER/configuration/ranger-env.xml +++ b/ambari-server/src/main/resources/stacks/HDP/2.3/services/RANGER/configuration/ranger-env.xml @@ -28,9 +28,24 @@ <property> <name>create_db_dbuser</name> - <value>true</value> - <display-name>Setup DB and DB user</display-name> - <description>Setup Ranger Database and Database User?</description> + <value>false</value> + <display-name>Setup Database and Databse User</display-name> + <description>If set to Yes, Ranger will Setup Database and Databse User. This will require to specify Database root user and password</description> + <value-attributes> + <type>value-list</type> + <overridable>false</overridable> + <entries> + <entry> + <value>true</value> + <label>Yes</label> + </entry> + <entry> + <value>false</value> + <label>No</label> + </entry> + </entries> + <selection-cardinality>1</selection-cardinality> + </value-attributes> </property> <property> http://git-wip-us.apache.org/repos/asf/ambari/blob/61540bbb/ambari-server/src/main/resources/stacks/HDP/2.3/services/RANGER/metainfo.xml ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/resources/stacks/HDP/2.3/services/RANGER/metainfo.xml b/ambari-server/src/main/resources/stacks/HDP/2.3/services/RANGER/metainfo.xml index a13fabf..69d908b 100644 --- a/ambari-server/src/main/resources/stacks/HDP/2.3/services/RANGER/metainfo.xml +++ b/ambari-server/src/main/resources/stacks/HDP/2.3/services/RANGER/metainfo.xml @@ -52,6 +52,13 @@ </osSpecific> </osSpecifics> + <themes> + <theme> + <fileName>theme.json</fileName> + <default>true</default> + </theme> + </themes> + <configuration-dependencies> <config-type>ranger-admin-site</config-type> <config-type>ranger-ugsync-site</config-type> http://git-wip-us.apache.org/repos/asf/ambari/blob/61540bbb/ambari-server/src/main/resources/stacks/HDP/2.3/services/RANGER/themes/theme.json ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/resources/stacks/HDP/2.3/services/RANGER/themes/theme.json b/ambari-server/src/main/resources/stacks/HDP/2.3/services/RANGER/themes/theme.json new file mode 100644 index 0000000..7160a4f --- /dev/null +++ b/ambari-server/src/main/resources/stacks/HDP/2.3/services/RANGER/themes/theme.json @@ -0,0 +1,294 @@ +{ + "name": "default", + "description": "Default theme for Ranger service", + "configuration": { + "layouts": [ + { + "name": "default", + "tabs": [ + { + "name": "ranger_admin_settings", + "display-name": "Ranger Admin", + "layout": { + "tab-columns": "2", + "tab-rows": "2", + "sections": [ + { + "name": "section-ranger-admin", + "display-name": "Ranger Admin", + "row-index": "0", + "column-index": "0", + "row-span": "4", + "column-span": "2", + "section-columns": "2", + "section-rows": "4", + "subsections": [ + { + "name": "subsection-ranger-db-row1-col1", + "row-index": "0", + "column-index": "0", + "row-span": "1", + "column-span": "1" + }, + { + "name": "subsection-ranger-db-row1-col2", + "row-index": "0", + "column-index": "1", + "row-span": "1", + "column-span": "1" + }, + { + "name": "subsection-ranger-db-row2-col1", + "row-index": "1", + "column-index": "0", + "row-span": "1", + "column-span": "1" + }, + { + "name": "subsection-ranger-db-row2-col2", + "row-index": "1", + "column-index": "1", + "row-span": "1", + "column-span": "1", + "left-vertical-splitter": false + }, + { + "name": "subsection-ranger-db-row3", + "row-index": "2", + "column-index": "0", + "row-span": "1", + "column-span": "2" + }, + { + "name": "subsection-ranger-db-row4-col1", + "row-index": "3", + "column-index": "0", + "row-span": "1", + "column-span": "1", + "depends-on": [ + { + "configs":[ + "ranger-env/create_db_dbuser" + ], + "if": "${ranger-env/create_db_dbuser}", + "then": { + "property_value_attributes": { + "visible": true + } + }, + "else": { + "property_value_attributes": { + "visible": false + } + } + } + ] + }, + { + "name": "subsection-ranger-db-row4-col2", + "row-index": "3", + "column-index": "1", + "row-span": "1", + "column-span": "1", + "depends-on": [ + { + "configs":[ + "ranger-env/create_db_dbuser" + ], + "if": "${ranger-env/create_db_dbuser}", + "then": { + "property_value_attributes": { + "visible": true + } + }, + "else": { + "property_value_attributes": { + "visible": false + } + } + } + ], + "left-vertical-splitter": false + } + ] + } + ] + } + } + ] + } + ], + "placement": { + "configuration-layout": "default", + "configs": [ + { + "config": "admin-properties/DB_FLAVOR", + "subsection-name": "subsection-ranger-db-row1-col1" + }, + { + "config": "admin-properties/db_name", + "subsection-name": "subsection-ranger-db-row1-col1" + }, + { + "config": "ranger-admin-site/ranger.jpa.jdbc.url", + "subsection-name": "subsection-ranger-db-row1-col1" + }, + { + "config": "admin-properties/db_host", + "subsection-name": "subsection-ranger-db-row1-col2" + }, + { + "config": "ranger-admin-site/ranger.jpa.jdbc.driver", + "subsection-name": "subsection-ranger-db-row1-col2" + }, + { + "config": "admin-properties/db_user", + "subsection-name": "subsection-ranger-db-row2-col1" + }, + { + "config": "admin-properties/db_password", + "subsection-name": "subsection-ranger-db-row2-col2" + }, + { + "config": "ranger-env/test_db_connection", + "subsection-name": "subsection-ranger-db-row2-col2", + "property_value_attributes": { + "ui_only_property": true + }, + "depends-on": [ + { + "configs":[ + "ranger-env/create_db_dbuser" + ], + "if": "${ranger-env/create_db_dbuser}", + "then": { + "property_value_attributes": { + "visible": false + } + }, + "else": { + "property_value_attributes": { + "visible": true + } + } + } + ] + }, + { + "config": "ranger-env/create_db_dbuser", + "subsection-name": "subsection-ranger-db-row3" + }, + { + "config": "admin-properties/db_root_user", + "subsection-name": "subsection-ranger-db-row4-col1" + }, + { + "config": "admin-properties/db_root_password", + "subsection-name": "subsection-ranger-db-row4-col2" + }, + { + "config": "ranger-env/test_root_db_connection", + "subsection-name": "subsection-ranger-db-row4-col2", + "property_value_attributes": { + "ui_only_property": true + } + } + ] + }, + "widgets": [ + { + "config": "admin-properties/DB_FLAVOR", + "widget": { + "type": "combo" + } + }, + { + "config": "admin-properties/db_user", + "widget": { + "type": "text-field" + } + }, + { + "config": "admin-properties/db_name", + "widget": { + "type": "text-field" + } + }, + { + "config": "ranger-admin-site/ranger.jpa.jdbc.url", + "widget": { + "type": "text-field" + } + }, + { + "config": "ranger-admin-site/ranger.jpa.jdbc.driver", + "widget": { + "type": "text-field" + } + }, + { + "config": "admin-properties/db_host", + "widget": { + "type": "text-field" + } + }, + { + "config": "admin-properties/db_password", + "widget": { + "type": "password" + } + }, + { + "config": "ranger-env/test_db_connection", + "widget": { + "type": "test-db-connection", + "display-name": "Test Connection", + "required-properties": { + "jdbc.driver.class": "ranger-admin-site/ranger.jpa.jdbc.driver", + "jdbc.driver.url": "ranger-admin-site/ranger.jpa.jdbc.url", + "db.connection.source.host": "ranger-site/ranger_admin_hosts", + "db.type": "admin-properties/DB_FLAVOR", + "db.connection.destination.host": "admin-properties/db_host", + "db.connection.user": "admin-properties/db_user", + "db.connection.password": "admin-properties/db_password" + } + } + }, + { + "config": "ranger-env/create_db_dbuser", + "widget": { + "type": "toggle" + } + }, + { + "config": "admin-properties/db_root_user", + "widget": { + "type": "text-field" + } + }, + { + "config": "admin-properties/db_root_password", + "widget": { + "type": "password" + } + }, + { + "config": "ranger-env/test_root_db_connection", + "widget": { + "type": "test-db-connection", + "display-name": "Test Connection", + "required-properties": { + "jdbc.driver.class": "ranger-admin-site/ranger.jpa.jdbc.driver", + "jdbc.driver.url": "ranger-admin-site/ranger.jpa.jdbc.url", + "db.connection.source.host": "ranger-site/ranger_admin_hosts", + "db.type": "admin-properties/DB_FLAVOR", + "db.connection.destination.host": "admin-properties/db_host", + "db.connection.user": "admin-properties/db_root_user", + "db.connection.password": "admin-properties/db_root_password" + } + } + } + ] + } +} + http://git-wip-us.apache.org/repos/asf/ambari/blob/61540bbb/ambari-web/app/app.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/app.js b/ambari-web/app/app.js index f7c86b1..16bcc28 100644 --- a/ambari-web/app/app.js +++ b/ambari-web/app/app.js @@ -184,6 +184,8 @@ module.exports = Em.Application.create({ allHostNames: [], + uiOnlyConfigDerivedFromTheme: [], + currentStackVersionNumber: function () { var regExp = new RegExp(this.get('currentStackName') + '-'); return (this.get('currentStackVersion') || this.get('defaultStackVersion')).replace(regExp, ''); http://git-wip-us.apache.org/repos/asf/ambari/blob/61540bbb/ambari-web/app/controllers/main/service/info/configs.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/controllers/main/service/info/configs.js b/ambari-web/app/controllers/main/service/info/configs.js index db5f1ed..3252fa3 100644 --- a/ambari-web/app/controllers/main/service/info/configs.js +++ b/ambari-web/app/controllers/main/service/info/configs.js @@ -135,7 +135,7 @@ App.MainServiceInfoConfigsController = Em.Controller.extend(App.ConfigsLoader, A }).filter(function(config) { return !config.get('isValid') || (config.get('overrides') || []).someProperty('isValid', false); }).filterProperty('isVisible').length; - }.property('[email protected]', '[email protected]'), + }.property('[email protected]', '[email protected]', '[email protected]'), /** * Determines if Save-button should be disabled @@ -302,17 +302,18 @@ App.MainServiceInfoConfigsController = Em.Controller.extend(App.ConfigsLoader, A * @method loadStep */ loadStep: function () { + var self = this; var serviceName = this.get('content.serviceName'); this.clearStep(); this.set('dependentServiceNames', App.StackService.find(serviceName).get('dependentServiceNames')); if (App.get('isClusterSupportsEnhancedConfigs')) { this.loadConfigTheme(serviceName).always(function() { App.themesMapper.generateAdvancedTabs([serviceName]); + // Theme mapper has UI only configs that needs to be merged with current service version configs + // This requires calling `loadCurrentVersions` after theme has loaded + self.loadCurrentVersions(); }); } - if (!this.get('preSelectedConfigVersion')) { - this.loadCurrentVersions(); - } this.loadServiceConfigVersions(); }, http://git-wip-us.apache.org/repos/asf/ambari/blob/61540bbb/ambari-web/app/controllers/wizard/step7_controller.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/controllers/wizard/step7_controller.js b/ambari-web/app/controllers/wizard/step7_controller.js index bedd164..ff0e2ce 100644 --- a/ambari-web/app/controllers/wizard/step7_controller.js +++ b/ambari-web/app/controllers/wizard/step7_controller.js @@ -128,7 +128,7 @@ App.WizardStep7Controller = Em.Controller.extend(App.ServerValidatorMixin, App.E }).filter(function(config) { return !config.get('isValid') || (config.get('overrides') || []).someProperty('isValid', false); }).filterProperty('isVisible').length; - }.property('[email protected]', '[email protected]'), + }.property('[email protected]', '[email protected]','[email protected]'), /** * Should Next-button be disabled http://git-wip-us.apache.org/repos/asf/ambari/blob/61540bbb/ambari-web/app/data/HDP2.2/site_properties.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/data/HDP2.2/site_properties.js b/ambari-web/app/data/HDP2.2/site_properties.js index 7341387..397e748 100644 --- a/ambari-web/app/data/HDP2.2/site_properties.js +++ b/ambari-web/app/data/HDP2.2/site_properties.js @@ -210,16 +210,25 @@ hdp22properties.push( }, /**********************************************RANGER***************************************/ { + "name": "ranger_admin_username", + "serviceName": "RANGER", + "filename": "ranger-env.xml", + "category": "RANGER_ADMIN", + "index": 0 + }, + { "name": "ranger_admin_password", "serviceName": "RANGER", "filename": "ranger-env.xml", - "category": "RANGER_ADMIN" + "category": "RANGER_ADMIN", + "index": 1 }, { "name": "SQL_CONNECTOR_JAR", "serviceName": "RANGER", "filename": "admin-properties.xml", - "category": "RANGER_ADMIN" + "category": "RANGER_ADMIN", + "index": 2 }, { "name": "DB_FLAVOR", http://git-wip-us.apache.org/repos/asf/ambari/blob/61540bbb/ambari-web/app/data/HDP2.3/site_properties.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/data/HDP2.3/site_properties.js b/ambari-web/app/data/HDP2.3/site_properties.js index adf8cae..8041bc6 100644 --- a/ambari-web/app/data/HDP2.3/site_properties.js +++ b/ambari-web/app/data/HDP2.3/site_properties.js @@ -23,6 +23,8 @@ var hdp22properties = require('data/HDP2.2/site_properties').configProperties; var excludedConfigs = [ 'DB_FLAVOR', 'db_name', + 'db_user', + 'db_password', 'db_root_user', 'db_root_password', 'nimbus.host', @@ -67,48 +69,8 @@ var hdp23properties = hdp22properties.filter(function (item) { }); hdp23properties.push({ - "name": "DB_FLAVOR", - "options": [ - { - displayName: 'MYSQL' - }, - { - displayName: 'ORACLE' - }, - { - displayName: 'POSTGRES' - }, - { - displayName: 'MSSQL' - }, - { - displayName: 'SQLA', - hidden: App.get('currentStackName') !== 'SAPHD' && App.get('currentStackName') !== 'HDP' - } - ], - "displayType": "radio button", - "radioName": "RANGER DB_FLAVOR", - "serviceName": "RANGER", - "filename": "admin-properties.xml", - "category": "DBSettings", - "index": 1 - }, - { - "name": "db_host", - "serviceName": "RANGER", - "filename": "admin-properties.xml", - "category": "DBSettings", - "index": 2 - }, - { - "name": "create_db_dbuser", - "displayType": "checkbox", - "filename": "ranger-env.xml", - "category": "Advanced ranger-env", - "serviceName": "RANGER" - }, /**************************************** RANGER - HDFS Plugin ***************************************/ - { + "name": "xasecure.audit.destination.db", "displayType": "checkbox", "filename": "ranger-hdfs-audit.xml", http://git-wip-us.apache.org/repos/asf/ambari/blob/61540bbb/ambari-web/app/mappers/configs/themes_mapper.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/mappers/configs/themes_mapper.js b/ambari-web/app/mappers/configs/themes_mapper.js index e632860..b55a695 100644 --- a/ambari-web/app/mappers/configs/themes_mapper.js +++ b/ambari-web/app/mappers/configs/themes_mapper.js @@ -21,6 +21,7 @@ App.themesMapper = App.QuickDataMapper.create({ tabModel: App.Tab, sectionModel: App.Section, subSectionModel: App.SubSection, + configConditionModel: App.ConfigCondition, tabConfig: { "id": "name", @@ -55,7 +56,9 @@ App.themesMapper = App.QuickDataMapper.create({ "column_span": "column-span", "row_span": "row-span", "configProperties": "config_properties", - "section_id": "section_id" + "section_id": "section_id", + "depends_on": "depends-on", + "left_vertical_splitter": "left-vertical-splitter" }, map: function (json) { @@ -123,22 +126,85 @@ App.themesMapper = App.QuickDataMapper.create({ * @param {Object} json - json to parse */ mapThemeConfigs: function(json) { + var serviceName = Em.get(json, "ThemeInfo.service_name"); Em.getWithDefault(json, "ThemeInfo.theme_data.Theme.configuration.placement.configs", []).forEach(function(configLink) { var configId = this.getConfigId(configLink); var subSectionId = configLink["subsection-name"]; var subSection = App.SubSection.find(subSectionId); var configProperty = App.StackConfigProperty.find(configId); + var subSectionDependsOnConfigs = subSection.get('dependsOn'); + var configDependsOnOtherConfigs = configLink["depends-on"] || []; + var dependsOnConfigs = configDependsOnOtherConfigs.concat(subSectionDependsOnConfigs); - if (configProperty && subSection) { + if (configProperty.get('id') && subSection) { subSection.get('configProperties').pushObject(configProperty); configProperty.set('subSection', subSection); } else { - console.warn('there is no such property: ' + configId + '. Or subsection: ' + subSectionId); + console.log('there is no such property: ' + configId + '. Or subsection: ' + subSectionId); + var valueAttributes = configLink["property_value_attributes"]; + if (valueAttributes) { + var isUiOnlyProperty = valueAttributes["ui_only_property"]; + // UI only configs are mentioned in the themes for supporting widgets that is not intended for setting a value + // And thus is affiliated witha fake config peperty termed as ui only config property + if (isUiOnlyProperty && subSection) { + var split = configLink.config.split("/"); + var fileName = split[0] + '.xml'; + var configName = split[1]; + var uiOnlyConfig = App.uiOnlyConfigDerivedFromTheme.filterProperty('filename', fileName).findProperty('name', configName); + if (!uiOnlyConfig) { + var coreObject = { + id: configName + '_' + split[0], + isRequiredByAgent: false, + showLabel: false, + isOverridable: false, + recommendedValue: true, + name: configName, + isUserProperty: false, + filename: fileName, + serviceName: serviceName, + subSection: subSection + }; + var uiOnlyConfigDerivedFromTheme = Em.Object.create(App.config.createDefaultConfig(configName, serviceName, fileName, false, coreObject)); + App.uiOnlyConfigDerivedFromTheme.pushObject(uiOnlyConfigDerivedFromTheme); + } + } + } + } + + // map all the configs which conditionally affect the value attributes of a config + if (dependsOnConfigs && dependsOnConfigs.length) { + this.mapThemeConfigConditions(dependsOnConfigs, uiOnlyConfigDerivedFromTheme || configProperty); } + }, this); }, /** + * + * @param configConditions: Array + * @param configProperty: DS.Model Object (App.StackConfigProperty) + */ + mapThemeConfigConditions: function(configConditions, configProperty) { + var configConditionsCopy = []; + configConditions.forEach(function(_configCondition, index){ + var configCondition = $.extend({},_configCondition); + configCondition.id = configProperty.get('id') + '_' + index; + configCondition.config_name = configProperty.get('name'); + configCondition.file_name = configProperty.get('filename'); + configCondition.configs = _configCondition.configs.map(function(item) { + var result = {}; + result.fileName = item.split('/')[0] + '.xml'; + result.configName = item.split('/')[1]; + return result; + }); + configConditionsCopy.pushObject(configCondition); + }, this); + + App.store.loadMany(this.get("configConditionModel"), configConditionsCopy); + App.store.commit(); + }, + + /** * add widget object to <code>stackConfigProperty<code> * * @param {Object} json - json to parse @@ -148,10 +214,18 @@ App.themesMapper = App.QuickDataMapper.create({ var configId = this.getConfigId(widget); var configProperty = App.StackConfigProperty.find(configId); - if (configProperty) { + if (configProperty.get('id')) { configProperty.set('widget', widget.widget); } else { - console.warn('there is no such property: ' + configId); + var split = widget.config.split("/"); + var fileName = split[0] + '.xml'; + var configName = split[1]; + var uiOnlyProperty = App.uiOnlyConfigDerivedFromTheme.filterProperty('filename',fileName).findProperty('name',configName); + if (uiOnlyProperty) { + uiOnlyProperty.set('widget', widget.widget); + } else { + console.warn('there is no such property: ' + configId); + } } }, this); }, http://git-wip-us.apache.org/repos/asf/ambari/blob/61540bbb/ambari-web/app/models.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/models.js b/ambari-web/app/models.js index 77918e5..1b34b0c 100644 --- a/ambari-web/app/models.js +++ b/ambari-web/app/models.js @@ -60,6 +60,7 @@ require('models/master_component'); require('models/host_stack_version'); require('models/root_service'); require('models/upgrade_entity'); +require('models/configs/config_condition'); require('models/configs/service_config_version'); require('models/configs/stack_config_property'); require('models/configs/config_group'); http://git-wip-us.apache.org/repos/asf/ambari/blob/61540bbb/ambari-web/app/models/configs/config_condition.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/models/configs/config_condition.js b/ambari-web/app/models/configs/config_condition.js new file mode 100644 index 0000000..26cf219 --- /dev/null +++ b/ambari-web/app/models/configs/config_condition.js @@ -0,0 +1,60 @@ +/** + * 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. + */ + +/** + * THIS IS NOT USED FOR NOW + * FOR CONFIG GROUPS WE ARE USING OLD MODELS AND LOGIC + */ + +var App = require('app'); + +App.ConfigCondition = DS.Model.extend({ + /** + * unique id generated as <code>config_name<code><code>filename<code> + * @property {string} + */ + id: DS.attr('string'), + + /** + * Name of the config that is being affected with the condition + */ + configName: DS.attr('string'), + + /** + * File name to which the config getting affected belongs + */ + fileName: DS.attr('string'), + + /** + * List of configs whose values affect the config + * Each Object in an array consists of configName and fileName + */ + configs: DS.attr('array', {defaultValue: []}), + + /** + * conditional String which can be evaluated to boolean result. + * If evaluated result of this staring is true then use the statement provided by `then` attribute. + * Otherwise use the attribute provided by `else` attributes + */ + if: DS.attr('string'), + then: DS.attr('object', {defaultValue: null}), + else: DS.attr('object', {defaultValue: null}) + +}); + +App.ConfigCondition.FIXTURES = []; http://git-wip-us.apache.org/repos/asf/ambari/blob/61540bbb/ambari-web/app/models/configs/section.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/models/configs/section.js b/ambari-web/app/models/configs/section.js index 8f45757..c04665e 100644 --- a/ambari-web/app/models/configs/section.js +++ b/ambari-web/app/models/configs/section.js @@ -77,9 +77,9 @@ App.Section = DS.Model.extend({ * @type {number} */ errorsCount: function () { - var errors = this.get('subSections').mapProperty('errorsCount'); + var errors = this.get('subSections').filterProperty('isSectionVisible').mapProperty('errorsCount'); return errors.length ? errors.reduce(Em.sum) : 0; - }.property('[email protected]'), + }.property('[email protected]', '[email protected]'), /** * @type {boolean} @@ -128,7 +128,7 @@ App.Section = DS.Model.extend({ * @type {boolean} */ isHiddenByFilter: function () { - return this.get('subSections').everyProperty('isHiddenByFilter', true); + return !this.get('subSections').someProperty('isSectionVisible', true); }.property('[email protected]') }); http://git-wip-us.apache.org/repos/asf/ambari/blob/61540bbb/ambari-web/app/models/configs/stack_config_property.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/models/configs/stack_config_property.js b/ambari-web/app/models/configs/stack_config_property.js index 1289662..76e3b5f 100644 --- a/ambari-web/app/models/configs/stack_config_property.js +++ b/ambari-web/app/models/configs/stack_config_property.js @@ -284,3 +284,13 @@ App.StackConfigProperty = DS.Model.extend({ App.StackConfigProperty.FIXTURES = []; + +App.StackConfigValAttributesMap = { + 'overridable': 'isOverridable' , + 'visible': 'isVisible' , + 'empty_value_valid':'isRequired' , + 'editable_only_at_install': 'isReconfigurable' , + 'show_property_name': 'showLabel', + 'read_only': 'isEditable', + 'ui_only_property': 'isRequiredByAgent' +}; http://git-wip-us.apache.org/repos/asf/ambari/blob/61540bbb/ambari-web/app/models/configs/sub_section.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/models/configs/sub_section.js b/ambari-web/app/models/configs/sub_section.js index d33fbb9..b7abb4f 100644 --- a/ambari-web/app/models/configs/sub_section.js +++ b/ambari-web/app/models/configs/sub_section.js @@ -67,6 +67,13 @@ App.SubSection = DS.Model.extend({ */ configProperties: DS.hasMany('App.StackConfigProperty'), + dependsOn: DS.attr('array', {defaultValue: []}), + + /** + * @type {boolean} + */ + leftVerticalSplitter: DS.attr('boolean', {defaultValue: true}), + /** * @type {App.ServiceConfigProperty[]} */ @@ -86,8 +93,8 @@ App.SubSection = DS.Model.extend({ * @type {boolean} */ addLeftVerticalSplitter: function() { - return !this.get('isFirstColumn'); - }.property('isFirstColumn'), + return !this.get('isFirstColumn') && this.get('leftVerticalSplitter'); + }.property('isFirstColumn', 'leftVerticalSplitter'), /** * @type {boolean} @@ -153,7 +160,15 @@ App.SubSection = DS.Model.extend({ isHiddenByFilter: function () { var configs = this.get('configs'); return configs.length ? configs.everyProperty('isHiddenByFilter', true) : false; - }.property('[email protected]') + }.property('[email protected]'), + + /** + * Determines if subsection is visible + * @type {boolean} + */ + isSectionVisible: function () { + return !this.get('isHiddenByFilter') && this.get('configs').someProperty('isVisible', true); + }.property('isHiddenByFilter', '[email protected]') }); http://git-wip-us.apache.org/repos/asf/ambari/blob/61540bbb/ambari-web/app/templates/common/configs/service_config_layout_tab.hbs ---------------------------------------------------------------------- diff --git a/ambari-web/app/templates/common/configs/service_config_layout_tab.hbs b/ambari-web/app/templates/common/configs/service_config_layout_tab.hbs index ac1dcc7..69de315 100644 --- a/ambari-web/app/templates/common/configs/service_config_layout_tab.hbs +++ b/ambari-web/app/templates/common/configs/service_config_layout_tab.hbs @@ -29,7 +29,7 @@ {{#each subRow in section.subsectionRows}} <tr> {{#each subsection in subRow}} - <td {{bindAttr class="subsection.isHiddenByFilter:invisible subsection.showTopSplitter:top-horizontal-splitter:no-horizontal-splitter :config-subsection" colspan="subsection.columnSpan" rowspan="subsection.rowSpan"}}> + <td {{bindAttr class="subsection.isSectionVisible::invisible subsection.showTopSplitter:top-horizontal-splitter:no-horizontal-splitter :config-subsection" colspan="subsection.columnSpan" rowspan="subsection.rowSpan"}}> <div {{bindAttr class="subsection.addLeftVerticalSplitter:vertical-splitter-l"}}> <div {{bindAttr class="subsection.border:with-border"}}> <h5 class="subsection-display-name"> @@ -40,9 +40,11 @@ </h5> {{#each config in subsection.configs}} {{#if config.widget}} - {{#unless config.isHiddenByFilter}} - {{view config.widget configBinding="config" canEditBinding="view.canEdit" sectionBinding="section" subSectionBinding="subsection" tabBinding="tab"}} - {{/unless}} + {{#if config.isVisible}} + {{#unless config.isHiddenByFilter}} + {{view config.widget configBinding="config" canEditBinding="view.canEdit" sectionBinding="section" subSectionBinding="subsection" tabBinding="tab"}} + {{/unless}} + {{/if}} {{/if}} {{/each}} </div> http://git-wip-us.apache.org/repos/asf/ambari/blob/61540bbb/ambari-web/app/templates/common/configs/widgets/test_db_connection_widget.hbs ---------------------------------------------------------------------- diff --git a/ambari-web/app/templates/common/configs/widgets/test_db_connection_widget.hbs b/ambari-web/app/templates/common/configs/widgets/test_db_connection_widget.hbs new file mode 100644 index 0000000..1cd4aaf --- /dev/null +++ b/ambari-web/app/templates/common/configs/widgets/test_db_connection_widget.hbs @@ -0,0 +1,35 @@ +{{! +* 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. +}} + +<div class="entry-row db-connection"> + <span class="control-label"></span> + + <div class="controls"> + <div class="control-group"> + <div class="span9"> + <span {{bindAttr class=":pull-left :btn :btn-primary view.isBtnDisabled:disabled"}} {{action connectToDatabase target="view"}}>{{view.btnCaption}}</span> + + <div class="pull-left connection-result mll"> + <a {{bindAttr class="view.isConnectionSuccess:mute:action"}} {{action showLogsPopup target="view"}}>{{view.responseCaption}}</a> + </div> + <div {{bindAttr class=":spinner :mll :pull-left view.isConnecting::hide"}}></div> + <i {{bindAttr class=":pull-right view.isConnectionSuccess:icon-ok-sign:icon-warning-sign view.isRequestResolved::hide"}}></i> + </div> + </div> + </div> +</div> http://git-wip-us.apache.org/repos/asf/ambari/blob/61540bbb/ambari-web/app/utils/config.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/utils/config.js b/ambari-web/app/utils/config.js index 51dfd8c..fc47221 100644 --- a/ambari-web/app/utils/config.js +++ b/ambari-web/app/utils/config.js @@ -208,16 +208,17 @@ App.config = Em.Object.create({ /** * generates config objects - * @param configCategories + * @param configGroups * @param serviceName * @param selectedConfigGroup * @param canEdit * @returns {Array} */ - mergePredefinedWithSaved: function (configCategories, serviceName, selectedConfigGroup, canEdit) { + mergePredefinedWithSaved: function (configGroups, serviceName, selectedConfigGroup, canEdit) { var configs = []; + var serviceConfigProperty; - configCategories.forEach(function (siteConfig) { + configGroups.forEach(function (siteConfig) { var service = this.getServiceByConfigType(siteConfig.type); if (service && serviceName != 'MISC') { serviceName = service.get('serviceName'); @@ -227,11 +228,22 @@ App.config = Em.Object.create({ var finalAttributes = attributes.final || {}; var properties = siteConfig.properties || {}; + var uiOnlyConfigsObj = {}; + var uiOnlyConfigDerivedFromTheme = App.uiOnlyConfigDerivedFromTheme.toArray(); + uiOnlyConfigDerivedFromTheme.forEach(function(item) { + if (filename === item.filename) { + uiOnlyConfigsObj[item.name] = item.value; + } + }); + properties = $.extend({}, properties, uiOnlyConfigsObj); + for (var index in properties) { var id = this.configId(index, siteConfig.type); - var configsPropertyDef = this.get('preDefinedSitePropertiesMap')[id]; + var preDefinedPropertyDef = this.get('preDefinedSitePropertiesMap')[id]; + var uiOnlyConfigFromTheme = uiOnlyConfigDerivedFromTheme.findProperty('name', index); + var configsPropertyDef = preDefinedPropertyDef || uiOnlyConfigFromTheme; var advancedConfig = App.StackConfigProperty.find(id); - var isStackProperty = !!advancedConfig.get('id') || !!configsPropertyDef; + var isStackProperty = !!advancedConfig.get('id') || !!preDefinedPropertyDef; var template = this.createDefaultConfig(index, serviceName, filename, isStackProperty, configsPropertyDef); var serviceConfigObj = isStackProperty ? this.mergeStaticProperties(template, advancedConfig) : template; @@ -340,8 +352,10 @@ App.config = Em.Object.create({ mergeStaticProperties: function(coreObject, stackProperty, preDefined, propertiesToSkip) { propertiesToSkip = propertiesToSkip || ['name', 'filename', 'value', 'savedValue', 'isFinal', 'savedIsFinal']; for (var k in coreObject) { - if (!propertiesToSkip.contains(k)) { - coreObject[k] = this.getPropertyIfExists(k, coreObject[k], stackProperty, preDefined); + if (coreObject.hasOwnProperty(k)) { + if (!propertiesToSkip.contains(k)) { + coreObject[k] = this.getPropertyIfExists(k, coreObject[k], stackProperty, preDefined); + } } } return coreObject; @@ -522,19 +536,22 @@ App.config = Em.Object.create({ }).reduce(function(p,c) { return p.concat(c); }).concat(['cluster-env', 'alert_notification']) .uniq().compact().filter(function(configType) { return !!configType; }); + // ui only required configs from theme are required to show configless widgets (widget that are not related to a config) var predefinedIds = Object.keys(this.get('preDefinedSitePropertiesMap')); + var uiOnlyConfigDerivedFromTheme = App.uiOnlyConfigDerivedFromTheme.mapProperty('name'); var stackIds = App.StackConfigProperty.find().filterProperty('isValueDefined').mapProperty('id'); - var configIds = stackIds.concat(predefinedIds).uniq(); + var configIds = stackIds.concat(predefinedIds).concat(uiOnlyConfigDerivedFromTheme).uniq(); configIds.forEach(function(id) { var preDefined = this.get('preDefinedSitePropertiesMap')[id]; + var isUIOnlyFromTheme = App.uiOnlyConfigDerivedFromTheme.findProperty('name',id); var advanced = App.StackConfigProperty.find(id); - var name = preDefined ? preDefined.name : advanced.get('name'); - var filename = preDefined ? preDefined.filename : advanced.get('filename'); - var isUIOnly = Em.getWithDefault(preDefined || {}, 'isRequiredByAgent', true) === false; + var name = preDefined ? preDefined.name : isUIOnlyFromTheme ? isUIOnlyFromTheme.get('name') : advanced.get('name'); + var filename = preDefined ? preDefined.filename : isUIOnlyFromTheme ? isUIOnlyFromTheme.get('filename') : advanced.get('filename'); + var isUIOnly = (Em.getWithDefault(preDefined || {}, 'isRequiredByAgent', true) === false) || isUIOnlyFromTheme; /* Take properties that: - UI specific only, marked with <code>isRequiredByAgent: false</code> @@ -546,9 +563,9 @@ App.config = Em.Object.create({ if (!(uiPersistentProperties.contains(id) || isUIOnly || advanced.get('id')) && filename != 'alert_notification') { return; } - var serviceName = preDefined ? preDefined.serviceName : advanced.get('serviceName'); + var serviceName = preDefined ? preDefined.serviceName : isUIOnlyFromTheme ? isUIOnlyFromTheme.get('serviceName') : advanced.get('serviceName'); if (configTypes.contains(this.getConfigTagFromFileName(filename))) { - var configData = this.createDefaultConfig(name, serviceName, filename, true, preDefined || {}); + var configData = this.createDefaultConfig(name, serviceName, filename, true, preDefined || isUIOnlyFromTheme || {}); if (configData.recommendedValue) { configData.value = configData.recommendedValue; } http://git-wip-us.apache.org/repos/asf/ambari/blob/61540bbb/ambari-web/app/views.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/views.js b/ambari-web/app/views.js index 3e12998..33403a3 100644 --- a/ambari-web/app/views.js +++ b/ambari-web/app/views.js @@ -67,6 +67,7 @@ require('views/common/configs/widgets/string_config_widget_view'); require('views/common/configs/widgets/textfield_config_widget_view'); require('views/common/configs/widgets/time_interval_spinner_view'); require('views/common/configs/widgets/toggle_config_widget_view'); +require('views/common/configs/widgets/test_db_connection_widget_view'); require('views/common/configs/widgets/overrides/config_widget_override_view'); require('views/common/configs/widgets/comparison/config_widget_comparison_view'); require('views/common/configs/service_config_layout_tab_view'); http://git-wip-us.apache.org/repos/asf/ambari/blob/61540bbb/ambari-web/app/views/common/configs/service_config_layout_tab_view.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/views/common/configs/service_config_layout_tab_view.js b/ambari-web/app/views/common/configs/service_config_layout_tab_view.js index b3d69ee..6815a0d 100644 --- a/ambari-web/app/views/common/configs/service_config_layout_tab_view.js +++ b/ambari-web/app/views/common/configs/service_config_layout_tab_view.js @@ -64,7 +64,8 @@ App.ServiceConfigLayoutTabView = Em.View.extend(App.ConfigOverridable, { 'text-field': App.TextFieldConfigWidgetView, 'time-interval-spinner': App.TimeIntervalSpinnerView, toggle: App.ToggleConfigWidgetView, - 'text-area': App.StringConfigWidgetView + 'text-area': App.StringConfigWidgetView, + 'test-db-connection': App.TestDbConnectionWidgetView }, /** @@ -83,8 +84,11 @@ App.ServiceConfigLayoutTabView = Em.View.extend(App.ConfigOverridable, { row.forEach(function (section) { section.get('subsectionRows').forEach(function (subRow) { subRow.forEach(function (subsection) { + var subsectionName = subsection.get('name'); + var uiOnlyConfigs = App.uiOnlyConfigDerivedFromTheme.filterProperty('subSection.name', subsectionName); + subsection.set('configs', []); - subsection.get('configProperties').forEach(function (config) { + subsection.get('configProperties').toArray().concat(uiOnlyConfigs).forEach(function (config) { var service = self.get('controller.stepConfigs').findProperty('serviceName', serviceName); if (!service) return; @@ -95,10 +99,22 @@ App.ServiceConfigLayoutTabView = Em.View.extend(App.ConfigOverridable, { var configWidgetType = config.get('widget.type'); var widget = widgetTypeMap[configWidgetType]; Em.assert('Unknown config widget view for config ' + configProperty.get('id') + ' with type ' + configWidgetType, widget); - configProperty.setProperties({ + + var additionalProperties = { widget: widget, stackConfigProperty: config - }); + }; + + var configConditions = App.ConfigCondition.find().filter(function(_configCondition){ + var conditionalConfigs = _configCondition.get('configs').filterProperty('fileName', config.get('filename')).filterProperty('configName', config.get('name')); + return (conditionalConfigs && conditionalConfigs.length); + }, this); + + if (configConditions && configConditions.length) { + additionalProperties.configConditions = configConditions; + } + configProperty.setProperties(additionalProperties); + if (configProperty.get('overrides')) { configProperty.get('overrides').setEach('stackConfigProperty', config); } http://git-wip-us.apache.org/repos/asf/ambari/blob/61540bbb/ambari-web/app/views/common/configs/widgets/config_widget_view.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/views/common/configs/widgets/config_widget_view.js b/ambari-web/app/views/common/configs/widgets/config_widget_view.js index 354a44e..30c942b 100644 --- a/ambari-web/app/views/common/configs/widgets/config_widget_view.js +++ b/ambari-web/app/views/common/configs/widgets/config_widget_view.js @@ -375,6 +375,56 @@ App.ConfigWidgetView = Em.View.extend(App.SupportsDependentConfigs, App.WidgetPo this.initIncompatibleWidgetAsTextBox(); }, + willInsertElement: function() { + var configConditions = this.get('config.configConditions'); + if (configConditions && configConditions.length) { + this.configValueObserver(); + this.addObserver('config.value', this, this.configValueObserver); + } + }, + + willDestroyElement: function() { + if (this.get('config.configConditions')) { + this.removeObserver('config.value', this, this.configValueObserver); + } + }, + + configValueObserver: function() { + var configConditions = this.get('config.configConditions'); + var serviceName = this.get('config.serviceName'); + var serviceConfigs = this.get('controller.stepConfigs').findProperty('serviceName',serviceName).get('configs'); + configConditions.forEach(function(configCondition){ + var ifCondition = configCondition.get("if"); + var conditionalConfigName = configCondition.get("configName"); + var conditionalConfigFileName = configCondition.get("fileName"); + var parseIfConditionVal = ifCondition; + var regex = /\$\{.*?\}/g; + var configStrings = ifCondition.match(regex); + configStrings.forEach(function(_configString){ + var configObject = _configString.substring(2, _configString.length-1).split("/"); + var config = serviceConfigs.filterProperty('filename',configObject[0] + '.xml').findProperty('name', configObject[1]); + if (config) { + var configValue = config.get('value'); + parseIfConditionVal = parseIfConditionVal.replace(_configString, configValue); + } + }, this); + + var isConditionTrue = Boolean(window.eval(parseIfConditionVal)); + var action = isConditionTrue ? configCondition.get("then") : configCondition.get("else"); + var valueAttributes = action.property_value_attributes; + for (var key in valueAttributes) { + if (valueAttributes.hasOwnProperty(key)) { + var valueAttribute = App.StackConfigValAttributesMap[key] || key; + var conditionalConfig = serviceConfigs.filterProperty('filename',conditionalConfigFileName).findProperty('name', conditionalConfigName); + if (conditionalConfig) { + conditionalConfig.set(valueAttribute, valueAttributes[key]); + } + } + } + }, this); + }, + + /** * set widget value same as config value * useful for widgets that work with intermediate config value, not original http://git-wip-us.apache.org/repos/asf/ambari/blob/61540bbb/ambari-web/app/views/common/configs/widgets/password_config_widget_view.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/views/common/configs/widgets/password_config_widget_view.js b/ambari-web/app/views/common/configs/widgets/password_config_widget_view.js index d33cd13..fe3cf89 100644 --- a/ambari-web/app/views/common/configs/widgets/password_config_widget_view.js +++ b/ambari-web/app/views/common/configs/widgets/password_config_widget_view.js @@ -30,6 +30,7 @@ App.PasswordConfigWidgetView = App.ConfigWidgetView.extend({ }), didInsertElement: function() { + this._super(); this.set('config.displayType', this.get('config.stackConfigProperty.widget.type')); } }); http://git-wip-us.apache.org/repos/asf/ambari/blob/61540bbb/ambari-web/app/views/common/configs/widgets/test_db_connection_widget_view.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/views/common/configs/widgets/test_db_connection_widget_view.js b/ambari-web/app/views/common/configs/widgets/test_db_connection_widget_view.js new file mode 100644 index 0000000..d22cb1f --- /dev/null +++ b/ambari-web/app/views/common/configs/widgets/test_db_connection_widget_view.js @@ -0,0 +1,364 @@ +/** + * 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. + */ + +require('views/common/controls_view'); + +var App = require('app'); + +App.TestDbConnectionWidgetView = App.ConfigWidgetView.extend({ + templateName: require('templates/common/configs/widgets/test_db_connection_widget'), + classNames: ['widget'], + + /** @property {string} btnCaption - text for button **/ + btnCaption: function () { + return this.get('config.stackConfigProperty.widget.display-name'); + }.property('config.stackConfigProperty.widget.display-name'), + /** @property {string} responseCaption - text for status link **/ + responseCaption: null, + /** @property {boolean} isConnecting - is request to server activated **/ + isConnecting: false, + /** @property {boolean} isValidationPassed - check validation for required fields **/ + isValidationPassed: null, + /** @property {string} db_type- name of current database **/ + db_type: null, + /** @property {boolean} isRequestResolved - check for finished request to server **/ + isRequestResolved: false, + /** @property {boolean} isConnectionSuccess - check for successful connection to database **/ + isConnectionSuccess: null, + /** @property {string} responseFromServer - message from server response **/ + responseFromServer: null, + /** @property {Object} ambariRequiredProperties - properties that need for custom action request **/ + ambariRequiredProperties: null, + /** @property {Number} currentRequestId - current custom action request id **/ + currentRequestId: null, + /** @property {Number} currentTaskId - current custom action task id **/ + currentTaskId: null, + /** @property {jQuery.Deferred} request - current $.ajax request **/ + request: null, + /** @property {Number} pollInterval - timeout interval for ajax polling **/ + pollInterval: 3000, + /** @property {Object} logsPopup - popup with DB connection check info **/ + logsPopup: null, + /** @property {Array} or {String} masterHostName: The name of hosts from which the db connection will happen**/ + masterHostName: null, + /** @property {String} db_connection_url: The jdbc urlfor performing db connection**/ + db_connection_url: null, + /** @property {String} user_name: The user name to be used for performing db connection**/ + user_name: null, + /** @property {String} user_passwd: password for the user name to be used for performing db connection**/ + user_passwd: null, + + /** @property {boolean} isBtnDisabled - disable button on failed validation or active request **/ + isBtnDisabled: function () { + return !this.get('requiredProperties').everyProperty('isValid') || this.get('isConnecting'); + }.property('[email protected]', 'isConnecting'), + /** @property {object} requiredProperties - properties that necessary for database connection **/ + requiredProperties: [], + + /** Check validation and load ambari properties **/ + didInsertElement: function () { + var requiredProperties = this.get('config.stackConfigProperty.widget.required-properties'); + var serviceName = this.get('config.serviceName'); + var serviceConfigs = this.get('controller.stepConfigs').findProperty('serviceName',serviceName).get('configs'); + var requiredServiceConfigs = Object.keys(requiredProperties).map(function(key){ + var split = requiredProperties[key].split('/'); + var fileName = split[0] + '.xml'; + var configName = split[1]; + return serviceConfigs.filterProperty('filename',fileName).findProperty('name', configName); + }, this); + + this.set('requiredProperties', requiredServiceConfigs); + this.setDbProperties(requiredProperties); + this.getAmbariProperties(); + }, + + /** On view destroy **/ + willDestroyElement: function () { + this.set('isConnecting', false); + this._super(); + }, + + + /** + * This function is used to set Database name and master host name + * @param requiredProperties + */ + setDbProperties: function(requiredProperties) { + var dbInfo = require('data/db_properties_info'); + var dbProperties = { + 'db.connection.source.host' : 'masterHostName', + 'db.type' : 'db_type', + 'db.connection.user': 'user_name', + 'db.connection.password': 'user_passwd', + 'jdbc.driver.url': 'db_connection_url' + }; + + for (var key in dbProperties) { + var masterHostNameProperty = requiredProperties[key]; + var split = masterHostNameProperty.split('/'); + var fileName = split[0] + '.xml'; + var configName = split[1]; + var dbConfig = this.get('requiredProperties').filterProperty('filename',fileName).findProperty('name', configName); + if (key === 'db.type') { + dbConfig = dbInfo.dpPropertiesMap[dbConfig.value].db_type.toUpperCase(); + } + this.set(dbProperties[key], dbConfig); + } + }, + + + /** + * Set up ambari properties required for custom action request + * + * @method getAmbariProperties + **/ + getAmbariProperties: function () { + var clusterController = App.router.get('clusterController'); + var _this = this; + if (!App.isEmptyObject(App.db.get('tmp', 'ambariProperties')) && !this.get('ambariProperties')) { + this.set('ambariProperties', App.db.get('tmp', 'ambariProperties')); + return; + } + if (App.isEmptyObject(clusterController.get('ambariProperties'))) { + clusterController.loadAmbariProperties().done(function (data) { + _this.formatAmbariProperties(data.RootServiceComponents.properties); + }); + } else { + this.formatAmbariProperties(clusterController.get('ambariProperties')); + } + }, + + formatAmbariProperties: function (properties) { + var defaults = { + threshold: "60", + ambari_server_host: location.hostname, + check_execute_list: "db_connection_check" + }; + var properties = App.permit(properties, ['jdk.name', 'jdk_location', 'java.home']); + var renameKey = function (oldKey, newKey) { + if (properties[oldKey]) { + defaults[newKey] = properties[oldKey]; + delete properties[oldKey]; + } + }; + renameKey('java.home', 'java_home'); + renameKey('jdk.name', 'jdk_name'); + $.extend(properties, defaults); + App.db.set('tmp', 'ambariProperties', properties); + this.set('ambariProperties', properties); + }, + /** + * `Action` method for starting connect to current database. + * + * @method connectToDatabase + **/ + connectToDatabase: function () { + if (this.get('isBtnDisabled')) return; + this.set('isRequestResolved', false); + this.setConnectingStatus(true); + if (App.get('testMode')) { + this.startPolling(); + } else { + this.runCheckConnection(); + } + }, + + /** + * runs check connections methods depending on service + * @return {void} + * @method runCheckConnection + */ + runCheckConnection: function () { + this.createCustomAction(); + }, + + + /** + * Run custom action for database connection. + * + * @method createCustomAction + **/ + createCustomAction: function () { + var connectionProperties = this.getProperties('db_connection_url','user_name', 'user_passwd'); + for (var key in connectionProperties) { + if (connectionProperties.hasOwnProperty(key)) { + connectionProperties[key] = connectionProperties[key].value; + } + } + var params = $.extend(true, {}, {db_name: this.get('db_type').toLowerCase()}, connectionProperties, this.get('ambariProperties')); + var filteredHosts = Array.isArray(this.get('masterHostName.value')) ? this.get('masterHostName.value') : [this.get('masterHostName.value')]; + App.ajax.send({ + name: 'custom_action.create', + sender: this, + data: { + requestInfo: { + parameters: params + }, + filteredHosts: filteredHosts + }, + success: 'onCreateActionSuccess', + error: 'onCreateActionError' + }); + }, + /** + * Run updater if task is created successfully. + * + * @method onConnectActionS + **/ + onCreateActionSuccess: function (data) { + this.set('currentRequestId', data.Requests.id); + App.ajax.send({ + name: 'custom_action.request', + sender: this, + data: { + requestId: this.get('currentRequestId') + }, + success: 'setCurrentTaskId' + }); + }, + + setCurrentTaskId: function (data) { + this.set('currentTaskId', data.items[0].Tasks.id); + this.startPolling(); + }, + + startPolling: function () { + if (this.get('isConnecting')) + this.getTaskInfo(); + }, + + getTaskInfo: function () { + var request = App.ajax.send({ + name: 'custom_action.request', + sender: this, + data: { + requestId: this.get('currentRequestId'), + taskId: this.get('currentTaskId') + }, + success: 'getTaskInfoSuccess' + }); + this.set('request', request); + }, + + getTaskInfoSuccess: function (data) { + var task = data.Tasks; + this.set('responseFromServer', { + stderr: task.stderr, + stdout: task.stdout + }); + if (task.status === 'COMPLETED') { + var structuredOut = task.structured_out.db_connection_check; + if (structuredOut.exit_code != 0) { + this.set('responseFromServer', { + stderr: task.stderr, + stdout: task.stdout, + structuredOut: structuredOut.message + }); + this.setResponseStatus('failed'); + } else { + this.setResponseStatus('success'); + } + } + if (task.status === 'FAILED') { + this.setResponseStatus('failed'); + } + if (/PENDING|QUEUED|IN_PROGRESS/.test(task.status)) { + Em.run.later(this, function () { + this.startPolling(); + }, this.get('pollInterval')); + } + }, + + onCreateActionError: function (jqXhr, status, errorMessage) { + this.setResponseStatus('failed'); + this.set('responseFromServer', errorMessage); + }, + + setResponseStatus: function (isSuccess) { + var isSuccess = isSuccess == 'success'; + this.setConnectingStatus(false); + this.set('responseCaption', isSuccess ? Em.I18n.t('services.service.config.database.connection.success') : Em.I18n.t('services.service.config.database.connection.failed')); + this.set('isConnectionSuccess', isSuccess); + this.set('isRequestResolved', true); + if (this.get('logsPopup')) { + var statusString = isSuccess ? 'common.success' : 'common.error'; + this.set('logsPopup.header', Em.I18n.t('services.service.config.connection.logsPopup.header').format(this.get('db_type'), Em.I18n.t(statusString))); + } + }, + /** + * Switch captions and statuses for active/non-active request. + * + * @method setConnectionStatus + * @param {Boolean} [active] + */ + setConnectingStatus: function (active) { + if (active) { + this.set('responseCaption', Em.I18n.t('services.service.config.database.connection.inProgress')); + } + this.set('controller.testConnectionInProgress', !!active); + this.set('btnCaption', !!active ? Em.I18n.t('services.service.config.database.btn.connecting') : Em.I18n.t('services.service.config.database.btn.idle')); + this.set('isConnecting', !!active); + }, + /** + * Set view to init status. + * + * @method restore + **/ + restore: function () { + if (this.get('request')) { + this.get('request').abort(); + this.set('request', null); + } + this.set('responseCaption', null); + this.set('responseFromServer', null); + this.setConnectingStatus(false); + this.set('isRequestResolved', false); + }, + /** + * `Action` method for showing response from server in popup. + * + * @method showLogsPopup + **/ + showLogsPopup: function () { + if (this.get('isConnectionSuccess')) return; + var _this = this; + var statusString = this.get('isRequestResolved') ? 'common.error' : 'common.testing'; + var popup = App.showAlertPopup(Em.I18n.t('services.service.config.connection.logsPopup.header').format(this.get('db_type'), Em.I18n.t(statusString)), null, function () { + _this.set('logsPopup', null); + }); + popup.reopen({ + onClose: function () { + this._super(); + _this.set('logsPopup', null); + } + }); + if (typeof this.get('responseFromServer') == 'object') { + popup.set('bodyClass', Em.View.extend({ + checkDBConnectionView: _this, + templateName: require('templates/common/error_log_body'), + openedTask: function () { + return this.get('checkDBConnectionView.responseFromServer'); + }.property('checkDBConnectionView.responseFromServer.stderr', 'checkDBConnectionView.responseFromServer.stdout', 'checkDBConnectionView.responseFromServer.structuredOut') + })); + } else { + popup.set('body', this.get('responseFromServer')); + } + this.set('logsPopup', popup); + return popup; + } +}); http://git-wip-us.apache.org/repos/asf/ambari/blob/61540bbb/ambari-web/test/mappers/configs/themes_mapper_test.js ---------------------------------------------------------------------- diff --git a/ambari-web/test/mappers/configs/themes_mapper_test.js b/ambari-web/test/mappers/configs/themes_mapper_test.js index 7e6d35f..99456e0 100644 --- a/ambari-web/test/mappers/configs/themes_mapper_test.js +++ b/ambari-web/test/mappers/configs/themes_mapper_test.js @@ -188,6 +188,8 @@ describe('App.themeMapper', function () { "row_index": "0", "row_span": "1", "column_index": "0", + "depends_on": [], + "left_vertical_splitter": true, "column_span": "1", "section_id": "Section-1" }); http://git-wip-us.apache.org/repos/asf/ambari/blob/61540bbb/ambari-web/test/models/configs/section_test.js ---------------------------------------------------------------------- diff --git a/ambari-web/test/models/configs/section_test.js b/ambari-web/test/models/configs/section_test.js index c8f2ebf..055c532 100644 --- a/ambari-web/test/models/configs/section_test.js +++ b/ambari-web/test/models/configs/section_test.js @@ -56,24 +56,24 @@ describe('App.Section', function () { }, { subSections: [ - App.SubSection.createRecord({configs: [{isHiddenByFilter: false}, {isHiddenByFilter: false}]}), - App.SubSection.createRecord({configs: [{isHiddenByFilter: false}, {isHiddenByFilter: false}]}) + App.SubSection.createRecord({configs: [{isHiddenByFilter: false, isVisible: true}, {isHiddenByFilter: false, isVisible: true}]}), + App.SubSection.createRecord({configs: [{isHiddenByFilter: false, isVisible: true}, {isHiddenByFilter: false, isVisible: true}]}) ], m: 'no subsections are hidden', e: false }, { subSections: [ - App.SubSection.createRecord({configs: [{isHiddenByFilter: true}, {isHiddenByFilter: true}]}), - App.SubSection.createRecord({configs: [{isHiddenByFilter: false}, {isHiddenByFilter: false}]}) + App.SubSection.createRecord({configs: [{isHiddenByFilter: true, isVisible: true}, {isHiddenByFilter: true, isVisible: true}]}), + App.SubSection.createRecord({configs: [{isHiddenByFilter: false, isVisible: true}, {isHiddenByFilter: false, isVisible: true}]}) ], m: 'one subsection is hidden', e: false }, { subSections: [ - App.SubSection.createRecord({configs: [{isHiddenByFilter: true}, {isHiddenByFilter: true}]}), - App.SubSection.createRecord({configs: [{isHiddenByFilter: true}, {isHiddenByFilter: true}]}) + App.SubSection.createRecord({configs: [{isHiddenByFilter: true, isVisible: true}, {isHiddenByFilter: true, isVisible: true}]}), + App.SubSection.createRecord({configs: [{isHiddenByFilter: true, isVisible: true}, {isHiddenByFilter: true, isVisible: true}]}) ], m: 'all subsections are hidden', e: true
