You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by db...@apache.org on 2016/05/11 09:15:43 UTC
[1/4] ambari git commit: AMBARI-16274. Views: Simplify View
Configuration for Remote Ambari Managed Cluster. (Gaurav Nagar via dipayanb)
Repository: ambari
Updated Branches:
refs/heads/trunk bc82a6eca -> c150f0ded
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/contrib/views/utils/src/main/java/org/apache/ambari/view/utils/hdfs/AuthConfigurationBuilder.java
----------------------------------------------------------------------
diff --git a/contrib/views/utils/src/main/java/org/apache/ambari/view/utils/hdfs/AuthConfigurationBuilder.java b/contrib/views/utils/src/main/java/org/apache/ambari/view/utils/hdfs/AuthConfigurationBuilder.java
index c8ca6cd..4911455 100644
--- a/contrib/views/utils/src/main/java/org/apache/ambari/view/utils/hdfs/AuthConfigurationBuilder.java
+++ b/contrib/views/utils/src/main/java/org/apache/ambari/view/utils/hdfs/AuthConfigurationBuilder.java
@@ -54,13 +54,11 @@ public class AuthConfigurationBuilder {
String auth;
auth = context.getProperties().get("webhdfs.auth");
- if (auth == null || auth.isEmpty()) {
- try {
- auth = getConfigurationFromAmbari();
- } catch (NoClusterAssociatedException e) {
- auth = "auth=SIMPLE";
- LOG.warn(String.format("HDFS090 Authentication parameters could not be determined. %s assumed.", auth));
- }
+ if ((auth == null || auth.isEmpty()) && context.getCluster() != null) {
+ auth = getConfigurationFromAmbari();
+ } else {
+ auth = "auth=SIMPLE";
+ LOG.warn(String.format("HDFS090 Authentication parameters could not be determined. %s assumed.", auth));
}
parseAuthString(auth);
@@ -81,7 +79,7 @@ public class AuthConfigurationBuilder {
* Determine configuration from Ambari.
*/
private String getConfigurationFromAmbari() throws NoClusterAssociatedException {
- String authMethod = ambariApi.getCluster().getConfigurationValue(
+ String authMethod = context.getCluster().getConfigurationValue(
"core-site", "hadoop.security.authentication");
return String.format("auth=%s", authMethod);
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/contrib/views/utils/src/main/java/org/apache/ambari/view/utils/hdfs/ConfigurationBuilder.java
----------------------------------------------------------------------
diff --git a/contrib/views/utils/src/main/java/org/apache/ambari/view/utils/hdfs/ConfigurationBuilder.java b/contrib/views/utils/src/main/java/org/apache/ambari/view/utils/hdfs/ConfigurationBuilder.java
index 4518ac6..8b45cd6 100644
--- a/contrib/views/utils/src/main/java/org/apache/ambari/view/utils/hdfs/ConfigurationBuilder.java
+++ b/contrib/views/utils/src/main/java/org/apache/ambari/view/utils/hdfs/ConfigurationBuilder.java
@@ -121,9 +121,10 @@ public class ConfigurationBuilder {
private String getProperty(String type, String key, String instanceProperty) {
String value;
- try {
- value = ambariApi.getCluster().getConfigurationValue(type, key);
- } catch (NoClusterAssociatedException e) {
+
+ if(context.getCluster() != null) {
+ value = context.getCluster().getConfigurationValue(type, key);
+ } else {
value = context.getProperties().get(instanceProperty);
}
return value;
@@ -131,15 +132,16 @@ public class ConfigurationBuilder {
private void copyPropertyIfExists(String type, String key) {
String value;
- try {
- value = ambariApi.getCluster().getConfigurationValue(type, key);
+
+ if(context.getCluster() != null) {
+ value = context.getCluster().getConfigurationValue(type, key);
if (value != null) {
conf.set(key, value);
LOG.debug("set " + key + " = " + value);
} else {
LOG.debug("No such property " + type + "/" + key);
}
- } catch (NoClusterAssociatedException e) {
+ } else {
LOG.debug("No such property " + type + "/" + key);
}
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/contrib/views/utils/src/test/java/org/apache/ambari/view/utils/ambari/RemoteClusterTest.java
----------------------------------------------------------------------
diff --git a/contrib/views/utils/src/test/java/org/apache/ambari/view/utils/ambari/RemoteClusterTest.java b/contrib/views/utils/src/test/java/org/apache/ambari/view/utils/ambari/RemoteClusterTest.java
deleted file mode 100644
index ec4df7d..0000000
--- a/contrib/views/utils/src/test/java/org/apache/ambari/view/utils/ambari/RemoteClusterTest.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.ambari.view.utils.ambari;
-
-import org.apache.ambari.view.URLStreamProvider;
-import org.apache.ambari.view.ViewContext;
-import org.apache.ambari.view.cluster.Cluster;
-import org.apache.commons.collections4.map.PassiveExpiringMap;
-import org.easymock.IAnswer;
-import org.json.simple.JSONObject;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-
-import java.io.ByteArrayInputStream;
-import java.io.InputStream;
-import java.util.HashMap;
-import java.util.Map;
-
-import static org.easymock.EasyMock.*;
-import static org.junit.Assert.*;
-
-public class RemoteClusterTest {
- public static final String AMBARI_CLUSTER_REST_URL = "http://example.com:8080/api/v1/clusters/c1";
-
- @Rule
- public ExpectedException thrown= ExpectedException.none();
-
- @Test
- public void testGetRemoteClusterThatIsNotPresent() throws Exception {
- ViewContext viewContext = createNiceMock(ViewContext.class);
- Map<String, String> instanceProperties = new HashMap<String, String>();
- expect(viewContext.getProperties()).andReturn(instanceProperties).anyTimes();
- replay(viewContext);
-
- AmbariApi ambariApi = new AmbariApi(viewContext);
- Cluster cluster = ambariApi.getRemoteCluster();
- assertNull(cluster);
- }
-
- @Test
- public void testGetRemoteClusterNoCredentials() throws Exception {
- ViewContext viewContext = createNiceMock(ViewContext.class);
- Map<String, String> instanceProperties = new HashMap<String, String>();
- instanceProperties.put(AmbariApi.AMBARI_SERVER_URL_INSTANCE_PROPERTY,
- AMBARI_CLUSTER_REST_URL);
- expect(viewContext.getProperties()).andReturn(instanceProperties).anyTimes();
- replay(viewContext);
-
- thrown.expect(AmbariApiException.class);
- AmbariApi ambariApi = new AmbariApi(viewContext);
- Cluster cluster = ambariApi.getRemoteCluster();
- }
-
- @Test
- public void testGetRemoteClusterThatIsPresent() throws Exception {
- ViewContext viewContext = createNiceMock(ViewContext.class);
- Map<String, String> instanceProperties = new HashMap<String, String>();
- instanceProperties.put(AmbariApi.AMBARI_SERVER_URL_INSTANCE_PROPERTY,
- AMBARI_CLUSTER_REST_URL);
- instanceProperties.put(AmbariApi.AMBARI_SERVER_USERNAME_INSTANCE_PROPERTY, "admin");
- instanceProperties.put(AmbariApi.AMBARI_SERVER_PASSWORD_INSTANCE_PROPERTY, "admin");
- expect(viewContext.getProperties()).andReturn(instanceProperties).anyTimes();
- replay(viewContext);
-
- AmbariApi ambariApi = new AmbariApi(viewContext);
- Cluster cluster = ambariApi.getRemoteCluster();
- assertNotNull(cluster);
- assertEquals(cluster.getName(), "c1");
- }
-
- @Test
- public void testGetConfigurationValue() throws Exception {
- URLStreamProvider urlStreamProvider = createNiceMock(URLStreamProvider.class);
-
- final String desiredConfigsString = "{\"Clusters\": {\"desired_configs\": {\"test-site\": {\"tag\": \"TAG\"}}}}";
- final String configurationString = "{\"items\": [{\"properties\": {\"test.property.name\": \"test property value\"}}]}";
- final int[] desiredConfigPolls = {0};
- final int[] testConfigPolls = {0};
-
- expect(urlStreamProvider.readFrom(eq(AMBARI_CLUSTER_REST_URL + "?fields=services/ServiceInfo,hosts,Clusters"),
- eq("GET"), (String) isNull(), (Map<String, String>) anyObject())).andAnswer(new IAnswer<InputStream>() {
- @Override
- public InputStream answer() throws Throwable {
- desiredConfigPolls[0] += 1;
- return new ByteArrayInputStream(desiredConfigsString.getBytes());
- }
- }).anyTimes();
-
- expect(urlStreamProvider.readFrom(eq(AMBARI_CLUSTER_REST_URL + "/configurations?(type=test-site&tag=TAG)"),
- eq("GET"), (String)isNull(), (Map<String, String>) anyObject())).andAnswer(new IAnswer<InputStream>() {
- @Override
- public InputStream answer() throws Throwable {
- testConfigPolls[0] += 1;
- return new ByteArrayInputStream(configurationString.getBytes());
- }
- }).anyTimes();
-
- replay(urlStreamProvider);
-
- RemoteCluster cluster = new RemoteCluster(AMBARI_CLUSTER_REST_URL, urlStreamProvider);
- PassiveExpiringMap<String, JSONObject> cache = new PassiveExpiringMap<String, JSONObject>(10000L);
- cluster.configurationCache = cache;
-
- String value = cluster.getConfigurationValue("test-site", "test.property.name");
- assertEquals(value, "test property value");
- assertEquals(desiredConfigPolls[0], 1);
- assertEquals(testConfigPolls[0], 1);
-
- value = cluster.getConfigurationValue("test-site", "test.property.name");
- assertEquals(value, "test property value");
- assertEquals(desiredConfigPolls[0], 1); // cache hit
- assertEquals(testConfigPolls[0], 1);
-
- cache.clear();
- value = cluster.getConfigurationValue("test-site", "test.property.name");
- assertEquals(value, "test property value");
- assertEquals(desiredConfigPolls[0], 2);
- assertEquals(testConfigPolls[0], 2);
- }
-}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/contrib/views/utils/src/test/java/org/apache/ambari/view/utils/ambari/ServicesTest.java
----------------------------------------------------------------------
diff --git a/contrib/views/utils/src/test/java/org/apache/ambari/view/utils/ambari/ServicesTest.java b/contrib/views/utils/src/test/java/org/apache/ambari/view/utils/ambari/ServicesTest.java
index 455ca20..c7c0990 100644
--- a/contrib/views/utils/src/test/java/org/apache/ambari/view/utils/ambari/ServicesTest.java
+++ b/contrib/views/utils/src/test/java/org/apache/ambari/view/utils/ambari/ServicesTest.java
@@ -100,7 +100,7 @@ public class ServicesTest extends EasyMockSupport {
expect(ambariApi.isClusterAssociated()).andReturn(true).anyTimes();
setClusterExpectation(cluster, "HTTP_ONLY");
- expect(ambariApi.getCluster()).andReturn(cluster).anyTimes();
+ expect(viewContext.getCluster()).andReturn(cluster).anyTimes();
replayAll();
assertEquals(HTTP_RM_URL1, services.getTimelineServerUrl());
@@ -255,7 +255,7 @@ public class ServicesTest extends EasyMockSupport {
expect(ambariApi.isClusterAssociated()).andReturn(true).anyTimes();
setClusterExpectation(cluster, "HTTP_ONLY");
- expect(ambariApi.getCluster()).andReturn(cluster).anyTimes();
+ expect(viewContext.getCluster()).andReturn(cluster).anyTimes();
replayAll();
@@ -283,7 +283,7 @@ public class ServicesTest extends EasyMockSupport {
expect(ambariApi.isClusterAssociated()).andReturn(true).anyTimes();
setClusterExpectationWithEmptyWebappConfig(cluster, "HTTP_ONLY");
- expect(ambariApi.getCluster()).andReturn(cluster).anyTimes();
+ expect(viewContext.getCluster()).andReturn(cluster).anyTimes();
Services services = new Services(ambariApi, viewContext);
@@ -307,7 +307,7 @@ public class ServicesTest extends EasyMockSupport {
expect(ambariApi.isClusterAssociated()).andReturn(true).anyTimes();
setClusterExpectationInHAWithEmptyWebappConfig(cluster, "HTTP_ONLY");
- expect(ambariApi.getCluster()).andReturn(cluster).anyTimes();
+ expect(viewContext.getCluster()).andReturn(cluster).anyTimes();
Services services = new Services(ambariApi, viewContext);
@@ -342,7 +342,7 @@ public class ServicesTest extends EasyMockSupport {
expect(ambariApi.isClusterAssociated()).andReturn(true).anyTimes();
setClusterExpectationInHA(cluster, "HTTP_ONLY");
- expect(ambariApi.getCluster()).andReturn(cluster).anyTimes();
+ expect(viewContext.getCluster()).andReturn(cluster).anyTimes();
expect(viewContext.getURLStreamProvider()).andReturn(urlStreamProvider).anyTimes();
expect(urlStreamProvider.readFrom(eq(HTTP_RM_URL1 + RM_INFO_API_ENDPOINT), eq("GET"), anyString(), EasyMock.<Map<String, String>>anyObject())).andReturn(inputStream);
@@ -385,7 +385,7 @@ public class ServicesTest extends EasyMockSupport {
expect(ambariApi.isClusterAssociated()).andReturn(true).anyTimes();
setClusterExpectationWithEmptyWebappConfig(cluster, "HTTP_ONLY");
- expect(ambariApi.getCluster()).andReturn(cluster).anyTimes();
+ expect(viewContext.getCluster()).andReturn(cluster).anyTimes();
Services services = new Services(ambariApi, viewContext);
@@ -432,4 +432,4 @@ public class ServicesTest extends EasyMockSupport {
expect(viewContextMock.getProperties()).andReturn(map);
return viewContextMock;
}
-}
\ No newline at end of file
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/contrib/views/utils/src/test/java/org/apache/ambari/view/utils/ambari/URLStreamProviderBasicAuthTest.java
----------------------------------------------------------------------
diff --git a/contrib/views/utils/src/test/java/org/apache/ambari/view/utils/ambari/URLStreamProviderBasicAuthTest.java b/contrib/views/utils/src/test/java/org/apache/ambari/view/utils/ambari/URLStreamProviderBasicAuthTest.java
deleted file mode 100644
index 27e98f2..0000000
--- a/contrib/views/utils/src/test/java/org/apache/ambari/view/utils/ambari/URLStreamProviderBasicAuthTest.java
+++ /dev/null
@@ -1,159 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.ambari.view.utils.ambari;
-
-import org.apache.ambari.view.URLStreamProvider;
-import org.easymock.EasyMock;
-import org.easymock.IArgumentMatcher;
-
-import org.junit.Test;
-
-import java.io.InputStream;
-import java.util.HashMap;
-import java.util.Map;
-
-import static org.easymock.EasyMock.*;
-
-public class URLStreamProviderBasicAuthTest {
-
- @Test
- public void testReadFrom() throws Exception {
- URLStreamProvider urlStreamProvider = createNiceMock(URLStreamProvider.class);
- expect(urlStreamProvider.readFrom(anyString(), anyString(), anyString(), HeadersMatcher.mapContainsAuthHeader())).andReturn(null);
- URLStreamProviderBasicAuth urlStreamProviderBasicAuth =
- new URLStreamProviderBasicAuth(urlStreamProvider, "user", "pass");
-
- replay(urlStreamProvider);
-
- urlStreamProviderBasicAuth.readFrom("http://example.com", "GET",
- (String) null, null);
- urlStreamProviderBasicAuth.readFrom("http://example.com", "GET",
- (String)null, new HashMap<String, String>());
- }
-
- @Test
- public void testReadFrom1() throws Exception {
- URLStreamProvider urlStreamProvider = createNiceMock(URLStreamProvider.class);
- expect(urlStreamProvider.readFrom(anyString(), anyString(), (InputStream)anyObject(),
- HeadersMatcher.mapContainsAuthHeader())).andReturn(null);
- URLStreamProviderBasicAuth urlStreamProviderBasicAuth =
- new URLStreamProviderBasicAuth(urlStreamProvider, "user", "pass");
-
- replay(urlStreamProvider);
-
- urlStreamProviderBasicAuth.readFrom("http://example.com", "GET",
- (InputStream) null, null);
- urlStreamProviderBasicAuth.readFrom("http://example.com", "GET",
- (InputStream)null, new HashMap<String, String>());
- }
-
- @Test
- public void testReadAs() throws Exception {
- URLStreamProvider urlStreamProvider = createNiceMock(URLStreamProvider.class);
- expect(urlStreamProvider.readAs(anyString(), anyString(), anyString(),
- HeadersMatcher.mapContainsAuthHeader(), anyString())).andReturn(null);
- URLStreamProviderBasicAuth urlStreamProviderBasicAuth =
- new URLStreamProviderBasicAuth(urlStreamProvider, "user", "pass");
-
- replay(urlStreamProvider);
-
- urlStreamProviderBasicAuth.readAs("http://example.com", "GET",
- (String) null, null, "admin");
- urlStreamProviderBasicAuth.readAs("http://example.com", "GET",
- (String) null, new HashMap<String, String>(), "admin");
- }
-
- @Test
- public void testReadAs1() throws Exception {
- URLStreamProvider urlStreamProvider = createNiceMock(URLStreamProvider.class);
- expect(urlStreamProvider.readAs(anyString(), anyString(), (InputStream) anyObject(),
- HeadersMatcher.mapContainsAuthHeader(), anyString())).andReturn(null);
- URLStreamProviderBasicAuth urlStreamProviderBasicAuth =
- new URLStreamProviderBasicAuth(urlStreamProvider, "user", "pass");
-
- replay(urlStreamProvider);
-
- urlStreamProviderBasicAuth.readAs("http://example.com", "GET",
- (InputStream) null, null, "admin");
- urlStreamProviderBasicAuth.readAs("http://example.com", "GET",
- (InputStream) null, new HashMap<String, String>(), "admin");
- }
-
- @Test
- public void testReadAsCurrent() throws Exception {
- URLStreamProvider urlStreamProvider = createNiceMock(URLStreamProvider.class);
- expect(urlStreamProvider.readAsCurrent(anyString(), anyString(), anyString(),
- HeadersMatcher.mapContainsAuthHeader())).andReturn(null);
- URLStreamProviderBasicAuth urlStreamProviderBasicAuth =
- new URLStreamProviderBasicAuth(urlStreamProvider, "user", "pass");
-
- replay(urlStreamProvider);
-
- urlStreamProviderBasicAuth.readAsCurrent("http://example.com", "GET",
- (String) null, null);
- urlStreamProviderBasicAuth.readAsCurrent("http://example.com", "GET",
- (String) null, new HashMap<String, String>());
- }
-
- @Test
- public void testReadAsCurrent1() throws Exception {
- URLStreamProvider urlStreamProvider = createNiceMock(URLStreamProvider.class);
- expect(urlStreamProvider.readAsCurrent(anyString(), anyString(), (InputStream) anyObject(),
- HeadersMatcher.mapContainsAuthHeader())).andReturn(null);
- URLStreamProviderBasicAuth urlStreamProviderBasicAuth =
- new URLStreamProviderBasicAuth(urlStreamProvider, "user", "pass");
-
- replay(urlStreamProvider);
-
- urlStreamProviderBasicAuth.readAsCurrent("http://example.com", "GET",
- (InputStream) null, null);
- urlStreamProviderBasicAuth.readAsCurrent("http://example.com", "GET",
- (InputStream)null, new HashMap<String, String>());
- }
-
-
- public static class HeadersMatcher implements IArgumentMatcher {
-
- public static Map<String, String> mapContainsAuthHeader() {
- EasyMock.reportMatcher(new HeadersMatcher());
- return null;
- }
-
- public void appendTo(StringBuffer buffer) {
- buffer.append("Authentication header matcher");
- }
-
- public boolean matches(Object headers) {
- if (!(headers instanceof Map)) {
- return false;
- }
-
- Map<String, String> headersMap = (Map<String, String>) headers;
-
- if (!headersMap.containsKey("Authorization"))
- return false;
- String authHeader = headersMap.get("Authorization");
-
- if (!authHeader.startsWith("Basic "))
- return false;
-
- return true;
- }
- }
-}
\ No newline at end of file
[2/4] ambari git commit: AMBARI-16274. Views: Simplify View
Configuration for Remote Ambari Managed Cluster. (Gaurav Nagar via dipayanb)
Posted by db...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/ambari-server/src/main/java/org/apache/ambari/server/view/configuration/ViewConfig.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/view/configuration/ViewConfig.java b/ambari-server/src/main/java/org/apache/ambari/server/view/configuration/ViewConfig.java
index bb6a93c..f63c962 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/view/configuration/ViewConfig.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/view/configuration/ViewConfig.java
@@ -123,6 +123,12 @@ public class ViewConfig {
private String dataVersion;
/**
+ * Enable views to display cluster options in case of no cluster config properties.
+ */
+ @XmlElement(name="cluster-config-options")
+ private String clusterConfigOptions;
+
+ /**
* The view class.
*/
private Class<? extends ViewDataMigrator> dataMigratorClass = null;
@@ -450,4 +456,13 @@ public class ViewConfig {
public List<PermissionConfig> getPermissions() {
return permissions == null ? Collections.<PermissionConfig>emptyList() : permissions;
}
+
+ /**
+ * Enables views to display cluster options in case of no cluster config properties
+ *
+ * @return clusterConfigOptions
+ */
+ public String getClusterConfigOptions() {
+ return clusterConfigOptions;
+ }
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql
index 415e06b..d77a0b3 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql
@@ -567,6 +567,7 @@ CREATE TABLE viewinstance (
xml_driven CHAR(1),
alter_names SMALLINT NOT NULL DEFAULT 1,
cluster_handle VARCHAR(255),
+ cluster_type VARCHAR(100) NOT NULL DEFAULT 'LOCAL_AMBARI',
short_url BIGINT,
CONSTRAINT PK_viewinstance PRIMARY KEY (view_instance_id),
CONSTRAINT FK_instance_url_id FOREIGN KEY (short_url) REFERENCES viewurl(url_id),
@@ -601,7 +602,7 @@ CREATE TABLE viewparameter (
label VARCHAR(255),
placeholder VARCHAR(255),
default_value VARCHAR(2000),
- cluster_config VARCHAR(255),
+ cluster_config VARCHAR(255) ,
required CHAR(1),
masked CHAR(1),
CONSTRAINT PK_viewparameter PRIMARY KEY (view_name, name),
@@ -778,6 +779,26 @@ CREATE TABLE setting (
CONSTRAINT PK_setting PRIMARY KEY (id)
);
+-- Remote Cluster table
+
+CREATE TABLE remoteambaricluster(
+ cluster_id BIGINT NOT NULL,
+ name VARCHAR(255) NOT NULL,
+ username VARCHAR(255) NOT NULL,
+ url VARCHAR(255) NOT NULL,
+ password VARCHAR(255) NOT NULL,
+ CONSTRAINT PK_remote_ambari_cluster PRIMARY KEY (cluster_id),
+ CONSTRAINT unq_remote_ambari_cluster UNIQUE (name));
+
+CREATE TABLE remoteambariclusterservice(
+ id BIGINT NOT NULL,
+ cluster_id BIGINT NOT NULL,
+ service_name VARCHAR(255) NOT NULL,
+ CONSTRAINT PK_remote_ambari_service PRIMARY KEY (id),
+ CONSTRAINT FK_remote_ambari_cluster_id FOREIGN KEY (cluster_id) REFERENCES remoteambaricluster(cluster_id)
+);
+
+-- Remote Cluster table ends
-- upgrade tables
CREATE TABLE upgrade (
@@ -1094,7 +1115,11 @@ INSERT INTO ambari_sequences (sequence_name, sequence_value)
union all
select 'blueprint_setting_id_seq', 0 FROM SYSIBM.SYSDUMMY1
union all
- select 'ambari_operation_history_id_seq', 0 FROM SYSIBM.SYSDUMMY1;
+ select 'ambari_operation_history_id_seq', 0 FROM SYSIBM.SYSDUMMY1
+ union all
+ select 'remote_cluster_id_seq', 0 FROM SYSIBM.SYSDUMMY1
+ union all
+ select 'remote_cluster_service_id_seq', 0 FROM SYSIBM.SYSDUMMY1;
INSERT INTO adminresourcetype (resource_type_id, resource_type_name)
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
index e3ce816..22413e0 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
@@ -575,6 +575,7 @@ CREATE TABLE viewinstance (
xml_driven CHAR(1),
alter_names TINYINT(1) NOT NULL DEFAULT 1,
cluster_handle VARCHAR(255),
+ cluster_type VARCHAR(100) NOT NULL DEFAULT 'LOCAL_AMBARI',
short_url BIGINT,
CONSTRAINT PK_viewinstance PRIMARY KEY (view_instance_id),
CONSTRAINT FK_instance_url_id FOREIGN KEY (short_url) REFERENCES viewurl(url_id),
@@ -785,6 +786,26 @@ CREATE TABLE setting (
CONSTRAINT PK_setting PRIMARY KEY (id)
);
+-- Remote Cluster table
+
+CREATE TABLE remoteambaricluster(
+ cluster_id BIGINT NOT NULL,
+ name VARCHAR(255) NOT NULL,
+ username VARCHAR(255) NOT NULL,
+ url VARCHAR(255) NOT NULL,
+ password VARCHAR(255) NOT NULL,
+ CONSTRAINT PK_remote_ambari_cluster PRIMARY KEY (cluster_id),
+ CONSTRAINT unq_remote_ambari_cluster UNIQUE (name));
+
+CREATE TABLE remoteambariclusterservice(
+ id BIGINT NOT NULL,
+ cluster_id BIGINT NOT NULL,
+ service_name VARCHAR(255) NOT NULL,
+ CONSTRAINT PK_remote_ambari_service PRIMARY KEY (id),
+ CONSTRAINT FK_remote_ambari_cluster_id FOREIGN KEY (cluster_id) REFERENCES remoteambaricluster(cluster_id)
+);
+
+-- Remote Cluster table ends
-- upgrade tables
CREATE TABLE upgrade (
@@ -1053,7 +1074,9 @@ INSERT INTO ambari_sequences(sequence_name, sequence_value) VALUES
('servicecomponentdesiredstate_id_seq', 0),
('servicecomponent_history_id_seq', 0),
('blueprint_setting_id_seq', 0),
- ('ambari_operation_history_id_seq', 0);
+ ('ambari_operation_history_id_seq', 0),
+ ('remote_cluster_id_seq', 0),
+ ('remote_cluster_service_id_seq', 0),;
INSERT INTO adminresourcetype (resource_type_id, resource_type_name) VALUES
(1, 'AMBARI'),
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql
index cd88e8b..6000d24 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql
@@ -566,6 +566,7 @@ CREATE TABLE viewinstance (
xml_driven CHAR(1),
alter_names NUMBER(1) DEFAULT 1 NOT NULL,
cluster_handle VARCHAR(255),
+ cluster_type VARCHAR(100) DEFAULT 'LOCAL_AMBARI' NOT NULL,
short_url NUMBER,
CONSTRAINT PK_viewinstance PRIMARY KEY (view_instance_id),
CONSTRAINT FK_instance_url_id FOREIGN KEY (short_url) REFERENCES viewurl(url_id),
@@ -775,6 +776,26 @@ CREATE TABLE setting (
CONSTRAINT PK_setting PRIMARY KEY (id)
);
+-- Remote Cluster table
+
+CREATE TABLE remoteambaricluster(
+ cluster_id BIGINT NOT NULL,
+ name VARCHAR(255) NOT NULL,
+ username VARCHAR(255) NOT NULL,
+ url VARCHAR(255) NOT NULL,
+ password VARCHAR(255) NOT NULL,
+ CONSTRAINT PK_remote_ambari_cluster PRIMARY KEY (cluster_id),
+ CONSTRAINT unq_remote_ambari_cluster UNIQUE (name));
+
+CREATE TABLE remoteambariclusterservice(
+ id BIGINT NOT NULL,
+ cluster_id BIGINT NOT NULL,
+ service_name VARCHAR(255) NOT NULL,
+ CONSTRAINT PK_remote_ambari_service PRIMARY KEY (id),
+ CONSTRAINT FK_remote_ambari_cluster_id FOREIGN KEY (cluster_id) REFERENCES remoteambaricluster(cluster_id)
+);
+
+-- Remote Cluster table ends
-- upgrade tables
CREATE TABLE upgrade (
@@ -1044,6 +1065,8 @@ INSERT INTO ambari_sequences(sequence_name, sequence_value) values ('servicecomp
INSERT INTO ambari_sequences(sequence_name, sequence_value) values ('servicecomponent_history_id_seq', 0);
INSERT INTO ambari_sequences(sequence_name, sequence_value) values ('blueprint_setting_id_seq', 0);
INSERT INTO ambari_sequences(sequence_name, sequence_value) values ('ambari_operation_history_id_seq', 0);
+INSERT INTO ambari_sequences(sequence_name, sequence_value) values ('remote_cluster_id_seq', 0);
+INSERT INTO ambari_sequences(sequence_name, sequence_value) values ('remote_cluster_service_id_seq', 0);
INSERT INTO metainfo("metainfo_key", "metainfo_value") values ('version', '${ambariSchemaVersion}');
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
index 108e33e..67bd38a 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
@@ -567,6 +567,7 @@ CREATE TABLE viewinstance (
xml_driven CHAR(1),
alter_names SMALLINT NOT NULL DEFAULT 1,
cluster_handle VARCHAR(255),
+ cluster_type VARCHAR(100) NOT NULL DEFAULT 'LOCAL_AMBARI',
short_url BIGINT,
CONSTRAINT PK_viewinstance PRIMARY KEY (view_instance_id),
CONSTRAINT FK_instance_url_id FOREIGN KEY (short_url) REFERENCES viewurl(url_id),
@@ -777,6 +778,26 @@ CREATE TABLE setting (
update_timestamp BIGINT NOT NULL,
CONSTRAINT PK_setting PRIMARY KEY (id));
+-- Remote Cluster table
+
+CREATE TABLE remoteambaricluster(
+ cluster_id BIGINT NOT NULL,
+ name VARCHAR(255) NOT NULL,
+ username VARCHAR(255) NOT NULL,
+ url VARCHAR(255) NOT NULL,
+ password VARCHAR(255) NOT NULL,
+ CONSTRAINT PK_remote_ambari_cluster PRIMARY KEY (cluster_id),
+ CONSTRAINT unq_remote_ambari_cluster UNIQUE (name));
+
+CREATE TABLE remoteambariclusterservice(
+ id BIGINT NOT NULL,
+ cluster_id BIGINT NOT NULL,
+ service_name VARCHAR(255) NOT NULL,
+ CONSTRAINT PK_remote_ambari_service PRIMARY KEY (id),
+ CONSTRAINT FK_remote_ambari_cluster_id FOREIGN KEY (cluster_id) REFERENCES remoteambaricluster(cluster_id)
+);
+
+-- Remote Cluster table ends
-- upgrade tables
CREATE TABLE upgrade (
@@ -1044,7 +1065,9 @@ INSERT INTO ambari_sequences (sequence_name, sequence_value) VALUES
('servicecomponentdesiredstate_id_seq', 0),
('servicecomponent_history_id_seq', 0),
('blueprint_setting_id_seq', 0),
- ('ambari_operation_history_id_seq', 0);
+ ('ambari_operation_history_id_seq', 0),
+ ('remote_cluster_id_seq', 0),
+ ('remote_cluster_service_id_seq', 0);
INSERT INTO adminresourcetype (resource_type_id, resource_type_name) VALUES
(1, 'AMBARI'),
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/ambari-server/src/main/resources/Ambari-DDL-Postgres-EMBEDDED-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-Postgres-EMBEDDED-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-Postgres-EMBEDDED-CREATE.sql
index 566da84..ea7ab7a 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-Postgres-EMBEDDED-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-Postgres-EMBEDDED-CREATE.sql
@@ -668,6 +668,7 @@ CREATE TABLE ambari.viewinstance (
xml_driven CHAR(1),
alter_names SMALLINT NOT NULL DEFAULT 1,
cluster_handle VARCHAR(255),
+ cluster_type VARCHAR(100) NOT NULL DEFAULT 'LOCAL_AMBARI',
short_url BIGINT,
CONSTRAINT PK_viewinstance PRIMARY KEY (view_instance_id),
CONSTRAINT FK_instance_url_id FOREIGN KEY (short_url) REFERENCES ambari.viewurl(url_id),
@@ -913,6 +914,30 @@ CREATE TABLE ambari.setting (
);
GRANT ALL PRIVILEGES ON TABLE ambari.setting TO :username;
+-- Remote Cluster table
+
+CREATE TABLE ambari.remoteambaricluster(
+ cluster_id BIGINT NOT NULL,
+ name VARCHAR(255) NOT NULL,
+ username VARCHAR(255) NOT NULL,
+ url VARCHAR(255) NOT NULL,
+ password VARCHAR(255) NOT NULL,
+ CONSTRAINT PK_remote_ambari_cluster PRIMARY KEY (cluster_id),
+ CONSTRAINT unq_remote_ambari_cluster UNIQUE (name)
+);
+GRANT ALL PRIVILEGES ON TABLE ambari.remoteambaricluster TO :username;
+
+CREATE TABLE ambari.remoteambariclusterservice(
+ id BIGINT NOT NULL,
+ cluster_id BIGINT NOT NULL,
+ service_name VARCHAR(255) NOT NULL,
+ CONSTRAINT PK_remote_ambari_service PRIMARY KEY (id),
+ CONSTRAINT FK_remote_ambari_cluster_id FOREIGN KEY (cluster_id) REFERENCES ambari.remoteambaricluster(cluster_id)
+);
+GRANT ALL PRIVILEGES ON TABLE ambari.remoteambariclusterservice TO :username;
+
+-- Remote Cluster table ends
+
-- upgrade tables
CREATE TABLE ambari.upgrade (
upgrade_id BIGINT NOT NULL,
@@ -1202,7 +1227,9 @@ INSERT INTO ambari.ambari_sequences (sequence_name, sequence_value) VALUES
('servicecomponentdesiredstate_id_seq', 0),
('servicecomponent_history_id_seq', 0),
('blueprint_setting_id_seq', 0),
- ('ambari_operation_history_id_seq', 0);
+ ('ambari_operation_history_id_seq', 0),
+ ('remote_cluster_id_seq', 0),
+ ('remote_cluster_service_id_seq', 0);
INSERT INTO ambari.adminresourcetype (resource_type_id, resource_type_name) VALUES
(1, 'AMBARI'),
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql
index bd5d1ae..1c3393e 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql
@@ -564,6 +564,7 @@ CREATE TABLE viewinstance (
xml_driven CHAR(1),
alter_names BIT NOT NULL DEFAULT 1,
cluster_handle VARCHAR(255),
+ cluster_type VARCHAR(100) NOT NULL DEFAULT 'LOCAL_AMBARI',
short_url NUMERIC,
CONSTRAINT PK_viewinstance PRIMARY KEY (view_instance_id),
CONSTRAINT FK_instance_url_id FOREIGN KEY (short_url) REFERENCES viewurl(url_id),
@@ -774,6 +775,26 @@ CREATE TABLE setting (
CONSTRAINT PK_setting PRIMARY KEY (id)
);
+-- Remote Cluster table
+
+CREATE TABLE remoteambaricluster(
+ cluster_id BIGINT NOT NULL,
+ name VARCHAR(255) NOT NULL,
+ username VARCHAR(255) NOT NULL,
+ url VARCHAR(255) NOT NULL,
+ password VARCHAR(255) NOT NULL,
+ CONSTRAINT PK_remote_ambari_cluster PRIMARY KEY (cluster_id),
+ CONSTRAINT unq_remote_ambari_cluster UNIQUE (name));
+
+CREATE TABLE remoteambariclusterservice(
+ id BIGINT NOT NULL,
+ cluster_id BIGINT NOT NULL,
+ service_name VARCHAR(255) NOT NULL,
+ CONSTRAINT PK_remote_ambari_service PRIMARY KEY (id),
+ CONSTRAINT FK_remote_ambari_cluster_id FOREIGN KEY (cluster_id) REFERENCES remoteambaricluster(cluster_id)
+);
+
+-- Remote Cluster table ends
-- upgrade tables
CREATE TABLE upgrade (
@@ -1043,6 +1064,8 @@ INSERT INTO ambari_sequences(sequence_name, sequence_value) values ('servicecomp
INSERT INTO ambari_sequences(sequence_name, sequence_value) values ('servicecomponent_history_id_seq', 0);
INSERT INTO ambari_sequences(sequence_name, sequence_value) values ('blueprint_setting_id_seq', 0);
INSERT INTO ambari_sequences(sequence_name, sequence_value) values ('ambari_operation_history_id_seq', 0);
+INSERT INTO ambari_sequences(sequence_name, sequence_value) values ('remote_cluster_id_seq', 0);
+INSERT INTO ambari_sequences(sequence_name, sequence_value) values ('remote_cluster_service_id_seq', 0);
insert into adminresourcetype (resource_type_id, resource_type_name)
select 1, 'AMBARI'
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql
index 20c706a..2245f77 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql
@@ -574,6 +574,7 @@ CREATE TABLE viewinstance (
xml_driven CHAR(1),
alter_names BIT NOT NULL DEFAULT 1,
cluster_handle VARCHAR(255),
+ cluster_type VARCHAR(100) NOT NULL DEFAULT 'LOCAL_AMBARI',
short_url BIGINT,
CONSTRAINT PK_viewinstance PRIMARY KEY CLUSTERED (view_instance_id),
CONSTRAINT FK_instance_url_id FOREIGN KEY (short_url) REFERENCES viewurl(url_id),
@@ -795,6 +796,26 @@ CREATE TABLE setting (
CONSTRAINT PK_setting PRIMARY KEY (id)
);
+-- Remote Cluster table
+
+CREATE TABLE remoteambaricluster(
+ cluster_id BIGINT NOT NULL,
+ name VARCHAR(255) NOT NULL,
+ username VARCHAR(255) NOT NULL,
+ url VARCHAR(255) NOT NULL,
+ password VARCHAR(255) NOT NULL,
+ CONSTRAINT PK_remote_ambari_cluster PRIMARY KEY (cluster_id),
+ CONSTRAINT unq_remote_ambari_cluster UNIQUE (name));
+
+CREATE TABLE remoteambariclusterservice(
+ id BIGINT NOT NULL,
+ cluster_id BIGINT NOT NULL,
+ service_name VARCHAR(255) NOT NULL,
+ CONSTRAINT PK_remote_ambari_service PRIMARY KEY (id),
+ CONSTRAINT FK_remote_ambari_cluster_id FOREIGN KEY (cluster_id) REFERENCES remoteambaricluster(cluster_id)
+);
+
+-- Remote Cluster table ends
-- upgrade tables
CREATE TABLE upgrade (
@@ -1068,7 +1089,9 @@ BEGIN TRANSACTION
('servicecomponentdesiredstate_id_seq', 0),
('servicecomponent_history_id_seq', 0),
('blueprint_setting_id_seq', 0),
- ('ambari_operation_history_id_seq', 0);
+ ('ambari_operation_history_id_seq', 0),
+ ('remote_cluster_id_seq', 0),
+ ('remote_cluster_service_id_seq', 0);
insert into adminresourcetype (resource_type_id, resource_type_name)
values
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/ambari-server/src/main/resources/META-INF/persistence.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/META-INF/persistence.xml b/ambari-server/src/main/resources/META-INF/persistence.xml
index ce563cb..5671dcf 100644
--- a/ambari-server/src/main/resources/META-INF/persistence.xml
+++ b/ambari-server/src/main/resources/META-INF/persistence.xml
@@ -93,6 +93,8 @@
<class>org.apache.ambari.server.orm.entities.TopologyLogicalTaskEntity</class>
<class>org.apache.ambari.server.orm.entities.SettingEntity</class>
<class>org.apache.ambari.server.orm.entities.KerberosDescriptorEntity</class>
+ <class>org.apache.ambari.server.orm.entities.RemoteAmbariClusterEntity</class>
+ <class>org.apache.ambari.server.orm.entities.RemoteAmbariClusterServiceEntity</class>
<properties>
<property name="eclipselink.cache.size.default" value="10000" />
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/RemoteClusterResourceProviderTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/RemoteClusterResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/RemoteClusterResourceProviderTest.java
new file mode 100644
index 0000000..546f155
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/RemoteClusterResourceProviderTest.java
@@ -0,0 +1,193 @@
+/**
+ * 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.controller.internal;
+
+import org.apache.ambari.server.controller.predicate.EqualsPredicate;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.controller.utilities.PropertyHelper;
+import org.apache.ambari.server.orm.dao.RemoteAmbariClusterDAO;
+import org.apache.ambari.server.orm.entities.RemoteAmbariClusterEntity;
+import org.apache.ambari.server.orm.entities.RemoteAmbariClusterServiceEntity;
+import org.apache.ambari.server.security.TestAuthenticationFactory;
+import org.apache.ambari.server.view.RemoteAmbariClusterRegistry;
+import org.easymock.Capture;
+import org.junit.After;
+import org.junit.Test;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import static org.easymock.EasyMock.capture;
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.createNiceMock;
+import static org.easymock.EasyMock.eq;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.newCapture;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertEquals;
+
+public class RemoteClusterResourceProviderTest {
+
+ @After
+ public void clearAuthentication() {
+ SecurityContextHolder.getContext().setAuthentication(null);
+ }
+
+ @Test
+ public void testToResource() throws Exception {
+ RemoteClusterResourceProvider provider = new RemoteClusterResourceProvider();
+ Set<String> propertyIds = new HashSet<String>();
+ propertyIds.add(RemoteClusterResourceProvider.CLUSTER_NAME_PROPERTY_ID);
+ propertyIds.add(RemoteClusterResourceProvider.CLUSTER_URL_PROPERTY_ID);
+ propertyIds.add(RemoteClusterResourceProvider.USERNAME_PROPERTY_ID);
+ propertyIds.add(RemoteClusterResourceProvider.PASSWORD_PROPERTY_ID);
+ propertyIds.add(RemoteClusterResourceProvider.SERVICES_PROPERTY_ID);
+
+ RemoteAmbariClusterServiceEntity service1 = createNiceMock(RemoteAmbariClusterServiceEntity.class);
+ expect(service1.getServiceName()).andReturn("service1").once();
+
+ RemoteAmbariClusterServiceEntity service2 = createNiceMock(RemoteAmbariClusterServiceEntity.class);
+ expect(service2.getServiceName()).andReturn("service2").once();
+
+ List<RemoteAmbariClusterServiceEntity> serviceList = new ArrayList<RemoteAmbariClusterServiceEntity>();
+ serviceList.add(service1);
+ serviceList.add(service2);
+
+ RemoteAmbariClusterEntity entity = createNiceMock(RemoteAmbariClusterEntity.class);
+ expect(entity.getName()).andReturn("test").once();
+ expect(entity.getUrl()).andReturn("url").once();
+ expect(entity.getUsername()).andReturn("user").once();
+ expect(entity.getServices()).andReturn(serviceList).once();
+
+ replay(service1, service2, entity);
+
+ List<String> services = new ArrayList<String>();
+ services.add("service1");
+ services.add("service2");
+
+ Resource resource = provider.toResource(propertyIds, entity);
+ assertEquals(resource.getPropertyValue(RemoteClusterResourceProvider.CLUSTER_NAME_PROPERTY_ID), "test");
+ assertEquals(resource.getPropertyValue(RemoteClusterResourceProvider.CLUSTER_URL_PROPERTY_ID), "url");
+ assertEquals(resource.getPropertyValue(RemoteClusterResourceProvider.USERNAME_PROPERTY_ID), "user");
+ assertEquals(resource.getPropertyValue(RemoteClusterResourceProvider.SERVICES_PROPERTY_ID), services);
+ verify(service1, service2, entity);
+ }
+
+ @Test
+ public void testCreateResourcesAsAdministrator() throws Exception {
+ testCreateResources(TestAuthenticationFactory.createAdministrator());
+ }
+
+ static void setField(Field field, Object newValue) throws Exception {
+ field.setAccessible(true);
+
+ Field modifiersField = Field.class.getDeclaredField("modifiers");
+ modifiersField.setAccessible(true);
+ modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
+ field.set(null, newValue);
+ }
+
+ private void testCreateResources(Authentication authentication) throws Exception {
+
+ RemoteClusterResourceProvider provider = new RemoteClusterResourceProvider();
+
+ RemoteAmbariClusterDAO clusterDAO = createMock(RemoteAmbariClusterDAO.class);
+ setField(RemoteClusterResourceProvider.class.getDeclaredField("remoteAmbariClusterDAO"), clusterDAO);
+
+ RemoteAmbariClusterRegistry clusterRegistry = createMock(RemoteAmbariClusterRegistry.class);
+ setField(RemoteClusterResourceProvider.class.getDeclaredField("remoteAmbariClusterRegistry"), clusterRegistry);
+
+ Set<Map<String, Object>> properties = new HashSet<>();
+ Map<String, Object> propertyMap = new HashMap<>();
+ propertyMap.put(RemoteClusterResourceProvider.CLUSTER_NAME_PROPERTY_ID, "test");
+ propertyMap.put(RemoteClusterResourceProvider.CLUSTER_URL_PROPERTY_ID, "url");
+ propertyMap.put(RemoteClusterResourceProvider.USERNAME_PROPERTY_ID, "username");
+ propertyMap.put(RemoteClusterResourceProvider.PASSWORD_PROPERTY_ID, "password");
+
+ RemoteAmbariClusterServiceEntity service1 = createNiceMock(RemoteAmbariClusterServiceEntity.class);
+ expect(service1.getServiceName()).andReturn("service1").once();
+
+ RemoteAmbariClusterServiceEntity service2 = createNiceMock(RemoteAmbariClusterServiceEntity.class);
+ expect(service2.getServiceName()).andReturn("service2").once();
+
+ List<RemoteAmbariClusterServiceEntity> serviceList = new ArrayList<RemoteAmbariClusterServiceEntity>();
+ serviceList.add(service1);
+ serviceList.add(service2);
+
+ expect(clusterDAO.findByName("test")).andReturn(null).anyTimes();
+ Capture<RemoteAmbariClusterEntity> clusterEntityCapture = newCapture();
+
+ clusterRegistry.saveOrUpdate(capture(clusterEntityCapture),eq(false));
+
+ replay(clusterRegistry, clusterDAO, service1, service2);
+
+ properties.add(propertyMap);
+
+ SecurityContextHolder.getContext().setAuthentication(authentication);
+
+ provider.createResources(PropertyHelper.getCreateRequest(properties, null));
+
+ RemoteAmbariClusterEntity clusterEntity = clusterEntityCapture.getValue();
+ assertEquals(clusterEntity.getName(), "test");
+ assertEquals(clusterEntity.getPassword(), "password");
+ assertEquals(clusterEntity.getUrl(), "url");
+ assertEquals(clusterEntity.getUsername(), "username");
+
+ }
+
+ @Test
+ public void testDeleteResources() throws Exception {
+ RemoteClusterResourceProvider provider = new RemoteClusterResourceProvider();
+ RemoteAmbariClusterDAO clusterDAO = createNiceMock(RemoteAmbariClusterDAO.class);
+ RemoteAmbariClusterEntity clusterEntity = new RemoteAmbariClusterEntity();
+
+ setField(RemoteClusterResourceProvider.class.getDeclaredField("remoteAmbariClusterDAO"), clusterDAO);
+
+ EqualsPredicate equalsPredicate = new EqualsPredicate(RemoteClusterResourceProvider.CLUSTER_NAME_PROPERTY_ID,"test");
+
+ RemoteAmbariClusterRegistry clusterRegistry = createMock(RemoteAmbariClusterRegistry.class);
+ setField(RemoteClusterResourceProvider.class.getDeclaredField("remoteAmbariClusterRegistry"), clusterRegistry);
+
+ Set<Map<String, Object>> properties = new HashSet<>();
+ Map<String, Object> propertyMap = new HashMap<>();
+ propertyMap.put(RemoteClusterResourceProvider.CLUSTER_NAME_PROPERTY_ID,"test");
+
+ expect(clusterDAO.findByName("test")).andReturn(clusterEntity);
+ clusterRegistry.delete(clusterEntity);
+
+ replay(clusterDAO);
+
+ properties.add(propertyMap);
+
+ SecurityContextHolder.getContext().setAuthentication(TestAuthenticationFactory.createAdministrator());
+
+ provider.deleteResources(PropertyHelper.getCreateRequest(properties, null),equalsPredicate);
+
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog240Test.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog240Test.java b/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog240Test.java
index 78a910a..f36e640 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog240Test.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog240Test.java
@@ -243,6 +243,22 @@ public class UpgradeCatalog240Test {
dbAccessor.addFKConstraint(UpgradeCatalog240.VIEWINSTANCE_TABLE, "FK_instance_url_id",
UpgradeCatalog240.SHORT_URL_COLUMN, UpgradeCatalog240.VIEWURL_TABLE, "url_id", false);
+ Capture<DBAccessor.DBColumnInfo> viewInstanceClusterType = newCapture();
+ dbAccessor.addColumn(eq(UpgradeCatalog240.VIEWINSTANCE_TABLE), capture(viewInstanceClusterType));
+
+ // Test remote Cluster Tables
+ Capture<List<DBAccessor.DBColumnInfo>> capturedRemoteAmbariClusterColumns = EasyMock.newCapture();
+ dbAccessor.createTable(eq(UpgradeCatalog240.REMOTE_AMBARI_CLUSTER_TABLE), capture(capturedRemoteAmbariClusterColumns),anyString());
+ dbAccessor.addUniqueConstraint(UpgradeCatalog240.REMOTE_AMBARI_CLUSTER_TABLE , "unq_remote_ambari_cluster" , UpgradeCatalog240.CLUSTER_NAME);
+ expect(dbAccessor.getConnection()).andReturn(connection);
+ expect(connection.createStatement()).andReturn(statement);
+
+ Capture<List<DBAccessor.DBColumnInfo>> capturedRemoteClusterServiceColumns = EasyMock.newCapture();
+ dbAccessor.createTable(eq(UpgradeCatalog240.REMOTE_AMBARI_CLUSTER_SERVICE_TABLE), capture(capturedRemoteClusterServiceColumns),anyString());
+ dbAccessor.addFKConstraint(UpgradeCatalog240.REMOTE_AMBARI_CLUSTER_SERVICE_TABLE, "FK_remote_ambari_cluster_id",
+ UpgradeCatalog240.CLUSTER_ID, UpgradeCatalog240.REMOTE_AMBARI_CLUSTER_TABLE, UpgradeCatalog240.CLUSTER_ID, false);
+ expect(dbAccessor.getConnection()).andReturn(connection);
+ expect(connection.createStatement()).andReturn(statement);
replay(dbAccessor, configuration, connection, statement, resultSet);
@@ -403,6 +419,20 @@ public class UpgradeCatalog240Test {
Assert.assertNotNull(capturedViewUrlColumsValue);
Assert.assertEquals(capturedViewUrlColumsValue.size(),3);
+ // Verify cluster_type column
+ DBAccessor.DBColumnInfo viewInstanceEntityClusterTypeValue = viewInstanceClusterType.getValue();
+ Assert.assertNotNull(viewInstanceClusterType);
+ Assert.assertEquals("cluster_type", viewInstanceEntityClusterTypeValue.getName());
+ Assert.assertEquals(String.class, viewInstanceEntityClusterTypeValue.getType());
+
+ List<DBAccessor.DBColumnInfo> capturedRemoteAmbariClusterColumnsValue = capturedRemoteAmbariClusterColumns.getValue();
+ Assert.assertNotNull(capturedRemoteAmbariClusterColumnsValue);
+ Assert.assertEquals(capturedRemoteAmbariClusterColumnsValue.size(),5);
+
+ List<DBAccessor.DBColumnInfo> capturedRemoteClusterServiceColumnsValue = capturedRemoteClusterServiceColumns.getValue();
+ Assert.assertNotNull(capturedRemoteClusterServiceColumnsValue);
+ Assert.assertEquals(capturedRemoteClusterServiceColumnsValue.size(),3);
+
verify(dbAccessor);
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/ambari-server/src/test/java/org/apache/ambari/server/view/RemoteAmbariClusterTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/view/RemoteAmbariClusterTest.java b/ambari-server/src/test/java/org/apache/ambari/server/view/RemoteAmbariClusterTest.java
new file mode 100644
index 0000000..ce8fe7d
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/view/RemoteAmbariClusterTest.java
@@ -0,0 +1,90 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.view;
+
+import org.apache.ambari.server.orm.entities.RemoteAmbariClusterEntity;
+import org.apache.ambari.view.AmbariStreamProvider;
+import org.easymock.IAnswer;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.util.Map;
+
+import static org.easymock.EasyMock.anyObject;
+import static org.easymock.EasyMock.createNiceMock;
+import static org.easymock.EasyMock.eq;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.isNull;
+import static org.easymock.EasyMock.replay;
+import static org.junit.Assert.assertEquals;
+
+public class RemoteAmbariClusterTest {
+
+ @Rule
+ public ExpectedException thrown= ExpectedException.none();
+
+
+ @Test
+ public void testGetConfigurationValue() throws Exception {
+
+ AmbariStreamProvider clusterStreamProvider = createNiceMock(AmbariStreamProvider.class);
+
+ final String desiredConfigsString = "{\"Clusters\": {\"desired_configs\": {\"test-site\": {\"tag\": \"TAG\"}}}}";
+ final String configurationString = "{\"items\": [{\"properties\": {\"test.property.name\": \"test property value\"}}]}";
+ final int[] desiredConfigPolls = {0};
+ final int[] testConfigPolls = {0};
+
+ expect(clusterStreamProvider.readFrom(eq( "?fields=services/ServiceInfo,hosts,Clusters"),
+ eq("GET"), (String) isNull(), (Map<String, String>) anyObject())).andAnswer(new IAnswer<InputStream>() {
+ @Override
+ public InputStream answer() throws Throwable {
+ desiredConfigPolls[0] += 1;
+ return new ByteArrayInputStream(desiredConfigsString.getBytes());
+ }
+ }).anyTimes();
+
+ expect(clusterStreamProvider.readFrom(eq( "/configurations?(type=test-site&tag=TAG)"),
+ eq("GET"), (String)isNull(), (Map<String, String>) anyObject())).andAnswer(new IAnswer<InputStream>() {
+ @Override
+ public InputStream answer() throws Throwable {
+ testConfigPolls[0] += 1;
+ return new ByteArrayInputStream(configurationString.getBytes());
+ }
+ }).anyTimes();
+
+ RemoteAmbariClusterEntity entity = createNiceMock(RemoteAmbariClusterEntity.class);
+
+ replay(clusterStreamProvider,entity);
+
+ RemoteAmbariCluster cluster = new RemoteAmbariCluster("Test", clusterStreamProvider);
+
+ String value = cluster.getConfigurationValue("test-site", "test.property.name");
+ assertEquals(value, "test property value");
+ assertEquals(desiredConfigPolls[0], 1);
+ assertEquals(testConfigPolls[0], 1);
+
+ value = cluster.getConfigurationValue("test-site", "test.property.name");
+ assertEquals(value, "test property value");
+ assertEquals(desiredConfigPolls[0], 1); // cache hit
+ assertEquals(testConfigPolls[0], 1);
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/ambari-server/src/test/java/org/apache/ambari/server/view/ViewAmbariStreamProviderTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/view/ViewAmbariStreamProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/view/ViewAmbariStreamProviderTest.java
index 8549d4a..98b57f0 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/view/ViewAmbariStreamProviderTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/view/ViewAmbariStreamProviderTest.java
@@ -69,7 +69,7 @@ public class ViewAmbariStreamProviderTest {
ViewAmbariStreamProvider viewAmbariStreamProvider = new ViewAmbariStreamProvider(streamProvider, sessionManager, controller);
- Assert.assertEquals(inputStream, viewAmbariStreamProvider.readFrom("spec", "requestMethod", "params", headers, true));
+ Assert.assertEquals(inputStream, viewAmbariStreamProvider.readFrom("spec", "requestMethod", "params", headers));
verify(streamProvider, sessionManager, urlConnection, inputStream);
}
@@ -104,7 +104,7 @@ public class ViewAmbariStreamProviderTest {
ViewAmbariStreamProvider viewAmbariStreamProvider = new ViewAmbariStreamProvider(streamProvider, sessionManager, controller);
- Assert.assertEquals(inputStream, viewAmbariStreamProvider.readFrom("spec", "requestMethod", body, headers, true));
+ Assert.assertEquals(inputStream, viewAmbariStreamProvider.readFrom("spec", "requestMethod", body, headers));
verify(streamProvider, sessionManager, urlConnection, inputStream);
}
@@ -139,7 +139,7 @@ public class ViewAmbariStreamProviderTest {
ViewAmbariStreamProvider viewAmbariStreamProvider = new ViewAmbariStreamProvider(streamProvider, sessionManager, controller);
- Assert.assertEquals(inputStream, viewAmbariStreamProvider.readFrom("spec", "requestMethod", body, headers, true));
+ Assert.assertEquals(inputStream, viewAmbariStreamProvider.readFrom("spec", "requestMethod", body, headers));
verify(streamProvider, sessionManager, urlConnection, inputStream);
}
@@ -174,7 +174,7 @@ public class ViewAmbariStreamProviderTest {
ViewAmbariStreamProvider viewAmbariStreamProvider = new ViewAmbariStreamProvider(streamProvider, sessionManager, controller);
- Assert.assertEquals(inputStream, viewAmbariStreamProvider.readFrom("spec", "requestMethod", body, headers, true));
+ Assert.assertEquals(inputStream, viewAmbariStreamProvider.readFrom("spec", "requestMethod", body, headers));
verify(streamProvider, sessionManager, urlConnection, inputStream);
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/ambari-server/src/test/java/org/apache/ambari/server/view/configuration/ViewConfigTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/view/configuration/ViewConfigTest.java b/ambari-server/src/test/java/org/apache/ambari/server/view/configuration/ViewConfigTest.java
index a41e137..f318dab 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/view/configuration/ViewConfigTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/view/configuration/ViewConfigTest.java
@@ -57,6 +57,7 @@ public class ViewConfigTest {
" <system>true</system>\n" +
" <icon64>/this/is/the/icon/url/icon64.png</icon64>\n" +
" <icon>/this/is/the/icon/url/icon.png</icon>\n" +
+ " <cluster-config-options>AMBARI-ONLY</cluster-config-options>\n" +
" <data-migrator-class>org.apache.ambari.server.view.configuration.ViewConfigTest$MyDataMigrator</data-migrator-class>" +
" <validator-class>org.apache.ambari.server.view.configuration.ViewConfigTest$MyValidator</validator-class>" +
" <masker-class>org.apache.ambari.server.view.DefaultMasker</masker-class>" +
@@ -352,6 +353,12 @@ public class ViewConfigTest {
Assert.assertEquals("2.0.0", config.getMaxAmbariVersion());
}
+ @Test
+ public void testGetClusterConfigOptions() throws Exception {
+ ViewConfig config = getConfig();
+ Assert.assertEquals("AMBARI-ONLY",config.getClusterConfigOptions());
+ }
+
public static ViewConfig getConfig() throws JAXBException {
return getConfig(xml);
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/ambari-views/src/main/java/org/apache/ambari/view/AmbariClusterStreamProvider.java
----------------------------------------------------------------------
diff --git a/ambari-views/src/main/java/org/apache/ambari/view/AmbariClusterStreamProvider.java b/ambari-views/src/main/java/org/apache/ambari/view/AmbariClusterStreamProvider.java
new file mode 100644
index 0000000..a48749a
--- /dev/null
+++ b/ambari-views/src/main/java/org/apache/ambari/view/AmbariClusterStreamProvider.java
@@ -0,0 +1,90 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.view;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Map;
+
+/**
+ * Provider of Input stream for Ambari cluster
+ */
+public interface AmbariClusterStreamProvider {
+
+
+ /**
+ * Read from the input stream specified by the given path for cluster on Ambari server.
+ * Base path will be /api/v1/clusters/${clusterName}
+ *
+ * @param path the String to parse as an Ambari cluster endpoint (e.g. /configurations)
+ * @param requestMethod the HTTP method (GET,POST,PUT,etc.).
+ * @param body the body of the request; may be null
+ * @param headers the headers of the request; may be null
+ *
+ * @return the input stream
+ *
+ * @throws IOException, AmbariHttpException
+ */
+ public InputStream readFromCluster(String path, String requestMethod, String body, Map<String, String> headers) throws IOException, AmbariHttpException;
+
+ /**
+ * Read from the input stream specified by the given path for cluster on Ambari server.
+ * Base path will be /api/v1/clusters/${clusterName}
+ *
+ * @param path the String to parse as an Ambari cluster endpoint (e.g. /configurations)
+ * @param requestMethod the HTTP method (GET,POST,PUT,etc.).
+ * @param body the body of the request; may be null
+ * @param headers the headers of the request; may be null
+ *
+ * @return the input stream
+ *
+ * @throws IOException, AmbariHttpException
+ */
+ public InputStream readFromCluster(String path, String requestMethod, InputStream body, Map<String, String> headers) throws IOException, AmbariHttpException;
+
+ /**
+ * Read from the input stream specified by the given path for cluster on the Ambari server.
+ *
+ * @param path the String to parse as an Ambari endpoint (e.g. /api/v1)
+ * @param requestMethod the HTTP method (GET,POST,PUT,etc.).
+ * @param body the body of the request; may be null
+ * @param headers the headers of the request; may be null
+ *
+ * @return the input stream
+ *
+ * @throws java.io.IOException if an error occurred connecting to the server
+ * AmbariHttpException if response to url is unsuccessful
+ */
+ public InputStream readFromAmbari(String path, String requestMethod, String body, Map<String, String> headers) throws IOException, AmbariHttpException;
+
+ /**
+ * Read from the input stream specified by the given path for cluster on the Ambari server.
+ *
+ * @param path the String to parse as an Ambari endpoint (e.g. /api/v1)
+ * @param requestMethod the HTTP method (GET,POST,PUT,etc.).
+ * @param body the body of the request; may be null
+ * @param headers the headers of the request; may be null
+ *
+ * @return the input stream
+ *
+ * @throws java.io.IOException if an error occurred connecting to the server ,
+ * AmbariHttpException if response to url is unsuccessful
+ */
+ public InputStream readFromAmbari(String path, String requestMethod, InputStream body, Map<String, String> headers) throws IOException, AmbariHttpException;
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/ambari-views/src/main/java/org/apache/ambari/view/AmbariHttpException.java
----------------------------------------------------------------------
diff --git a/ambari-views/src/main/java/org/apache/ambari/view/AmbariHttpException.java b/ambari-views/src/main/java/org/apache/ambari/view/AmbariHttpException.java
new file mode 100644
index 0000000..60c8e29
--- /dev/null
+++ b/ambari-views/src/main/java/org/apache/ambari/view/AmbariHttpException.java
@@ -0,0 +1,41 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.view;
+
+/**
+ * Ambari Http Exception : used to indicate unsuccessful response of url
+ */
+public class AmbariHttpException extends Exception {
+
+ private int responseCode ;
+
+ public AmbariHttpException(String message, int responseCode) {
+ super(message);
+ this.responseCode = responseCode;
+ }
+
+ /**
+ * Get the Error code
+ *
+ * @return responseCode
+ */
+ public int getResponseCode() {
+ return responseCode;
+ }
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/ambari-views/src/main/java/org/apache/ambari/view/AmbariStreamProvider.java
----------------------------------------------------------------------
diff --git a/ambari-views/src/main/java/org/apache/ambari/view/AmbariStreamProvider.java b/ambari-views/src/main/java/org/apache/ambari/view/AmbariStreamProvider.java
index ce91676..ec9e70c 100644
--- a/ambari-views/src/main/java/org/apache/ambari/view/AmbariStreamProvider.java
+++ b/ambari-views/src/main/java/org/apache/ambari/view/AmbariStreamProvider.java
@@ -33,14 +33,13 @@ public interface AmbariStreamProvider {
* @param requestMethod the HTTP method (GET,POST,PUT,etc.).
* @param body the body of the request; may be null
* @param headers the headers of the request; may be null
- * @param useAmbariSession indicates that the current Ambari session cookie should be set for the request
*
* @return the input stream
*
* @throws java.io.IOException if an error occurred connecting to the server
*/
public InputStream readFrom(String path, String requestMethod, String body,
- Map<String, String> headers, boolean useAmbariSession) throws IOException;
+ Map<String, String> headers) throws IOException,AmbariHttpException;
/**
* Read from the input stream specified by the given path on the Ambari server.
@@ -49,12 +48,11 @@ public interface AmbariStreamProvider {
* @param requestMethod the HTTP method (GET,POST,PUT,etc.).
* @param body the body of the request; may be null
* @param headers the headers of the request; may be null
- * @param useAmbariSession indicates that the current Ambari session cookie should be set for the request
*
* @return the input stream
*
* @throws java.io.IOException if an error occurred connecting to the server
*/
public InputStream readFrom(String path, String requestMethod, InputStream body,
- Map<String, String> headers, boolean useAmbariSession) throws IOException;
+ Map<String, String> headers) throws IOException,AmbariHttpException;
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/ambari-views/src/main/java/org/apache/ambari/view/ClusterType.java
----------------------------------------------------------------------
diff --git a/ambari-views/src/main/java/org/apache/ambari/view/ClusterType.java b/ambari-views/src/main/java/org/apache/ambari/view/ClusterType.java
new file mode 100644
index 0000000..bab2c41
--- /dev/null
+++ b/ambari-views/src/main/java/org/apache/ambari/view/ClusterType.java
@@ -0,0 +1,40 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.view;
+
+/**
+ * Cluster type enums
+ */
+public enum ClusterType {
+
+ /**
+ * Local ambari cluster
+ */
+ LOCAL_AMBARI,
+
+ /**
+ * Remote Ambari managed cluster
+ */
+ REMOTE_AMBARI,
+
+ /**
+ * Used when view is not managed by cluster
+ */
+ NONE
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/ambari-views/src/main/java/org/apache/ambari/view/ViewContext.java
----------------------------------------------------------------------
diff --git a/ambari-views/src/main/java/org/apache/ambari/view/ViewContext.java b/ambari-views/src/main/java/org/apache/ambari/view/ViewContext.java
index 7b7b025..7aaa799 100644
--- a/ambari-views/src/main/java/org/apache/ambari/view/ViewContext.java
+++ b/ambari-views/src/main/java/org/apache/ambari/view/ViewContext.java
@@ -172,6 +172,14 @@ public interface ViewContext {
public AmbariStreamProvider getAmbariStreamProvider();
/**
+ * Get Ambari stream provider attached as cluster to the view
+ * If view is not attached to ambari managed cluster then it will be null
+ *
+ * @return stream provider for the cluster
+ */
+ public AmbariStreamProvider getAmbariClusterStreamProvider();
+
+ /**
* Get a data store for view persistence entities.
*
* @return a data store; null if no instance is associated
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/ambari-views/src/main/java/org/apache/ambari/view/ViewInstanceDefinition.java
----------------------------------------------------------------------
diff --git a/ambari-views/src/main/java/org/apache/ambari/view/ViewInstanceDefinition.java b/ambari-views/src/main/java/org/apache/ambari/view/ViewInstanceDefinition.java
index 0c3d3ce..cea4c88 100644
--- a/ambari-views/src/main/java/org/apache/ambari/view/ViewInstanceDefinition.java
+++ b/ambari-views/src/main/java/org/apache/ambari/view/ViewInstanceDefinition.java
@@ -61,6 +61,13 @@ public interface ViewInstanceDefinition {
*/
public String getClusterHandle();
+ /**
+ * Get the type of cluster the view instance is attached to
+ *
+ * @return clusterType the type of cluster for cluster handle
+ */
+ public ClusterType getClusterType();
+
/**
* Indicates whether or not the view instance should be visible.
@@ -89,4 +96,5 @@ public interface ViewInstanceDefinition {
* @return the view definition
*/
public ViewDefinition getViewDefinition();
+
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/ambari-views/src/main/resources/view.xsd
----------------------------------------------------------------------
diff --git a/ambari-views/src/main/resources/view.xsd b/ambari-views/src/main/resources/view.xsd
index 04902e9..cc18950 100644
--- a/ambari-views/src/main/resources/view.xsd
+++ b/ambari-views/src/main/resources/view.xsd
@@ -347,6 +347,11 @@
<xs:documentation>The Masker class for masking view parameters.</xs:documentation>
</xs:annotation>
</xs:element>
+ <xs:element type="xs:string" name="cluster-config-options" minOccurs="0" maxOccurs="1">
+ <xs:annotation>
+ <xs:documentation>Enable views to display cluster options in case of no cluster config properties.</xs:documentation>
+ </xs:annotation>
+ </xs:element>
<xs:element type="xs:string" name="data-migrator-class" minOccurs="0" maxOccurs="1">
<xs:annotation>
<xs:documentation>The data migration class.</xs:documentation>
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/contrib/views/capacity-scheduler/src/main/java/org/apache/ambari/view/capacityscheduler/ConfigurationService.java
----------------------------------------------------------------------
diff --git a/contrib/views/capacity-scheduler/src/main/java/org/apache/ambari/view/capacityscheduler/ConfigurationService.java b/contrib/views/capacity-scheduler/src/main/java/org/apache/ambari/view/capacityscheduler/ConfigurationService.java
index 7f1d489..718c5a5 100644
--- a/contrib/views/capacity-scheduler/src/main/java/org/apache/ambari/view/capacityscheduler/ConfigurationService.java
+++ b/contrib/views/capacity-scheduler/src/main/java/org/apache/ambari/view/capacityscheduler/ConfigurationService.java
@@ -118,8 +118,6 @@ public class ConfigurationService {
public Response readLatestConfiguration() {
Response response = null;
try {
- validateViewConfiguration();
-
String versionTag = getVersionTag();
JSONObject configurations = getConfigurationFromAmbari(versionTag);
response = Response.ok(configurations).build();
@@ -143,8 +141,6 @@ public class ConfigurationService {
public Response readClusterInfo() {
Response response = null;
try {
- validateViewConfiguration();
-
JSONObject configurations = readFromCluster("");
response = Response.ok(configurations).build();
} catch (WebApplicationException ex) {
@@ -167,8 +163,6 @@ public class ConfigurationService {
public Response readAllConfigurations() {
Response response = null;
try {
- validateViewConfiguration();
-
JSONObject responseJSON = readFromCluster(CONFIGURATION_URL);
response = Response.ok( responseJSON ).build();
} catch (WebApplicationException ex) {
@@ -191,8 +185,6 @@ public class ConfigurationService {
public Response readConfigurationByTag(@PathParam("tag") String tag) {
Response response = null;
try {
- validateViewConfiguration();
-
JSONObject configurations = getConfigurationFromAmbari(tag);
response = Response.ok(configurations).build();
} catch (WebApplicationException ex) {
@@ -265,8 +257,7 @@ public class ConfigurationService {
* @return if <code>true</code>, the user is an operator; otherwise <code>false</code>
*/
private boolean isOperator() {
- validateViewConfiguration();
-
+
// first check if the user is an CLUSTER.ADMINISTRATOR
String url = String.format(CLUSTER_OPERATOR_PRIVILEGE_URL, context.getUsername());
JSONObject json = readFromCluster(url);
@@ -316,33 +307,6 @@ public class ConfigurationService {
return jsonObject;
}
- /**
- * Validates the view configuration properties.
- *
- * @throws MisconfigurationFormattedException if one of the required view configuration properties are not set
- */
- private void validateViewConfiguration() {
- // check if we are cluster config'd, if so, just go
- if (ambariApi.isLocalCluster()) {
- return;
- }
-
- String hostname = context.getProperties().get("ambari.server.url");
- if (hostname == null) {
- throw new MisconfigurationFormattedException("ambari.server.url");
- }
-
- String username = context.getProperties().get("ambari.server.username");
- if (username == null) {
- throw new MisconfigurationFormattedException("ambari.server.username");
- }
-
- String password = context.getProperties().get("ambari.server.password");
- if (password == null) {
- throw new MisconfigurationFormattedException("ambari.server.password");
- }
- }
-
private JSONObject getConfigurationFromAmbari(String versionTag) {
String url = String.format(CONFIGURATION_URL_BY_TAG, versionTag);
JSONObject responseJSON = readFromCluster(url);
@@ -398,7 +362,6 @@ public class ConfigurationService {
public Response writeConfiguration(JSONObject request) {
JSONObject response;
try {
- validateViewConfiguration();
if (isOperator() == false) {
return Response.status(401).build();
@@ -467,7 +430,7 @@ public class ConfigurationService {
String rmHosts = getRMHosts();
JSONObject data = getJsonObject(String.format(RESTART_RM_REQUEST_DATA,
- ambariApi.getCluster().getName(), rmHosts, rmHosts));
+ context.getCluster().getName(), rmHosts, rmHosts));
Map<String, String> headers = new HashMap<String, String>();
headers.put("Content-Type", "application/x-www-form-urlencoded");
@@ -491,7 +454,7 @@ public class ConfigurationService {
@Path("/getConfig")
public Response getConfigurationValue(@QueryParam("siteName") String siteName,@QueryParam("configName") String configName){
try{
- String configValue = ambariApi.getCluster().getConfigurationValue(siteName,configName);
+ String configValue = context.getCluster().getConfigurationValue(siteName,configName);
JSONObject res = new JSONObject();
JSONArray arr = new JSONArray();
JSONObject conf = new JSONObject();
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/contrib/views/capacity-scheduler/src/main/resources/view.xml
----------------------------------------------------------------------
diff --git a/contrib/views/capacity-scheduler/src/main/resources/view.xml b/contrib/views/capacity-scheduler/src/main/resources/view.xml
index 6dc3ffa..bd07a3f 100644
--- a/contrib/views/capacity-scheduler/src/main/resources/view.xml
+++ b/contrib/views/capacity-scheduler/src/main/resources/view.xml
@@ -24,30 +24,7 @@
<validator-class>org.apache.ambari.view.capacityscheduler.PropertyValidator</validator-class>
- <parameter>
- <name>ambari.server.url</name>
- <description>Enter the Ambari Server REST API cluster resource.</description>
- <label>Ambari Cluster URL</label>
- <placeholder>http://ambari.server:8080/api/v1/clusters/MyCluster</placeholder>
- <cluster-config>fake</cluster-config>
- <required>true</required>
- </parameter>
- <parameter>
- <name>ambari.server.username</name>
- <description>Enter the Cluster Operator username (for example: admin).</description>
- <label>Operator Username</label>
- <placeholder>admin</placeholder>
- <cluster-config>fake</cluster-config>
- <required>true</required>
- </parameter>
- <parameter>
- <name>ambari.server.password</name>
- <description>Enter the Cluster Operator password (for example: password).</description>
- <label>Operator Password</label>
- <cluster-config>fake</cluster-config>
- <required>true</required>
- <masked>true</masked>
- </parameter>
+ <cluster-config-options>AMBARI-ONLY</cluster-config-options>
<resource>
<name>scheduler</name>
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/contrib/views/capacity-scheduler/src/test/java/org/apache/ambari/view/capacityscheduler/ConfigurationServiceTest.java
----------------------------------------------------------------------
diff --git a/contrib/views/capacity-scheduler/src/test/java/org/apache/ambari/view/capacityscheduler/ConfigurationServiceTest.java b/contrib/views/capacity-scheduler/src/test/java/org/apache/ambari/view/capacityscheduler/ConfigurationServiceTest.java
index 62fa21e..add0d0f 100644
--- a/contrib/views/capacity-scheduler/src/test/java/org/apache/ambari/view/capacityscheduler/ConfigurationServiceTest.java
+++ b/contrib/views/capacity-scheduler/src/test/java/org/apache/ambari/view/capacityscheduler/ConfigurationServiceTest.java
@@ -57,11 +57,6 @@ public class ConfigurationServiceTest {
httpHeaders = createNiceMock(HttpHeaders.class);
ambariCluster = createNiceMock(Cluster.class);
- properties = new HashMap<String, String>();
- properties.put(AmbariApi.AMBARI_SERVER_URL_INSTANCE_PROPERTY, BASE_URI);
- properties.put(AmbariApi.AMBARI_SERVER_USERNAME_INSTANCE_PROPERTY, "admin");
- properties.put(AmbariApi.AMBARI_SERVER_PASSWORD_INSTANCE_PROPERTY, "admin");
-
EasyMock.expect(ambariCluster.getConfigurationValue("ranger-yarn-plugin-properties", "ranger-yarn-plugin-enabled")).andReturn("Yes").anyTimes();
EasyMock.expect(context.getCluster()).andReturn(ambariCluster).anyTimes();
EasyMock.expect(context.getProperties()).andReturn(properties).anyTimes();
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/uploads/UploadService.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/uploads/UploadService.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/uploads/UploadService.java
index 83eae9b..4afe80b 100644
--- a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/uploads/UploadService.java
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/uploads/UploadService.java
@@ -329,7 +329,7 @@ public class UploadService extends BaseService {
}
private String getHiveMetaStoreLocation() {
- String dir = this.getAmbariApi().getProperty(HIVE_SITE,HIVE_METASTORE_LOCATION_KEY,HIVE_METASTORE_LOCATION_KEY_VIEW_PROPERTY);
+ String dir = context.getProperties().get(HIVE_METASTORE_LOCATION_KEY_VIEW_PROPERTY);
if(dir != null && !dir.trim().isEmpty()){
return dir;
}else{
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/contrib/views/slider/src/main/java/org/apache/ambari/view/slider/rest/client/BaseHttpClient.java
----------------------------------------------------------------------
diff --git a/contrib/views/slider/src/main/java/org/apache/ambari/view/slider/rest/client/BaseHttpClient.java b/contrib/views/slider/src/main/java/org/apache/ambari/view/slider/rest/client/BaseHttpClient.java
index b4fccf9..3d4a08d 100644
--- a/contrib/views/slider/src/main/java/org/apache/ambari/view/slider/rest/client/BaseHttpClient.java
+++ b/contrib/views/slider/src/main/java/org/apache/ambari/view/slider/rest/client/BaseHttpClient.java
@@ -27,7 +27,6 @@ import java.util.Map;
import org.apache.ambari.view.URLStreamProvider;
import org.apache.ambari.view.ViewContext;
import org.apache.ambari.view.utils.ambari.AmbariApi;
-import org.apache.ambari.view.utils.ambari.URLStreamProviderBasicAuth;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.io.IOUtils;
@@ -76,10 +75,6 @@ public class BaseHttpClient {
return viewContext.getURLStreamProvider();
}
- public URLStreamProviderBasicAuth getUrlStreamProviderBasicAuth() {
- return ambariApi.getUrlStreamProviderBasicAuth();
- }
-
public String getUrl() {
return url;
}
@@ -118,42 +113,39 @@ public class BaseHttpClient {
public JsonElement doGetJson(String url, String path) throws HttpException,
IOException {
- InputStream inputStream = null;
+ String response = null;
try {
Map<String, String> headers = new HashMap<String, String>();
if (isNeedsAuthentication()) {
- inputStream = getUrlStreamProviderBasicAuth().readFrom(
+ response = ambariApi.readFromAmbari(
url + path, "GET", (String) null, headers);
} else {
- inputStream = getUrlStreamProviderBasicAuth().readAsCurrent(
- url + path, "GET", (String) null, headers);
+ response = IOUtils.toString(viewContext.getURLStreamProvider().readAsCurrent(
+ url + path, "GET", (String) null, headers));
}
- } catch (IOException e) {
+ } catch (Exception e) {
logger.error("Error while reading from url " + url + path, e);
HttpException httpException = new HttpException(
e.getLocalizedMessage());
throw httpException;
}
- JsonElement jsonElement = new JsonParser().parse(new JsonReader(
- new InputStreamReader(inputStream)));
+ JsonElement jsonElement = new JsonParser().parse(response);
return jsonElement;
}
public String doGet(String path) throws HttpException, IOException {
String response = null;
try {
- InputStream inputStream = null;
if (isNeedsAuthentication()) {
- inputStream = getUrlStreamProviderBasicAuth().readFrom(
+ response = ambariApi.readFromAmbari(
getUrl() + path, "GET", (String) null,
new HashMap<String, String>());
} else {
- inputStream = getUrlStreamProviderBasicAuth().readAsCurrent(
+ response = IOUtils.toString(viewContext.getURLStreamProvider().readAsCurrent(
getUrl() + path, "GET", (String) null,
- new HashMap<String, String>());
+ new HashMap<String, String>()));
}
- response = IOUtils.toString(inputStream);
- } catch (IOException e) {
+ } catch (Exception e) {
logger.error("Error while reading from url " + getUrl() + path, e);
HttpException httpException = new HttpException(
e.getLocalizedMessage());
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/contrib/views/utils/src/main/java/org/apache/ambari/view/utils/ambari/AmbariApi.java
----------------------------------------------------------------------
diff --git a/contrib/views/utils/src/main/java/org/apache/ambari/view/utils/ambari/AmbariApi.java b/contrib/views/utils/src/main/java/org/apache/ambari/view/utils/ambari/AmbariApi.java
index 6b88b6f..6072d28 100644
--- a/contrib/views/utils/src/main/java/org/apache/ambari/view/utils/ambari/AmbariApi.java
+++ b/contrib/views/utils/src/main/java/org/apache/ambari/view/utils/ambari/AmbariApi.java
@@ -18,6 +18,7 @@
package org.apache.ambari.view.utils.ambari;
+import org.apache.ambari.view.AmbariHttpException;
import org.apache.ambari.view.URLStreamProvider;
import org.apache.ambari.view.ViewContext;
import org.apache.ambari.view.cluster.Cluster;
@@ -31,6 +32,7 @@ import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -40,54 +42,31 @@ import java.util.Map;
* on both local and remote cluster.
*/
public class AmbariApi {
- public static final String AMBARI_SERVER_URL_INSTANCE_PROPERTY = "ambari.server.url";
- public static final String AMBARI_SERVER_USERNAME_INSTANCE_PROPERTY = "ambari.server.username";
- public static final String AMBARI_SERVER_PASSWORD_INSTANCE_PROPERTY = "ambari.server.password";
- private Cluster cluster;
private ViewContext context;
private Services services;
- private String remoteUrlCluster;
- private String remoteUsername;
- private String remotePassword;
private String requestedBy = "views";
+ public static String API_PREFIX = "/api/v1/clusters/";
+
/**
* Constructor for Ambari API based on ViewContext
* @param context View Context
*/
public AmbariApi(ViewContext context) {
this.context = context;
-
- remoteUrlCluster = context.getProperties().get(AMBARI_SERVER_URL_INSTANCE_PROPERTY);
- remoteUsername = context.getProperties().get(AMBARI_SERVER_USERNAME_INSTANCE_PROPERTY);
- remotePassword = context.getProperties().get(AMBARI_SERVER_PASSWORD_INSTANCE_PROPERTY);
}
/**
- * X-Requested-By header value
- * @param requestedBy value of X-Requested-By header
+ * Set requestedBy header
+ *
+ * @param requestedBy
*/
public void setRequestedBy(String requestedBy) {
this.requestedBy = requestedBy;
}
- private String parseAmbariHostname(String remoteUrlCluster) {
- String hostname;
- try {
- URI uri = new URI(remoteUrlCluster);
- hostname = String.format("%s://%s", uri.getScheme(), uri.getHost());
- if (uri.getPort() != -1) {
- hostname += ":" + uri.getPort();
- }
- } catch (URISyntaxException e) {
- throw new AmbariApiException("RA060 Malformed URI of remote Ambari");
- }
-
- return hostname;
- }
-
/**
* Provides ability to get cluster topology
* @param requestComponent name of component
@@ -153,27 +132,24 @@ public class AmbariApi {
*/
public String requestClusterAPI(String path, String method, String data, Map<String, String> headers) throws AmbariApiException {
String response;
- URLStreamProviderBasicAuth urlStreamProvider = getUrlStreamProviderBasicAuth();
try {
- String url;
- if (isLocalCluster()) {
- url = String.format("/api/v1/clusters/%s/%s", getCluster().getName(), path);
-
- } else if (isRemoteCluster()) {
-
- url = String.format("%s/%s", remoteUrlCluster, path);
-
- } else {
+ if (context.getAmbariClusterStreamProvider() == null || context.getCluster() == null) {
throw new NoClusterAssociatedException(
"RA030 View is not associated with any cluster. No way to request Ambari.");
}
- InputStream inputStream = urlStreamProvider.readFrom(url, method, data, headers);
+ if(!path.startsWith("/")) path = "/" + path;
+
+ path = API_PREFIX + context.getCluster().getName() + path;
+
+ InputStream inputStream = context.getAmbariClusterStreamProvider().readFrom(path, method, data, addRequestedByHeader(headers));
response = IOUtils.toString(inputStream);
} catch (IOException e) {
throw new AmbariApiException("RA040 I/O error while requesting Ambari", e);
+ } catch (AmbariHttpException e) {
+ throw new AmbariApiException("RA040 Request to Ambari is unsuccessful with response code "+e.getResponseCode(), e);
}
return response;
}
@@ -189,118 +165,25 @@ public class AmbariApi {
*/
public String readFromAmbari(String path, String method, String data, Map<String, String> headers) throws AmbariApiException {
String response;
- URLStreamProviderBasicAuth urlStreamProvider = getUrlStreamProviderBasicAuth();
try {
- String url;
-
- if (isLocalCluster()) {
- url = path;
-
- } else if (isRemoteCluster()) {
- String ambariUrl = parseAmbariHostname(remoteUrlCluster);
- url = ambariUrl + path;
- } else {
+ if (context.getAmbariClusterStreamProvider() == null) {
throw new NoClusterAssociatedException(
"RA060 View is not associated with any cluster. No way to request Ambari.");
}
- InputStream inputStream = urlStreamProvider.readFrom(url, method, data, headers);
+ InputStream inputStream = context.getAmbariClusterStreamProvider().readFrom(path, method, data, addRequestedByHeader(headers));
response = IOUtils.toString(inputStream);
} catch (IOException e) {
throw new AmbariApiException("RA050 I/O error while requesting Ambari", e);
+ } catch (AmbariHttpException e) {
+ throw new AmbariApiException("RA040 Request to Ambari is unsuccessful with response code "+e.getResponseCode(), e);
}
return response;
}
- /**
- * Check if associated with local or remote cluster
- * @return true if associated
- */
- public boolean isClusterAssociated() {
- try {
- getCluster();
- return true;
- } catch (NoClusterAssociatedException e) {
- return false;
- }
- }
-
- /**
- * Cluster object that provides access for Ambari configuration
- * @return cluster if locally associated or RemoteCluster
- * @throws NoClusterAssociatedException
- */
- public Cluster getCluster() throws NoClusterAssociatedException {
- if (cluster == null) {
- if (isLocalCluster()) {
- cluster = context.getCluster();
-
- } else if (isRemoteCluster()) {
- cluster = getRemoteCluster();
-
- } else {
- throw new NoClusterAssociatedException(
- "RA050 View is not associated with any cluster. No way to request Ambari.");
- }
- }
- return cluster;
- }
-
- /**
- * Is associated with local cluster
- * @return true if associated
- */
- public boolean isLocalCluster() {
- return context.getCluster() != null;
- }
-
- /**
- * Is associated with remote cluster
- * @return true if associated
- */
- public boolean isRemoteCluster() {
- return remoteUrlCluster != null && !remoteUrlCluster.isEmpty();
- }
-
- /**
- * Build RemoteCluster instance based on viewContext properties
- * @return RemoteCluster instance
- */
- public RemoteCluster getRemoteCluster() {
- if (!isRemoteCluster())
- return null;
-
- URLStreamProvider urlStreamProviderBasicAuth = getUrlStreamProviderBasicAuth();
- return new RemoteCluster(remoteUrlCluster, urlStreamProviderBasicAuth);
- }
-
- /**
- * Build URLStreamProvider with Basic Authentication for Remote Cluster
- * @return URLStreamProvider
- */
- public URLStreamProviderBasicAuth getUrlStreamProviderBasicAuth() {
- URLStreamProviderBasicAuth urlStreamProviderBasicAuth;
- if (isRemoteCluster()) {
- if (remoteUsername == null || remoteUsername.isEmpty() ||
- remotePassword == null || remotePassword.isEmpty()) {
- throw new AmbariApiException("RA020 Remote Ambari username and password are not filled");
- }
-
- URLStreamProvider urlStreamProvider = context.getURLStreamProvider();
- urlStreamProviderBasicAuth =
- new URLStreamProviderBasicAuth(urlStreamProvider, remoteUsername, remotePassword);
- } else if (isLocalCluster()) {
- urlStreamProviderBasicAuth = new URLStreamProviderBasicAuth(context.getAmbariStreamProvider());
- } else {
- throw new NoClusterAssociatedException(
- "RA070 Not associated with any cluster. URLStreamProvider is not available");
- }
- urlStreamProviderBasicAuth.setRequestedBy(requestedBy);
- return urlStreamProviderBasicAuth;
- }
/**
* Provides access to service-specific utilities
@@ -313,11 +196,23 @@ public class AmbariApi {
return services;
}
- public String getProperty(String type, String key, String instanceProperty) {
- try {
- return this.getCluster().getConfigurationValue(type, key);
- } catch (NoClusterAssociatedException e) {
- return context.getProperties().get(instanceProperty);
+ private Map<String,String> addRequestedByHeader(Map<String,String> headers){
+ if(headers == null){
+ headers = new HashMap<String, String>();
}
+
+ headers.put("X-Requested-By",this.requestedBy);
+
+ return headers;
}
+
+ /**
+ * Check if view is associated with cluster
+ *
+ * @return isClusterAssociated
+ */
+ public boolean isClusterAssociated(){
+ return context.getCluster() != null;
+ }
+
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/contrib/views/utils/src/main/java/org/apache/ambari/view/utils/ambari/RemoteCluster.java
----------------------------------------------------------------------
diff --git a/contrib/views/utils/src/main/java/org/apache/ambari/view/utils/ambari/RemoteCluster.java b/contrib/views/utils/src/main/java/org/apache/ambari/view/utils/ambari/RemoteCluster.java
deleted file mode 100644
index 41dc88d..0000000
--- a/contrib/views/utils/src/main/java/org/apache/ambari/view/utils/ambari/RemoteCluster.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.ambari.view.utils.ambari;
-
-import org.apache.ambari.view.URLStreamProvider;
-import org.apache.ambari.view.ViewContext;
-import org.apache.ambari.view.cluster.Cluster;
-import org.apache.commons.collections4.map.PassiveExpiringMap;
-import org.apache.commons.io.IOUtils;
-import org.apache.commons.io.input.NullInputStream;
-import org.json.simple.JSONArray;
-import org.json.simple.JSONObject;
-import org.json.simple.JSONValue;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.HttpURLConnection;
-import java.net.URL;
-import java.util.Collections;
-import java.util.Map;
-
-/**
- * Class that provides same interface as local Cluster, but
- * is able to retrieve configuration values by REST API
- */
-public class RemoteCluster implements Cluster {
- protected String name;
- protected String baseUrl;
- protected URLStreamProvider urlStreamProvider;
- protected Map<String, JSONObject> configurationCache;
-
- /**
- * Constructor for RemoteCluster
- * @param ambariClusterUrl Ambari Server Cluster REST API URL (for example: http://ambari.server:8080/api/v1/clusters/c1)
- * @param urlStreamProvider stream provider with authorization support
- */
- public RemoteCluster(String ambariClusterUrl, URLStreamProvider urlStreamProvider) {
- this.baseUrl = ambariClusterUrl;
- this.urlStreamProvider = urlStreamProvider;
-
- String[] parts = ambariClusterUrl.split("/");
- this.name = parts[parts.length-1];
- PassiveExpiringMap<String, JSONObject> configurations = new PassiveExpiringMap<String, JSONObject>(10000L); // keep cache for 10 seconds
- configurationCache = Collections.synchronizedMap(configurations);
- }
-
- @Override
- public String getName() {
- return name;
- }
-
- @Override
- public String getConfigurationValue(String type, String key) {
- JSONObject config;
- try {
- String desiredTag = getDesiredConfig(type);
- config = readFromUrlJSON(String.format("%s/configurations?(type=%s&tag=%s)", baseUrl, type, desiredTag));
- } catch (IOException e) {
- throw new AmbariApiException("RA010 Can't retrieve configuration from Remote Ambari", e);
- }
-
- JSONObject items = (JSONObject) ((JSONArray) config.get("items")).get(0);
- JSONObject properties = (JSONObject) items.get("properties");
- return (properties == null ? null : (String) properties.get(key));
- }
-
- private String getDesiredConfig(String type) throws IOException {
- JSONObject desiredConfigResponse = readFromUrlJSON(
- String.format("%s?fields=services/ServiceInfo,hosts,Clusters", baseUrl));
- JSONObject clusters = (JSONObject) (desiredConfigResponse.get("Clusters"));
- JSONObject desiredConfig = (JSONObject) (clusters.get("desired_configs"));
- JSONObject desiredConfigForType = (JSONObject) desiredConfig.get(type);
-
- return (String) desiredConfigForType.get("tag");
- }
-
- private JSONObject readFromUrlJSON(String url) throws IOException {
- JSONObject jsonObject = configurationCache.get(url);
- if (jsonObject == null) {
- InputStream inputStream = urlStreamProvider.readFrom(url, "GET", (String)null, null);
- String response = IOUtils.toString(inputStream);
- jsonObject = (JSONObject) JSONValue.parse(response);
-
- configurationCache.put(url, jsonObject);
- }
- return jsonObject;
- }
-}
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/contrib/views/utils/src/main/java/org/apache/ambari/view/utils/ambari/Services.java
----------------------------------------------------------------------
diff --git a/contrib/views/utils/src/main/java/org/apache/ambari/view/utils/ambari/Services.java b/contrib/views/utils/src/main/java/org/apache/ambari/view/utils/ambari/Services.java
index a8ef43f..1bace94 100644
--- a/contrib/views/utils/src/main/java/org/apache/ambari/view/utils/ambari/Services.java
+++ b/contrib/views/utils/src/main/java/org/apache/ambari/view/utils/ambari/Services.java
@@ -75,7 +75,7 @@ public class Services {
public String getRMUrl() {
String url;
- if (ambariApi.isClusterAssociated()) {
+ if (context.getCluster() != null) {
url = getRMUrlFromClusterConfig();
} else {
url = getRmUrlFromCustomConfig();
@@ -216,7 +216,7 @@ public class Services {
public String getWebHCatURL() {
String host = null;
- if (ambariApi.isClusterAssociated()) {
+ if (context.getCluster() != null) {
List<String> hiveServerHosts = ambariApi.getHostsWithComponent("WEBHCAT_SERVER");
if (!hiveServerHosts.isEmpty()) {
@@ -249,7 +249,7 @@ public class Services {
* yarn-site.xml else it is retrieved from the view configuration.
*/
public String getTimelineServerUrl() {
- String url = ambariApi.isClusterAssociated() ? getATSUrlFromCluster() : getATSUrlFromCustom();
+ String url = context.getCluster() != null ? getATSUrlFromCluster() : getATSUrlFromCustom();
return removeTrailingSlash(url);
}
@@ -337,7 +337,7 @@ public class Services {
}
private String getYarnConfig(String key) {
- return ambariApi.getCluster().getConfigurationValue(YARN_SITE, key);
+ return context.getCluster().getConfigurationValue(YARN_SITE, key);
}
/**
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/contrib/views/utils/src/main/java/org/apache/ambari/view/utils/ambari/URLStreamProviderBasicAuth.java
----------------------------------------------------------------------
diff --git a/contrib/views/utils/src/main/java/org/apache/ambari/view/utils/ambari/URLStreamProviderBasicAuth.java b/contrib/views/utils/src/main/java/org/apache/ambari/view/utils/ambari/URLStreamProviderBasicAuth.java
deleted file mode 100644
index c9f735a..0000000
--- a/contrib/views/utils/src/main/java/org/apache/ambari/view/utils/ambari/URLStreamProviderBasicAuth.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.ambari.view.utils.ambari;
-
-import org.apache.ambari.view.AmbariStreamProvider;
-import org.apache.ambari.view.URLStreamProvider;
-import org.apache.commons.codec.binary.Base64;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Wrapper for URLStreamProvider that adds authentication header.
- * Also supports AmbariStreamProvider. readAs or readAsCurrent should not be used
- * with AmbariStreamProvider.
- */
-public class URLStreamProviderBasicAuth implements URLStreamProvider {
- private URLStreamProvider urlStreamProvider;
- private AmbariStreamProvider ambariStreamProvider;
- private String username;
- private String password;
- private String requestedBy = "views";
-
- public URLStreamProviderBasicAuth(URLStreamProvider urlStreamProvider, String username, String password) {
- this.urlStreamProvider = urlStreamProvider;
- this.username = username;
- this.password = password;
- }
-
- public URLStreamProviderBasicAuth(AmbariStreamProvider urlStreamProvider) {
- this.ambariStreamProvider = urlStreamProvider;
- }
-
- /**
- * X-Requested-By header value
- * @param requestedBy value of X-Requested-By header
- */
- public void setRequestedBy(String requestedBy) {
- this.requestedBy = requestedBy;
- }
-
- @Override
- public InputStream readFrom(String url, String method, String data, Map<String, String> headers) throws IOException {
- if (urlStreamProvider != null) {
- return urlStreamProvider.readFrom(url, method, data, addHeaders(headers));
- } else {
- return ambariStreamProvider.readFrom(url, method, data, addHeaders(headers), true);
- }
- }
-
- @Override
- public InputStream readFrom(String url, String method, InputStream data, Map<String, String> headers) throws IOException {
- if (urlStreamProvider != null) {
- return urlStreamProvider.readFrom(url, method, data, addHeaders(headers));
- } else {
- return ambariStreamProvider.readFrom(url, method, data, addHeaders(headers), true);
- }
- }
-
- @Override
- public InputStream readAs(String url, String method, String data, Map<String, String> headers, String doAs) throws IOException {
- return urlStreamProvider.readAs(url, method, data, addHeaders(headers), doAs);
- }
-
- @Override
- public InputStream readAs(String url, String method, InputStream data, Map<String, String> headers, String doAs) throws IOException {
- return urlStreamProvider.readAs(url, method, data, addHeaders(headers), doAs);
- }
-
- @Override
- public InputStream readAsCurrent(String url, String method, String data, Map<String, String> headers) throws IOException {
- return urlStreamProvider.readAsCurrent(url, method, data, addHeaders(headers));
- }
-
- @Override
- public InputStream readAsCurrent(String url, String method, InputStream data, Map<String, String> headers) throws IOException {
- return urlStreamProvider.readAsCurrent(url, method, data, addHeaders(headers));
- }
-
- private HashMap<String, String> addHeaders(Map<String, String> customHeaders) {
- HashMap<String, String> newHeaders = new HashMap<String, String>();
- if (customHeaders != null)
- newHeaders.putAll(customHeaders);
-
- if (urlStreamProvider != null) {
- // basic auth is not needed for AmbariStreamProvider
- addBasicAuthHeaders(newHeaders);
- }
- addRequestedByHeaders(newHeaders);
- return newHeaders;
- }
-
- private void addRequestedByHeaders(HashMap<String, String> newHeaders) {
- newHeaders.put("X-Requested-By", requestedBy);
- }
-
- private void addBasicAuthHeaders(HashMap<String, String> headers) {
- String authString = username + ":" + password;
- byte[] authEncBytes = Base64.encodeBase64(authString.getBytes());
- String authStringEnc = new String(authEncBytes);
-
- headers.put("Authorization", "Basic " + authStringEnc);
- }
-}
[4/4] ambari git commit: AMBARI-16274. Views: Simplify View
Configuration for Remote Ambari Managed Cluster. (Gaurav Nagar via dipayanb)
Posted by db...@apache.org.
AMBARI-16274. Views: Simplify View Configuration for Remote Ambari Managed Cluster. (Gaurav Nagar via dipayanb)
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/c150f0de
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/c150f0de
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/c150f0de
Branch: refs/heads/trunk
Commit: c150f0ded83c0a2f4eac1d5bf12a0fbb643c9610
Parents: bc82a6e
Author: Dipayan Bhowmick <di...@gmail.com>
Authored: Wed May 11 14:22:34 2016 +0530
Committer: Dipayan Bhowmick <di...@gmail.com>
Committed: Wed May 11 14:22:34 2016 +0530
----------------------------------------------------------------------
.../main/resources/ui/admin-web/app/index.html | 280 ++++++++--------
.../ambariViews/CreateViewInstanceCtrl.js | 70 +++-
.../controllers/ambariViews/ViewsEditCtrl.js | 86 +++--
.../remoteClusters/RemoteClustersCreateCtrl.js | 63 ++++
.../remoteClusters/RemoteClustersEditCtrl.js | 159 +++++++++
.../remoteClusters/RemoteClustersListCtrl.js | 106 ++++++
.../ui/admin-web/app/scripts/i18n.config.js | 20 +-
.../ui/admin-web/app/scripts/routes.js | 17 +
.../app/scripts/services/RemoteCluster.js | 118 +++++++
.../ui/admin-web/app/scripts/services/View.js | 3 +-
.../resources/ui/admin-web/app/styles/main.css | 25 ++
.../admin-web/app/views/ambariViews/create.html | 38 ++-
.../admin-web/app/views/ambariViews/edit.html | 50 ++-
.../ui/admin-web/app/views/leftNavbar.html | 13 +-
.../remoteClusters/editRemoteClusterPage.html | 77 +++++
.../app/views/remoteClusters/list.html | 80 +++++
.../remoteClusters/modals/changePassword.html | 46 +++
.../views/remoteClusters/remoteClusterPage.html | 66 ++++
.../RemoteClusterResourceDefinition.java | 51 +++
.../resources/ResourceInstanceFactoryImpl.java | 4 +
.../api/services/RemoteClustersService.java | 139 ++++++++
.../internal/DefaultProviderModule.java | 2 +
.../internal/RemoteClusterResourceProvider.java | 327 +++++++++++++++++++
.../internal/ViewInstanceResourceProvider.java | 9 +
.../ambari/server/controller/spi/Resource.java | 4 +-
.../server/orm/dao/RemoteAmbariClusterDAO.java | 101 ++++++
.../orm/entities/RemoteAmbariClusterEntity.java | 201 ++++++++++++
.../RemoteAmbariClusterServiceEntity.java | 108 ++++++
.../ambari/server/orm/entities/ViewEntity.java | 9 +
.../server/orm/entities/ViewInstanceEntity.java | 29 ++
.../server/upgrade/UpgradeCatalog240.java | 37 +++
.../ambari/server/view/RemoteAmbariCluster.java | 190 +++++++++++
.../view/RemoteAmbariClusterRegistry.java | 116 +++++++
.../RemoteAmbariConfigurationReadException.java | 29 ++
.../server/view/RemoteAmbariStreamProvider.java | 118 +++++++
.../server/view/ViewAmbariStreamProvider.java | 51 +--
.../ambari/server/view/ViewContextImpl.java | 23 +-
.../apache/ambari/server/view/ViewRegistry.java | 50 ++-
.../server/view/configuration/ViewConfig.java | 15 +
.../main/resources/Ambari-DDL-Derby-CREATE.sql | 29 +-
.../main/resources/Ambari-DDL-MySQL-CREATE.sql | 25 +-
.../main/resources/Ambari-DDL-Oracle-CREATE.sql | 23 ++
.../resources/Ambari-DDL-Postgres-CREATE.sql | 25 +-
.../Ambari-DDL-Postgres-EMBEDDED-CREATE.sql | 29 +-
.../resources/Ambari-DDL-SQLAnywhere-CREATE.sql | 23 ++
.../resources/Ambari-DDL-SQLServer-CREATE.sql | 25 +-
.../src/main/resources/META-INF/persistence.xml | 2 +
.../RemoteClusterResourceProviderTest.java | 193 +++++++++++
.../server/upgrade/UpgradeCatalog240Test.java | 30 ++
.../server/view/RemoteAmbariClusterTest.java | 90 +++++
.../view/ViewAmbariStreamProviderTest.java | 8 +-
.../view/configuration/ViewConfigTest.java | 7 +
.../view/AmbariClusterStreamProvider.java | 90 +++++
.../apache/ambari/view/AmbariHttpException.java | 41 +++
.../ambari/view/AmbariStreamProvider.java | 6 +-
.../org/apache/ambari/view/ClusterType.java | 40 +++
.../org/apache/ambari/view/ViewContext.java | 8 +
.../ambari/view/ViewInstanceDefinition.java | 8 +
ambari-views/src/main/resources/view.xsd | 5 +
.../capacityscheduler/ConfigurationService.java | 43 +--
.../src/main/resources/view.xml | 25 +-
.../ConfigurationServiceTest.java | 5 -
.../hive/resources/uploads/UploadService.java | 2 +-
.../view/slider/rest/client/BaseHttpClient.java | 28 +-
.../ambari/view/utils/ambari/AmbariApi.java | 177 ++--------
.../ambari/view/utils/ambari/RemoteCluster.java | 104 ------
.../ambari/view/utils/ambari/Services.java | 8 +-
.../ambari/URLStreamProviderBasicAuth.java | 122 -------
.../utils/hdfs/AuthConfigurationBuilder.java | 14 +-
.../view/utils/hdfs/ConfigurationBuilder.java | 14 +-
.../view/utils/ambari/RemoteClusterTest.java | 137 --------
.../ambari/view/utils/ambari/ServicesTest.java | 14 +-
.../ambari/URLStreamProviderBasicAuthTest.java | 159 ---------
73 files changed, 3458 insertions(+), 1031 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/ambari-admin/src/main/resources/ui/admin-web/app/index.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/index.html b/ambari-admin/src/main/resources/ui/admin-web/app/index.html
index 8d7e8e7..a4a5b28 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/index.html
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/index.html
@@ -17,156 +17,160 @@
-->
<!doctype html>
<html class="no-js">
- <head>
- <meta charset="utf-8">
- <title>Ambari</title>
- <meta name="description" content="">
- <meta name="viewport" content="width=device-width, initial-scale=1">
- <meta http-equiv="X-UA-Compatible" content="IE=edge">
- <link rel="shortcut icon" href="/img/logo.png" type="image/x-icon">
- <!-- Place favicon.ico and apple-touch-icon.png in the root directory -->
+<head>
+ <meta charset="utf-8">
+ <title>Ambari</title>
+ <meta name="description" content="">
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <link rel="shortcut icon" href="/img/logo.png" type="image/x-icon">
+ <!-- Place favicon.ico and apple-touch-icon.png in the root directory -->
- <!-- build:css styles/vendor.css -->
- <!-- bower:css -->
- <link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap.css" />
- <link rel="stylesheet" href="bower_components/angular-bootstrap-toggle-switch/style/bootstrap3/angular-toggle-switch-bootstrap-3.css" />
- <link rel="stylesheet" href="bower_components/font-awesome/css/font-awesome.min.css"/>
- <!-- endbower -->
- <!-- endbuild -->
+ <!-- build:css styles/vendor.css -->
+ <!-- bower:css -->
+ <link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap.css" />
+ <link rel="stylesheet" href="bower_components/angular-bootstrap-toggle-switch/style/bootstrap3/angular-toggle-switch-bootstrap-3.css" />
+ <link rel="stylesheet" href="bower_components/font-awesome/css/font-awesome.min.css"/>
+ <!-- endbower -->
+ <!-- endbuild -->
- <!-- build:css styles/main.css -->
- <link rel="stylesheet" href="styles/main.css">
- <!-- endbuild -->
+ <!-- build:css styles/main.css -->
+ <link rel="stylesheet" href="styles/main.css">
+ <!-- endbuild -->
- </head>
- <body ng-app="ambariAdminConsole">
- <!--[if lt IE 9]>
- <p class="browsehappy">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p>
- <![endif]-->
+</head>
+<body ng-app="ambariAdminConsole">
+<!--[if lt IE 9]>
+<p class="browsehappy">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p>
+<![endif]-->
- <div id="top-nav" ng-controller="MainCtrl">
- <header class="navbar navbar-static-top navbar-inverse">
- <div class="navbar-inner">
- <div class="container">
- <a href="/#/main/dashboard" class="logo"><img src="/img/logo-white.png" alt="{{'common.apacheAmbari' | translate}}" title="{{'common.apacheAmbari' | translate}}"></a>
- <a href="/#/main/dashboard" class="brand" title="{{'common.apacheAmbari' | translate}}">{{'common.ambari' | translate}}</a>
- <ul class="nav navbar-nav navbar-right">
- <li>
- <div class="btn-group navbar-views-dropdown" dropdown is-open="viewsdropdown.isopen" ng-mouseover="viewsdropdown.isopen=true" ng-mouseout="viewsdropdown.isopen=false">
- <a href="/#/main/views" ng-click="gotoViewsDashboard()" class="dropdown-toggle"><i class="fa fa-th"></i></a>
- <ul class="dropdown-menu" role="menu">
- <li ng-repeat="instance in viewInstances"><a href="/#/main{{instance.context_path}}" ng-click="about()">{{instance.label}}</a></li>
- <li ng-show="!viewInstances.length" class="disabled"><a>{{'common.noViews' | translate}}</a></li>
- </ul>
- </div>
- </li>
- <li>
- <div class="btn-group" dropdown is-open="status.isopen">
- <button type="button" class="btn btn-default dropdown-toggle navbar-btn" ng-disabled="disabled">
- <i class="fa fa-user"></i> {{currentUser}} <span class="caret"></span>
- </button>
- <ul class="dropdown-menu" role="menu">
- <li><a href ng-click="about()">{{'common.about' | translate}}</a></li>
- <li class="divider"></li>
- <li><a href ng-click="signOut()">{{'common.signOut' | translate}}</a></li>
- </ul>
- </div>
- </li>
- </ul>
- </div>
- </div>
- </header>
+<div id="top-nav" ng-controller="MainCtrl">
+ <header class="navbar navbar-static-top navbar-inverse">
+ <div class="navbar-inner">
+ <div class="container">
+ <a href="/#/main/dashboard" class="logo"><img src="/img/logo-white.png" alt="{{'common.apacheAmbari' | translate}}" title="{{'common.apacheAmbari' | translate}}"></a>
+ <a href="/#/main/dashboard" class="brand" title="{{'common.apacheAmbari' | translate}}">{{'common.ambari' | translate}}</a>
+ <ul class="nav navbar-nav navbar-right">
+ <li>
+ <div class="btn-group navbar-views-dropdown" dropdown is-open="viewsdropdown.isopen" ng-mouseover="viewsdropdown.isopen=true" ng-mouseout="viewsdropdown.isopen=false">
+ <a href="/#/main/views" ng-click="gotoViewsDashboard()" class="dropdown-toggle"><i class="fa fa-th"></i></a>
+ <ul class="dropdown-menu" role="menu">
+ <li ng-repeat="instance in viewInstances"><a href="/#/main{{instance.context_path}}" ng-click="about()">{{instance.label}}</a></li>
+ <li ng-show="!viewInstances.length" class="disabled"><a>{{'common.noViews' | translate}}</a></li>
+ </ul>
+ </div>
+ </li>
+ <li>
+ <div class="btn-group" dropdown is-open="status.isopen">
+ <button type="button" class="btn btn-default dropdown-toggle navbar-btn" ng-disabled="disabled">
+ <i class="fa fa-user"></i> {{currentUser}} <span class="caret"></span>
+ </button>
+ <ul class="dropdown-menu" role="menu">
+ <li><a href ng-click="about()">{{'common.about' | translate}}</a></li>
+ <li class="divider"></li>
+ <li><a href ng-click="signOut()">{{'common.signOut' | translate}}</a></li>
+ </ul>
+ </div>
+ </li>
+ </ul>
+ </div>
</div>
+ </header>
+</div>
- <div class="container">
- <div class="row">
- <div class="col-sm-3">
- <div ng-include="'views/leftNavbar.html'" ng-controller="NavbarCtrl"></div>
- </div>
- <div class="col-sm-9">
- <ng-view></ng-view>
- </div>
- </div>
+<div class="container">
+ <div class="row">
+ <div class="col-sm-3">
+ <div ng-include="'views/leftNavbar.html'" ng-controller="NavbarCtrl"></div>
+ </div>
+ <div class="col-sm-9">
+ <ng-view></ng-view>
</div>
+ </div>
+</div>
- <!-- build:js scripts/vendor.js -->
- <!-- bower:js -->
- <script src="bower_components/jquery/dist/jquery.js"></script>
- <script src="bower_components/bootstrap/dist/js/bootstrap.js"></script>
- <script src="bower_components/angular/angular.js"></script>
- <script src="bower_components/angular-animate/angular-animate.js"></script>
- <script src="bower_components/angular-route/angular-route.js"></script>
- <script src="bower_components/angular-bootstrap/ui-bootstrap-tpls.js"></script>
- <script src="bower_components/lodash/dist/lodash.compat.js"></script>
- <script src="bower_components/restangular/dist/restangular.js"></script>
- <script src="bower_components/angular-bootstrap-toggle-switch/angular-toggle-switch.min.js"></script>
- <script src="bower_components/angular-translate/angular-translate.min.js"></script>
- <!-- endbower -->
- <!-- endbuild -->
+<!-- build:js scripts/vendor.js -->
+<!-- bower:js -->
+<script src="bower_components/jquery/dist/jquery.js"></script>
+<script src="bower_components/bootstrap/dist/js/bootstrap.js"></script>
+<script src="bower_components/angular/angular.js"></script>
+<script src="bower_components/angular-animate/angular-animate.js"></script>
+<script src="bower_components/angular-route/angular-route.js"></script>
+<script src="bower_components/angular-bootstrap/ui-bootstrap-tpls.js"></script>
+<script src="bower_components/lodash/dist/lodash.compat.js"></script>
+<script src="bower_components/restangular/dist/restangular.js"></script>
+<script src="bower_components/angular-bootstrap-toggle-switch/angular-toggle-switch.min.js"></script>
+<script src="bower_components/angular-translate/angular-translate.min.js"></script>
+<!-- endbower -->
+<!-- endbuild -->
- <!-- build:js scripts/plugins.js -->
- <script src="bower_components/bootstrap/js/affix.js"></script>
- <script src="bower_components/bootstrap/js/alert.js"></script>
- <script src="bower_components/bootstrap/js/dropdown.js"></script>
- <script src="bower_components/bootstrap/js/tooltip.js"></script>
- <script src="bower_components/bootstrap/js/modal.js"></script>
- <script src="bower_components/bootstrap/js/transition.js"></script>
- <script src="bower_components/bootstrap/js/button.js"></script>
- <script src="bower_components/bootstrap/js/popover.js"></script>
- <script src="bower_components/bootstrap/js/carousel.js"></script>
- <script src="bower_components/bootstrap/js/scrollspy.js"></script>
- <script src="bower_components/bootstrap/js/collapse.js"></script>
- <script src="bower_components/bootstrap/js/tab.js"></script>
+<!-- build:js scripts/plugins.js -->
+<script src="bower_components/bootstrap/js/affix.js"></script>
+<script src="bower_components/bootstrap/js/alert.js"></script>
+<script src="bower_components/bootstrap/js/dropdown.js"></script>
+<script src="bower_components/bootstrap/js/tooltip.js"></script>
+<script src="bower_components/bootstrap/js/modal.js"></script>
+<script src="bower_components/bootstrap/js/transition.js"></script>
+<script src="bower_components/bootstrap/js/button.js"></script>
+<script src="bower_components/bootstrap/js/popover.js"></script>
+<script src="bower_components/bootstrap/js/carousel.js"></script>
+<script src="bower_components/bootstrap/js/scrollspy.js"></script>
+<script src="bower_components/bootstrap/js/collapse.js"></script>
+<script src="bower_components/bootstrap/js/tab.js"></script>
- <!-- endbuild -->
+<!-- endbuild -->
- <!-- build:js scripts/main.js -->
- <script src="scripts/app.js"></script>
- <script src="scripts/routes.js"></script>
- <script src="scripts/i18n.config.js"></script>
- <script src="scripts/controllers/mainCtrl.js"></script>
- <script src="scripts/controllers/NavbarCtrl.js"></script>
- <script src="scripts/controllers/authentication/AuthenticationMainCtrl.js"></script>
- <script src="scripts/controllers/loginActivities/LoginActivitiesMainCtrl.js"></script>
- <script src="scripts/controllers/loginActivities/LoginMessageMainCtrl.js"></script>
- <script src="scripts/controllers/loginActivities/HomeDirectoryCtrl.js"></script>
- <script src="scripts/controllers/users/UsersCreateCtrl.js"></script>
- <script src="scripts/controllers/users/UsersListCtrl.js"></script>
- <script src="scripts/controllers/users/UsersShowCtrl.js"></script>
- <script src="scripts/controllers/groups/GroupsListCtrl.js"></script>
- <script src="scripts/controllers/groups/GroupsCreateCtrl.js"></script>
- <script src="scripts/controllers/groups/GroupsEditCtrl.js"></script>
- <script src="scripts/controllers/ambariViews/ViewsListCtrl.js"></script>
- <script src="scripts/controllers/ambariViews/ViewsEditCtrl.js"></script>
- <script src="scripts/controllers/ambariViews/ViewUrlCtrl.js"></script>
- <script src="scripts/controllers/ambariViews/ViewUrlEditCtrl.js"></script>
- <script src="scripts/controllers/ambariViews/CreateViewInstanceCtrl.js"></script>
- <script src="scripts/controllers/clusters/ClustersManageAccessCtrl.js"></script>
- <script src="scripts/controllers/clusters/UserAccessListCtrl.js"></script>
- <script src="scripts/controllers/stackVersions/StackVersionsCreateCtrl.js"></script>
- <script src="scripts/controllers/stackVersions/StackVersionsListCtrl.js"></script>
- <script src="scripts/controllers/stackVersions/StackVersionsEditCtrl.js"></script>
- <script src="scripts/directives/linkToDir.js"></script>
- <script src="scripts/directives/PasswordVerify.js"></script>
- <script src="scripts/directives/disabledTooltip.js"></script>
- <script src="scripts/directives/editableList.js"></script>
- <script src="scripts/services/UserConstants.js"></script>
- <script src="scripts/services/User.js"></script>
- <script src="scripts/services/Group.js"></script>
- <script src="scripts/services/View.js"></script>
- <script src="scripts/services/Cluster.js"></script>
- <script src="scripts/services/Alert.js"></script>
- <script src="scripts/services/PermissionLoader.js"></script>
- <script src="scripts/services/PermissionsSaver.js"></script>
- <script src="scripts/services/ConfirmationModal.js"></script>
- <script src="scripts/services/Auth.js"></script>
- <script src="scripts/services/GetDifference.js"></script>
- <script src="scripts/services/UnsavedDialog.js"></script>
- <script src="scripts/services/Stack.js"></script>
- <script src="scripts/services/AddRepositoryModal.js"></script>
- <script src="scripts/services/RoleDetailsModal.js"></script>
- <!-- endbuild -->
+<!-- build:js scripts/main.js -->
+<script src="scripts/app.js"></script>
+<script src="scripts/routes.js"></script>
+<script src="scripts/i18n.config.js"></script>
+<script src="scripts/controllers/mainCtrl.js"></script>
+<script src="scripts/controllers/NavbarCtrl.js"></script>
+<script src="scripts/controllers/authentication/AuthenticationMainCtrl.js"></script>
+<script src="scripts/controllers/loginActivities/LoginActivitiesMainCtrl.js"></script>
+<script src="scripts/controllers/loginActivities/LoginMessageMainCtrl.js"></script>
+<script src="scripts/controllers/loginActivities/HomeDirectoryCtrl.js"></script>
+<script src="scripts/controllers/users/UsersCreateCtrl.js"></script>
+<script src="scripts/controllers/users/UsersListCtrl.js"></script>
+<script src="scripts/controllers/users/UsersShowCtrl.js"></script>
+<script src="scripts/controllers/groups/GroupsListCtrl.js"></script>
+<script src="scripts/controllers/groups/GroupsCreateCtrl.js"></script>
+<script src="scripts/controllers/groups/GroupsEditCtrl.js"></script>
+<script src="scripts/controllers/ambariViews/ViewsListCtrl.js"></script>
+<script src="scripts/controllers/ambariViews/ViewsEditCtrl.js"></script>
+<script src="scripts/controllers/ambariViews/ViewUrlCtrl.js"></script>
+<script src="scripts/controllers/ambariViews/ViewUrlEditCtrl.js"></script>
+<script src="scripts/controllers/ambariViews/CreateViewInstanceCtrl.js"></script>
+<script src="scripts/controllers/clusters/ClustersManageAccessCtrl.js"></script>
+<script src="scripts/controllers/clusters/UserAccessListCtrl.js"></script>
+<script src="scripts/controllers/stackVersions/StackVersionsCreateCtrl.js"></script>
+<script src="scripts/controllers/stackVersions/StackVersionsListCtrl.js"></script>
+<script src="scripts/controllers/stackVersions/StackVersionsEditCtrl.js"></script>
+<script src="scripts/controllers/remoteClusters/RemoteClustersCreateCtrl.js"></script>
+<script src="scripts/controllers/remoteClusters/RemoteClustersListCtrl.js"></script>
+<script src="scripts/controllers/remoteClusters/RemoteClustersEditCtrl.js"></script>
+<script src="scripts/directives/linkToDir.js"></script>
+<script src="scripts/directives/PasswordVerify.js"></script>
+<script src="scripts/directives/disabledTooltip.js"></script>
+<script src="scripts/directives/editableList.js"></script>
+<script src="scripts/services/UserConstants.js"></script>
+<script src="scripts/services/User.js"></script>
+<script src="scripts/services/Group.js"></script>
+<script src="scripts/services/RemoteCluster.js"></script>
+<script src="scripts/services/View.js"></script>
+<script src="scripts/services/Cluster.js"></script>
+<script src="scripts/services/Alert.js"></script>
+<script src="scripts/services/PermissionLoader.js"></script>
+<script src="scripts/services/PermissionsSaver.js"></script>
+<script src="scripts/services/ConfirmationModal.js"></script>
+<script src="scripts/services/Auth.js"></script>
+<script src="scripts/services/GetDifference.js"></script>
+<script src="scripts/services/UnsavedDialog.js"></script>
+<script src="scripts/services/Stack.js"></script>
+<script src="scripts/services/AddRepositoryModal.js"></script>
+<script src="scripts/services/RoleDetailsModal.js"></script>
+<!-- endbuild -->
</body>
</html>
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/CreateViewInstanceCtrl.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/CreateViewInstanceCtrl.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/CreateViewInstanceCtrl.js
index 127bc74..034b113 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/CreateViewInstanceCtrl.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/CreateViewInstanceCtrl.js
@@ -18,7 +18,7 @@
'use strict';
angular.module('ambariAdminConsole')
-.controller('CreateViewInstanceCtrl',['$scope', 'View', 'Alert', 'Cluster', '$routeParams', '$location', 'UnsavedDialog', '$translate', function($scope, View, Alert, Cluster, $routeParams, $location, UnsavedDialog, $translate) {
+.controller('CreateViewInstanceCtrl',['$scope', 'View','RemoteCluster' , 'Alert', 'Cluster', '$routeParams', '$location', 'UnsavedDialog', '$translate', function($scope, View, RemoteCluster, Alert, Cluster, $routeParams, $location, UnsavedDialog, $translate) {
var $t = $translate.instant;
$scope.form = {};
$scope.constants = {
@@ -54,9 +54,10 @@ angular.module('ambariAdminConsole')
icon64_path: '',
properties: parameters,
description: '',
- isLocalCluster: false
+ clusterType: 'NONE'
};
loadClusters();
+ loadRemoteClusters();
});
}
@@ -91,26 +92,46 @@ angular.module('ambariAdminConsole')
$scope.clusterConfigurable = false;
$scope.clusterConfigurableErrorMsg = "";
$scope.clusters = [];
- $scope.noClusterAvailible = true;
+ $scope.remoteClusters = [];
+ $scope.noLocalClusterAvailible = true;
+ $scope.noRemoteClusterAvailible = true;
$scope.cluster = null;
+ $scope.data = {};
+ $scope.data.remoteCluster = null;
$scope.numberOfClusterConfigs = 0;
$scope.numberOfSettingConfigs = 0;
- function loadClusters () {
- Cluster.getAllClusters().then(function (clusters) {
- if(clusters.length >0){
- clusters.forEach(function(cluster) {
- $scope.clusters.push(cluster.Clusters.cluster_name)
- });
- $scope.noClusterAvailible = false;
- $scope.instance.isLocalCluster = $scope.clusterConfigurable;
- }else{
- $scope.clusters.push($t('common.noClusters'));
- }
- $scope.cluster = $scope.clusters[0];
- });
+ function loadClusters() {
+ Cluster.getAllClusters().then(function (clusters) {
+ if(clusters.length >0){
+ clusters.forEach(function(cluster) {
+ $scope.clusters.push(cluster.Clusters.cluster_name)
+ });
+ $scope.noLocalClusterAvailible = false;
+ if($scope.clusterConfigurable){
+ $scope.instance.clusterType = "LOCAL_AMBARI";
+ }
+ }else{
+ $scope.clusters.push($t('common.noClusters'));
+ }
+ $scope.cluster = $scope.clusters[0];
+ });
}
+ function loadRemoteClusters() {
+ RemoteCluster.listAll().then(function (clusters) {
+ if(clusters.length >0){
+ clusters.forEach(function(cluster) {
+ $scope.remoteClusters.push(cluster.ClusterInfo.name)
+ });
+ $scope.noRemoteClusterAvailible = false;
+ }else{
+ $scope.remoteClusters.push($t('common.noClusters'));
+ }
+ $scope.data.remoteCluster = $scope.remoteClusters[0];
+ });
+ }
+
$scope.versions = [];
$scope.version = null;
@@ -128,7 +149,20 @@ angular.module('ambariAdminConsole')
$scope.form.instanceCreateForm.submitted = true;
if($scope.form.instanceCreateForm.$valid){
$scope.form.instanceCreateForm.isSaving = true;
- $scope.instance.clusterName = $scope.cluster;
+
+ switch($scope.instance.clusterType) {
+ case 'LOCAL_AMBARI':
+ console.log($scope.cluster);
+ $scope.instance.clusterName = $scope.cluster;
+ break;
+ case 'REMOTE_AMBARI':
+ console.log($scope.data.remoteCluster);
+ $scope.instance.clusterName = $scope.data.remoteCluster;
+ break;
+ default:
+ $scope.instance.clusterName = null;
+ }
+ console.log($scope.instance.clusterName);
View.createInstance($scope.instance)
.then(function(data) {
Alert.success($t('views.alerts.instanceCreated', {instanceName: $scope.instance.instance_name}));
@@ -145,7 +179,7 @@ angular.module('ambariAdminConsole')
var errorMessage = data.message;
var showGeneralError = true;
- if (data.status >= 400 && !$scope.instance.isLocalCluster) {
+ if (data.status >= 400 && $scope.instance.clusterType == 'NONE') {
try {
var errorObject = JSON.parse(errorMessage);
errorMessage = errorObject.detail;
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/ViewsEditCtrl.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/ViewsEditCtrl.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/ViewsEditCtrl.js
index 480f85d..b4a9656 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/ViewsEditCtrl.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/ViewsEditCtrl.js
@@ -18,7 +18,7 @@
'use strict';
angular.module('ambariAdminConsole')
- .controller('ViewsEditCtrl', ['$scope', '$routeParams' , 'Cluster', 'View', 'Alert', 'PermissionLoader', 'PermissionSaver', 'ConfirmationModal', '$location', 'UnsavedDialog', '$translate', function($scope, $routeParams, Cluster, View, Alert, PermissionLoader, PermissionSaver, ConfirmationModal, $location, UnsavedDialog, $translate) {
+ .controller('ViewsEditCtrl', ['$scope', '$routeParams', 'RemoteCluster', 'Cluster', 'View', 'Alert', 'PermissionLoader', 'PermissionSaver', 'ConfirmationModal', '$location', 'UnsavedDialog', '$translate', function($scope, $routeParams, RemoteCluster, Cluster, View, Alert, PermissionLoader, PermissionSaver, ConfirmationModal, $location, UnsavedDialog, $translate) {
var $t = $translate.instant;
$scope.identity = angular.identity;
$scope.isConfigurationEmpty = true;
@@ -62,14 +62,16 @@ angular.module('ambariAdminConsole')
}
function initCtrlVariables(instance) {
- if(instance.ViewInstanceInfo.cluster_handle) {
- $scope.isLocalCluster = true;
- $scope.cluster = instance.ViewInstanceInfo.cluster_handle;
- }else{
- $scope.isLocalCluster = false;
- $scope.cluster = $scope.clusters.length > 0 ? $scope.clusters[0] : $t('common.noClusters');
- }
- $scope.originalLocalCluster = $scope.isLocalCluster;
+ $scope.data.clusterType = instance.ViewInstanceInfo.cluster_type;
+ switch($scope.data.clusterType) {
+ case 'LOCAL_AMBARI':
+ $scope.cluster = instance.ViewInstanceInfo.cluster_handle;
+ break;
+ case 'REMOTE_AMBARI':
+ $scope.data.remoteCluster = instance.ViewInstanceInfo.cluster_handle;
+ break;
+ }
+ $scope.originalClusterType = $scope.data.clusterType;
$scope.isConfigurationEmpty = !$scope.numberOfClusterConfigs;
$scope.isSettingsEmpty = !$scope.numberOfSettingsConfigs;
}
@@ -101,7 +103,7 @@ angular.module('ambariAdminConsole')
function filterClusterConfigs() {
$scope.configurationMeta.forEach(function (element) {
- if (element.masked && !$scope.editConfigurationDisabled && element.clusterConfig && !$scope.isLocalCluster) {
+ if (element.masked && !$scope.editConfigurationDisabled && element.clusterConfig && $scope.data.clusterType == 'NONE') {
$scope.configuration[element.name] = '';
}
if(!element.clusterConfig) {
@@ -150,9 +152,13 @@ angular.module('ambariAdminConsole')
$scope.clusterConfigurable = false;
$scope.clusterConfigurableErrorMsg = "";
$scope.clusters = [];
+ $scope.remoteClusters = [];
$scope.cluster = null;
- $scope.noClusterAvailible = true;
-
+ $scope.noLocalClusterAvailible = true;
+ $scope.noRemoteClusterAvailible = true;
+ $scope.data = {};
+ $scope.data.remoteCluster = null;
+ $scope.data.clusterType = 'NONE';
$scope.editSettingsDisabled = true;
$scope.editDetailsSettingsDisabled = true;
@@ -199,13 +205,29 @@ angular.module('ambariAdminConsole')
clusters.forEach(function(cluster) {
$scope.clusters.push(cluster.Clusters.cluster_name)
});
- $scope.noClusterAvailible = false;
+ $scope.noLocalClusterAvailible = false;
}else{
$scope.clusters.push($t('common.noClusters'));
}
$scope.cluster = $scope.clusters[0];
});
+ loadRemoteClusters();
+
+ function loadRemoteClusters() {
+ RemoteCluster.listAll().then(function (clusters) {
+ if(clusters.length >0){
+ clusters.forEach(function(cluster) {
+ $scope.remoteClusters.push(cluster.ClusterInfo.name)
+ });
+ $scope.noRemoteClusterAvailible = false;
+ }else{
+ $scope.remoteClusters.push($t('common.noClusters'));
+ }
+ $scope.data.remoteCluster = $scope.remoteClusters[0];
+ });
+ }
+
$scope.saveSettings = function(callback) {
if( $scope.settingsForm.$valid ){
@@ -292,18 +314,28 @@ angular.module('ambariAdminConsole')
'properties':{}
}
};
- if($scope.isLocalCluster) {
- data.ViewInstanceInfo.cluster_handle = $scope.cluster;
- } else {
- data.ViewInstanceInfo.cluster_handle = null;
- $scope.configurationMeta.forEach(function (element) {
- if(element.clusterConfig) {
- data.ViewInstanceInfo.properties[element.name] = $scope.configuration[element.name];
- }
- });
- $scope.clearClusterInheritedPermissions();
- }
- $scope.originalLocalCluster = $scope.isLocalCluster;
+
+ data.ViewInstanceInfo.cluster_type = $scope.data.clusterType;
+
+ switch($scope.data.clusterType) {
+ case 'LOCAL_AMBARI':
+ data.ViewInstanceInfo.cluster_handle = $scope.cluster;
+ break;
+ case 'REMOTE_AMBARI':
+ data.ViewInstanceInfo.cluster_handle = $scope.data.remoteCluster;
+ break;
+ default :
+ data.ViewInstanceInfo.cluster_handle = null;
+ $scope.configurationMeta.forEach(function (element) {
+ if(element.clusterConfig) {
+ data.ViewInstanceInfo.properties[element.name] = $scope.configuration[element.name];
+ }
+ });
+ $scope.clearClusterInheritedPermissions();
+
+ }
+
+ $scope.originalClusterType = $scope.data.clusterType;
return View.updateInstance($routeParams.viewId, $routeParams.version, $routeParams.instanceId, data)
.success(function() {
$scope.editConfigurationDisabled = true;
@@ -315,7 +347,7 @@ angular.module('ambariAdminConsole')
//TODO: maybe the BackEnd should sanitize the string beforehand?
errorMessage = errorMessage.substr(errorMessage.indexOf("\{"));
- if (data.status >= 400 && !$scope.isLocalCluster) {
+ if (data.status >= 400 && $scope.data.clusterType == 'NONE') {
try {
var errorObject = JSON.parse(errorMessage);
errorMessage = errorObject.detail;
@@ -335,7 +367,7 @@ angular.module('ambariAdminConsole')
};
$scope.cancelConfiguration = function() {
angular.extend($scope.configuration, $scope.configurationBeforeEdit);
- $scope.isLocalCluster = $scope.originalLocalCluster;
+ $scope.data.clusterType = $scope.originalClusterType;
$scope.editConfigurationDisabled = true;
$scope.propertiesForm.$setPristine();
};
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/remoteClusters/RemoteClustersCreateCtrl.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/remoteClusters/RemoteClustersCreateCtrl.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/remoteClusters/RemoteClustersCreateCtrl.js
new file mode 100644
index 0000000..e669c82
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/remoteClusters/RemoteClustersCreateCtrl.js
@@ -0,0 +1,63 @@
+/**
+ * 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.
+ */
+'use strict';
+
+angular.module('ambariAdminConsole')
+.controller('RemoteClustersCreateCtrl', ['$scope', '$routeParams', '$location', 'Alert', '$translate', 'Cluster', 'AddRepositoryModal' , 'Settings', 'RemoteCluster', function($scope, $routeParams, $location, Alert, $translate, Cluster, AddRepositoryModal, Settings, RemoteCluster) {
+ var $t = $translate.instant;
+
+ $scope.cluster = {};
+
+ $scope.registerRemoteCluster = function () {
+ $scope.form.submitted = true;
+ if ($scope.form.$valid){
+ var payload = {
+ "ClusterInfo" :{
+ "name" : $scope.cluster.cluster_name,
+ "url" : $scope.cluster.cluster_url,
+ "username" : $scope.cluster.cluster_user,
+ "password" : $scope.cluster.cluster_password
+ }
+ };
+
+ var config = {
+ headers : {
+ 'X-Requested-By': 'Ambari;'
+ }
+ }
+
+ RemoteCluster.register(payload, config).then(function(data) {
+ Alert.success($t('common.alerts.remoteClusterRegistered', {clusterName: payload.ClusterInfo.name}));
+ $scope.form.$setPristine();
+ $location.path('/remoteClusters/'+ $scope.cluster.cluster_name +'/edit')
+ })
+ .catch(function(data) {
+ console.log(data);
+ Alert.error(data.message);
+ });
+
+ }
+ };
+
+ $scope.cancel = function () {
+ $scope.editVersionDisabled = true;
+ $location.path('/remoteClusters');
+ };
+
+
+}]);
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/remoteClusters/RemoteClustersEditCtrl.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/remoteClusters/RemoteClustersEditCtrl.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/remoteClusters/RemoteClustersEditCtrl.js
new file mode 100644
index 0000000..20eb552
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/remoteClusters/RemoteClustersEditCtrl.js
@@ -0,0 +1,159 @@
+/**
+ * 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.
+ */
+'use strict';
+
+angular.module('ambariAdminConsole')
+.controller('RemoteClustersEditCtrl', ['$scope', '$modal', '$routeParams', '$location', 'Alert', '$translate', 'Cluster', 'Settings','RemoteCluster', 'ConfirmationModal', function($scope, $modal, $routeParams, $location, Alert, $translate, Cluster, Settings, RemoteCluster, ConfirmationModal) {
+ var $t = $translate.instant;
+
+ $scope.cluster = {};
+
+ $scope.openChangePwdDialog = function() {
+ var modalInstance = $modal.open({
+ templateUrl: 'views/remoteClusters/modals/changePassword.html',
+ resolve: {
+ clusterName: function() {
+ return $scope.cluster.cluster_name;
+ },
+ clusterUrl: function() {
+ return $scope.cluster.cluster_url;
+ },
+ clusterUser: function() {
+ return $scope.cluster.cluster_user;
+ }
+ },
+ controller: ['$scope', 'clusterName', 'clusterUrl', 'clusterUser', 'Settings','Alert', function($scope, clusterName, clusterUrl , clusterUser , Settings, Alert) {
+ $scope.passwordData = {
+ password: '',
+ currentUserName: clusterUser || ''
+ };
+
+ $scope.form = {};
+
+ $scope.currentUser = clusterUser;
+ $scope.clusterName = clusterName;
+ $scope.clusterUrl = clusterUrl;
+
+ $scope.ok = function() {
+ $scope.form.passwordChangeForm.submitted = true;
+
+
+ if ($scope.form.passwordChangeForm.$valid){
+
+ var payload = {
+ "ClusterInfo" :{
+ "name" : $scope.clusterName,
+ "url" : $scope.clusterUrl,
+ "username" : $scope.passwordData.currentUserName,
+ "password" : $scope.passwordData.password //This field will go once backend API changes are done.
+ }
+ };
+
+ var config = {
+ headers : {
+ 'X-Requested-By': 'Ambari;'
+ }
+ }
+
+ RemoteCluster.edit(payload, config).then(function(data) {
+ Alert.success($t('views.alerts.credentialsUpdated'));
+ $scope.form.passwordChangeForm.$setPristine();
+ })
+ .catch(function(data) {
+ console.log(data);
+ Alert.error(data.message);
+ });
+
+ modalInstance.dismiss('cancel');
+ }
+
+ };
+ $scope.cancel = function() {
+ modalInstance.dismiss('cancel');
+ };
+ }]
+ });
+ };
+
+ $scope.deleteCluster = function() {
+ ConfirmationModal.show(
+ $t('common.deregisterCluster', {
+ term: $t('common.cluster')
+ }),
+ $t('common.deleteConfirmation', {
+ instanceType: $t('common.cluster').toLowerCase(),
+ instanceName: '"' + $scope.cluster.cluster_name + '"'
+ })
+ ).then(function() {
+ RemoteCluster.deregister($scope.cluster.cluster_name).then(function() {
+ $location.path('/remoteClusters');
+ });
+ });
+ };
+
+ $scope.editRemoteCluster = function () {
+ $scope.form.submitted = true;
+ if ($scope.form.$valid){
+ var payload = {
+ "ClusterInfo" :{
+ "name" : $scope.cluster.cluster_name,
+ "url" : $scope.cluster.cluster_url,
+ "username" : $scope.cluster.cluster_user
+ }
+ };
+
+ var config = {
+ headers : {
+ 'X-Requested-By': 'Ambari;'
+ }
+ }
+
+ RemoteCluster.edit(payload, config).then(function(data) {
+ Alert.success($t('views.alerts.savedRemoteClusterInformation'));
+ $scope.form.$setPristine();
+ })
+ .catch(function(data) {
+ console.log(data);
+ Alert.error(data.message);
+ });
+ }
+ };
+
+ $scope.cancel = function () {
+ $scope.editVersionDisabled = true;
+ $location.path('/remoteClusters');
+ };
+
+ // Fetch remote cluster details
+ $scope.fetchRemoteClusterDetails = function (clusterName) {
+
+ RemoteCluster.getDetails(clusterName).then(function(response) {
+ $scope.cluster.cluster_name = response.ClusterInfo.name
+ $scope.cluster.cluster_url = response.ClusterInfo.url;
+ $scope.cluster.cluster_user = response.ClusterInfo.username;
+ })
+ .catch(function(data) {
+ console.log(data);
+ });
+
+ };
+
+ $scope.fetchRemoteClusterDetails($routeParams.clusterName);
+
+
+}]);
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/remoteClusters/RemoteClustersListCtrl.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/remoteClusters/RemoteClustersListCtrl.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/remoteClusters/RemoteClustersListCtrl.js
new file mode 100644
index 0000000..4eb3633
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/remoteClusters/RemoteClustersListCtrl.js
@@ -0,0 +1,106 @@
+/**
+ * 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.
+ */
+'use strict';
+
+angular.module('ambariAdminConsole')
+.controller('RemoteClustersListCtrl', ['$scope', '$routeParams', '$translate', 'RemoteCluster' ,'UserConstants', function ($scope, $routeParams, $translate, RemoteCluster, UserConstants) {
+ var $t = $translate.instant;
+
+ $scope.clusterName = $routeParams.clusterName;
+
+ $scope.constants = {
+ groups: $t('common.clusters').toLowerCase()
+ };
+
+ $scope.groupsPerPage = 10;
+ $scope.currentPage = 1;
+ $scope.totalGroups = 1;
+ $scope.currentNameFilter = '';
+ $scope.maxVisiblePages=20;
+ $scope.tableInfo = {
+ total: 0,
+ showed: 0
+ };
+
+ $scope.isNotEmptyFilter = true;
+
+ $scope.pageChanged = function() {
+ loadRemoteClusters();
+ };
+ $scope.groupsPerPageChanges = function() {
+ loadRemoteClusters();
+ };
+
+ $scope.resetPagination = function() {
+ $scope.currentPage = 1;
+ loadRemoteClusters();
+ };
+
+ $scope.typeFilterOptions = [
+ $t('common.any')
+ ];
+
+ $scope.currentTypeFilter = $scope.typeFilterOptions[0];
+
+ $scope.clearFilters = function () {
+ $scope.currentNameFilter = '';
+ $scope.currentTypeFilter = $scope.typeFilterOptions[0];
+ $scope.resetPagination();
+ };
+
+ function loadRemoteClusters(){
+ RemoteCluster.all({
+ currentPage: $scope.currentPage,
+ groupsPerPage: $scope.groupsPerPage,
+ searchString: $scope.currentNameFilter,
+ service: $scope.currentTypeFilter
+ }).then(function(remoteclusters) {
+
+ $scope.totalGroups = remoteclusters.itemTotal;
+ $scope.tableInfo.total = remoteclusters.itemTotal;
+ $scope.tableInfo.showed = remoteclusters.items.length;
+
+ $scope.remoteClusters = remoteclusters.items;
+
+ remoteclusters.items.map(function(clusteritem){
+ clusteritem.ClusterInfo.services.map(function(service){
+ var serviceIndex = $scope.typeFilterOptions.indexOf(service);
+ if(serviceIndex == -1){
+ $scope.typeFilterOptions.push(service);
+ }
+ })
+ })
+
+ })
+ .catch(function(data) {
+ console.error('Error in fetching remote clusters.', data);
+ });
+ };
+
+ loadRemoteClusters();
+
+ $scope.$watch(
+ function (scope) {
+ return Boolean(scope.currentNameFilter || (scope.currentTypeFilter));
+ },
+ function (newValue, oldValue, scope) {
+ scope.isNotEmptyFilter = newValue;
+ }
+ );
+
+}]);
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/ambari-admin/src/main/resources/ui/admin-web/app/scripts/i18n.config.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/i18n.config.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/i18n.config.js
index 80a5352..c74ed77 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/i18n.config.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/i18n.config.js
@@ -30,6 +30,7 @@ angular.module('ambariAdminConsole')
'about': 'About',
'version': 'Version',
'signOut': 'Sign out',
+ 'register':'Register',
'clusters': 'Clusters',
'views': 'Views',
'viewUrls': 'View URLs',
@@ -50,9 +51,12 @@ angular.module('ambariAdminConsole')
'type': 'Type',
'add': 'Add {{term}}',
'delete': 'Delete {{term}}',
+ 'deregisterCluster': 'Deregister Cluster',
'cannotDelete': 'Cannot Delete {{term}}',
'privileges': 'Privileges',
'cluster': 'Cluster',
+ 'remoteClusters': 'Remote Clusters',
+ 'services':'Services',
'clusterRole': 'Cluster Role',
'viewPermissions': 'View Permissions',
'getInvolved': 'Get involved!',
@@ -126,6 +130,7 @@ angular.module('ambariAdminConsole')
'fieldIsRequired': 'This field is required.',
'noSpecialChars': 'Must not contain special characters!',
'nothingToDisplay': 'No {{term}} to display.',
+ 'noRemoteClusterDisplay':'No Remote Clusters to display.',
'noPrivileges': 'No {{term}} privileges',
'noPrivilegesDescription': 'This {{term}} does not have any privileges.',
'timeOut': 'You will be automatically logged out in <b>{{time}}</b> seconds due to inactivity.',
@@ -134,11 +139,13 @@ angular.module('ambariAdminConsole')
'cannotLoadPrivileges': 'Cannot load privileges',
'cannotLoadClusterStatus': 'Cannot load cluster status',
'clusterRenamed': 'The cluster has been renamed to {{clusterName}}.',
+ 'remoteClusterRegistered': 'The cluster has been registered as {{clusterName}}.',
'cannotRenameCluster': 'Cannot rename cluster to {{clusterName}}',
'tooShort': 'Too short',
'tooLong': 'Too long',
'onlyText': 'Only lowercase alphanumeric characters are allowed.',
- 'onlyAnScore': 'Invalid input, only alphanumerics allowed eg: My_default_view'
+ 'onlyAnScore': 'Invalid input, only alphanumerics allowed eg: My_default_view',
+ 'passwordRequired':'Password Required'
}
},
@@ -195,6 +202,8 @@ angular.module('ambariAdminConsole')
'instanceDescription': 'Instance Description',
'clusterConfiguration': 'Cluster Configuration',
'localCluster': 'Local Ambari Managed Cluster',
+ 'remoteCluster': 'Remote Cluster',
+ 'registerRemoteCluster' : 'Register Remote Cluster',
'clusterName': 'Cluster Name',
'custom': 'Custom',
'icon': 'Icon',
@@ -241,7 +250,9 @@ angular.module('ambariAdminConsole')
'cannotDeleteInstance': 'Cannot delete instance',
'cannotLoadViews': 'Cannot load views',
'cannotLoadViewUrls': 'Cannot load view URLs',
- 'cannotLoadViewUrl': 'Cannot load view URL'
+ 'cannotLoadViewUrl': 'Cannot load view URL',
+ 'savedRemoteClusterInformation':'Remote cluster information is saved.',
+ 'credentialsUpdated':'Credentials Updated.'
}
},
@@ -296,7 +307,9 @@ angular.module('ambariAdminConsole')
'userName': 'User name',
'admin': 'Admin',
'ambariAdmin': 'Ambari Admin',
+ 'ambariClusterURL':'Ambari Cluster URL',
'changePassword': 'Change Password',
+ 'updateCredentials':'Update Credentials',
'changePasswordFor': 'Change Password for {{userName}}',
'yourPassword': 'Your Password',
'newPassword': 'New User Password',
@@ -335,8 +348,9 @@ angular.module('ambariAdminConsole')
},
'alerts': {
- 'passwordRequired': 'Password required!',
+ 'passwordRequired': 'Password required',
'wrongPassword': 'Password must match!',
+ 'usernameRequired':'Username Required',
'cannotChange': 'Cannot Change {{term}}',
'userCreated': 'Created user <a href="#/users/{{encUserName}}">{{userName}}</a>',
'userCreationError': 'User creation error',
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/ambari-admin/src/main/resources/ui/admin-web/app/scripts/routes.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/routes.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/routes.js
index 0566969..81b4d28 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/routes.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/routes.js
@@ -136,6 +136,23 @@ angular.module('ambariAdminConsole')
controller: 'StackVersionsEditCtrl'
}
},
+ remoteClusters: {
+ list: {
+ url: '/remoteClusters',
+ templateUrl: 'views/remoteClusters/list.html',
+ controller: 'RemoteClustersListCtrl'
+ },
+ create: {
+ url: '/remoteClusters/create',
+ templateUrl: 'views/remoteClusters/remoteClusterPage.html',
+ controller: 'RemoteClustersCreateCtrl'
+ },
+ edit: {
+ url: '/remoteClusters/:clusterName/edit',
+ templateUrl: 'views/remoteClusters/editRemoteClusterPage.html',
+ controller: 'RemoteClustersEditCtrl'
+ }
+ },
clusters: {
manageAccess: {
url: '/clusters/:id/manageAccess',
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/RemoteCluster.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/RemoteCluster.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/RemoteCluster.js
new file mode 100644
index 0000000..e4826e6
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/RemoteCluster.js
@@ -0,0 +1,118 @@
+/**
+ * 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.
+ */
+'use strict';
+
+angular.module('ambariAdminConsole')
+ .factory('RemoteCluster', ['$http', '$q', 'Settings', function($http, $q, Settings) {
+
+ function RemoteCluster(){
+ }
+
+ RemoteCluster.edit = function(payload, config){
+ var deferred = $q.defer();
+
+ $http.put(Settings.baseUrl + '/remoteclusters/' + payload.ClusterInfo.name , payload, config)
+ .success(function (data) {
+ deferred.resolve(data)
+ })
+ .error(function (data) {
+ deferred.reject(data);
+ });
+ return deferred.promise;
+ }
+
+
+ RemoteCluster.getDetails = function(clusterName) {
+ var deferred = $q.defer();
+
+ $http.get( Settings.baseUrl + '/remoteclusters/' + clusterName)
+ .success(function(response) {
+ deferred.resolve(response);
+ })
+ .error(function(data) {
+ deferred.reject(data);
+ });
+
+ return deferred.promise;
+
+ };
+
+ RemoteCluster.deregister = function(clusterName){
+ var deferred = $q.defer();
+
+ $http.delete( Settings.baseUrl + '/remoteclusters/' + clusterName)
+ .success(function(response) {
+ deferred.resolve(response);
+ })
+ .error(function(data) {
+ deferred.reject(data);
+ });
+
+ return deferred.promise;
+
+ };
+
+ RemoteCluster.register = function(payload, config){
+ var deferred = $q.defer();
+
+ $http.post(Settings.baseUrl + '/remoteclusters/' + payload.ClusterInfo.name , payload, config)
+ .success(function (data) {
+ deferred.resolve(data)
+ })
+ .error(function (data) {
+ deferred.reject(data);
+ });
+ return deferred.promise;
+ }
+
+ RemoteCluster.all = function(params) {
+ var deferred = $q.defer();
+
+ $http.get(Settings.baseUrl + "/remoteclusters?"
+ + 'ClusterInfo/name.matches(.*'+params.searchString+'.*)'
+ + '&fields=*'
+ + '&from='+ (params.currentPage-1)*params.groupsPerPage
+ + '&page_size=' + params.groupsPerPage
+ + (params.service === 'Any' ? '' : '&ClusterInfo/services.matches(.*'+params.service+'.*)')
+ )
+ .success(function(response) {
+ deferred.resolve(response);
+ })
+ .error(function(data) {
+ deferred.reject(data);
+ });
+ return deferred.promise;
+ };
+
+ RemoteCluster.listAll = function() {
+ var deferred = $q.defer();
+
+ /* TODO :: Add params like RemoteCluster.matches and &from , &page_size */
+ $http.get(Settings.baseUrl + "/remoteclusters?fields=ClusterInfo/services")
+ .success(function(response) {
+ deferred.resolve(response.items);
+ })
+ .error(function(data) {
+ deferred.reject(data);
+ });
+ return deferred.promise;
+ };
+
+ return RemoteCluster;
+
+ }]);
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/View.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/View.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/View.js
index 780352d..dfe7ba8 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/View.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/View.js
@@ -325,8 +325,9 @@ angular.module('ambariAdminConsole')
});
data.properties = settings;
+ data.cluster_type = instanceInfo.clusterType;
- if(instanceInfo.isLocalCluster) {
+ if(instanceInfo.clusterName != null) {
data.cluster_handle = instanceInfo.clusterName;
} else {
angular.extend(data.properties, properties);
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/ambari-admin/src/main/resources/ui/admin-web/app/styles/main.css
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/styles/main.css b/ambari-admin/src/main/resources/ui/admin-web/app/styles/main.css
index c573b72..fbad224 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/styles/main.css
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/styles/main.css
@@ -1626,6 +1626,31 @@ thead.view-permission-header > tr > th {
margin:0px;
}
+.proxied-field-wrap {
+ display:block;
+ position:absolute;
+ height:0;
+ width:0;
+ overflow:hidden;
+}
+
+legend.legendStyle {
+ padding-left: 5px;
+ padding-right: 5px;
+ font-size: 16px;
+}
+
+fieldset.fsStyle {
+ border: 1px solid #DDD;
+ padding: 4px;
+ margin: 15px 0;
+}
+
+legend {
+ width: auto;
+ border-bottom: 0;
+}
+
.cluster-inherited-permission {
border-bottom: 2px solid #ddd;
padding-bottom: 10px;
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/create.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/create.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/create.html
index eaff70b..051d720 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/create.html
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/create.html
@@ -115,7 +115,7 @@
</div>
</div>
- <div class="panel panel-default" ng-hide="!numberOfClusterConfigs">
+ <div class="panel panel-default" ng-hide="!numberOfClusterConfigs && !clusterConfigurable">
<div class="panel-heading">
<h3 class="panel-title">{{'views.clusterConfiguration' | translate}}</h3>
</div>
@@ -123,7 +123,7 @@
<div class="panel-body property-form" popover="{{clusterConfigurableErrorMsg}}" popover-trigger="mouseenter">
<div class="checkbox create-checkbox-cluster">
<label>
- <input type="radio" ng-disabled="!clusterConfigurable || noClusterAvailible" ng-model="instance.isLocalCluster" ng-change="enableLocalCluster()" ng-value="true" class="visibilityCheckbox"> {{'views.localCluster' | translate}}
+ <input type="radio" ng-disabled="!clusterConfigurable || noLocalClusterAvailible" ng-model="instance.clusterType" ng-change="enableLocalCluster()" value="LOCAL_AMBARI" class="visibilityCheckbox"> {{'views.localCluster' | translate}}
</label>
</div>
@@ -133,17 +133,39 @@
<label for="" class="control-label col-sm-3 ng-binding not-required" >{{'views.clusterName' | translate}}</label>
<div>
<div class="col-sm-9">
- <select ng-model="cluster" ng-disabled="!instance.isLocalCluster" ng-change="onClusterChange()" class="clusters-name-dropdown form-control" ng-options="o as o for o in clusters"></select>
+ <select ng-model="cluster" ng-disabled="instance.clusterType != 'LOCAL_AMBARI' || noLocalClusterAvailible" ng-change="onClusterChange()" class="clusters-name-dropdown form-control" ng-options="o as o for o in clusters"></select>
</div>
</div>
</div>
</div>
</div>
- <div class="panel-body property-form">
+
+ <div class="panel-body property-form" popover="{{clusterConfigurableErrorMsg}}" popover-trigger="mouseenter">
+ <div class="checkbox create-checkbox-cluster">
+ <label>
+ <input type="radio" ng-disabled="!clusterConfigurable || noRemoteClusterAvailible" ng-model="instance.clusterType" ng-change="enableLocalCluster()" value="REMOTE_AMBARI" class="visibilityCheckbox"> {{'views.remoteCluster' | translate}}
+ </label>
+ </div>
+
+ <div class="form-horizontal property-form">
+ <div class="form-group">
+
+ <label for="" class="control-label col-sm-3 ng-binding not-required" >{{'views.clusterName' | translate}}</label>
+ <div>
+ <div class="col-sm-9">
+ <select ng-model="data.remoteCluster" ng-disabled="instance.clusterType != 'REMOTE_AMBARI' || noRemoteClusterAvailable" ng-change="onClusterChange()" class="clusters-name-dropdown form-control" ng-options="o as o for o in remoteClusters"></select>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ </div>
+
+ <div class="panel-body property-form" ng-hide="!numberOfClusterConfigs">
<div class="checkbox">
<label>
- <input type="radio" ng-model="instance.isLocalCluster" ng-value="false" class="visibilityCheckbox"> {{'views.custom' | translate}}
+ <input type="radio" ng-model="instance.clusterType" value="NONE" class="visibilityCheckbox"> {{'views.custom' | translate}}
</label>
</div>
<div class="alert alert-danger bottom-margin top-margin" ng-show='form.instanceCreateForm.generalValidationError'>
@@ -154,11 +176,11 @@
<label for="" class="col-sm-3 control-label" ng-class="{'not-required': !parameter.required}">{{parameter.label || parameter.displayName}}{{parameter.required ? '*' : ''}}</label>
<div ng-switch="parameter.type">
<div class="col-sm-9 checkbox" ng-switch-when="boolean">
- <input type="checkbox" class="viewproperty-input" name="{{parameter.name}}" ng-disabled="instance.isLocalCluster" ng-required="parameter.required && instance.isLocalCluster" ng-model="parameter.value" popover="{{parameter.description}}" popover-title="{{parameter.name}}" popover-trigger="mouseenter">
+ <input type="checkbox" class="viewproperty-input" name="{{parameter.name}}" ng-disabled="instance.clusterType == 'NONE'" ng-required="parameter.required && (instance.clusterType == 'NONE')" ng-model="parameter.value" popover="{{parameter.description}}" popover-title="{{parameter.name}}" popover-trigger="mouseenter">
</div>
<div class="col-sm-9" ng-switch-default>
- <input type="{{parameter.masked ? 'password' : 'text'}}" class="form-control viewproperty-input" name="{{parameter.name}}" ng-disabled="instance.isLocalCluster" ng-change="form.instanceCreateForm[parameter.name].validationError=''" ng-required="parameter.required && !instance.isLocalCluster" ng-model="parameter.value" autocomplete="off" popover="{{parameter.description}}" popover-title="{{parameter.name}}" popover-trigger="mouseenter" placeholder="{{parameter.placeholder}}">
- <div class="alert alert-danger no-margin-bottom top-margin" ng-show='form.instanceCreateForm[parameter.name].$error.required && form.instanceCreateForm.submitted && !instance.isLocalCluster'>
+ <input type="{{parameter.masked ? 'password' : 'text'}}" class="form-control viewproperty-input" name="{{parameter.name}}" ng-disabled="instance.clusterType != 'NONE'" ng-change="form.instanceCreateForm[parameter.name].validationError=''" ng-required="parameter.required && (instance.clusterType == 'NONE')" ng-model="parameter.value" autocomplete="off" popover="{{parameter.description}}" popover-title="{{parameter.name}}" popover-trigger="mouseenter" placeholder="{{parameter.placeholder}}">
+ <div class="alert alert-danger no-margin-bottom top-margin" ng-show="form.instanceCreateForm[parameter.name].$error.required && form.instanceCreateForm.submitted && (instance.clusterType == 'NONE')">
{{'common.alerts.fieldIsRequired' | translate}}
</div>
<div class="alert alert-danger no-margin-bottom top-margin" ng-show='form.instanceCreateForm[parameter.name].validationError'>
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/edit.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/edit.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/edit.html
index 4003137..92cde74 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/edit.html
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/edit.html
@@ -158,18 +158,18 @@
</div>
</div>
-<div class="panel panel-default" ng-hide="isConfigurationEmpty">
+<div class="panel panel-default" ng-hide="isConfigurationEmpty && !clusterConfigurable">
<div class="panel-heading clearfix">
<h3 class="panel-title pull-left">{{'views.clusterConfiguration' | translate}}</h3>
<div class="pull-right" ng-switch="instance.ViewInstanceInfo.static">
- <a href ng-switch-when="false" ng-hide="isConfigurationEmpty" ng-click="togglePropertiesEditing()" ng-show="editConfigurationDisabled" class="properties-toggle"> <span class="glyphicon glyphicon-pencil"></span> {{'views.edit' | translate}}</a>
- <a href ng-switch-when="true" ng-hide="isConfigurationEmpty" class="properties-toggle disabled"> <span class="glyphicon glyphicon-pencil"></span> {{'views.edit' | translate}}</a>
+ <a href ng-switch-when="false" ng-hide="isConfigurationEmpty && !clusterConfigurable" ng-click="togglePropertiesEditing()" ng-show="editConfigurationDisabled" class="properties-toggle"> <span class="glyphicon glyphicon-pencil"></span> {{'views.edit' | translate}}</a>
+ <a href ng-switch-when="true" ng-hide="isConfigurationEmpty && !clusterConfigurable" class="properties-toggle disabled"> <span class="glyphicon glyphicon-pencil"></span> {{'views.edit' | translate}}</a>
</div>
</div>
<div class="panel-body property-form" popover="{{clusterConfigurableErrorMsg}}" popover-trigger="mouseenter">
<div class="checkbox">
<label>
- <input type="radio" ng-model="$parent.isLocalCluster" ng-change="enableLocalCluster()" ng-disabled="!clusterConfigurable || editConfigurationDisabled || noClusterAvailible" ng-value="true" class="visibilityCheckbox"> {{'views.localCluster' | translate}}
+ <input type="radio" ng-model="data.clusterType" ng-change="enableLocalCluster()" ng-disabled="!clusterConfigurable || editConfigurationDisabled || noLocalClusterAvailible" value="LOCAL_AMBARI" class="visibilityCheckbox"> {{'views.localCluster' | translate}}
</label>
</div>
<div class="form-horizontal property-form">
@@ -177,18 +177,34 @@
<label for="" class="control-label col-sm-3 ng-binding not-required" >{{'views.clusterName' | translate}}</label>
<div>
<div class="col-sm-9">
- <select ng-model="cluster" ng-disabled="!$parent.isLocalCluster || editConfigurationDisabled" ng-change="onClusterChange()" class="clusters-name-dropdown form-control" ng-options="o as o for o in clusters"></select>
+ <select ng-model="cluster" ng-disabled="(data.clusterType != 'LOCAL_AMBARI') || editConfigurationDisabled" ng-change="onClusterChange()" class="clusters-name-dropdown form-control" ng-options="o as o for o in clusters"></select>
</div>
</div>
</div>
</div>
<p> </p>
- <div class="checkbox">
+ <div class="checkbox">
+ <label>
+ <input type="radio" ng-model="data.clusterType" ng-change="enableLocalCluster()" ng-disabled="!clusterConfigurable || editConfigurationDisabled || noRemoteClusterAvailible" value="REMOTE_AMBARI" class="visibilityCheckbox"> {{'views.remoteCluster' | translate}}
+ </label>
+ </div>
+ <div class="form-horizontal property-form">
+ <div class="form-group">
+ <label for="" class="control-label col-sm-3 ng-binding not-required" >{{'views.clusterName' | translate}}</label>
+ <div>
+ <div class="col-sm-9">
+ <select ng-model="data.remoteCluster" ng-disabled="(data.clusterType != 'REMOTE_AMBARI') || editConfigurationDisabled" ng-change="onClusterChange()" class="clusters-name-dropdown form-control" ng-options="o as o for o in remoteClusters"></select>
+ </div>
+ </div>
+ </div>
+ </div>
+ <p> </p>
+ <div class="checkbox" ng-hide="isConfigurationEmpty">
<label>
<input type="radio"
- ng-model="$parent.isLocalCluster"
+ ng-model="data.clusterType"
ng-disabled="editConfigurationDisabled"
- ng-value="false"
+ value="NONE"
ng-change="disableLocalCluster()"
class="visibilityCheckbox">
{{'views.custom' | translate}}
@@ -196,20 +212,20 @@
</div>
</div>
<div class="panel-body edit-view-custom-wrap">
- <form name="propertiesForm" class="form-horizontal property-form" ng-hide="isConfigurationEmpty" novalidate>
+ <form name="propertiesForm" class="form-horizontal property-form" novalidate>
<fieldset>
- <div class="form-group" ng-repeat="property in configurationMeta | filter:{clusterConfig:true}" ng-class="{'has-error' : (!editConfigurationDisabled && !isLocalCluster && ((property.required && propertiesForm[property.name].$error.required && !editConfigurationDisabled) || propertiesForm[property.name].validationError))}">
+ <div class="form-group" ng-hide="isConfigurationEmpty" ng-repeat="property in configurationMeta | filter:{clusterConfig:true}" ng-class="{'has-error' : (!editConfigurationDisabled && (data.clusterType == 'NONE') && ((property.required && propertiesForm[property.name].$error.required && !editConfigurationDisabled) || propertiesForm[property.name].validationError))}">
<label for="" class="control-label col-sm-3" ng-class="{'not-required': !property.required}">{{property.label || property.displayName}}{{property.required ? '*' : ''}}</label>
<div ng-switch="property.type">
<div class="col-sm-9 checkbox" ng-switch-when="boolean">
- <input type="checkbox" class="propertie-input" ng-disabled="isLocalCluster || editConfigurationDisabled" name="{{property.name}}" ng-model="configuration[property.name]" ng-true-value="true" ng-false-value="false" popover="{{property.description}}" popover-title="{{property.name}}" popover-trigger="mouseenter">
+ <input type="checkbox" class="propertie-input" ng-disabled="(data.clusterType != 'NONE') || editConfigurationDisabled" name="{{property.name}}" ng-model="configuration[property.name]" ng-true-value="true" ng-false-value="false" popover="{{property.description}}" popover-title="{{property.name}}" popover-trigger="mouseenter">
</div>
<div class="col-sm-9" ng-switch-default>
- <input type="{{property.masked ? 'password' : 'text'}}" class="form-control propertie-input" ng-required="property.required && !isLocalCluster" ng-change="propertiesForm[property.name].validationError=''" ng-disabled="isLocalCluster || editConfigurationDisabled" name="{{property.name}}" ng-model="configuration[property.name]" popover="{{property.description}}" popover-title="{{property.name}}" popover-trigger="mouseenter" placeholder="{{property.placeholder}}">
- <div class="alert alert-danger no-margin-bottom top-margin" ng-show='property.required && propertiesForm[property.name].$error.required && !editConfigurationDisabled && !isLocalCluster'>
+ <input type="{{property.masked ? 'password' : 'text'}}" class="form-control propertie-input" ng-required="property.required && (data.clusterType == 'NONE')" ng-change="propertiesForm[property.name].validationError=''" ng-disabled="(data.clusterType != 'NONE') || editConfigurationDisabled" name="{{property.name}}" ng-model="configuration[property.name]" popover="{{property.description}}" popover-title="{{property.name}}" popover-trigger="mouseenter" placeholder="{{property.placeholder}}">
+ <div class="alert alert-danger no-margin-bottom top-margin" ng-show="property.required && propertiesForm[property.name].$error.required && !editConfigurationDisabled && (data.clusterType == 'NONE')">
{{'common.alerts.fieldIsRequired' | translate}}
</div>
- <div class="alert alert-danger no-margin-bottom top-margin" ng-show='property.required && propertiesForm[property.name].validationError && !editConfigurationDisabled && !isLocalCluster'>
+ <div class="alert alert-danger no-margin-bottom top-margin" ng-show="property.required && propertiesForm[property.name].validationError && !editConfigurationDisabled && (data.clusterType == 'NONE')">
{{propertiesForm[property.name].validationMessage}}
</div>
</div>
@@ -223,7 +239,7 @@
</div>
</fieldset>
</form>
- <div ng-show="isConfigurationEmpty">
+ <div ng-show="isConfigurationEmpty && !clusterConfigurable">
<div class="alert alert-info">{{'views.alerts.notDefined' | translate: '{term: constants.props}'}}</div>
</div>
</div>
@@ -258,7 +274,7 @@
</tr>
</tbody>
</table>
- <div ng-show="!isPermissionsEmpty && isLocalCluster && editConfigurationDisabled">
+ <div ng-show="!isPermissionsEmpty && (data.clusterType == 'LOCAL_AMBARI') && editConfigurationDisabled">
<div class="col-sm-12 cluster-inherited-permission">
<strong>{{'views.clusterPermissions.label' | translate}}</strong>
</div>
@@ -277,4 +293,4 @@
<div class="alert alert-info">{{'views.alerts.notDefined' | translate: '{term: constants.perms}'}}</div>
</div>
</div>
-</div>
+</div>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/ambari-admin/src/main/resources/ui/admin-web/app/views/leftNavbar.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/leftNavbar.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/leftNavbar.html
index f93867c..f99e0cc 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/views/leftNavbar.html
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/leftNavbar.html
@@ -53,9 +53,9 @@
<i class="glyphicon glyphicon-remove"></i>
</button>
<button
- type="submit"
- class="btn btn-primary btn-xs"
- ng-class="{'disabled': editClusterNameForm.newClusterName.$invalid || editCluster.name == cluster.Clusters.cluster_name}">
+ type="submit"
+ class="btn btn-primary btn-xs"
+ ng-class="{'disabled': editClusterNameForm.newClusterName.$invalid || editCluster.name == cluster.Clusters.cluster_name}">
<i class="glyphicon glyphicon-ok"></i>
</button>
</div>
@@ -78,10 +78,13 @@
<li><p class="noclusters">{{'common.noClusters' | translate}}</p></li>
</ul>
</div>
- <ul class="nav nav-pills nav-stacked" ng-show="cluster && totalRepos > 0">
- <li ng-class="{active: isActive('stackVersions.list')}">
+ <ul class="nav nav-pills nav-stacked" >
+ <li ng-class="{active: isActive('stackVersions.list')}" ng-show="cluster && totalRepos > 0">
<a href="#/stackVersions">{{'common.versions' | translate}}</a>
</li>
+ <li ng-class="{active: isActive('remoteClusters.list')}">
+ <a href="#/remoteClusters">{{'common.remoteClusters' | translate}}</a>
+ </li>
</ul>
</div>
</div>
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/ambari-admin/src/main/resources/ui/admin-web/app/views/remoteClusters/editRemoteClusterPage.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/remoteClusters/editRemoteClusterPage.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/remoteClusters/editRemoteClusterPage.html
new file mode 100644
index 0000000..b5890bf
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/remoteClusters/editRemoteClusterPage.html
@@ -0,0 +1,77 @@
+<!--
+* 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="clearfix">
+ <ol class="breadcrumb pull-left">
+ <li><a href="#/remoteClusters">{{'common.remoteClusters' | translate}}</a></li>
+ <li class="active">{{cluster.cluster_name}}</li>
+ </ol>
+ <div class="pull-right top-margin-4">
+ <div>
+ <button class="btn deleteuser-btn btn-danger" ng-click="deleteCluster()">{{'common.deregisterCluster' | translate}}</button>
+ </div>
+ </div>
+</div>
+<hr>
+
+
+
+
+<form class="form-horizontal create-user-form" role="form" novalidate name="form" autocomplete="off">
+
+ <div class="form-group" ng-class="{'has-error' : form.user_name.$error.required && form.submitted}">
+ <label for="clustername" class="col-sm-2 control-label">{{'views.clusterName' | translate}}</label>
+ <div class="col-sm-10">
+ <input type="text" id="clustername" disabled class="form-control" name="cluster_name" ng-pattern="/[a-zA-Z0-9\-]*/" placeholder="Cluster Name" ng-model="cluster.cluster_name" required autocomplete="off">
+ <div class="alert alert-danger top-margin" ng-show="form.cluster_name.$error.required && form.submitted"> {{'common.alerts.fieldIsRequired' | translate}}</div>
+ </div>
+ </div>
+
+ <div class="form-group" ng-class="{'has-error' : form.user_name.$error.required && form.submitted}">
+ <label for="clusterurl" class="col-sm-2 control-label">{{'users.ambariClusterURL' | translate}}</label>
+ <div class="col-sm-10">
+ <input type="text" id="clusterurl" class="form-control" name="cluster_url" placeholder="Ambari Cluster URL" ng-model="cluster.cluster_url" required autocomplete="off">
+ <div class="alert alert-danger top-margin" ng-show="form.cluster_url.$error.required && form.submitted"> {{'common.alerts.fieldIsRequired' | translate}}</div>
+ </div>
+ </div>
+
+ <div class="form-group" ng-class="{'has-error' : form.user_name.$error.required && form.submitted}" style="display: none" >
+ <label for="clusteruser" class="col-sm-2 control-label"> {{'users.roles.clusterUser' | translate}}</label>
+ <div class="col-sm-10">
+ <input type="text" id="clusteruser" class="form-control" name="cluster_user" placeholder="Cluster User" ng-model="cluster.cluster_user" required autocomplete="off">
+ <div class="alert alert-danger top-margin" ng-show="form.cluster_user.$error.required && form.submitted"> {{'common.alerts.fieldIsRequired' | translate}}</div>
+ </div>
+ </div>
+
+ <div class="form-group">
+ <label for="" class="col-sm-2 control-label"></label>
+ <div class="col-sm-10">
+ <div>
+ <a href ng-click="openChangePwdDialog()" class="btn btn-default changepassword">{{'users.updateCredentials' | translate}}</a>
+ </div>
+ </div>
+ </div>
+
+
+ <div class="form-group">
+ <div class="col-sm-offset-2 col-sm-10">
+ <button class="btn btn-primary pull-right left-margin saveremotecluster" ng-click="editRemoteCluster()">{{'common.controls.save' | translate}}</button>
+ <a class="btn btn-default pull-right cancel" href ng-click="cancel()">{{'common.controls.cancel' | translate}}</a>
+ </div>
+ </div>
+
+</form>
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/ambari-admin/src/main/resources/ui/admin-web/app/views/remoteClusters/list.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/remoteClusters/list.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/remoteClusters/list.html
new file mode 100644
index 0000000..e386ffd
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/remoteClusters/list.html
@@ -0,0 +1,80 @@
+<!--
+* 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="users-pane">
+ <div class="clearfix">
+ <ol class="breadcrumb pull-left">
+ <li class="active">Remote Clusters</li>
+ </ol>
+ <div class="pull-right top-margin-4">
+ <a href="#/remoteClusters/create" class="btn btn-primary">
+ <span class="glyphicon glyphicon-plus"></span>
+ {{'views.registerRemoteCluster' | translate}}
+ </a>
+ </div>
+ </div>
+ <hr>
+ <table class="table table-striped table-hover">
+ <thead>
+ <tr>
+ <th class="col-sm-3">
+ <div class="search-container">
+ <label for="">{{'views.clusterName' | translate}}</label>
+ <input type="text" class="form-control namefilter" placeholder="{{'common.any' | translate}}" ng-model="currentNameFilter" ng-change="resetPagination()">
+ <button type="button" class="close" ng-show="currentNameFilter" ng-click="currentNameFilter=''; resetPagination()"><span aria-hidden="true">×</span><span class="sr-only">{{'common.controls.close' | translate}}</span></button>
+ </div>
+ </th>
+ <th class="col-sm-9">
+ <label for="">{{'common.services' | translate}}</label>
+ <select class="form-control typefilter"
+ ng-model="currentTypeFilter"
+ ng-options="item for item in typeFilterOptions"
+ ng-change="resetPagination();">
+ </select>
+ </th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr ng-repeat="remoteCluster in remoteClusters" >
+ <td class="col-sm-3"><a href="#/remoteClusters/{{remoteCluster.ClusterInfo.name}}/edit">{{ remoteCluster.ClusterInfo.name }}</a></td>
+ <td class="col-sm-9">
+ <span ng-repeat="service in remoteCluster.ClusterInfo.services" ng-if="remoteCluster.ClusterInfo.services.length > 0">{{ service }} {{$last ? '' : ','}} </span>
+ <span ng-if="remoteCluster.ClusterInfo.services.length == 0">--</span>
+ </td>
+ </tr>
+ </tbody>
+
+ </table>
+ <div class="alert alert-info col-sm-12" ng-show="!remoteClusters.length">
+ {{'common.alerts.noRemoteClusterDisplay' | translate}}
+ </div>
+ <div class="col-sm-12 table-bar">
+ <div class="pull-left filtered-info">
+ <span>{{'common.filterInfo' | translate: '{showed: tableInfo.showed, total: tableInfo.total, term: constants.groups}'}}</span>
+ <span ng-show="isNotEmptyFilter">- <a href ng-click="clearFilters()">{{'common.controls.clearFilters' | translate}}</a></span>
+ </div>
+ <div class="pull-right left-margin">
+ <pagination class="paginator" total-items="totalGroups" max-size="maxVisiblePages" items-per-page="groupsPerPage" ng-model="currentPage" ng-change="pageChanged()"></pagination>
+ </div>
+ <div class="pull-right">
+ <select class="form-control" ng-model="groupsPerPage" ng-change="groupsPerPageChanges()" ng-options="currOption for currOption in [10, 25, 50, 100]"></select>
+ </div>
+ </div>
+
+</div>
+
[3/4] ambari git commit: AMBARI-16274. Views: Simplify View
Configuration for Remote Ambari Managed Cluster. (Gaurav Nagar via dipayanb)
Posted by db...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/ambari-admin/src/main/resources/ui/admin-web/app/views/remoteClusters/modals/changePassword.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/remoteClusters/modals/changePassword.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/remoteClusters/modals/changePassword.html
new file mode 100644
index 0000000..a05e13d
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/remoteClusters/modals/changePassword.html
@@ -0,0 +1,46 @@
+<!--
+* 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="modal-header">
+ <h3 class="modal-title">{{'users.updateCredentials' | translate}}</h3>
+</div>
+<div class="modal-body">
+ <form class="form-horizontal" novalidate name="form.passwordChangeForm" role="form" >
+
+ <div class="form-group" ng-class="{'has-error' : (form.passwordChangeForm.currentPassword.$error.required && form.passwordChangeForm.submitted)}">
+ <label for="" class="col-sm-4 control-label" >{{'users.roles.clusterUser' | translate}}</label>
+ <div class="col-sm-8">
+ <input type="text" name="currentUserName" class="form-control bottom-margin" placeholder="Cluster User" required ng-model="passwordData.currentUserName" autocomplete="off">
+ <div class="alert alert-danger no-margin-bottom" ng-show='form.passwordChangeForm.currentUserName.$error.required && form.passwordChangeForm.submitted'>{{'users.alerts.usernameRequired' | translate}}</div>
+ </div>
+ </div>
+
+ <div class="form-group no-margin-bottom" ng-class="{'has-error' : (form.passwordChangeForm.password.$error.required && form.passwordChangeForm.submitted) || form.passwordChangeForm.confirmPassword.$error.passwordVerify}">
+ <label for="" class="col-sm-4 control-label">{{'users.password' | translate}}</label>
+ <div class="col-sm-8">
+ <input type="password" class="form-control bottom-margin" name="password" placeholder="Password" required ng-model="passwordData.password" autocomplete="off">
+ <div class="alert alert-danger no-margin-bottom" ng-show='form.passwordChangeForm.password.$error.required && form.passwordChangeForm.submitted'>{{'users.alerts.passwordRequired' | translate}}</div>
+ <div class="alert alert-danger no-margin-bottom" ng-show='form.passwordChangeForm.confirmPassword.$error.passwordVerify'>{{'users.alerts.wrongPassword' | translate}}</div>
+ </div>
+
+ </div>
+ </form>
+</div>
+<div class="modal-footer">
+ <button class="btn btn-default" ng-click="cancel()">{{'common.controls.cancel' | translate}}</button>
+ <button class="btn btn-primary" ng-click="ok()">{{'common.controls.ok' | translate}}</button>
+</div>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/ambari-admin/src/main/resources/ui/admin-web/app/views/remoteClusters/remoteClusterPage.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/remoteClusters/remoteClusterPage.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/remoteClusters/remoteClusterPage.html
new file mode 100644
index 0000000..0f82360
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/remoteClusters/remoteClusterPage.html
@@ -0,0 +1,66 @@
+<!--
+* 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.
+-->
+<ol class="breadcrumb">
+ <li><a href="#/remoteClusters">{{'common.remoteClusters' | translate}}</a></li>
+ <li class="active">{{'common.register' | translate}}</li>
+</ol>
+<hr>
+<form class="form-horizontal create-user-form" role="form" novalidate name="form" autocomplete="off">
+
+ <div class="form-group" ng-class="{'has-error' : form.user_name.$error.required && form.submitted}">
+ <label for="clustername" class="col-sm-2 control-label">{{'views.clusterName' | translate}} </label>
+ <div class="col-sm-10">
+ <input type="text" id="clustername" class="form-control" ng-pattern="/[a-zA-Z0-9\-]*/" name="cluster_name" placeholder="Ambari Cluster Name" ng-model="cluster.cluster_name" required autocomplete="off">
+ <div class="alert alert-danger top-margin" ng-show="form.cluster_name.$error.required && form.submitted"> {{'common.alerts.fieldIsRequired' | translate}}</div>
+ <div class="alert alert-danger top-margin" ng-show="form.cluster_name.$error.pattern && form.submitted"> {{'views.alerts.noSpecialChars' | translate}}</div>
+ </div>
+ </div>
+
+ <div class="form-group" ng-class="{'has-error' : form.user_name.$error.required && form.submitted}">
+ <label for="clusterurl" class="col-sm-2 control-label">{{'users.ambariClusterURL' | translate}}</label>
+ <div class="col-sm-10">
+ <input type="text" id="clusterurl" class="form-control" name="cluster_url" placeholder="http://ambari.server:8080/api/v1/clusters/c1" ng-model="cluster.cluster_url" required autocomplete="off">
+ <div class="alert alert-danger top-margin" ng-show="form.cluster_url.$error.required && form.submitted"> {{'common.alerts.fieldIsRequired' | translate}}</div>
+ </div>
+ </div>
+
+ <div class="form-group" ng-class="{'has-error' : form.user_name.$error.required && form.submitted}">
+ <label for="clusteruser" class="col-sm-2 control-label"> {{'users.roles.clusterUser' | translate}}</label>
+ <div class="col-sm-10">
+ <input type="text" id="clusteruser" class="form-control" name="cluster_user" placeholder="Cluster User" ng-model="cluster.cluster_user" required autocomplete="off">
+ <div class="alert alert-danger top-margin" ng-show="form.cluster_user.$error.required && form.submitted"> {{'common.alerts.fieldIsRequired' | translate}}</div>
+ </div>
+ </div>
+
+ <div class="form-group" ng-class="{'has-error' : (form.password.$error.required && form.submitted) || form.confirmPassword.$error.passwordVerify}">
+ <label for="password" class="col-sm-2 control-label">{{'users.password' | translate}}</label>
+ <div class="col-sm-10">
+ <input type="password" id="password" class="form-control bottom-margin userpassword" name="password" placeholder="Password" required ng-model="cluster.cluster_password" autocomplete="off">
+ <div class="alert alert-danger" ng-show='form.confirmPassword.$error.passwordVerify'>Wrong Password</div>
+ <div class="alert alert-danger" ng-show='form.password.$error.required && form.submitted'>{{'common.alerts.passwordRequired' | translate}}</div>
+ </div>
+ </div>
+
+ <div class="form-group">
+ <div class="col-sm-offset-2 col-sm-10">
+ <button class="btn btn-primary pull-right left-margin saveremotecluster" ng-click="registerRemoteCluster()">{{'common.controls.save' | translate}}</button>
+ <a class="btn btn-default pull-right cancel" href ng-click="cancel()"> {{'common.controls.cancel' | translate}}</a>
+ </div>
+ </div>
+
+</form>
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/ambari-server/src/main/java/org/apache/ambari/server/api/resources/RemoteClusterResourceDefinition.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/RemoteClusterResourceDefinition.java b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/RemoteClusterResourceDefinition.java
new file mode 100644
index 0000000..b656a30
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/RemoteClusterResourceDefinition.java
@@ -0,0 +1,51 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.api.resources;
+
+import org.apache.ambari.server.controller.spi.Resource;
+
+
+/**
+ * Remote Cluster resource definition.
+ */
+public class RemoteClusterResourceDefinition extends BaseResourceDefinition {
+
+ // ----- Constructors ------------------------------------------------------
+
+ /**
+ * Construct a view resource definition.
+ */
+ public RemoteClusterResourceDefinition() {
+ super(Resource.Type.RemoteCluster);
+ }
+
+
+ // ----- ResourceDefinition ------------------------------------------------
+
+ @Override
+ public String getPluralName() {
+ return "remote_clusters";
+ }
+
+ @Override
+ public String getSingularName() {
+ return "remote_cluster";
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java
index 0b77511..9c864b6 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java
@@ -437,6 +437,10 @@ public class ResourceInstanceFactoryImpl implements ResourceInstanceFactory {
resourceDefinition = new LoggingResourceDefinition();
break;
+ case RemoteCluster:
+ resourceDefinition = new RemoteClusterResourceDefinition();
+ break;
+
default:
throw new IllegalArgumentException("Unsupported resource type: " + type);
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/ambari-server/src/main/java/org/apache/ambari/server/api/services/RemoteClustersService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/RemoteClustersService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/RemoteClustersService.java
new file mode 100644
index 0000000..d7c7a20
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/RemoteClustersService.java
@@ -0,0 +1,139 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.api.services;
+
+import com.google.common.base.Optional;
+import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.security.authorization.AuthorizationException;
+
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+import java.util.Collections;
+
+
+/**
+ * Service responsible for Remote Cluster resource requests.
+ */
+@Path("/remoteclusters")
+public class RemoteClustersService extends BaseService {
+
+ /**
+ * Get the list of all Remote Clusters
+ * @param headers
+ * @param ui
+ * @return collections of all remote clusters
+ */
+ @GET
+ @Produces("text/plain")
+ public Response getRemoteClusters(@Context HttpHeaders headers, @Context UriInfo ui) {
+ return handleRequest(headers, null, ui, Request.Type.GET, createRemoteClusterResource(null));
+ }
+
+
+ /**
+ * Create a new RemoteAmbariCluster
+ * @param body
+ * @param headers
+ * @param ui
+ * @param clusterName
+ * @return
+ */
+ @POST
+ @Path("{clusterName}")
+ @Produces("text/plain")
+ public Response createRemoteCluster(String body, @Context HttpHeaders headers, @Context UriInfo ui,
+ @PathParam("clusterName") String clusterName) {
+ return handleRequest(headers, body, ui, Request.Type.POST, createRemoteClusterResource(clusterName));
+ }
+
+
+ /**
+ * Update a Remote Cluster
+ * @param body
+ * @param headers
+ * @param ui
+ * @param clusterName
+ * @return
+ */
+ @PUT
+ @Path("{clusterName}")
+ @Produces("text/plain")
+ public Response updateRemoteCluster(String body, @Context HttpHeaders headers, @Context UriInfo ui,
+ @PathParam("clusterName") String clusterName) {
+ return handleRequest(headers, body, ui, Request.Type.PUT, createRemoteClusterResource(clusterName));
+ }
+
+ /**
+ * Delete a Remote Cluster
+ * @param body
+ * @param headers
+ * @param ui
+ * @param clusterName
+ * @return
+ */
+ @DELETE
+ @Path("{clusterName}")
+ @Produces("text/plain")
+ public Response deleteRemoteCluster(String body, @Context HttpHeaders headers, @Context UriInfo ui,
+ @PathParam("clusterName") String clusterName) {
+ return handleRequest(headers, body, ui, Request.Type.DELETE, createRemoteClusterResource(clusterName));
+ }
+
+
+ /**
+ * Get information about a Remote Cluster
+ * @param headers
+ * @param ui
+ * @param clusterName
+ * @return
+ */
+ @GET
+ @Path("{clusterName}")
+ @Produces("text/plain")
+ public Response getRemoteCluster(@Context HttpHeaders headers, @Context UriInfo ui,
+ @PathParam("clusterName") String clusterName) {
+ return handleRequest(headers, null, ui, Request.Type.GET, createRemoteClusterResource(clusterName));
+ }
+
+
+
+
+ // ----- helper methods ----------------------------------------------------
+
+ /**
+ * Create a Remote Cluster resource.
+ *
+ * @param clusterName Name of the Cluster
+ *
+ * @return a RemoteCluster resource Instance
+ */
+ private ResourceInstance createRemoteClusterResource(String clusterName) {
+ return createResource(Resource.Type.RemoteCluster,Collections.singletonMap(Resource.Type.RemoteCluster, clusterName));
+ }
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/DefaultProviderModule.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/DefaultProviderModule.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/DefaultProviderModule.java
index 4e7a032..35fdcf6 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/DefaultProviderModule.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/DefaultProviderModule.java
@@ -122,6 +122,8 @@ public class DefaultProviderModule extends AbstractProviderModule {
return new SettingResourceProvider();
case Artifact:
return new ArtifactResourceProvider(managementController);
+ case RemoteCluster:
+ return new RemoteClusterResourceProvider();
default:
return AbstractControllerResourceProvider.getResourceProvider(type, propertyIds,
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RemoteClusterResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RemoteClusterResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RemoteClusterResourceProvider.java
new file mode 100644
index 0000000..413dbff
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RemoteClusterResourceProvider.java
@@ -0,0 +1,327 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.controller.internal;
+
+import com.google.common.base.Strings;
+import com.google.inject.Inject;
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.DuplicateResourceException;
+import org.apache.ambari.server.StaticallyInject;
+import org.apache.ambari.server.configuration.Configuration;
+import org.apache.ambari.server.controller.predicate.EqualsPredicate;
+import org.apache.ambari.server.controller.spi.NoSuchParentResourceException;
+import org.apache.ambari.server.controller.spi.NoSuchResourceException;
+import org.apache.ambari.server.controller.spi.Predicate;
+import org.apache.ambari.server.controller.spi.Request;
+import org.apache.ambari.server.controller.spi.RequestStatus;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.controller.spi.ResourceAlreadyExistsException;
+import org.apache.ambari.server.controller.spi.SystemException;
+import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
+import org.apache.ambari.server.orm.dao.RemoteAmbariClusterDAO;
+import org.apache.ambari.server.orm.entities.RemoteAmbariClusterEntity;
+import org.apache.ambari.server.orm.entities.RemoteAmbariClusterServiceEntity;
+import org.apache.ambari.server.security.authorization.RoleAuthorization;
+import org.apache.ambari.server.view.RemoteAmbariClusterRegistry;
+import org.apache.ambari.view.MaskException;
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Resource Provider for Remote Cluster
+ */
+@StaticallyInject
+public class RemoteClusterResourceProvider extends AbstractAuthorizedResourceProvider {
+
+ /**
+ * Remote Cluster property id constants.
+ */
+ public static final String CLUSTER_NAME_PROPERTY_ID = "ClusterInfo/name";
+ public static final String CLUSTER_URL_PROPERTY_ID = "ClusterInfo/url";
+ public static final String USERNAME_PROPERTY_ID = "ClusterInfo/username";
+ public static final String PASSWORD_PROPERTY_ID = "ClusterInfo/password";
+ public static final String SERVICES_PROPERTY_ID = "ClusterInfo/services";
+
+ /**
+ * The logger.
+ */
+ private final static Logger LOG = LoggerFactory.getLogger(RemoteClusterResourceProvider.class);
+
+ /**
+ * The key property ids for a Remote Cluster resource.
+ */
+ private static Map<Resource.Type, String> keyPropertyIds = new HashMap<Resource.Type, String>();
+ static {
+ keyPropertyIds.put(Resource.Type.RemoteCluster, CLUSTER_NAME_PROPERTY_ID);
+ }
+
+ /**
+ * The property ids for a Remote Cluster resource.
+ */
+ private static Set<String> propertyIds = new HashSet<String>();
+ static {
+ propertyIds.add(CLUSTER_NAME_PROPERTY_ID);
+ propertyIds.add(CLUSTER_URL_PROPERTY_ID);
+ propertyIds.add(USERNAME_PROPERTY_ID);
+ propertyIds.add(PASSWORD_PROPERTY_ID);
+ propertyIds.add(SERVICES_PROPERTY_ID);
+ }
+
+ @Inject
+ private static RemoteAmbariClusterDAO remoteAmbariClusterDAO;
+
+ @Inject
+ private static Configuration configuration;
+
+ @Inject
+ private static RemoteAmbariClusterRegistry remoteAmbariClusterRegistry;
+
+ /**
+ * Create a new resource provider.
+ */
+ protected RemoteClusterResourceProvider() {
+ super(propertyIds, keyPropertyIds);
+
+ EnumSet<RoleAuthorization> requiredAuthorizations = EnumSet.of(RoleAuthorization.AMBARI_ADD_DELETE_CLUSTERS);
+ setRequiredCreateAuthorizations(requiredAuthorizations);
+ setRequiredDeleteAuthorizations(requiredAuthorizations);
+ setRequiredUpdateAuthorizations(requiredAuthorizations);
+ }
+
+ @Override
+ public Map<Resource.Type, String> getKeyPropertyIds() {
+ return keyPropertyIds;
+ }
+
+ @Override
+ protected Set<String> getPKPropertyIds() {
+ return new HashSet<String>(keyPropertyIds.values());
+ }
+
+ @Override
+ public RequestStatus createResourcesAuthorized(Request request) throws SystemException, UnsupportedPropertyException, ResourceAlreadyExistsException, NoSuchParentResourceException {
+ for (Map<String, Object> properties : request.getProperties()) {
+ createResources(getCreateCommand(properties));
+ }
+ notifyCreate(Resource.Type.RemoteCluster, request);
+
+ return getRequestStatus(null);
+ }
+
+ @Override
+ public Set<Resource> getResources(Request request, Predicate predicate) throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
+ Set<Resource> resources = new HashSet<Resource>();
+ Set<String> requestedIds = getRequestPropertyIds(request, predicate);
+
+ Set<Map<String, Object>> propertyMaps = getPropertyMaps(predicate);
+ if (propertyMaps.isEmpty()) {
+ propertyMaps.add(Collections.<String, Object>emptyMap());
+ }
+
+ for (Map<String, Object> propertyMap : propertyMaps) {
+
+ String clusterName = (String) propertyMap.get(CLUSTER_NAME_PROPERTY_ID);
+
+ if(!Strings.isNullOrEmpty(clusterName)){
+ RemoteAmbariClusterEntity cluster = remoteAmbariClusterDAO.findByName(clusterName);
+ if(cluster == null) {
+ throw new NoSuchResourceException(String.format("Cluster with name %s cannot be found",clusterName) );
+ }
+ resources.add(toResource(requestedIds, cluster));
+ }else {
+ for (RemoteAmbariClusterEntity cluster : remoteAmbariClusterDAO.findAll()){
+ Resource resource = toResource(requestedIds, cluster);
+ resources.add(resource);
+ }
+ }
+ }
+ return resources;
+ }
+
+ protected Resource toResource(Set<String> requestedIds, RemoteAmbariClusterEntity cluster) {
+ Resource resource = new ResourceImpl(Resource.Type.RemoteCluster);
+ setResourceProperty(resource, CLUSTER_NAME_PROPERTY_ID, cluster.getName(), requestedIds);
+ setResourceProperty(resource, CLUSTER_URL_PROPERTY_ID, cluster.getUrl(), requestedIds);
+ setResourceProperty(resource, USERNAME_PROPERTY_ID, cluster.getUsername(), requestedIds);
+ ArrayList<String> services = new ArrayList<String>();
+ for (RemoteAmbariClusterServiceEntity remoteClusterServiceEntity : cluster.getServices()) {
+ services.add(remoteClusterServiceEntity.getServiceName());
+ }
+ setResourceProperty(resource, SERVICES_PROPERTY_ID,services, requestedIds);
+ return resource;
+ }
+
+ @Override
+ public RequestStatus updateResourcesAuthorized(Request request, Predicate predicate) throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
+ Iterator<Map<String,Object>> iterator = request.getProperties().iterator();
+ if (iterator.hasNext()) {
+ for (Map<String, Object> propertyMap : getPropertyMaps(iterator.next(), predicate)) {
+ modifyResources(getUpdateCommand(propertyMap));
+ }
+ }
+ notifyUpdate(Resource.Type.RemoteCluster, request, predicate);
+
+ return getRequestStatus(null);
+ }
+
+ @Override
+ protected RequestStatus deleteResourcesAuthorized(Request request, Predicate predicate)
+ throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
+
+ modifyResources(getDeleteCommand(predicate));
+ notifyDelete(Resource.Type.ViewInstance, predicate);
+ return getRequestStatus(null);
+
+ }
+
+ /**
+ * Get the command to create the RemoteAmbariCluster
+ * @param properties
+ * @return A command to create the RemoteAmbariCluster
+ */
+ private Command<Void> getCreateCommand(final Map<String, Object> properties) {
+ return new Command<Void>() {
+ @Override
+ public Void invoke() throws AmbariException {
+ String name = (String)properties.get(CLUSTER_NAME_PROPERTY_ID);
+
+ if(StringUtils.isEmpty(name)){
+ throw new IllegalArgumentException("Cluster Name cannot ne null or Empty");
+ }
+
+ if(remoteAmbariClusterDAO.findByName(name) != null){
+ throw new DuplicateResourceException(String.format("Remote cluster with name %s already exists",name));
+ }
+
+ saveOrUpdateRemoteAmbariClusterEntity(properties,false);
+
+ return null;
+ }
+ };
+ }
+
+ /**
+ * Get the command to update the RemoteAmbariCluster
+ * @param properties
+ * @return A command to update the RemoteAmbariCluster
+ */
+ private Command<Void> getUpdateCommand(final Map<String, Object> properties) {
+ return new Command<Void>() {
+ @Override
+ public Void invoke() throws AmbariException {
+ String name = (String)properties.get(CLUSTER_NAME_PROPERTY_ID);
+
+ if(StringUtils.isEmpty(name)){
+ throw new IllegalArgumentException("Cluster Name cannot ne null or Empty");
+ }
+
+ saveOrUpdateRemoteAmbariClusterEntity(properties,true);
+ return null;
+
+ }
+ };
+ }
+
+ /**
+ * Save or update Remote Ambari Cluster Entity to database
+ *
+ * @param properties
+ * @param update
+ * @throws AmbariException
+ */
+ private void saveOrUpdateRemoteAmbariClusterEntity(Map<String, Object> properties,boolean update) throws AmbariException {
+ String name = (String)properties.get(CLUSTER_NAME_PROPERTY_ID);
+ String url = (String)properties.get(CLUSTER_URL_PROPERTY_ID);
+ String username = (String)properties.get(USERNAME_PROPERTY_ID);
+ String password = (String)properties.get(PASSWORD_PROPERTY_ID);
+
+ if(StringUtils.isEmpty(url) && StringUtils.isEmpty(username)){
+ throw new IllegalArgumentException("Url or username cannot be null");
+ }
+
+ RemoteAmbariClusterEntity entity = remoteAmbariClusterDAO.findByName(name);
+
+ if(update && entity == null){
+ throw new IllegalArgumentException(String.format("Cannot find cluster with name : \"%s\"",name));
+ }else if(!update && entity != null){
+ throw new DuplicateResourceException(String.format("Cluster with name : \"%s\" already exists",name));
+ }
+
+ // Check Password not null for create
+ //Check username matches the entity username if password not present
+ if(StringUtils.isBlank(password) && !update){
+ throw new IllegalArgumentException("Password cannot be null");
+ }else if(StringUtils.isBlank(password) && update && !username.equals(entity.getUsername())){
+ throw new IllegalArgumentException("Failed to update. Username does not match.");
+ }
+
+ if (entity == null) {
+ entity = new RemoteAmbariClusterEntity();
+ }
+
+ entity.setName(name);
+ entity.setUrl(url);
+ try {
+ if(password != null) {
+ entity.setUsername(username);
+ entity.setPassword(password);
+ }
+ } catch (MaskException e) {
+ throw new IllegalArgumentException("Failed to create new Remote Cluster " + name + ". Illegal Password");
+ }
+
+ try {
+ remoteAmbariClusterRegistry.saveOrUpdate(entity,update);
+ } catch (Exception e) {
+ throw new IllegalArgumentException("Failed to create new Remote Cluster " + name +". " + e.getMessage(),e);
+ }
+ }
+
+ /**
+ * Get the command to delete the Cluster
+ * @param predicate
+ * @return The delete command
+ */
+ private Command<Void> getDeleteCommand(final Predicate predicate) {
+ return new Command<Void>() {
+ @Override
+ public Void invoke() throws AmbariException {
+ Comparable deletedCluster = ((EqualsPredicate) predicate).getValue();
+ String toDelete = deletedCluster.toString();
+ RemoteAmbariClusterEntity clusterEntity = remoteAmbariClusterDAO.findByName(toDelete);
+ if(clusterEntity == null){
+ throw new IllegalArgumentException("The Cluster "+ toDelete +" does not exist");
+ }
+
+ remoteAmbariClusterRegistry.delete(clusterEntity);
+ return null;
+ }
+ };
+ }
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ViewInstanceResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ViewInstanceResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ViewInstanceResourceProvider.java
index 605f68d..b8ed215 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ViewInstanceResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ViewInstanceResourceProvider.java
@@ -41,6 +41,7 @@ import org.apache.ambari.server.view.ViewRegistry;
import org.apache.ambari.server.view.validation.InstanceValidationResultImpl;
import org.apache.ambari.server.view.validation.ValidationException;
import org.apache.ambari.server.view.validation.ValidationResultImpl;
+import org.apache.ambari.view.ClusterType;
import org.apache.ambari.view.validation.Validator;
import java.util.Collections;
@@ -72,6 +73,7 @@ public class ViewInstanceResourceProvider extends AbstractAuthorizedResourceProv
public static final String CONTEXT_PATH_PROPERTY_ID = "ViewInstanceInfo/context_path";
public static final String STATIC_PROPERTY_ID = "ViewInstanceInfo/static";
public static final String CLUSTER_HANDLE_PROPERTY_ID = "ViewInstanceInfo/cluster_handle";
+ public static final String CLUSTER_TYPE_PROPERTY_ID = "ViewInstanceInfo/cluster_type";
public static final String SHORT_URL_PROPERTY_ID = "ViewInstanceInfo/short_url";
public static final String SHORT_URL_NAME_PROPERTY_ID = "ViewInstanceInfo/short_url_name";
@@ -113,6 +115,7 @@ public class ViewInstanceResourceProvider extends AbstractAuthorizedResourceProv
propertyIds.add(CONTEXT_PATH_PROPERTY_ID);
propertyIds.add(STATIC_PROPERTY_ID);
propertyIds.add(CLUSTER_HANDLE_PROPERTY_ID);
+ propertyIds.add(CLUSTER_TYPE_PROPERTY_ID);
propertyIds.add(SHORT_URL_PROPERTY_ID);
propertyIds.add(SHORT_URL_NAME_PROPERTY_ID);
propertyIds.add(VALIDATION_RESULT_PROPERTY_ID);
@@ -245,6 +248,7 @@ public class ViewInstanceResourceProvider extends AbstractAuthorizedResourceProv
setResourceProperty(resource, VISIBLE_PROPERTY_ID, viewInstanceEntity.isVisible(), requestedIds);
setResourceProperty(resource, STATIC_PROPERTY_ID, viewInstanceEntity.isXmlDriven(), requestedIds);
setResourceProperty(resource, CLUSTER_HANDLE_PROPERTY_ID, viewInstanceEntity.getClusterHandle(), requestedIds);
+ setResourceProperty(resource, CLUSTER_TYPE_PROPERTY_ID, viewInstanceEntity.getClusterType(), requestedIds);
ViewURLEntity viewUrl = viewInstanceEntity.getViewUrl();
if(viewUrl != null) {
setResourceProperty(resource, SHORT_URL_PROPERTY_ID, viewUrl.getUrlSuffix(), requestedIds);
@@ -351,6 +355,11 @@ public class ViewInstanceResourceProvider extends AbstractAuthorizedResourceProv
viewInstanceEntity.setClusterHandle((String) properties.get(CLUSTER_HANDLE_PROPERTY_ID));
}
+ if (properties.containsKey(CLUSTER_TYPE_PROPERTY_ID)) {
+ String clusterType = (String) properties.get(CLUSTER_TYPE_PROPERTY_ID);
+ viewInstanceEntity.setClusterType(ClusterType.valueOf(clusterType));
+ }
+
Map<String, String> instanceProperties = new HashMap<String, String>();
boolean isUserAdmin = viewRegistry.checkAdmin();
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java
index 386e657..99e4ccd 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java
@@ -156,7 +156,8 @@ public interface Resource {
UserAuthorization,
VersionDefinition,
ClusterKerberosDescriptor,
- LoggingQuery;
+ LoggingQuery,
+ RemoteCluster;
/**
* Get the {@link Type} that corresponds to this InternalType.
@@ -274,6 +275,7 @@ public interface Resource {
public static final Type VersionDefinition = InternalType.VersionDefinition.getType();
public static final Type ClusterKerberosDescriptor = InternalType.ClusterKerberosDescriptor.getType();
public static final Type LoggingQuery = InternalType.LoggingQuery.getType();
+ public static final Type RemoteCluster = InternalType.RemoteCluster.getType();
/**
* The type name.
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/RemoteAmbariClusterDAO.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/RemoteAmbariClusterDAO.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/RemoteAmbariClusterDAO.java
new file mode 100644
index 0000000..72ab368
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/RemoteAmbariClusterDAO.java
@@ -0,0 +1,101 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.orm.dao;
+
+import com.google.common.base.Optional;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.google.inject.Singleton;
+import com.google.inject.persist.Transactional;
+import org.apache.ambari.server.orm.RequiresSession;
+import org.apache.ambari.server.orm.entities.RemoteAmbariClusterEntity;
+import org.apache.ambari.server.orm.entities.ViewURLEntity;
+
+import javax.persistence.EntityManager;
+import javax.persistence.TypedQuery;
+import java.util.List;
+
+/**
+ * Remote Ambari Cluster Data Access Object.
+ */
+@Singleton
+public class RemoteAmbariClusterDAO {
+ /**
+ * JPA entity manager
+ */
+ @Inject
+ private Provider<EntityManager> entityManagerProvider;
+ @Inject
+ private DaoUtils daoUtils;
+
+
+ /**
+ * Find all view instances.
+ *
+ * @return all views or an empty List
+ */
+ @RequiresSession
+ public List<RemoteAmbariClusterEntity> findAll() {
+ TypedQuery<RemoteAmbariClusterEntity> query = entityManagerProvider.get().
+ createNamedQuery("allRemoteAmbariClusters", RemoteAmbariClusterEntity.class);
+
+ return query.getResultList();
+ }
+
+ /**
+ * Find Cluster by name
+ * @param clusterName
+ * @return
+ */
+ @RequiresSession
+ public RemoteAmbariClusterEntity findByName(String clusterName) {
+ TypedQuery<RemoteAmbariClusterEntity> query = entityManagerProvider.get().
+ createNamedQuery("remoteAmbariClusterByName", RemoteAmbariClusterEntity.class);
+ query.setParameter("clusterName", clusterName);
+ return daoUtils.selectSingle(query);
+ }
+
+ /**
+ * Save a Cluster entity
+ * @param entity
+ */
+ @Transactional
+ public void save(RemoteAmbariClusterEntity entity) {
+ entityManagerProvider.get().persist(entity);
+ }
+
+ /**
+ * Update and merge a Remote Ambari Cluster entity
+ * @param entity
+ */
+ @Transactional
+ public void update(RemoteAmbariClusterEntity entity) {
+ entityManagerProvider.get().merge(entity);
+
+ }
+
+ /**
+ * Remove a cluster entity
+ * @param clusterEntity
+ */
+ @Transactional
+ public void delete(RemoteAmbariClusterEntity clusterEntity) {
+ entityManagerProvider.get().remove(clusterEntity);
+ }
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RemoteAmbariClusterEntity.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RemoteAmbariClusterEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RemoteAmbariClusterEntity.java
new file mode 100644
index 0000000..99c9f2a
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RemoteAmbariClusterEntity.java
@@ -0,0 +1,201 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.orm.entities;
+
+import org.apache.ambari.server.view.DefaultMasker;
+import org.apache.ambari.view.MaskException;
+import org.apache.ambari.view.Masker;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.NamedQueries;
+import javax.persistence.NamedQuery;
+import javax.persistence.OneToMany;
+import javax.persistence.Table;
+import javax.persistence.TableGenerator;
+import java.util.Collection;
+
+/**
+ * Remote Ambari Managed Cluster
+ */
+@Table(name = "remoteambaricluster")
+@TableGenerator(name = "remote_cluster_id_generator",
+ table = "ambari_sequences", pkColumnName = "sequence_name", valueColumnName = "sequence_value"
+ , pkColumnValue = "remote_cluster_id_seq"
+ , initialValue = 1
+)
+
+@NamedQueries({
+ @NamedQuery(name = "allRemoteAmbariClusters",
+ query = "SELECT remoteAmbariCluster FROM RemoteAmbariClusterEntity remoteambaricluster"),
+ @NamedQuery(name = "remoteAmbariClusterByName", query =
+ "SELECT remoteAmbariCluster " +
+ "FROM RemoteAmbariClusterEntity remoteAmbariCluster " +
+ "WHERE remoteAmbariCluster.name=:clusterName")})
+@Entity
+public class RemoteAmbariClusterEntity {
+
+ /**
+ * The logger.
+ */
+ protected final static Logger LOG = LoggerFactory.getLogger(RemoteAmbariClusterEntity.class);
+
+ @Id
+ @Column(name = "cluster_id", nullable = false)
+ @GeneratedValue(strategy = GenerationType.TABLE, generator = "remote_cluster_id_generator")
+ private Long id;
+
+ @Column(name = "name", nullable = false, insertable = true, updatable = false)
+ private String name;
+
+ @Column(name = "url", nullable = false, insertable = true, updatable = true)
+ private String url;
+
+ @Column(name = "username", nullable = false, insertable = true, updatable = true)
+ private String username;
+
+ @Column(name = "password", nullable = false, insertable = true, updatable = true)
+ private String password;
+
+ @OneToMany(cascade = CascadeType.ALL, mappedBy = "cluster")
+ private Collection<RemoteAmbariClusterServiceEntity> services;
+
+ private static Masker masker = new DefaultMasker();
+
+ /**
+ * Get the id
+ *
+ * @return id
+ */
+ public Long getId() {
+ return id;
+ }
+
+ /**
+ * Set the id of cluster
+ *
+ * @param id
+ */
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ /**
+ * Get the name of cluster
+ *
+ * @return name
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Set the cluster name
+ *
+ * @param name
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * Get the cluster url
+ *
+ * @return url
+ */
+ public String getUrl() {
+ return url;
+ }
+
+ /**
+ * Set the url
+ *
+ * @param url
+ */
+ public void setUrl(String url) {
+ this.url = url;
+ }
+
+ /**
+ * Get username
+ *
+ * @return username
+ */
+ public String getUsername() {
+ return username;
+ }
+
+ /**
+ * Set the username
+ *
+ * @param username
+ */
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ /**
+ * Get the password
+ *
+ * @return password
+ */
+ public String getPassword() {
+ try {
+ return masker.unmask(password);
+ } catch (MaskException e) {
+ // Log exception
+ LOG.error("Unable to unmask password for Remote Cluster : "+name , e);
+ }
+ return null;
+ }
+
+ /**
+ * Set the password
+ *
+ * @param password
+ * @throws MaskException
+ */
+ public void setPassword(String password) throws MaskException {
+ this.password = masker.mask(password);
+ }
+
+ /**
+ * Get the services installed on the cluster
+ *
+ * @return services
+ */
+ public Collection<RemoteAmbariClusterServiceEntity> getServices() {
+ return services;
+ }
+
+ /**
+ * Set the services installed on the cluster
+ *
+ * @param services
+ */
+ public void setServices(Collection<RemoteAmbariClusterServiceEntity> services) {
+ this.services = services;
+ }
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RemoteAmbariClusterServiceEntity.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RemoteAmbariClusterServiceEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RemoteAmbariClusterServiceEntity.java
new file mode 100644
index 0000000..55e8b2c
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RemoteAmbariClusterServiceEntity.java
@@ -0,0 +1,108 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.orm.entities;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+import javax.persistence.TableGenerator;
+
+/**
+ * Remote Ambari Service to Remote Cluster Mapping
+ */
+@Table(name = "remoteambariclusterservice")
+@TableGenerator(name = "remote_cluster_service_id_generator",
+ table = "ambari_sequences", pkColumnName = "sequence_name", valueColumnName = "sequence_value"
+ , pkColumnValue = "remote_cluster_service_id_seq"
+ , initialValue = 1
+)
+@Entity
+public class RemoteAmbariClusterServiceEntity {
+
+ @Id
+ @Column(name = "id")
+ @GeneratedValue(strategy = GenerationType.TABLE, generator = "remote_cluster_service_id_generator")
+ private Long id;
+
+ @Column(name = "service_name", nullable = false, insertable = true, updatable = false)
+ private String serviceName;
+
+ @ManyToOne
+ @JoinColumn(name = "cluster_id", referencedColumnName = "cluster_id", nullable = false)
+ private RemoteAmbariClusterEntity cluster;
+
+ /**
+ * Get Id
+ *
+ * @return id
+ */
+ public Long getId() {
+ return id;
+ }
+
+ /**
+ * Set id for the service
+ *
+ * @param id
+ */
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ /**
+ * Get cluster attached to the service
+ *
+ * @return cluster
+ */
+ public RemoteAmbariClusterEntity getCluster() {
+ return cluster;
+ }
+
+ /**
+ * Set cluster for the service
+ *
+ * @param cluster
+ */
+ public void setCluster(RemoteAmbariClusterEntity cluster) {
+ this.cluster = cluster;
+ }
+
+ /**
+ * Get service name
+ *
+ * @return service name
+ */
+ public String getServiceName() {
+ return serviceName;
+ }
+
+ /**
+ * Set service name
+ *
+ * @param serviceName
+ */
+ public void setServiceName(String serviceName) {
+ this.serviceName = serviceName;
+ }
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ViewEntity.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ViewEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ViewEntity.java
index 29dc2a7..74de530 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ViewEntity.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ViewEntity.java
@@ -56,6 +56,9 @@ import java.util.Set;
query = "SELECT view FROM ViewEntity view")
@Entity
public class ViewEntity implements ViewDefinition {
+
+ public static final String AMBARI_ONLY = "AMBARI-ONLY";
+
/**
* The unique view name.
*/
@@ -729,6 +732,12 @@ public class ViewEntity implements ViewDefinition {
this.configuration = configuration;
this.clusterConfigurable = false;
+ if(configuration.getClusterConfigOptions() != null &&
+ configuration.getClusterConfigOptions().equals(AMBARI_ONLY)){
+ this.clusterConfigurable = true;
+ return;
+ }
+
// if any of the parameters contain a cluster config element then the view is cluster configurable
for (ParameterConfig parameterConfig : configuration.getParameters()) {
String clusterConfig = parameterConfig.getClusterConfig();
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ViewInstanceEntity.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ViewInstanceEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ViewInstanceEntity.java
index 2d6e5ba..ba5774f 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ViewInstanceEntity.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ViewInstanceEntity.java
@@ -28,6 +28,8 @@ import javax.persistence.Basic;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@@ -122,6 +124,13 @@ public class ViewInstanceEntity implements ViewInstanceDefinition {
private String clusterHandle;
/**
+ * Cluster Type for cluster Handle
+ */
+ @Enumerated(EnumType.STRING)
+ @Column(name = "cluster_type", nullable = false)
+ private ClusterType clusterType;
+
+ /**
* Visible flag.
*/
@Column
@@ -251,6 +260,7 @@ public class ViewInstanceEntity implements ViewInstanceDefinition {
this.clusterHandle = null;
this.visible = instanceConfig.isVisible() ? 'Y' : 'N';
this.alterNames = 1;
+ this.clusterType = ClusterType.LOCAL_AMBARI;
String label = instanceConfig.getLabel();
this.label = (label == null || label.length() == 0) ? view.getLabel() : label;
@@ -442,6 +452,24 @@ public class ViewInstanceEntity implements ViewInstanceDefinition {
}
/**
+ * Get the type of cluster the view instance is attached to
+ *
+ * @return clusterType the type of cluster for cluster handle
+ */
+ public ClusterType getClusterType() {
+ return clusterType;
+ }
+
+ /**
+ * Set the type of cluster for cluster handle
+ *
+ * @param clusterType
+ */
+ public void setClusterType(ClusterType clusterType) {
+ this.clusterType = clusterType;
+ }
+
+ /**
* Set the visible flag.
*
* @param visible visible flag
@@ -1029,4 +1057,5 @@ public class ViewInstanceEntity implements ViewInstanceDefinition {
return instanceName;
}
}
+
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog240.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog240.java b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog240.java
index 4ed4a13..3547ad3 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog240.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog240.java
@@ -75,6 +75,7 @@ import org.apache.ambari.server.state.ServiceInfo;
import org.apache.ambari.server.state.StackId;
import org.apache.ambari.server.state.StackInfo;
import org.apache.ambari.server.state.State;
+import org.apache.ambari.view.ClusterType;
import org.apache.ambari.server.state.stack.WidgetLayout;
import org.apache.ambari.server.state.stack.WidgetLayoutInfo;
import org.apache.commons.lang.StringUtils;
@@ -219,6 +220,14 @@ public class UpgradeCatalog240 extends AbstractUpgradeCatalog {
return "2.3.0";
}
+ public static final String CLUSTER_TYPE_COLUMN = "cluster_type";
+ public static final String REMOTE_AMBARI_CLUSTER_TABLE = "remoteambaricluster";
+ public static final String REMOTE_AMBARI_CLUSTER_SERVICE_TABLE = "remoteambariclusterservice";
+
+ public static final String CLUSTER_ID = "cluster_id";
+ public static final String SERVICE_NAME = "service_name";
+ public static final String CLUSTER_NAME = "name";
+
@Override
protected void executeDDLUpdates() throws AmbariException, SQLException {
@@ -236,6 +245,32 @@ public class UpgradeCatalog240 extends AbstractUpgradeCatalog {
updateHostRoleCommandTableDDL();
createViewUrlTableDDL();
updateViewInstanceEntityTable();
+ createRemoteClusterTable();
+ }
+
+ private void createRemoteClusterTable() throws SQLException {
+
+ List<DBColumnInfo> columns = new ArrayList<>();
+ LOG.info("Creating {} table", REMOTE_AMBARI_CLUSTER_TABLE);
+ columns.add(new DBColumnInfo(CLUSTER_ID, Long.class, null, null, false));
+ columns.add(new DBColumnInfo(CLUSTER_NAME, String.class, 255, null, false));
+ columns.add(new DBColumnInfo("url", String.class, 255, null, false));
+ columns.add(new DBColumnInfo("username", String.class, 255, null, false));
+ columns.add(new DBColumnInfo("password", String.class, 255, null, false));
+ dbAccessor.createTable(REMOTE_AMBARI_CLUSTER_TABLE, columns, CLUSTER_ID);
+ dbAccessor.addUniqueConstraint(REMOTE_AMBARI_CLUSTER_TABLE , "unq_remote_ambari_cluster" , CLUSTER_NAME);
+ addSequence("remote_cluster_id_seq", 1L, false);
+
+ List<DBColumnInfo> remoteClusterServiceColumns = new ArrayList<>();
+ LOG.info("Creating {} table", REMOTE_AMBARI_CLUSTER_SERVICE_TABLE);
+ remoteClusterServiceColumns.add(new DBColumnInfo(ID, Long.class, null, null, false));
+ remoteClusterServiceColumns.add(new DBColumnInfo(SERVICE_NAME, String.class, 255, null, false));
+ remoteClusterServiceColumns.add(new DBColumnInfo(CLUSTER_ID, Long.class, null, null, false));
+ dbAccessor.createTable(REMOTE_AMBARI_CLUSTER_SERVICE_TABLE, remoteClusterServiceColumns, ID);
+ dbAccessor.addFKConstraint(REMOTE_AMBARI_CLUSTER_SERVICE_TABLE, "FK_remote_ambari_cluster_id",
+ CLUSTER_ID, REMOTE_AMBARI_CLUSTER_TABLE, CLUSTER_ID, false);
+ addSequence("remote_cluster_service_id_seq", 1L, false);
+
}
private void createViewUrlTableDDL() throws SQLException {
@@ -256,6 +291,8 @@ public class UpgradeCatalog240 extends AbstractUpgradeCatalog {
new DBColumnInfo(SHORT_URL_COLUMN, Long.class, null, null, true));
dbAccessor.addFKConstraint(VIEWINSTANCE_TABLE, "FK_instance_url_id",
SHORT_URL_COLUMN, VIEWURL_TABLE, URL_ID_COLUMN, false);
+ dbAccessor.addColumn(VIEWINSTANCE_TABLE,
+ new DBColumnInfo(CLUSTER_TYPE_COLUMN, String.class, 100, ClusterType.LOCAL_AMBARI, false));
}
private void updateClusterTableDDL() throws SQLException {
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/ambari-server/src/main/java/org/apache/ambari/server/view/RemoteAmbariCluster.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/view/RemoteAmbariCluster.java b/ambari-server/src/main/java/org/apache/ambari/server/view/RemoteAmbariCluster.java
new file mode 100644
index 0000000..f661844
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/view/RemoteAmbariCluster.java
@@ -0,0 +1,190 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.view;
+
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonParser;
+import org.apache.ambari.server.configuration.Configuration;
+import org.apache.ambari.server.orm.entities.RemoteAmbariClusterEntity;
+import org.apache.ambari.view.AmbariHttpException;
+import org.apache.ambari.view.AmbariStreamProvider;
+import org.apache.ambari.view.cluster.Cluster;
+import org.apache.commons.io.IOUtils;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * View associated Remote cluster implementation.
+ */
+public class RemoteAmbariCluster implements Cluster {
+
+ private String name;
+
+ private AmbariStreamProvider streamProvider;
+
+ private final LoadingCache<String, JsonElement> configurationCache = CacheBuilder.newBuilder()
+ .expireAfterWrite(10, TimeUnit.SECONDS)
+ .build(new CacheLoader<String, JsonElement>() {
+ @Override
+ public JsonElement load(String url) throws Exception {
+ return readFromUrlJSON(url);
+ }
+ });
+
+
+ /**
+ * Constructor for Remote Ambari Cluster
+ *
+ * @param remoteAmbariClusterEntity
+ */
+ public RemoteAmbariCluster(RemoteAmbariClusterEntity remoteAmbariClusterEntity, Configuration config) {
+ String [] urlSplit = remoteAmbariClusterEntity.getUrl().split("/");
+
+ // remoteAmbariClusterEntity.getName() is not the actual name of Remote Cluster
+ // We need to extract the name from cluster url which is like. http://host:port/api/vi/clusters/${clusterName}
+ this.name = urlSplit[urlSplit.length -1];
+
+ this.streamProvider = new RemoteAmbariStreamProvider(
+ remoteAmbariClusterEntity.getUrl(), remoteAmbariClusterEntity.getUsername(),
+ remoteAmbariClusterEntity.getPassword(),config.getRequestConnectTimeout(),config.getRequestReadTimeout());
+ }
+
+ /**
+ * Constructor for Remote Ambari Cluster
+ *
+ * @param name
+ * @param streamProvider
+ */
+ public RemoteAmbariCluster(String name, AmbariStreamProvider streamProvider) {
+ this.name = name;
+ this.streamProvider = streamProvider;
+ }
+
+ @Override
+ public String getName() {
+ return this.name;
+ }
+
+ @Override
+ public String getConfigurationValue(String type, String key) {
+ JsonElement config = null;
+ try {
+ String desiredTag = getDesiredConfig(type);
+ if(desiredTag != null){
+ config = configurationCache.get(String.format("/configurations?(type=%s&tag=%s)", type, desiredTag));
+ }
+ } catch (ExecutionException e) {
+ throw new RemoteAmbariConfigurationReadException("Can't retrieve configuration from Remote Ambari", e);
+ }
+
+ if(config == null || !config.isJsonObject()) return null;
+ JsonElement items = config.getAsJsonObject().get("items");
+
+ if(items == null || !items.isJsonArray()) return null;
+ JsonElement item = items.getAsJsonArray().get(0);
+
+ if(item == null || !item.isJsonObject()) return null;
+ JsonElement properties = item.getAsJsonObject().get("properties");
+
+ if(properties == null || !properties.isJsonObject()) return null;
+ JsonElement property = properties.getAsJsonObject().get(key);
+
+ if(property == null || !property.isJsonPrimitive()) return null;
+
+ return property.getAsJsonPrimitive().getAsString();
+ }
+
+ /**
+ * Get list of services installed on the remote cluster
+ *
+ * @return list of services Available on cluster
+ */
+ public Set<String> getServices() throws IOException, AmbariHttpException {
+ Set<String> services = new HashSet<String>();
+ String path = "?fields=services/ServiceInfo/service_name";
+ JsonElement config = configurationCache.getUnchecked(path);
+
+ if(config != null && config.isJsonObject()){
+ JsonElement items = config.getAsJsonObject().get("services");
+ if(items != null && items.isJsonArray()){
+ for (JsonElement item : items.getAsJsonArray()) {
+ JsonElement serviceInfo = item.getAsJsonObject().get("ServiceInfo");
+ if(serviceInfo != null && serviceInfo.isJsonObject()){
+ String serviceName = serviceInfo.getAsJsonObject().get("service_name").getAsString();
+ services.add(serviceName);
+ }
+ }
+ }
+ }
+
+ return services;
+ }
+
+ /**
+ * Get the current tag for the config type
+ *
+ * @param type
+ * @return
+ * @throws ExecutionException
+ */
+ private String getDesiredConfig(String type) throws ExecutionException {
+ JsonElement desiredConfigResponse = configurationCache.get("?fields=services/ServiceInfo,hosts,Clusters");
+
+ if(desiredConfigResponse == null || !desiredConfigResponse.isJsonObject()) return null;
+ JsonElement clusters = desiredConfigResponse.getAsJsonObject().get("Clusters");
+
+ if(clusters == null || !clusters.isJsonObject()) return null;
+ JsonElement desiredConfig = clusters.getAsJsonObject().get("desired_configs");
+
+ if(desiredConfig == null || !desiredConfig.isJsonObject()) return null;
+ JsonElement desiredConfigForType = desiredConfig.getAsJsonObject().get(type);
+
+ if(desiredConfigForType == null || !desiredConfigForType.isJsonObject()) return null;
+ JsonElement typeJson = desiredConfigForType.getAsJsonObject().get("tag");
+
+ if( typeJson == null || !(typeJson.isJsonPrimitive())) return null;
+
+ return typeJson.getAsJsonPrimitive().getAsString();
+ }
+
+ /**
+ * Read the content of the url from remote cluster
+ *
+ * @param url
+ * @return
+ * @throws IOException
+ * @throws AmbariHttpException
+ */
+ private JsonElement readFromUrlJSON(String url) throws IOException, AmbariHttpException {
+ InputStream inputStream = streamProvider.readFrom(url, "GET", (String)null, null);
+ String response = IOUtils.toString(inputStream);
+ return new JsonParser().parse(response);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/ambari-server/src/main/java/org/apache/ambari/server/view/RemoteAmbariClusterRegistry.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/view/RemoteAmbariClusterRegistry.java b/ambari-server/src/main/java/org/apache/ambari/server/view/RemoteAmbariClusterRegistry.java
new file mode 100644
index 0000000..38a47a4
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/view/RemoteAmbariClusterRegistry.java
@@ -0,0 +1,116 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.view;
+
+import org.apache.ambari.server.configuration.Configuration;
+import org.apache.ambari.server.orm.dao.RemoteAmbariClusterDAO;
+import org.apache.ambari.server.orm.entities.RemoteAmbariClusterEntity;
+import org.apache.ambari.server.orm.entities.RemoteAmbariClusterServiceEntity;
+import org.apache.ambari.view.AmbariHttpException;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Registry for Remote Ambari Cluster
+ */
+@Singleton
+public class RemoteAmbariClusterRegistry {
+
+ private ConcurrentHashMap<String,RemoteAmbariCluster> clusterMap = new ConcurrentHashMap<String,RemoteAmbariCluster>();
+
+ @Inject
+ private RemoteAmbariClusterDAO remoteAmbariClusterDAO;
+
+ @Inject
+ private Configuration configuration;
+
+ public RemoteAmbariCluster get(String clusterName){
+ RemoteAmbariCluster remoteAmbariCluster = clusterMap.get(clusterName);
+ if(remoteAmbariCluster == null){
+ RemoteAmbariCluster cluster = getCluster(clusterName);
+ RemoteAmbariCluster oldCluster = clusterMap.putIfAbsent(clusterName, cluster);
+ if(oldCluster == null) remoteAmbariCluster = cluster;
+ else remoteAmbariCluster = oldCluster;
+ }
+ return remoteAmbariCluster;
+ }
+
+
+ private RemoteAmbariCluster getCluster(String clusterName) {
+ RemoteAmbariClusterEntity remoteAmbariClusterEntity = remoteAmbariClusterDAO.findByName(clusterName);
+ RemoteAmbariCluster remoteAmbariCluster = new RemoteAmbariCluster(remoteAmbariClusterEntity, configuration);
+ return remoteAmbariCluster;
+ }
+
+ /**
+ * Update the remote cluster properties
+ *
+ * @param entity
+ */
+ public void update(RemoteAmbariClusterEntity entity){
+ remoteAmbariClusterDAO.update(entity);
+ clusterMap.remove(entity.getName());
+ }
+
+ /**
+ * Remove the cluster entity from registry and database
+ *
+ * @param entity
+ */
+ public void delete(RemoteAmbariClusterEntity entity) {
+ remoteAmbariClusterDAO.delete(entity);
+ clusterMap.remove(entity.getName());
+ }
+
+ /**
+ * Save Remote Cluster Entity after setting services.
+ *
+ * @param entity
+ * @param update
+ * @throws IOException
+ * @throws AmbariHttpException
+ */
+ public void saveOrUpdate(RemoteAmbariClusterEntity entity, boolean update) throws IOException, AmbariHttpException {
+ RemoteAmbariCluster cluster = new RemoteAmbariCluster(entity,configuration);
+ Set<String> services = cluster.getServices();
+ Collection<RemoteAmbariClusterServiceEntity> serviceEntities = new ArrayList<RemoteAmbariClusterServiceEntity>();
+
+ for (String service : services) {
+ RemoteAmbariClusterServiceEntity serviceEntity = new RemoteAmbariClusterServiceEntity();
+ serviceEntity.setServiceName(service);
+ serviceEntity.setCluster(entity);
+ serviceEntities.add(serviceEntity);
+ }
+
+ entity.setServices(serviceEntities);
+
+ if(update){
+ update(entity);
+ }else{
+ remoteAmbariClusterDAO.save(entity);
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/ambari-server/src/main/java/org/apache/ambari/server/view/RemoteAmbariConfigurationReadException.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/view/RemoteAmbariConfigurationReadException.java b/ambari-server/src/main/java/org/apache/ambari/server/view/RemoteAmbariConfigurationReadException.java
new file mode 100644
index 0000000..a80fe35
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/view/RemoteAmbariConfigurationReadException.java
@@ -0,0 +1,29 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.view;
+
+/**
+ * Exception while reading Remote Ambari Configuration
+ */
+public class RemoteAmbariConfigurationReadException extends RuntimeException{
+
+ public RemoteAmbariConfigurationReadException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/ambari-server/src/main/java/org/apache/ambari/server/view/RemoteAmbariStreamProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/view/RemoteAmbariStreamProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/view/RemoteAmbariStreamProvider.java
new file mode 100644
index 0000000..f043521
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/view/RemoteAmbariStreamProvider.java
@@ -0,0 +1,118 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.view;
+
+import org.apache.ambari.server.configuration.ComponentSSLConfiguration;
+import org.apache.ambari.server.controller.internal.URLStreamProvider;
+import org.apache.ambari.server.proxy.ProxyService;
+import org.apache.ambari.view.AmbariHttpException;
+import org.apache.ambari.view.AmbariStreamProvider;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.io.IOUtils;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Provider of an input stream for a request to the Remote Ambari server.
+ */
+public class RemoteAmbariStreamProvider implements AmbariStreamProvider {
+
+ private String baseUrl;
+
+ private String username;
+
+ private String password;
+
+ private URLStreamProvider urlStreamProvider;
+
+ public RemoteAmbariStreamProvider(String baseUrl, String username, String password, int connectTimeout, int readTimeout) {
+ this.baseUrl = baseUrl;
+ this.username = username;
+ this.password = password;
+
+ ComponentSSLConfiguration sslConfiguration = ComponentSSLConfiguration.instance();
+ this.urlStreamProvider =
+ new URLStreamProvider(
+ connectTimeout,
+ readTimeout,
+ sslConfiguration.getTruststorePath(),
+ sslConfiguration.getTruststorePassword(),
+ sslConfiguration.getTruststoreType());
+ }
+
+ @Override
+ public InputStream readFrom(String path, String requestMethod, String body, Map<String, String> headers) throws IOException, AmbariHttpException {
+ return getInputStream(urlStreamProvider.processURL(getUrl(path), requestMethod, body, addHeaders(headers)));
+ }
+
+ @Override
+ public InputStream readFrom(String path, String requestMethod, InputStream body, Map<String, String> headers) throws IOException, AmbariHttpException {
+ return getInputStream(urlStreamProvider.processURL(getUrl(path), requestMethod, body, addHeaders(headers)));
+ }
+
+ private InputStream getInputStream(HttpURLConnection connection) throws IOException, AmbariHttpException {
+ int responseCode = connection.getResponseCode();
+ if(responseCode >= ProxyService.HTTP_ERROR_RANGE_START){
+ throw new AmbariHttpException(IOUtils.toString(connection.getErrorStream()),responseCode);
+ }
+ return connection.getInputStream();
+ }
+
+ private String getUrl(String path){
+ String basePath = baseUrl;
+ return path.startsWith("/") ? basePath + path : basePath + "/" + path;
+ }
+
+ private void addRequestedByHeaders(HashMap<String, String> newHeaders) {
+ newHeaders.put("X-Requested-By", "AMBARI");
+ }
+
+ private Map<String,List<String>> modifyHeaders(Map<String,String> headers){
+ Map<String, List<String>> headerMap = new HashMap<String, List<String>>();
+ for (Map.Entry<String, String> entry : headers.entrySet()) {
+ headerMap.put(entry.getKey(), Collections.singletonList(entry.getValue()));
+ }
+ return headerMap;
+ }
+
+ private Map<String, List<String>> addHeaders(Map<String, String> customHeaders) {
+ HashMap<String, String> newHeaders = new HashMap<String, String>();
+ if (customHeaders != null)
+ newHeaders.putAll(customHeaders);
+
+ addBasicAuthHeaders(newHeaders);
+ addRequestedByHeaders(newHeaders);
+ return modifyHeaders(newHeaders);
+ }
+
+ private void addBasicAuthHeaders(HashMap<String, String> headers) {
+ String authString = username + ":" + password;
+ byte[] authEncBytes = Base64.encodeBase64(authString.getBytes());
+ String authStringEnc = new String(authEncBytes);
+
+ headers.put("Authorization", "Basic " + authStringEnc);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/ambari-server/src/main/java/org/apache/ambari/server/view/ViewAmbariStreamProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/view/ViewAmbariStreamProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/view/ViewAmbariStreamProvider.java
index 1dacd92..5e0f3fa 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/view/ViewAmbariStreamProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/view/ViewAmbariStreamProvider.java
@@ -21,11 +21,14 @@ package org.apache.ambari.server.view;
import org.apache.ambari.server.controller.AmbariManagementController;
import org.apache.ambari.server.controller.AmbariSessionManager;
import org.apache.ambari.server.controller.internal.URLStreamProvider;
+import org.apache.ambari.server.proxy.ProxyService;
+import org.apache.ambari.view.AmbariHttpException;
import org.apache.ambari.view.AmbariStreamProvider;
import org.apache.commons.io.IOUtils;
import java.io.IOException;
import java.io.InputStream;
+import java.net.HttpURLConnection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
@@ -73,39 +76,37 @@ public class ViewAmbariStreamProvider implements AmbariStreamProvider {
// ----- AmbariStreamProvider -----------------------------------------------
@Override
- public InputStream readFrom(String path, String requestMethod, String body, Map<String, String> headers,
- boolean useAmbariSession) throws IOException {
- return getInputStream(path, requestMethod, headers, useAmbariSession, body == null ? null : body.getBytes());
+ public InputStream readFrom(String path, String requestMethod, String body, Map<String, String> headers
+ ) throws IOException, AmbariHttpException {
+ return getInputStream(path, requestMethod, headers, body == null ? null : body.getBytes());
}
@Override
- public InputStream readFrom(String path, String requestMethod, InputStream body, Map<String, String> headers,
- boolean useAmbariSession) throws IOException {
+ public InputStream readFrom(String path, String requestMethod, InputStream body, Map<String, String> headers
+ ) throws IOException, AmbariHttpException {
- return getInputStream(path, requestMethod, headers, useAmbariSession, body == null ? null : IOUtils.toByteArray(body));
+ return getInputStream(path, requestMethod, headers, body == null ? null : IOUtils.toByteArray(body));
}
// ----- helper methods ----------------------------------------------------
- private InputStream getInputStream(String path, String requestMethod, Map<String, String> headers,
- boolean useAmbariSession, byte[] body) throws IOException {
+ private InputStream getInputStream(String path, String requestMethod, Map<String, String> headers
+ , byte[] body) throws IOException, AmbariHttpException {
// add the Ambari session cookie to the given headers
- if (useAmbariSession) {
- String sessionId = ambariSessionManager.getCurrentSessionId();
- if (sessionId != null) {
+ String sessionId = ambariSessionManager.getCurrentSessionId();
+ if (sessionId != null) {
- String ambariSessionCookie = ambariSessionManager.getSessionCookie() + "=" + sessionId;
+ String ambariSessionCookie = ambariSessionManager.getSessionCookie() + "=" + sessionId;
- if (headers == null || headers.isEmpty()) {
- headers = Collections.singletonMap(URLStreamProvider.COOKIE, ambariSessionCookie);
- } else {
- headers = new HashMap<String, String>(headers);
+ if (headers == null || headers.isEmpty()) {
+ headers = Collections.singletonMap(URLStreamProvider.COOKIE, ambariSessionCookie);
+ } else {
+ headers = new HashMap<String, String>(headers);
- String cookies = headers.get(URLStreamProvider.COOKIE);
+ String cookies = headers.get(URLStreamProvider.COOKIE);
- headers.put(URLStreamProvider.COOKIE, URLStreamProvider.appendCookie(cookies, ambariSessionCookie));
- }
+ headers.put(URLStreamProvider.COOKIE, URLStreamProvider.appendCookie(cookies, ambariSessionCookie));
}
}
@@ -115,8 +116,16 @@ public class ViewAmbariStreamProvider implements AmbariStreamProvider {
headerMap.put(entry.getKey(), Collections.singletonList(entry.getValue()));
}
- return streamProvider.processURL(controller.getAmbariServerURI(path.startsWith("/") ? path : "/" + path),
- requestMethod, body, headerMap).getInputStream();
+ return getInputStream(streamProvider.processURL(controller.getAmbariServerURI(path.startsWith("/") ? path : "/" + path),
+ requestMethod, body, headerMap));
+ }
+
+ private InputStream getInputStream(HttpURLConnection connection) throws IOException, AmbariHttpException {
+ int responseCode = connection.getResponseCode();
+ if(responseCode >= ProxyService.HTTP_ERROR_RANGE_START){
+ throw new AmbariHttpException(IOUtils.toString(connection.getErrorStream()),responseCode);
+ }
+ return connection.getInputStream();
}
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/ambari-server/src/main/java/org/apache/ambari/server/view/ViewContextImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/view/ViewContextImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/view/ViewContextImpl.java
index ba7f446..e98a4cd 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/view/ViewContextImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/view/ViewContextImpl.java
@@ -31,6 +31,7 @@ import org.apache.ambari.server.view.persistence.DataStoreImpl;
import org.apache.ambari.server.view.persistence.DataStoreModule;
import org.apache.ambari.server.view.validation.ValidationException;
import org.apache.ambari.view.AmbariStreamProvider;
+import org.apache.ambari.view.ClusterType;
import org.apache.ambari.view.DataStore;
import org.apache.ambari.view.ImpersonatorSetting;
import org.apache.ambari.view.MaskException;
@@ -54,7 +55,6 @@ import org.apache.hadoop.security.authentication.util.KerberosUtil;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.exception.ParseErrorException;
-import sun.security.krb5.KrbException;
import java.io.StringWriter;
import java.io.Writer;
@@ -305,6 +305,27 @@ public class ViewContextImpl implements ViewContext, ViewController {
}
@Override
+ public AmbariStreamProvider getAmbariClusterStreamProvider() {
+
+ String clusterHandle = viewInstanceEntity.getClusterHandle();
+ ClusterType clusterType = viewInstanceEntity.getClusterType();
+
+ AmbariStreamProvider clusterStreamProvider = null;
+
+ if(clusterHandle != null && clusterType == ClusterType.LOCAL_AMBARI){
+
+ clusterStreamProvider = getAmbariStreamProvider();
+
+ } else if(clusterHandle != null && clusterType == ClusterType.REMOTE_AMBARI){
+
+ clusterStreamProvider = viewRegistry.createRemoteAmbariStreamProvider(clusterHandle);
+
+ }
+
+ return clusterStreamProvider;
+ }
+
+ @Override
public synchronized DataStore getDataStore() {
if (viewInstanceEntity != null) {
if (dataStore == null) {
http://git-wip-us.apache.org/repos/asf/ambari/blob/c150f0de/ambari-server/src/main/java/org/apache/ambari/server/view/ViewRegistry.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/view/ViewRegistry.java b/ambari-server/src/main/java/org/apache/ambari/server/view/ViewRegistry.java
index d2d48a9..6d4ef82 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/view/ViewRegistry.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/view/ViewRegistry.java
@@ -45,6 +45,7 @@ import org.apache.ambari.server.orm.dao.MemberDAO;
import org.apache.ambari.server.orm.dao.PermissionDAO;
import org.apache.ambari.server.orm.dao.PrincipalDAO;
import org.apache.ambari.server.orm.dao.PrivilegeDAO;
+import org.apache.ambari.server.orm.dao.RemoteAmbariClusterDAO;
import org.apache.ambari.server.orm.dao.ResourceDAO;
import org.apache.ambari.server.orm.dao.ResourceTypeDAO;
import org.apache.ambari.server.orm.dao.UserDAO;
@@ -55,6 +56,7 @@ import org.apache.ambari.server.orm.entities.MemberEntity;
import org.apache.ambari.server.orm.entities.PermissionEntity;
import org.apache.ambari.server.orm.entities.PrincipalEntity;
import org.apache.ambari.server.orm.entities.PrivilegeEntity;
+import org.apache.ambari.server.orm.entities.RemoteAmbariClusterEntity;
import org.apache.ambari.server.orm.entities.ResourceEntity;
import org.apache.ambari.server.orm.entities.ResourceTypeEntity;
import org.apache.ambari.server.orm.entities.UserEntity;
@@ -83,6 +85,8 @@ import org.apache.ambari.server.view.configuration.PropertyConfig;
import org.apache.ambari.server.view.configuration.ResourceConfig;
import org.apache.ambari.server.view.configuration.ViewConfig;
import org.apache.ambari.server.view.validation.ValidationException;
+import org.apache.ambari.view.AmbariStreamProvider;
+import org.apache.ambari.view.ClusterType;
import org.apache.ambari.view.Masker;
import org.apache.ambari.view.SystemException;
import org.apache.ambari.view.View;
@@ -134,6 +138,7 @@ public class ViewRegistry {
protected static final int DEFAULT_REQUEST_READ_TIMEOUT = 10000;
private static final String VIEW_AMBARI_VERSION_REGEXP = "^((\\d+\\.)?)*(\\*|\\d+)$";
private static final String VIEW_LOG_FILE = "view.log4j.properties";
+ public static final String API_PREFIX = "/api/v1/clusters/";
/**
* Thread pool
@@ -281,6 +286,18 @@ public class ViewRegistry {
@Inject
AmbariSessionManager ambariSessionManager;
+ /**
+ * Registry for Remote Ambari Cluster
+ */
+ @Inject
+ RemoteAmbariClusterRegistry remoteAmbariClusterRegistry;
+
+ /**
+ * Remote Ambari Cluster Dao
+ */
+ @Inject
+ RemoteAmbariClusterDAO remoteAmbariClusterDAO;
+
// ----- Constructors -----------------------------------------------------
@@ -896,12 +913,14 @@ public class ViewRegistry {
if (viewInstance != null) {
String clusterId = viewInstance.getClusterHandle();
- if (clusterId != null) {
+ if (clusterId != null && viewInstance.getClusterType() == ClusterType.LOCAL_AMBARI) {
try {
return new ClusterImpl(clustersProvider.get().getCluster(clusterId));
} catch (AmbariException e) {
LOG.warn("Could not find the cluster identified by " + clusterId + ".");
}
+ } else if(clusterId != null && viewInstance.getClusterType() == ClusterType.REMOTE_AMBARI){
+ return remoteAmbariClusterRegistry.get(clusterId);
}
}
return null;
@@ -1409,6 +1428,7 @@ public class ViewRegistry {
instance1.setResource(instance2.getResource());
instance1.setViewInstanceId(instance2.getViewInstanceId());
instance1.setClusterHandle(instance2.getClusterHandle());
+ instance1.setClusterType(instance2.getClusterType());
instance1.setData(instance2.getData());
instance1.setEntities(instance2.getEntities());
instance1.setProperties(instance2.getProperties());
@@ -1884,6 +1904,34 @@ public class ViewRegistry {
return new ViewAmbariStreamProvider(streamProvider, ambariSessionManager, AmbariServer.getController());
}
+ /**
+ * Get Remote Ambari Cluster Stream provider
+ *
+ * @param clusterName
+ * @return
+ */
+ protected AmbariStreamProvider createRemoteAmbariStreamProvider(String clusterName){
+ RemoteAmbariClusterEntity clusterEntity = remoteAmbariClusterDAO.findByName(clusterName);
+ if(clusterEntity != null) {
+ return new RemoteAmbariStreamProvider(getBaseurl(clusterEntity.getUrl()),
+ clusterEntity.getUsername(),clusterEntity.getPassword(),
+ configuration.getViewAmbariRequestConnectTimeout(),configuration.getViewAmbariRequestReadTimeout());
+ }
+ return null;
+ }
+
+ /**
+ * Get baseurl of the cluster
+ * baseurl wil be http://host:port
+ *
+ * @param url will be in format like http://host:port/api/v1/clusters/clusterName
+ * @return baseurl
+ */
+ private String getBaseurl(String url){
+ int index = url.indexOf(API_PREFIX);
+ return url.substring(0,index);
+ }
+