You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by yu...@apache.org on 2014/05/31 09:21:16 UTC
[12/12] git commit: AMBARI-5482. Integrate Ambari Shell. (Janos
Matyas and Krisztian Horvath via yusaku)
AMBARI-5482. Integrate Ambari Shell. (Janos Matyas and Krisztian Horvath via yusaku)
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/11dd9df8
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/11dd9df8
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/11dd9df8
Branch: refs/heads/trunk
Commit: 11dd9df85b0470a283feb2d2cde75a5a46927e86
Parents: c6402f5
Author: Yusaku Sako <yu...@hortonworks.com>
Authored: Sat May 31 07:02:19 2014 +0000
Committer: Yusaku Sako <yu...@hortonworks.com>
Committed: Sat May 31 07:02:19 2014 +0000
----------------------------------------------------------------------
ambari-client/assemblies/client.xml | 20 +
ambari-client/groovy-client/pom.xml | 113 +++
.../ambari/groovy/client/AmbariClient.groovy | 510 +++++++++++
.../client/AmbariConnectionException.groovy | 27 +
.../ambari/groovy/client/DoNotDeleteMe.java | 26 +
.../resources/blueprints/multi-node-hdfs-yarn | 57 ++
.../resources/blueprints/single-node-hdfs-yarn | 48 +
.../AmbariClientTest.groovy | 425 +++++++++
.../apache/ambari/groovy/client/NeitherMe.java | 27 +
.../src/test/resources/blueprint.json | 48 +
.../src/test/resources/blueprints.json | 21 +
.../src/test/resources/cluster.json | 16 +
.../test/resources/hdfsServiceComponents.json | 63 ++
.../src/test/resources/services.json | 14 +
.../groovy-client/src/test/resources/tasks.json | 471 ++++++++++
ambari-client/pom.xml | 151 +---
ambari-client/python-client/pom.xml | 195 ++++
.../python-client/src/examples/create.py | 147 +++
.../python-client/src/examples/delete.py | 66 ++
.../python-client/src/examples/example.py | 133 +++
.../python-client/src/examples/main.py | 166 ++++
.../python-client/src/examples/trial.py | 145 +++
.../src/main/python/ambari_client/__init__.py | 16 +
.../src/main/python/ambari_client/ambari_api.py | 185 ++++
.../main/python/ambari_client/core/__init__.py | 16 +
.../main/python/ambari_client/core/coreutils.py | 16 +
.../main/python/ambari_client/core/errors.py | 78 ++
.../python/ambari_client/core/http_client.py | 175 ++++
.../python/ambari_client/core/http_utils.py | 52 ++
.../python/ambari_client/core/rest_resource.py | 120 +++
.../main/python/ambari_client/model/__init__.py | 16 +
.../python/ambari_client/model/base_model.py | 109 +++
.../main/python/ambari_client/model/cluster.py | 331 +++++++
.../python/ambari_client/model/component.py | 97 ++
.../python/ambari_client/model/configuration.py | 138 +++
.../src/main/python/ambari_client/model/host.py | 255 ++++++
.../main/python/ambari_client/model/paths.py | 50 +
.../main/python/ambari_client/model/service.py | 203 +++++
.../main/python/ambari_client/model/stack.py | 79 ++
.../main/python/ambari_client/model/status.py | 71 ++
.../main/python/ambari_client/model/utils.py | 231 +++++
.../python/ambari_client/resources/__init__.py | 16 +
.../python/ambari_client/resources/clusters.py | 58 ++
.../python/ambari_client/resources/hosts.py | 127 +++
.../python/ambari_client/resources/stacks.py | 41 +
.../python-client/src/main/python/setup.py | 39 +
.../python-client/src/packages/tarball/all.xml | 34 +
.../src/test/python/TestAmbariClient.py | 211 +++++
.../src/test/python/TestClusterModel.py | 428 +++++++++
.../src/test/python/TestComponentModel.py | 54 ++
.../src/test/python/TestHostModel.py | 80 ++
.../src/test/python/TestServiceModel.py | 105 +++
.../src/test/python/TestStatusModel.py | 82 ++
.../json/ambariclient_bootstrap_hosts.json | 5 +
.../json/ambariclient_get_all_clusters.json | 12 +
.../python/json/ambariclient_get_all_hosts.json | 77 ++
.../json/ambariclient_get_components.json | 53 ++
.../python/json/ambariclient_get_config.json | 905 +++++++++++++++++++
.../test/python/json/ambariclient_get_host.json | 63 ++
.../json/clustermodel_error_deleting_host.json | 4 +
.../python/json/clustermodel_get_all_hosts.json | 375 ++++++++
.../json/clustermodel_get_all_services.json | 120 +++
.../python/json/clustermodel_get_cluster.json | 103 +++
.../json/clustermodel_get_core_site_config.json | 32 +
.../json/clustermodel_get_global_config.json | 64 ++
.../json/clustermodel_get_hdfs_site_config.json | 53 ++
.../test/python/json/clustermodel_get_host.json | 250 +++++
.../clustermodel_get_mapred_site_config.json | 58 ++
.../python/json/clustermodel_get_service.json | 29 +
.../python/json/componentmodel_get_metrics.json | 133 +++
.../test/python/json/get_cluster_service.json | 27 +
.../python/json/get_components_from_stack.json | 41 +
.../test/python/json/get_host_component.json | 41 +
.../test/python/json/get_host_components.json | 60 ++
.../test/python/json/get_service_component.json | 108 +++
.../python/json/get_service_components.json | 133 +++
.../json/hostmodel_get_host_component.json | 181 ++++
.../json/hostmodel_get_host_components.json | 222 +++++
.../python/json/servicemodel_get_component.json | 20 +
.../json/servicemodel_get_components.json | 61 ++
.../python/json/status_error_with_message.json | 4 +
.../src/test/python/json/status_ok_with_id.json | 7 +
.../python-client/src/test/python/unitTests.py | 119 +++
.../src/test/python/utils/HttpClientInvoker.py | 153 ++++
ambari-client/src/examples/create.py | 147 ---
ambari-client/src/examples/delete.py | 66 --
ambari-client/src/examples/example.py | 133 ---
ambari-client/src/examples/main.py | 166 ----
ambari-client/src/examples/trial.py | 145 ---
.../src/main/python/ambari_client/__init__.py | 16 -
.../src/main/python/ambari_client/ambari_api.py | 185 ----
.../main/python/ambari_client/core/__init__.py | 16 -
.../main/python/ambari_client/core/coreutils.py | 16 -
.../main/python/ambari_client/core/errors.py | 78 --
.../python/ambari_client/core/http_client.py | 175 ----
.../python/ambari_client/core/http_utils.py | 52 --
.../python/ambari_client/core/rest_resource.py | 120 ---
.../main/python/ambari_client/model/__init__.py | 16 -
.../python/ambari_client/model/base_model.py | 109 ---
.../main/python/ambari_client/model/cluster.py | 331 -------
.../python/ambari_client/model/component.py | 97 --
.../python/ambari_client/model/configuration.py | 138 ---
.../src/main/python/ambari_client/model/host.py | 255 ------
.../main/python/ambari_client/model/paths.py | 50 -
.../main/python/ambari_client/model/service.py | 203 -----
.../main/python/ambari_client/model/stack.py | 79 --
.../main/python/ambari_client/model/status.py | 71 --
.../main/python/ambari_client/model/utils.py | 231 -----
.../python/ambari_client/resources/__init__.py | 16 -
.../python/ambari_client/resources/clusters.py | 58 --
.../python/ambari_client/resources/hosts.py | 127 ---
.../python/ambari_client/resources/stacks.py | 41 -
ambari-client/src/main/python/setup.py | 39 -
ambari-client/src/packages/tarball/all.xml | 34 -
.../src/test/python/TestAmbariClient.py | 211 -----
.../src/test/python/TestClusterModel.py | 428 ---------
.../src/test/python/TestComponentModel.py | 54 --
ambari-client/src/test/python/TestHostModel.py | 80 --
.../src/test/python/TestServiceModel.py | 105 ---
.../src/test/python/TestStatusModel.py | 82 --
.../json/ambariclient_bootstrap_hosts.json | 5 -
.../json/ambariclient_get_all_clusters.json | 12 -
.../python/json/ambariclient_get_all_hosts.json | 77 --
.../json/ambariclient_get_components.json | 53 --
.../python/json/ambariclient_get_config.json | 905 -------------------
.../test/python/json/ambariclient_get_host.json | 63 --
.../json/clustermodel_error_deleting_host.json | 4 -
.../python/json/clustermodel_get_all_hosts.json | 375 --------
.../json/clustermodel_get_all_services.json | 120 ---
.../python/json/clustermodel_get_cluster.json | 103 ---
.../json/clustermodel_get_core_site_config.json | 32 -
.../json/clustermodel_get_global_config.json | 64 --
.../json/clustermodel_get_hdfs_site_config.json | 53 --
.../test/python/json/clustermodel_get_host.json | 250 -----
.../clustermodel_get_mapred_site_config.json | 58 --
.../python/json/clustermodel_get_service.json | 29 -
.../python/json/componentmodel_get_metrics.json | 133 ---
.../test/python/json/get_cluster_service.json | 27 -
.../python/json/get_components_from_stack.json | 41 -
.../test/python/json/get_host_component.json | 41 -
.../test/python/json/get_host_components.json | 60 --
.../test/python/json/get_service_component.json | 108 ---
.../python/json/get_service_components.json | 133 ---
.../json/hostmodel_get_host_component.json | 181 ----
.../json/hostmodel_get_host_components.json | 222 -----
.../python/json/servicemodel_get_component.json | 20 -
.../json/servicemodel_get_components.json | 61 --
.../python/json/status_error_with_message.json | 4 -
.../src/test/python/json/status_ok_with_id.json | 7 -
ambari-client/src/test/python/unitTests.py | 119 ---
.../src/test/python/utils/HttpClientInvoker.py | 153 ----
ambari-project/pom.xml | 72 +-
ambari-shell/pom.xml | 120 +++
.../org/apache/ambari/shell/AmbariShell.java | 110 +++
.../ambari/shell/commands/BasicCommands.java | 173 ++++
.../shell/commands/BlueprintCommands.java | 184 ++++
.../ambari/shell/commands/ClusterCommands.java | 260 ++++++
.../ambari/shell/commands/ElephantCommand.java | 53 ++
.../ambari/shell/commands/HostCommands.java | 117 +++
.../configuration/ConverterConfiguration.java | 125 +++
.../shell/configuration/ShellConfiguration.java | 102 +++
.../shell/customization/AmbariBanner.java | 50 +
.../shell/customization/AmbariPrompt.java | 43 +
.../ambari/shell/model/AmbariContext.java | 159 ++++
.../org/apache/ambari/shell/model/Focus.java | 53 ++
.../apache/ambari/shell/model/FocusType.java | 55 ++
.../org/apache/ambari/shell/model/Hints.java | 59 ++
.../ambari/shell/support/TableRenderer.java | 121 +++
ambari-shell/src/main/resources/elephant.txt | 8 +
.../shell/commands/BlueprintCommandsTest.java | 115 +++
.../shell/commands/ClusterCommandsTest.java | 246 +++++
.../ambari/shell/commands/HostCommandsTest.java | 65 ++
.../shell/customization/AmbariPromptTest.java | 54 ++
.../ambari/shell/model/AmbariContextTest.java | 66 ++
.../ambari/shell/support/TableRendererTest.java | 54 ++
ambari-shell/src/test/resources/2columns | 5 +
ambari-shell/src/test/resources/3columns | 5 +
.../src/test/resources/testBlueprint.json | 48 +
pom.xml | 2 +
179 files changed, 12282 insertions(+), 7840 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/ambari/blob/11dd9df8/ambari-client/assemblies/client.xml
----------------------------------------------------------------------
diff --git a/ambari-client/assemblies/client.xml b/ambari-client/assemblies/client.xml
new file mode 100644
index 0000000..20670cd
--- /dev/null
+++ b/ambari-client/assemblies/client.xml
@@ -0,0 +1,20 @@
+<?xml version="1.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.
+-->
+<assembly>
+</assembly>
http://git-wip-us.apache.org/repos/asf/ambari/blob/11dd9df8/ambari-client/groovy-client/pom.xml
----------------------------------------------------------------------
diff --git a/ambari-client/groovy-client/pom.xml b/ambari-client/groovy-client/pom.xml
new file mode 100644
index 0000000..ed34848
--- /dev/null
+++ b/ambari-client/groovy-client/pom.xml
@@ -0,0 +1,113 @@
+<?xml version="1.0"?>
+<!-- Licensed 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.
+ See accompanying LICENSE file. -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <parent>
+ <artifactId>ambari-client</artifactId>
+ <groupId>org.apache.ambari</groupId>
+ <version>1.3.0-SNAPSHOT</version>
+ <relativePath>../../ambari-client/</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.apache.ambari</groupId>
+ <artifactId>groovy-client</artifactId>
+ <packaging>jar</packaging>
+ <version>1.3.0-SNAPSHOT</version>
+ <name>Ambari Groovy Client</name>
+ <description>Ambari Groovy client</description>
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ </properties>
+ <dependencies>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-log4j12</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.codehaus.groovy</groupId>
+ <artifactId>groovy-all</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.codehaus.groovy.modules.http-builder</groupId>
+ <artifactId>http-builder</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.easymock</groupId>
+ <artifactId>easymock</artifactId>
+ <version>3.2</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.spockframework</groupId>
+ <artifactId>spock-core</artifactId>
+ <version>0.7-groovy-2.0</version>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <!-- 2.8.0-01 and later require maven-compiler-plugin 3.1 or higher -->
+ <version>3.1</version>
+ <configuration>
+ <compilerId>groovy-eclipse-compiler</compilerId>
+ </configuration>
+ <dependencies>
+ <dependency>
+ <groupId>org.codehaus.groovy</groupId>
+ <artifactId>groovy-eclipse-compiler</artifactId>
+ <version>2.8.0-01</version>
+ </dependency>
+ <!-- for 2.8.0-01 and later you must have an explicit dependency on
+ groovy-eclipse-batch -->
+ <dependency>
+ <groupId>org.codehaus.groovy</groupId>
+ <artifactId>groovy-eclipse-batch</artifactId>
+ <version>2.1.8-01</version>
+ </dependency>
+ </dependencies>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.rat</groupId>
+ <artifactId>apache-rat-plugin</artifactId>
+ <configuration>
+ <excludes>
+ <exclude>src/main/resources/blueprints/multi-node-hdfs-yarn</exclude>
+ <exclude>src/main/resources/blueprints/single-node-hdfs-yarn</exclude>
+ <exclude>src/test/resources/blueprint.json</exclude>
+ <exclude>src/test/resources/blueprints.json</exclude>
+ <exclude>src/test/resources/cluster.json</exclude>
+ <exclude>src/test/resources/hdfsServiceComponents.json</exclude>
+ <exclude>src/test/resources/services.json</exclude>
+ <exclude>src/test/resources/tasks.json</exclude>
+ </excludes>
+ </configuration>
+ <executions>
+ <execution>
+ <phase>test</phase>
+ <goals>
+ <goal>check</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <configuration>
+ <skipAssembly>true</skipAssembly>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ambari/blob/11dd9df8/ambari-client/groovy-client/src/main/groovy/org/apache/ambari/groovy/client/AmbariClient.groovy
----------------------------------------------------------------------
diff --git a/ambari-client/groovy-client/src/main/groovy/org/apache/ambari/groovy/client/AmbariClient.groovy b/ambari-client/groovy-client/src/main/groovy/org/apache/ambari/groovy/client/AmbariClient.groovy
new file mode 100644
index 0000000..5b05c60
--- /dev/null
+++ b/ambari-client/groovy-client/src/main/groovy/org/apache/ambari/groovy/client/AmbariClient.groovy
@@ -0,0 +1,510 @@
+/**
+ * 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.groovy.client
+
+import groovy.json.JsonBuilder
+import groovy.json.JsonSlurper
+import groovyx.net.http.HttpResponseException
+import groovyx.net.http.RESTClient
+import org.apache.http.NoHttpResponseException
+import org.apache.http.client.ClientProtocolException
+import org.slf4j.Logger
+import org.slf4j.LoggerFactory
+
+/**
+ * Basic client to send requests to the Ambari server.
+ */
+class AmbariClient {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(AmbariClient.class)
+ private static final int PAD = 30
+ private static final int OK_RESPONSE = 200
+ boolean debugEnabled = false;
+ def RESTClient ambari
+ def slurper = new JsonSlurper()
+ def clusterName
+
+ /**
+ * Connects to the ambari server.
+ *
+ * @param host host of the Ambari server; default value is localhost
+ * @param port port of the Ambari server; default value is 8080
+ * @param user username of the Ambari server; default is admin
+ * @param password password fom the Ambari server; default is admin
+ */
+ AmbariClient(host = 'localhost', port = '8080', user = 'admin', password = 'admin') {
+ ambari = new RESTClient("http://${host}:${port}/api/v1/" as String)
+ ambari.headers['Authorization'] = 'Basic ' + "$user:$password".getBytes('iso-8859-1').encodeBase64()
+ ambari.headers['X-Requested-By'] = 'ambari'
+ }
+
+ /**
+ * Connects to the ambari server.
+ *
+ * @param restClient underlying client
+ * @param slurper slurper to parse responses
+ */
+ AmbariClient(RESTClient restClient, JsonSlurper slurper) {
+ this.ambari = restClient
+ this.slurper = slurper
+ }
+
+ /**
+ * Sets the debug variable. Used by printing the API calls for the Ambari Shell.
+ *
+ * @param enabled enable or disable
+ */
+ def setDebugEnabled(boolean enabled) {
+ debugEnabled = enabled;
+ }
+
+ /**
+ * Returns the name of the cluster.
+ *
+ * @return the name of the cluster of null if no cluster yet
+ */
+ def String getClusterName() {
+ if (!clusterName) {
+ def clusters = getClusters();
+ if (clusters) {
+ clusterName = clusters.items[0]?.Clusters?.cluster_name
+ }
+ }
+ return clusterName
+ }
+
+ /**
+ * Checks whether the blueprint exists or not.
+ *
+ * @param id id of the blueprint
+ * @return true if exists false otherwise
+ */
+ def boolean doesBlueprintExists(String id) {
+ def result = false
+ try {
+ result = ambari.get(path: "blueprints/$id", query: ['fields': "Blueprints"]).status == OK_RESPONSE
+ } catch (e) {
+ LOGGER.info("Blueprint does not exist", e)
+ }
+ return result
+ }
+
+ /**
+ * Checks whether there are available blueprints or not.
+ *
+ * @return true if blueprints are available false otherwise
+ */
+ def boolean isBlueprintAvailable() {
+ return getBlueprints().items?.size > 0
+ }
+
+ /**
+ * Returns a pre-formatted String of the blueprint.
+ *
+ * @param id id of the blueprint
+ * @return formatted String
+ */
+ def String showBlueprint(String id) {
+ def resp = getBlueprint(id)
+ if (resp) {
+ def groups = resp.host_groups.collect {
+ def name = it.name
+ def comps = it.components.collect { it.name.padRight(PAD).padLeft(PAD + 10) }.join("\n")
+ return "HOSTGROUP: $name\n$comps"
+ }.join("\n")
+ return "[${resp.Blueprints.stack_name}:${resp.Blueprints.stack_version}]\n$groups"
+ }
+ return "Not found"
+ }
+
+ /**
+ * Returns the host group - components mapping of the blueprint.
+ *
+ * @param id id of the blueprint
+ * @return Map where the key is the host group and the value is the list of components
+ */
+ def Map<String, List<String>> getBlueprintMap(String id) {
+ def result = getBlueprint(id).host_groups?.collectEntries { [(it.name): it.components.collect { it.name }] }
+ result ?: new HashMap()
+ }
+
+ /**
+ * Returns a pre-formatted String of the blueprints.
+ *
+ * @return formatted blueprint list
+ */
+ def String showBlueprints() {
+ getBlueprints().items.collect { "${it.Blueprints.blueprint_name.padRight(PAD)} [${it.Blueprints.stack_name}:${it.Blueprints.stack_version}]" }.join("\n")
+ }
+
+ /**
+ * Returns a Map containing the blueprint name - stack association.
+ *
+ * @return Map where the key is the blueprint's name value is the used stack
+ */
+ def Map<String, String> getBlueprintsMap() {
+ def result = getBlueprints().items?.collectEntries { [(it.Blueprints.blueprint_name): it.Blueprints.stack_name + ":" + it.Blueprints.stack_version] }
+ result ?: new HashMap()
+ }
+
+ /**
+ * Returns the name of the host groups for a given blueprint.
+ *
+ * @param blueprint id of the blueprint
+ * @return host group list or empty list
+ */
+ def List<String> getHostGroups(String blueprint) {
+ def result = getBlueprint(blueprint)
+ result ? result.host_groups.collect { it.name } : new ArrayList<String>()
+ }
+
+ /**
+ * Returns a pre-formatted String of a blueprint used by the cluster.
+ *
+ * @return formatted String
+ */
+ def String showClusterBlueprint() {
+ ambari.get(path: "clusters/${getClusterName()}", query: ['format': "blueprint"]).data.text
+ }
+
+ /**
+ * Adds a blueprint to the Ambari server. Exception is thrown if fails.
+ *
+ * @param json blueprint as json
+ * @throws HttpResponseException in case of error
+ */
+ def void addBlueprint(String json) throws HttpResponseException {
+ if (json) {
+ postBlueprint(json)
+ }
+ }
+
+ /**
+ * Adds 2 default blueprints.
+ *
+ * @throws HttpResponseException in case of error
+ */
+ def void addDefaultBlueprints() throws HttpResponseException {
+ addBlueprint(getResourceContent("blueprints/multi-node-hdfs-yarn"))
+ addBlueprint(getResourceContent("blueprints/single-node-hdfs-yarn"))
+ }
+
+ /**
+ * Creates a cluster with the given blueprint and host group - host association.
+ *
+ * @param clusterName name of the cluster
+ * @param blueprintName blueprint id used to create this cluster
+ * @param hostGroups Map<String, List<String> key - host group, value - host list
+ * @return true if the creation was successful false otherwise
+ * @throws HttpResponseException in case of error
+ */
+ def void createCluster(String clusterName, String blueprintName, Map<String, List<String>> hostGroups) throws HttpResponseException {
+ ambari.post(path: "clusters/$clusterName", body: createClusterJson(blueprintName, hostGroups), { it })
+ }
+
+ /**
+ * Deletes the cluster.
+ *
+ * @param clusterName name of the cluster
+ * @throws HttpResponseException in case of error
+ */
+ def void deleteCluster(String clusterName) throws HttpResponseException {
+ ambari.delete(path: "clusters/$clusterName")
+ }
+
+ /**
+ * Returns the active cluster as json
+ *
+ * @return cluster as json String
+ * @throws HttpResponseException in case of error
+ */
+ def String getClusterAsJson() throws HttpResponseException {
+ getRequest("clusters/${getClusterName()}")
+ }
+
+ /**
+ * Returns all clusters as json
+ *
+ * @return json String
+ * @throws HttpResponseException in case of error
+ */
+ def getClustersAsJson() throws HttpResponseException {
+ getRequest("clusters")
+ }
+
+ /**
+ * Returns a pre-formatted String of the clusters.
+ *
+ * @return pre-formatted cluster list
+ */
+ def String showClusterList() {
+ getClusters().items.collect { "[$it.Clusters.cluster_id] $it.Clusters.cluster_name:$it.Clusters.version" }.join("\n")
+ }
+
+ /**
+ * Returns the task properties as Map.
+ *
+ * @param request request id; default is 1
+ * @return property Map or empty Map
+ */
+ def getTasks(request = 1) {
+ getAllResources("requests/$request", "tasks/Tasks")
+ }
+
+ /**
+ * Returns a pre-formatted task list.
+ *
+ * @param request request id; default is 1
+ * @return pre-formatted task list
+ */
+ def String showTaskList(request = 1) {
+ getTasks(request)?.tasks.collect { "${it.Tasks.command_detail.padRight(PAD)} [${it.Tasks.status}]" }.join("\n")
+ }
+
+ /**
+ * Returns a Map containing the task's command detail as key and the task's status as value.
+ *
+ * @param request request id; default is 1
+ * @return key task command detail; task value status
+ */
+ def Map<String, String> getTaskMap(request = 1) {
+ def result = getTasks(request).tasks?.collectEntries { [(it.Tasks.command_detail): it.Tasks.status] }
+ result ?: new HashMap()
+ }
+
+ /**
+ * Returns the available host names and its states.
+ *
+ * @return hostname state association
+ */
+ def Map<String, String> getHostNames() {
+ getHosts().items.collectEntries { [(it.Hosts.host_name): it.Hosts.host_status] }
+ }
+
+ /**
+ * Returns a pre-formatted list of the hosts.
+ *
+ * @return pre-formatted String
+ */
+ def String showHostList() {
+ getHosts().items.collect { "$it.Hosts.host_name [$it.Hosts.host_status] $it.Hosts.ip $it.Hosts.os_type:$it.Hosts.os_arch" }.join("\n")
+ }
+
+ /**
+ * Returns a pre-formatted list of the service components.
+ *
+ * @return pre-formatted String
+ */
+ def String showServiceComponents() {
+ getServices().items.collect {
+ def name = it.ServiceInfo.service_name
+ def state = it.ServiceInfo.state
+ def componentList = getServiceComponents(name).items.collect {
+ " ${it.ServiceComponentInfo.component_name.padRight(PAD)} [$it.ServiceComponentInfo.state]"
+ }.join("\n")
+ "${name.padRight(PAD)} [$state]\n$componentList"
+ }.join("\n")
+ }
+
+ /**
+ * Returns the service components properties as Map where the key is the service name and
+ * value is a component - state association.
+ *
+ * @return service name - [component name - status]
+ */
+ def Map<String, Map<String, String>> getServiceComponentsMap() {
+ def result = getServices().items.collectEntries {
+ def name = it.ServiceInfo.service_name
+ def componentList = getServiceComponents(name).items.collectEntries { [(it.ServiceComponentInfo.component_name): it.ServiceComponentInfo.state] }
+ [(name): componentList]
+ }
+ result ?: new HashMap()
+ }
+
+ /**
+ * Returns a pre-formatted service list.
+ *
+ * @return formatted String
+ */
+ def String showServiceList() {
+ getServices().items.collect { "${it.ServiceInfo.service_name.padRight(PAD)} [$it.ServiceInfo.state]" }.join("\n")
+ }
+
+ /**
+ * Returns the services properties as Map where the key is the service's name and the values is the service's state.
+ *
+ * @return service name - service state association as Map
+ */
+ def Map<String, String> getServicesMap() {
+ def result = getServices().items.collectEntries { [(it.ServiceInfo.service_name): it.ServiceInfo.state] }
+ result ?: new HashMap()
+ }
+
+ /**
+ * Returns a pre-formatted component list of a host.
+ *
+ * @param host which host's components are requested
+ * @return formatted String
+ */
+ def String showHostComponentList(host) {
+ getHostComponents(host).items.collect { "${it.HostRoles.component_name.padRight(PAD)} [$it.HostRoles.state]" }.join("\n")
+ }
+
+ /**
+ * Returns the host's components as Map where the key is the component's name and values is its state.
+ *
+ * @param host which host's components are requested
+ * @return component name - state association
+ */
+ def Map<String, String> getHostComponentsMap(host) {
+ def result = getHostComponents(host).items?.collectEntries { [(it.HostRoles.component_name): it.HostRoles.state] }
+ result ?: new HashMap()
+ }
+
+ /**
+ * Returns the blueprint json as String.
+ *
+ * @param id id of the blueprint
+ * @return json as String, exception if thrown is it fails
+ */
+ def String getBlueprintAsJson(id) {
+ return getRequest("blueprints/$id", "host_groups,Blueprints")
+ }
+
+ private def getAllResources(resourceName, fields) {
+ slurp("clusters/${getClusterName()}/$resourceName", "$fields/*")
+ }
+
+ /**
+ * Posts the blueprint JSON to Ambari with name 'bp' in the URL
+ * because it does not matter here. The blueprint's name is
+ * provided in the JSON.
+ *
+ * @param blueprint json
+ * @return response message
+ */
+ private void postBlueprint(String blueprint) {
+ ambari.post(path: "blueprints/bp", body: blueprint, { it })
+ }
+
+ private def createClusterJson(String name, Map hostGroups) {
+ def builder = new JsonBuilder()
+ def groups = hostGroups.collect {
+ def hostList = it.value.collect { ['fqdn': it] }
+ [name: it.key, hosts: hostList]
+ }
+ builder { "blueprint" name; "host-groups" groups }
+ builder.toPrettyString()
+ }
+
+ private def slurp(path, fields = "") {
+ def baseUri = ambari.getUri();
+ if (debugEnabled) {
+ println "[DEBUG] ${baseUri}${path}?fields=$fields"
+ }
+ def result = new HashMap()
+ try {
+ result = slurper.parseText(getRequest(path, fields))
+ } catch (e) {
+ if (e instanceof NoHttpResponseException || e instanceof ConnectException || e instanceof ClientProtocolException ||
+ e instanceof UnknownHostException || (e instanceof HttpResponseException && e.message == "Bad credentials")) {
+ throw new AmbariConnectionException("Cannot connect to Ambari $baseUri")
+ }
+ LOGGER.error("Error occurred during GET request to $baseUri/$path", e)
+ }
+ return result
+ }
+
+ /**
+ * Return the blueprint's properties as a Map.
+ *
+ * @param id id of the blueprint
+ * @return properties as Map
+ */
+ private def getBlueprint(id) {
+ slurp("blueprints/$id", "host_groups,Blueprints")
+ }
+
+ /**
+ * Returns a Map containing the blueprint's properties parsed from the Ambari response json.
+ *
+ * @return blueprint's properties as Map or empty Map
+ */
+ private def getBlueprints() {
+ slurp("blueprints", "Blueprints")
+ }
+
+ /**
+ * Returns a Map containing the cluster's properties parsed from the Ambari response json.
+ *
+ * @return cluster's properties as Map or empty Map
+ */
+ private def getClusters() {
+ slurp("clusters", "Clusters")
+ }
+
+ /**
+ * Returns the available hosts properties as a Map.
+ *
+ * @return Map containing the hosts properties
+ */
+ private def getHosts() {
+ slurp("hosts", "Hosts")
+ }
+
+ /**
+ * Returns the service components properties as Map.
+ *
+ * @param service id of the service
+ * @return service component properties as Map
+ */
+ private def getServiceComponents(service) {
+ getAllResources("services/$service/components", "ServiceComponentInfo")
+ }
+
+ /**
+ * Returns the services properties as Map parsed from Ambari response json.
+ *
+ * @return service properties as Map
+ */
+ private def getServices() {
+ getAllResources("services", "ServiceInfo")
+ }
+
+ /**
+ * Returns the properties of the host components as a Map parsed from the Ambari response json.
+ *
+ * @param host which host's components are requested
+ * @return component properties as Map
+ */
+ private def getHostComponents(host) {
+ getAllResources("hosts/$host/host_components", "HostRoles")
+ }
+
+ private String getRequest(path, fields = "") {
+ if (fields) {
+ ambari.get(path: "$path", query: ['fields': "$fields"]).data.text
+ } else {
+ ambari.get(path: "$path").data.text
+ }
+ }
+
+ private String getResourceContent(name) {
+ getClass().getClassLoader().getResourceAsStream(name)?.text
+ }
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/11dd9df8/ambari-client/groovy-client/src/main/groovy/org/apache/ambari/groovy/client/AmbariConnectionException.groovy
----------------------------------------------------------------------
diff --git a/ambari-client/groovy-client/src/main/groovy/org/apache/ambari/groovy/client/AmbariConnectionException.groovy b/ambari-client/groovy-client/src/main/groovy/org/apache/ambari/groovy/client/AmbariConnectionException.groovy
new file mode 100644
index 0000000..f88223c
--- /dev/null
+++ b/ambari-client/groovy-client/src/main/groovy/org/apache/ambari/groovy/client/AmbariConnectionException.groovy
@@ -0,0 +1,27 @@
+/**
+ * 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.groovy.client
+
+/**
+ * Exception used to indicate that there are connection issues.
+ */
+class AmbariConnectionException extends RuntimeException {
+ public AmbariConnectionException(String s) {
+ super(s)
+ }
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/11dd9df8/ambari-client/groovy-client/src/main/java/org/apache/ambari/groovy/client/DoNotDeleteMe.java
----------------------------------------------------------------------
diff --git a/ambari-client/groovy-client/src/main/java/org/apache/ambari/groovy/client/DoNotDeleteMe.java b/ambari-client/groovy-client/src/main/java/org/apache/ambari/groovy/client/DoNotDeleteMe.java
new file mode 100644
index 0000000..6b2ec19
--- /dev/null
+++ b/ambari-client/groovy-client/src/main/java/org/apache/ambari/groovy/client/DoNotDeleteMe.java
@@ -0,0 +1,26 @@
+/**
+ * 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.groovy.client;
+
+/**
+ * The maven plugin will only compile the groovy classes into the jar
+ * if it contains at least one java class, otherwise it will tell you that
+ * there are no source classes found.
+ */
+public class DoNotDeleteMe {
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/11dd9df8/ambari-client/groovy-client/src/main/resources/blueprints/multi-node-hdfs-yarn
----------------------------------------------------------------------
diff --git a/ambari-client/groovy-client/src/main/resources/blueprints/multi-node-hdfs-yarn b/ambari-client/groovy-client/src/main/resources/blueprints/multi-node-hdfs-yarn
new file mode 100644
index 0000000..0630453
--- /dev/null
+++ b/ambari-client/groovy-client/src/main/resources/blueprints/multi-node-hdfs-yarn
@@ -0,0 +1,57 @@
+{
+ "host_groups" : [
+ {
+ "name" : "master",
+ "components" : [
+ {
+ "name" : "NAMENODE"
+ },
+ {
+ "name" : "SECONDARY_NAMENODE"
+ },
+ {
+ "name" : "RESOURCEMANAGER"
+ },
+ {
+ "name" : "HISTORYSERVER"
+ },
+ {
+ "name" : "NAGIOS_SERVER"
+ },
+ {
+ "name" : "ZOOKEEPER_SERVER"
+ }
+ ],
+ "cardinality" : "1"
+ },
+ {
+ "name" : "slaves",
+ "components" : [
+ {
+ "name" : "DATANODE"
+ },
+ {
+ "name" : "HDFS_CLIENT"
+ },
+ {
+ "name" : "NODEMANAGER"
+ },
+ {
+ "name" : "YARN_CLIENT"
+ },
+ {
+ "name" : "MAPREDUCE2_CLIENT"
+ },
+ {
+ "name" : "ZOOKEEPER_CLIENT"
+ }
+ ],
+ "cardinality" : "2"
+ }
+ ],
+ "Blueprints" : {
+ "blueprint_name" : "multi-node-hdfs-yarn",
+ "stack_name" : "HDP",
+ "stack_version" : "2.0"
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ambari/blob/11dd9df8/ambari-client/groovy-client/src/main/resources/blueprints/single-node-hdfs-yarn
----------------------------------------------------------------------
diff --git a/ambari-client/groovy-client/src/main/resources/blueprints/single-node-hdfs-yarn b/ambari-client/groovy-client/src/main/resources/blueprints/single-node-hdfs-yarn
new file mode 100644
index 0000000..1a7d302
--- /dev/null
+++ b/ambari-client/groovy-client/src/main/resources/blueprints/single-node-hdfs-yarn
@@ -0,0 +1,48 @@
+{
+ "host_groups" : [
+ {
+ "name" : "host_group_1",
+ "components" : [
+ {
+ "name" : "NAMENODE"
+ },
+ {
+ "name" : "SECONDARY_NAMENODE"
+ },
+ {
+ "name" : "DATANODE"
+ },
+ {
+ "name" : "HDFS_CLIENT"
+ },
+ {
+ "name" : "RESOURCEMANAGER"
+ },
+ {
+ "name" : "NODEMANAGER"
+ },
+ {
+ "name" : "YARN_CLIENT"
+ },
+ {
+ "name" : "HISTORYSERVER"
+ },
+ {
+ "name" : "MAPREDUCE2_CLIENT"
+ },
+ {
+ "name" : "ZOOKEEPER_SERVER"
+ },
+ {
+ "name" : "ZOOKEEPER_CLIENT"
+ }
+ ],
+ "cardinality" : "1"
+ }
+ ],
+ "Blueprints" : {
+ "blueprint_name" : "single-node-hdfs-yarn",
+ "stack_name" : "HDP",
+ "stack_version" : "2.0"
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ambari/blob/11dd9df8/ambari-client/groovy-client/src/test/groovy/com.sequenceiq.ambari.client/AmbariClientTest.groovy
----------------------------------------------------------------------
diff --git a/ambari-client/groovy-client/src/test/groovy/com.sequenceiq.ambari.client/AmbariClientTest.groovy b/ambari-client/groovy-client/src/test/groovy/com.sequenceiq.ambari.client/AmbariClientTest.groovy
new file mode 100644
index 0000000..77ad26a
--- /dev/null
+++ b/ambari-client/groovy-client/src/test/groovy/com.sequenceiq.ambari.client/AmbariClientTest.groovy
@@ -0,0 +1,425 @@
+/**
+ * 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.groovy.client
+
+import groovy.json.JsonSlurper
+import groovyx.net.http.HttpResponseDecorator
+import groovyx.net.http.HttpResponseException
+import groovyx.net.http.RESTClient
+import spock.lang.Specification
+
+class AmbariClientTest extends Specification {
+
+ def rest = Mock(RESTClient)
+ def slurper = Mock(JsonSlurper)
+ def decorator = Mock(HttpResponseDecorator)
+ def ambari = new AmbariClient(rest, slurper)
+ def realSlurper = new JsonSlurper()
+
+ def "test get the name of the cluster"() {
+ given:
+ def request = [path: "clusters", query: [fields: "Clusters"]]
+ def items = new ArrayList()
+ items.add([Clusters: [cluster_name: "cluster1"]])
+ def mockResponse = ["items": items]
+ rest.get(request) >> decorator
+ decorator.data >> [text: "map"]
+ slurper.parseText("map") >> mockResponse
+
+ when:
+ def result = ambari.getClusterName()
+
+ then:
+ "cluster1" == result
+ }
+
+ def "test get the name when there is no cluster"() {
+ given:
+ def request = [path: "clusters", query: [fields: "Clusters"]]
+ def mockResponse = ["items": new ArrayList()]
+ rest.get(request) >> decorator
+ decorator.data >> [text: "map"]
+ slurper.parseText("map") >> mockResponse
+
+ when:
+ def result = ambari.getClusterName()
+
+ then:
+ null == result
+ }
+
+ def "test if blueprint does not exists"() {
+ given:
+ decorator.status >> 500
+ def request = [path: "blueprints/bp", query: ['fields': "Blueprints"]]
+ rest.get(request) >> decorator
+
+ when:
+ def result = ambari.doesBlueprintExists("bp")
+
+ then:
+ result == false
+ }
+
+ def "test if blueprint exists"() {
+ given:
+ decorator.status >> 200
+ def request = [path: "blueprints/bp", query: ['fields': "Blueprints"]]
+ rest.get(request) >> decorator
+
+ when:
+ def result = ambari.doesBlueprintExists("bp")
+
+ then:
+ result == true
+ }
+
+ def "test get blueprint as map"() {
+ given:
+ def request = [path: "blueprints/bp", query: [fields: "host_groups,Blueprints"]]
+ rest.get(request) >> decorator
+ decorator.data >> [text: "map"]
+ def mockResponse = [host_groups: [[name: "bp", components: [[name: "hdfs"], [name: "yarn"]]]]]
+ slurper.parseText("map") >> mockResponse
+
+ when:
+ def response = ambari.getBlueprintMap("bp")
+
+ then:
+ [bp: ["hdfs", "yarn"]] == response
+ }
+
+ def "test get blueprint as map for empty result"() {
+ given:
+ def request = [path: "blueprints/bp", query: [fields: "host_groups,Blueprints"]]
+ rest.get(request) >> decorator
+ decorator.data >> [text: "map"]
+ slurper.parseText("map") >> [:]
+
+ when:
+ def response = ambari.getBlueprintMap("bp")
+
+ then:
+ [:] == response
+ }
+
+ def "test get host groups"() {
+ given:
+ def request = [path: "blueprints/bp", query: [fields: "host_groups,Blueprints"]]
+ rest.get(request) >> decorator
+ decorator.data >> [text: "map"]
+ slurper.parseText("map") >> [host_groups: [[name: "group1"], [name: "group2"]]]
+
+ when:
+ def result = ambari.getHostGroups("bp")
+
+ then:
+ ["group1", "group2"] == result
+ }
+
+ def "test get host groups for no groups"() {
+ given:
+ def request = [path: "blueprints/bp", query: [fields: "host_groups,Blueprints"]]
+ rest.get(request) >> decorator
+ decorator.data >> [text: "map"]
+ slurper.parseText("map") >> null
+
+ when:
+ def result = ambari.getHostGroups("bp")
+
+ then:
+ [] == result
+ }
+
+ def "test get host names"() {
+ given:
+ def request = [path: "hosts", query: [fields: "Hosts"]]
+ rest.get(request) >> decorator
+ decorator.data >> [text: "map"]
+ def hosts = [[Hosts: [host_name: "server.ambari.com", host_status: "HEALTHY"]]]
+ def mapResponse = [items: hosts]
+ slurper.parseText("map") >> mapResponse
+
+ when:
+ def result = ambari.getHostNames()
+
+ then:
+ "HEALTHY" == result["server.ambari.com"]
+ 1 == result.size()
+ }
+
+ def "test get host names for empty result"() {
+ given:
+ def request = [path: "hosts", query: [fields: "Hosts"]]
+ rest.get(request) >> decorator
+ decorator.data >> [text: "map"]
+ slurper.parseText("map") >> []
+
+ when:
+ def result = ambari.getHostNames()
+
+ then:
+ [:] == result
+ }
+
+ def "test add blueprint for success"() {
+ given:
+ def json = getClass().getResourceAsStream("blueprint.json")
+ def request = [path: "blueprints/bp", body: json]
+ rest.post(request, { it })
+
+ when:
+ ambari.addBlueprint(json)
+
+ then:
+ notThrown(HttpResponseException)
+ }
+
+ def "test add blueprint for empty json"() {
+ given:
+ def request = [path: "blueprints/bp", body: ""]
+ rest.post(request, { it })
+
+ when:
+ ambari.addBlueprint("")
+
+ then:
+ notThrown(HttpResponseException)
+ }
+
+ def "test create cluster json"() {
+ given:
+ def json = getClass().getResourceAsStream("/cluster.json").text
+ def groups = [host_group_1: ["server.ambari.com", "server2.ambari.com"]]
+ def request = [path: "clusters/c1", body: json]
+
+ when:
+ ambari.createCluster("c1", "c1", groups)
+
+ then:
+ 1 * rest.post(request, { it })
+ }
+
+ def "test get task as map"() {
+ given:
+ //get the name of the cluster
+ def req1 = [path: "clusters", query: [fields: "Clusters"]]
+ def items = new ArrayList()
+ items.add([Clusters: [cluster_name: "cluster1"]])
+ def mockResponse = ["items": items]
+ rest.get(req1) >> decorator
+ decorator.data >> [text: "map"]
+ slurper.parseText("map") >> mockResponse
+ // get the actual tasks
+ def req2 = [path: "clusters/cluster1/requests/1", query: ['fields': "tasks/Tasks/*"]]
+ def decorator2 = Mock(HttpResponseDecorator)
+ rest.get(req2) >> decorator2
+ decorator2.data >> [text: "map2"]
+ def json = realSlurper.parseText(getClass().getResourceAsStream("/tasks.json").text)
+ slurper.parseText("map2") >> json
+
+ when:
+ def result = ambari.getTaskMap()
+
+ then:
+ ["DATANODE INSTALL" : "COMPLETED",
+ "DATANODE START" : "COMPLETED",
+ "HDFS_CLIENT INSTALL" : "COMPLETED",
+ "HISTORYSERVER INSTALL" : "COMPLETED",
+ "HISTORYSERVER START" : "COMPLETED",
+ "MAPREDUCE2_CLIENT INSTALL" : "COMPLETED",
+ "NAMENODE INSTALL" : "COMPLETED",
+ "NAMENODE START" : "COMPLETED",
+ "NODEMANAGER INSTALL" : "COMPLETED",
+ "NODEMANAGER START" : "COMPLETED",
+ "RESOURCEMANAGER INSTALL" : "COMPLETED",
+ "RESOURCEMANAGER START" : "COMPLETED",
+ "SECONDARY_NAMENODE INSTALL": "COMPLETED",
+ "SECONDARY_NAMENODE START" : "COMPLETED",
+ "YARN_CLIENT INSTALL" : "COMPLETED",
+ "ZOOKEEPER_CLIENT INSTALL" : "COMPLETED",
+ "ZOOKEEPER_SERVER INSTALL" : "COMPLETED",
+ "ZOOKEEPER_SERVER START" : "COMPLETED"
+ ] == result
+ }
+
+ def "test get task as map for no task"() {
+ given:
+ //get the name of the cluster
+ def req1 = [path: "clusters", query: [fields: "Clusters"]]
+ def items = new ArrayList()
+ items.add([Clusters: [cluster_name: "cluster1"]])
+ def mockResponse = ["items": items]
+ rest.get(req1) >> decorator
+ decorator.data >> [text: "map"]
+ slurper.parseText("map") >> mockResponse
+ // get the actual tasks
+ def req2 = [path: "clusters/cluster1/requests/1", query: ['fields': "tasks/Tasks/*"]]
+ def decorator2 = Mock(HttpResponseDecorator)
+ rest.get(req2) >> decorator2
+ decorator2.data >> [text: "map2"]
+ slurper.parseText("map2") >> [:]
+
+ when:
+ def result = ambari.getTaskMap()
+
+ then:
+ [:] == result
+ }
+
+ def "test get service components map"() {
+ given:
+ // get the name of the cluster
+ def req1 = [path: "clusters", query: [fields: "Clusters"]]
+ def items = new ArrayList()
+ items.add([Clusters: [cluster_name: "cluster1"]])
+ def mockResponse = ["items": items]
+ rest.get(req1) >> decorator
+ decorator.data >> [text: "map"]
+ slurper.parseText("map") >> mockResponse
+ // get the services
+ def req2 = [path: "clusters/cluster1/services", query: ['fields': "ServiceInfo/*"]]
+ def decorator2 = Mock(HttpResponseDecorator)
+ rest.get(req2) >> decorator2
+ decorator2.data >> [text: "dec"]
+ def json = realSlurper.parseText(getClass().getResourceAsStream("/services.json").text)
+ slurper.parseText("dec") >> json
+ // get service components
+ def req3 = [path: "clusters/cluster1/services/HDFS/components", query: ['fields': "ServiceComponentInfo/*"]]
+ def decorator3 = Mock(HttpResponseDecorator)
+ rest.get(req3) >> decorator3
+ decorator3.data >> [text: "dec3"]
+ def json2 = realSlurper.parseText(getClass().getResourceAsStream("/hdfsServiceComponents.json").text)
+ slurper.parseText("dec3") >> json2
+
+ when:
+ def Map result = ambari.getServiceComponentsMap()
+
+ then:
+ [HDFS: [
+ DATANODE : "STARTED",
+ HDFS_CLIENT : "INSTALLED",
+ NAMENODE : "STARTED",
+ SECONDARY_NAMENODE: "STARTED"]
+ ] == result
+ }
+
+ def "test get service components map for empty services"() {
+ given:
+ // get the name of the cluster
+ def req1 = [path: "clusters", query: [fields: "Clusters"]]
+ def items = new ArrayList()
+ items.add([Clusters: [cluster_name: "cluster1"]])
+ def mockResponse = ["items": items]
+ rest.get(req1) >> decorator
+ decorator.data >> [text: "map"]
+ slurper.parseText("map") >> mockResponse
+ // get the services
+ def req2 = [path: "clusters/cluster1/services", query: ['fields': "ServiceInfo/*"]]
+ def decorator2 = Mock(HttpResponseDecorator)
+ rest.get(req2) >> decorator2
+ decorator2.data >> [text: "dec"]
+ slurper.parseText("dec") >> []
+
+ when:
+ def Map result = ambari.getServiceComponentsMap()
+
+ then:
+ [:] == result
+ }
+
+ def "test get service components map for empty components"() {
+ given:
+ // get the name of the cluster
+ def req1 = [path: "clusters", query: [fields: "Clusters"]]
+ def items = new ArrayList()
+ items.add([Clusters: [cluster_name: "cluster1"]])
+ def mockResponse = ["items": items]
+ rest.get(req1) >> decorator
+ decorator.data >> [text: "map"]
+ slurper.parseText("map") >> mockResponse
+ // get the services
+ def req2 = [path: "clusters/cluster1/services", query: ['fields': "ServiceInfo/*"]]
+ def decorator2 = Mock(HttpResponseDecorator)
+ rest.get(req2) >> decorator2
+ decorator2.data >> [text: "dec"]
+ def json = realSlurper.parseText(getClass().getResourceAsStream("/services.json").text)
+ slurper.parseText("dec") >> json
+ // get service components
+ def req3 = [path: "clusters/cluster1/services/HDFS/components", query: ['fields': "ServiceComponentInfo/*"]]
+ def decorator3 = Mock(HttpResponseDecorator)
+ rest.get(req3) >> decorator3
+ decorator3.data >> [text: "dec3"]
+ slurper.parseText("dec3") >> []
+
+ when:
+ def Map result = ambari.getServiceComponentsMap()
+
+ then:
+ [HDFS: [:]] == result
+ }
+
+ def "test get services as map"() {
+ given:
+ // get the name of the cluster
+ def req1 = [path: "clusters", query: [fields: "Clusters"]]
+ def items = new ArrayList()
+ items.add([Clusters: [cluster_name: "cluster1"]])
+ def mockResponse = ["items": items]
+ rest.get(req1) >> decorator
+ decorator.data >> [text: "map"]
+ slurper.parseText("map") >> mockResponse
+ // get the services
+ def req2 = [path: "clusters/cluster1/services", query: ['fields': "ServiceInfo/*"]]
+ def decorator2 = Mock(HttpResponseDecorator)
+ rest.get(req2) >> decorator2
+ decorator2.data >> [text: "dec"]
+ def json = realSlurper.parseText(getClass().getResourceAsStream("/services.json").text)
+ slurper.parseText("dec") >> json
+
+ when:
+ def result = ambari.getServicesMap()
+
+ then:
+ [HDFS: "STARTED"] == result
+ }
+
+ def "test get services as map for empty result"() {
+ given:
+ // get the name of the cluster
+ def req1 = [path: "clusters", query: [fields: "Clusters"]]
+ def items = new ArrayList()
+ items.add([Clusters: [cluster_name: "cluster1"]])
+ def mockResponse = ["items": items]
+ rest.get(req1) >> decorator
+ decorator.data >> [text: "map"]
+ slurper.parseText("map") >> mockResponse
+ // get the services
+ def req2 = [path: "clusters/cluster1/services", query: ['fields': "ServiceInfo/*"]]
+ def decorator2 = Mock(HttpResponseDecorator)
+ rest.get(req2) >> decorator2
+ decorator2.data >> [text: "dec"]
+ slurper.parseText("dec") >> []
+
+ when:
+ def result = ambari.getServicesMap()
+
+ then:
+ [:] == result
+ }
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/11dd9df8/ambari-client/groovy-client/src/test/java/org/apache/ambari/groovy/client/NeitherMe.java
----------------------------------------------------------------------
diff --git a/ambari-client/groovy-client/src/test/java/org/apache/ambari/groovy/client/NeitherMe.java b/ambari-client/groovy-client/src/test/java/org/apache/ambari/groovy/client/NeitherMe.java
new file mode 100644
index 0000000..18d3579
--- /dev/null
+++ b/ambari-client/groovy-client/src/test/java/org/apache/ambari/groovy/client/NeitherMe.java
@@ -0,0 +1,27 @@
+/**
+ * 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.groovy.client;
+
+/**
+ * The maven plugin will only run the tests if it contains
+ * at least one java class.
+ *
+ * @see org.apache.ambari.groovy.client.DoNotDeleteMe
+ */
+public class NeitherMe {
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/11dd9df8/ambari-client/groovy-client/src/test/resources/blueprint.json
----------------------------------------------------------------------
diff --git a/ambari-client/groovy-client/src/test/resources/blueprint.json b/ambari-client/groovy-client/src/test/resources/blueprint.json
new file mode 100644
index 0000000..1a7d302
--- /dev/null
+++ b/ambari-client/groovy-client/src/test/resources/blueprint.json
@@ -0,0 +1,48 @@
+{
+ "host_groups" : [
+ {
+ "name" : "host_group_1",
+ "components" : [
+ {
+ "name" : "NAMENODE"
+ },
+ {
+ "name" : "SECONDARY_NAMENODE"
+ },
+ {
+ "name" : "DATANODE"
+ },
+ {
+ "name" : "HDFS_CLIENT"
+ },
+ {
+ "name" : "RESOURCEMANAGER"
+ },
+ {
+ "name" : "NODEMANAGER"
+ },
+ {
+ "name" : "YARN_CLIENT"
+ },
+ {
+ "name" : "HISTORYSERVER"
+ },
+ {
+ "name" : "MAPREDUCE2_CLIENT"
+ },
+ {
+ "name" : "ZOOKEEPER_SERVER"
+ },
+ {
+ "name" : "ZOOKEEPER_CLIENT"
+ }
+ ],
+ "cardinality" : "1"
+ }
+ ],
+ "Blueprints" : {
+ "blueprint_name" : "single-node-hdfs-yarn",
+ "stack_name" : "HDP",
+ "stack_version" : "2.0"
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ambari/blob/11dd9df8/ambari-client/groovy-client/src/test/resources/blueprints.json
----------------------------------------------------------------------
diff --git a/ambari-client/groovy-client/src/test/resources/blueprints.json b/ambari-client/groovy-client/src/test/resources/blueprints.json
new file mode 100644
index 0000000..208a954
--- /dev/null
+++ b/ambari-client/groovy-client/src/test/resources/blueprints.json
@@ -0,0 +1,21 @@
+{
+ "href" : "http://localhost:49233/api/v1/blueprints?fields=Blueprints",
+ "items" : [
+ {
+ "href" : "http://localhost:49233/api/v1/blueprints/multi-node-hdfs-yarn",
+ "Blueprints" : {
+ "blueprint_name" : "multi-node-hdfs-yarn",
+ "stack_name" : "HDP",
+ "stack_version" : "2.0"
+ }
+ },
+ {
+ "href" : "http://localhost:49233/api/v1/blueprints/single-node-hdfs-yarn",
+ "Blueprints" : {
+ "blueprint_name" : "single-node-hdfs-yarn",
+ "stack_name" : "HDP",
+ "stack_version" : "2.0"
+ }
+ }
+ ]
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ambari/blob/11dd9df8/ambari-client/groovy-client/src/test/resources/cluster.json
----------------------------------------------------------------------
diff --git a/ambari-client/groovy-client/src/test/resources/cluster.json b/ambari-client/groovy-client/src/test/resources/cluster.json
new file mode 100644
index 0000000..886a960
--- /dev/null
+++ b/ambari-client/groovy-client/src/test/resources/cluster.json
@@ -0,0 +1,16 @@
+{
+ "blueprint": "c1",
+ "host-groups": [
+ {
+ "name": "host_group_1",
+ "hosts": [
+ {
+ "fqdn": "server.ambari.com"
+ },
+ {
+ "fqdn": "server2.ambari.com"
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ambari/blob/11dd9df8/ambari-client/groovy-client/src/test/resources/hdfsServiceComponents.json
----------------------------------------------------------------------
diff --git a/ambari-client/groovy-client/src/test/resources/hdfsServiceComponents.json b/ambari-client/groovy-client/src/test/resources/hdfsServiceComponents.json
new file mode 100644
index 0000000..b4f8e50
--- /dev/null
+++ b/ambari-client/groovy-client/src/test/resources/hdfsServiceComponents.json
@@ -0,0 +1,63 @@
+{
+ "href" : "http://localhost:49271/api/v1/clusters/single-node-hdfs-yarn/services/HDFS/components?fields=ServiceComponentInfo/*",
+ "items" : [
+ {
+ "href" : "http://localhost:49271/api/v1/clusters/single-node-hdfs-yarn/services/HDFS/components/DATANODE",
+ "ServiceComponentInfo" : {
+ "category" : "SLAVE",
+ "cluster_name" : "single-node-hdfs-yarn",
+ "component_name" : "DATANODE",
+ "service_name" : "HDFS",
+ "state" : "STARTED"
+ }
+ },
+ {
+ "href" : "http://localhost:49271/api/v1/clusters/single-node-hdfs-yarn/services/HDFS/components/HDFS_CLIENT",
+ "ServiceComponentInfo" : {
+ "category" : "CLIENT",
+ "cluster_name" : "single-node-hdfs-yarn",
+ "component_name" : "HDFS_CLIENT",
+ "service_name" : "HDFS",
+ "state" : "INSTALLED"
+ }
+ },
+ {
+ "href" : "http://localhost:49271/api/v1/clusters/single-node-hdfs-yarn/services/HDFS/components/NAMENODE",
+ "ServiceComponentInfo" : {
+ "CapacityRemaining" : 31924920320,
+ "CapacityTotal" : 39078707200,
+ "CapacityUsed" : 24576,
+ "DeadNodes" : "{}",
+ "DecomNodes" : "{}",
+ "HeapMemoryMax" : 1052770304,
+ "HeapMemoryUsed" : 100962448,
+ "LiveNodes" : "{\"server.ambari.com\":{\"infoAddr\":\"172.17.0.2:50075\",\"infoSecureAddr\":\"172.17.0.2:0\",\"xferaddr\":\"172.17.0.2:50010\",\"lastContact\":0,\"usedSpace\":24576,\"adminState\":\"In Service\",\"nonDfsUsedSpace\":7153762304,\"capacity\":39078707200,\"numBlocks\":0,\"version\":\"2.4.0.2.1.1.0-385\",\"used\":24576,\"remaining\":31924920320,\"blockScheduled\":0,\"blockPoolUsed\":24576,\"blockPoolUsedPercent\":6.2888466E-5,\"volfails\":0}}",
+ "NonDfsUsedSpace" : 7153762304,
+ "NonHeapMemoryMax" : 136314880,
+ "NonHeapMemoryUsed" : 33860904,
+ "PercentRemaining" : 81.6939,
+ "PercentUsed" : 6.2888466E-5,
+ "Safemode" : "",
+ "StartTime" : 1400572832732,
+ "TotalFiles" : 10,
+ "UpgradeFinalized" : true,
+ "Version" : "2.4.0.2.1.1.0-385, r68ceccf06a4441273e81a5ec856d41fc7e11c792",
+ "category" : "MASTER",
+ "cluster_name" : "single-node-hdfs-yarn",
+ "component_name" : "NAMENODE",
+ "service_name" : "HDFS",
+ "state" : "STARTED"
+ }
+ },
+ {
+ "href" : "http://localhost:49271/api/v1/clusters/single-node-hdfs-yarn/services/HDFS/components/SECONDARY_NAMENODE",
+ "ServiceComponentInfo" : {
+ "category" : "MASTER",
+ "cluster_name" : "single-node-hdfs-yarn",
+ "component_name" : "SECONDARY_NAMENODE",
+ "service_name" : "HDFS",
+ "state" : "STARTED"
+ }
+ }
+ ]
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ambari/blob/11dd9df8/ambari-client/groovy-client/src/test/resources/services.json
----------------------------------------------------------------------
diff --git a/ambari-client/groovy-client/src/test/resources/services.json b/ambari-client/groovy-client/src/test/resources/services.json
new file mode 100644
index 0000000..aceed13
--- /dev/null
+++ b/ambari-client/groovy-client/src/test/resources/services.json
@@ -0,0 +1,14 @@
+{
+ "href" : "http://localhost:49271/api/v1/clusters/single-node-hdfs-yarn/services?fields=ServiceInfo/*",
+ "items" : [
+ {
+ "href" : "http://localhost:49271/api/v1/clusters/single-node-hdfs-yarn/services/HDFS",
+ "ServiceInfo" : {
+ "cluster_name" : "single-node-hdfs-yarn",
+ "maintenance_state" : "OFF",
+ "service_name" : "HDFS",
+ "state" : "STARTED"
+ }
+ }
+ ]
+}
\ No newline at end of file