You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by su...@apache.org on 2014/07/02 19:36:52 UTC

[4/4] git commit: AMBARI-6176. Integrate python shell into Ambari-shell module(subin)

AMBARI-6176. Integrate python shell into Ambari-shell module(subin)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/c8eceafc
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/c8eceafc
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/c8eceafc

Branch: refs/heads/trunk
Commit: c8eceafc9efc6fa305519f27c21ab51531c0d7cb
Parents: 2ff2849
Author: Subin <su...@apache.org>
Authored: Wed Jul 2 23:03:34 2014 +0530
Committer: Subin <su...@apache.org>
Committed: Wed Jul 2 23:04:34 2014 +0530

----------------------------------------------------------------------
 .../src/main/python/ambari_client/ambari_api.py |  26 +-
 .../python/ambari_client/core/http_client.py    |  13 +-
 .../python/ambari_client/model/blueprint.py     |  53 +++
 .../src/main/python/ambari_client/model/host.py |   7 +-
 .../main/python/ambari_client/model/paths.py    |   2 +
 .../main/python/ambari_client/model/status.py   |  42 +-
 .../main/python/ambari_client/model/utils.py    |  39 +-
 ambari-shell/ambari-groovy-shell/pom.xml        | 142 +++++++
 .../org/apache/ambari/shell/AmbariShell.java    | 111 +++++
 .../ambari/shell/commands/BasicCommands.java    | 207 ++++++++++
 .../shell/commands/BlueprintCommands.java       | 198 +++++++++
 .../ambari/shell/commands/ClusterCommands.java  | 294 +++++++++++++
 .../ambari/shell/commands/ElephantCommand.java  |  53 +++
 .../ambari/shell/commands/HostCommands.java     | 119 ++++++
 .../ambari/shell/completion/Blueprint.java      |  34 ++
 .../apache/ambari/shell/completion/Host.java    |  34 ++
 .../configuration/ConverterConfiguration.java   | 142 +++++++
 .../shell/configuration/ShellConfiguration.java | 114 +++++
 .../shell/converter/BlueprintConverter.java     |  58 +++
 .../ambari/shell/converter/HostConverter.java   |  58 +++
 .../shell/customization/AmbariBanner.java       |  50 +++
 .../shell/customization/AmbariHistory.java      |  40 ++
 .../shell/customization/AmbariPrompt.java       |  43 ++
 .../ambari/shell/flash/AbstractFlash.java       |  66 +++
 .../apache/ambari/shell/flash/FlashService.java |  47 +++
 .../apache/ambari/shell/flash/FlashType.java    |  39 ++
 .../ambari/shell/flash/InstallProgress.java     |  79 ++++
 .../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 ++++++
 .../src/main/resources/elephant.txt             |   8 +
 .../shell/commands/BlueprintCommandsTest.java   | 128 ++++++
 .../shell/commands/ClusterCommandsTest.java     | 279 +++++++++++++
 .../ambari/shell/commands/HostCommandsTest.java |  66 +++
 .../shell/customization/AmbariPromptTest.java   |  54 +++
 .../ambari/shell/model/AmbariContextTest.java   |  66 +++
 .../ambari/shell/support/TableRendererTest.java |  54 +++
 .../src/test/resources/2columns                 |   5 +
 .../src/test/resources/3columns                 |   5 +
 .../src/test/resources/testBlueprint.json       |  48 +++
 .../ambari-python-shell/conf/unix/ambari-shell  |  62 +++
 .../conf/unix/ambari-shell.ini                  |  19 +
 ambari-shell/ambari-python-shell/pom.xml        | 237 +++++++++++
 .../src/main/package/deb/control/control        |  22 +
 .../src/main/package/deb/control/postinst       |  15 +
 .../src/main/package/deb/control/postrm         |  15 +
 .../src/main/package/deb/control/posttrm        |  15 +
 .../src/main/package/deb/control/preinst        |  15 +
 .../src/main/package/deb/control/prerm          |  15 +
 .../src/main/python/ambari_shell/__init__.py    |  16 +
 .../main/python/ambari_shell/ambari_shell.py    | 412 +++++++++++++++++++
 .../python/ambari_shell/plugins/__init__.py     |  16 +
 .../python/ambari_shell/plugins/blueprint.py    |  21 +
 .../ambari_shell/plugins/connect_cluster.py     |  81 ++++
 .../ambari_shell/plugins/create_cluster.py      |  34 ++
 .../main/python/ambari_shell/plugins/service.py | 125 ++++++
 .../python/ambari_shell/plugins/shell_config.py |  77 ++++
 .../main/python/ambari_shell/plugins/show.py    | 155 +++++++
 .../main/python/ambari_shell/utils/__init__.py  |  16 +
 .../python/ambari_shell/utils/displayutils.py   | 128 ++++++
 .../main/python/ambari_shell/utils/osutils.py   |  69 ++++
 .../python/ambari_shell/utils/pluginutils.py    | 100 +++++
 .../src/main/python/setup.py                    |  40 ++
 .../src/packages/tarball/all.xml                |  34 ++
 ambari-shell/assemblies/client.xml              |  20 +
 ambari-shell/pom.xml                            | 128 ++----
 .../org/apache/ambari/shell/AmbariShell.java    | 111 -----
 .../ambari/shell/commands/BasicCommands.java    | 207 ----------
 .../shell/commands/BlueprintCommands.java       | 198 ---------
 .../ambari/shell/commands/ClusterCommands.java  | 294 -------------
 .../ambari/shell/commands/ElephantCommand.java  |  53 ---
 .../ambari/shell/commands/HostCommands.java     | 119 ------
 .../ambari/shell/completion/Blueprint.java      |  34 --
 .../apache/ambari/shell/completion/Host.java    |  34 --
 .../configuration/ConverterConfiguration.java   | 142 -------
 .../shell/configuration/ShellConfiguration.java | 114 -----
 .../shell/converter/BlueprintConverter.java     |  58 ---
 .../ambari/shell/converter/HostConverter.java   |  58 ---
 .../shell/customization/AmbariBanner.java       |  50 ---
 .../shell/customization/AmbariHistory.java      |  40 --
 .../shell/customization/AmbariPrompt.java       |  43 --
 .../ambari/shell/flash/AbstractFlash.java       |  66 ---
 .../apache/ambari/shell/flash/FlashService.java |  47 ---
 .../apache/ambari/shell/flash/FlashType.java    |  39 --
 .../ambari/shell/flash/InstallProgress.java     |  79 ----
 .../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   | 128 ------
 .../shell/commands/ClusterCommandsTest.java     | 279 -------------
 .../ambari/shell/commands/HostCommandsTest.java |  66 ---
 .../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 ---
 102 files changed, 5039 insertions(+), 3064 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-client/python-client/src/main/python/ambari_client/ambari_api.py
----------------------------------------------------------------------
diff --git a/ambari-client/python-client/src/main/python/ambari_client/ambari_api.py b/ambari-client/python-client/src/main/python/ambari_client/ambari_api.py
index 470db36..a79d907 100644
--- a/ambari-client/python-client/src/main/python/ambari_client/ambari_api.py
+++ b/ambari-client/python-client/src/main/python/ambari_client/ambari_api.py
@@ -18,7 +18,7 @@
 import logging
 from ambari_client.core.http_client import HttpClient
 from ambari_client.core.rest_resource import RestResource
-from ambari_client.model import blueprint, stack, cluster, host
+from ambari_client.model import blueprint, stack, cluster, host, status
 
 __docformat__ = "epytext"
 
@@ -66,6 +66,13 @@ class AmbariClient(RestResource):
             if port is None:
                 port = 8080
 
+        if not http_header:
+            http_header = {'X-Requested-By': 'pythonclient'}
+        elif 'X-Requested-By' not in http_header.keys():
+            http_header.update({'X-Requested-By': 'pythonclient'})
+        else:
+            pass
+
         host_url = "%s://%s:%s/api/v%s" % (protocol, host_name, port, version)
         if client is None:
             client = HttpClient(host_url, user_name, password)
@@ -224,6 +231,15 @@ class AmbariClient(RestResource):
         """
         return cluster._task_status(self, cluster_name, requestid)
 
+    def get_requests(self, cluster_name, noOfrequest=3):
+        """
+        get components from stack
+        @param version: The HDP version.
+        @param service_name: service name
+        @return: A ConfigModel object
+        """
+        return status._get_N_requests(self, cluster_name, noOfrequest)
+
     def get_blueprint(self, blueprint_name=None):
         """
         get blueprint
@@ -232,6 +248,14 @@ class AmbariClient(RestResource):
         """
         return blueprint.get_blueprint(self, blueprint_name)
 
+    def get_cluster_blueprint(self, cluster_name):
+        """
+        get blueprint
+        @param cluster_name:cluster_name name.
+        @return: A BlueprintModel object
+        """
+        return blueprint.get_cluster_blueprint(self, cluster_name)
+
     def delete_blueprint(self, blueprint_name=None):
         """
         get blueprint

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-client/python-client/src/main/python/ambari_client/core/http_client.py
----------------------------------------------------------------------
diff --git a/ambari-client/python-client/src/main/python/ambari_client/core/http_client.py b/ambari-client/python-client/src/main/python/ambari_client/core/http_client.py
index 299b279..72b3b5f 100644
--- a/ambari-client/python-client/src/main/python/ambari_client/core/http_client.py
+++ b/ambari-client/python-client/src/main/python/ambari_client/core/http_client.py
@@ -103,6 +103,13 @@ class HttpClient(object):
         self.c.setopt(pycurl.WRITEFUNCTION, buf.write)
         self.c.setopt(pycurl.SSL_VERIFYPEER, 0)
 
+        # make sure options are reset from previous requests or your GET might
+        # become a DELETE
+        self.c.setopt(pycurl.CUSTOMREQUEST, None)
+        self.c.setopt(pycurl.HTTPGET, 0)
+        self.c.setopt(pycurl.NOBODY, 0)
+        self.c.setopt(pycurl.POST, 0)
+
         LOG.debug("invoke : url = " + str(url))
         # set http_method
         if http_method == "GET":
@@ -121,9 +128,9 @@ class HttpClient(object):
         if http_method in ('POST', 'PUT'):
             LOG.debug("data..........." + str(payload))
             data = json.dumps(payload)
-            #data= data.decode('unicode-escape')
-            #LOG.debug( "after unicode decode")
-            #LOG.debug( data)
+            # data= data.decode('unicode-escape')
+            # LOG.debug( "after unicode decode")
+            # LOG.debug( data)
             data = self._to_bytestring(data)
             LOG.debug("after _to_bytestring")
             LOG.debug(data)

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-client/python-client/src/main/python/ambari_client/model/blueprint.py
----------------------------------------------------------------------
diff --git a/ambari-client/python-client/src/main/python/ambari_client/model/blueprint.py b/ambari-client/python-client/src/main/python/ambari_client/model/blueprint.py
index 8497dc6..e207a6b 100644
--- a/ambari-client/python-client/src/main/python/ambari_client/model/blueprint.py
+++ b/ambari-client/python-client/src/main/python/ambari_client/model/blueprint.py
@@ -15,6 +15,7 @@
 #  limitations under the License.
 
 import logging
+import json
 from ambari_client.model.base_model import BaseModel, ModelList
 from ambari_client.model import paths, utils, status
 
@@ -46,6 +47,33 @@ def get_blueprint(resource_root, blueprint_name):
             "Blueprints")
 
 
+def get_cluster_blueprint(resource_root, cluster_name):
+    """
+    Get all Blueprint
+    @param root_resource: The root Resource .
+    @param name: blueprint_name
+    @return: A list of BlueprintModel objects.
+    """
+    resp = resource_root.get(paths.BLUEPRINT_CLUSTER_PATH % cluster_name)
+    result = json.dumps(resp)
+    resp_dictt = json.loads(result)
+    objects = [
+        utils.ModelUtils.create_model(
+            BlueprintHostModel,
+            x,
+            resource_root,
+            "NO_KEY") for x in resp_dictt['host_groups']]
+    LOG.debug(objects)
+
+    bluep = utils.ModelUtils.create_model(
+        BlueprintModel,
+        resp,
+        resource_root,
+        "Blueprints")
+
+    return bluep, ModelList(objects)
+
+
 def delete_blueprint(resource_root, blueprint_name):
     """
     Delete a blueprint by name
@@ -93,6 +121,31 @@ class BlueprintModel(BaseModel):
         return "<<BlueprintModel>> blueprint_name = %s " % (
             self.blueprint_name)
 
+    def _get_cluster_name(self):
+        if self.clusterRef:
+            return self.clusterRef.cluster_name
+        return None
+
+
+class BlueprintHostModel(BaseModel):
+
+    """
+    The BlueprintHostModel class
+    """
+    RO_ATTR = ('blueprint_name',)
+    RW_ATTR = ('name', 'components', 'cardinality')
+    REF_ATTR = ()
+
+    def __init__(self, resource_root, name, components, cardinality):
+        utils.retain_self_helper(BaseModel, **locals())
+
+    def __str__(self):
+        return "<<BlueprintHostModel>> name = %s ,components =%s" % (
+            self.name, str(self.components))
+
+    def to_json(self):
+        pass
+
 
 class BlueprintConfigModel(BaseModel):
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-client/python-client/src/main/python/ambari_client/model/host.py
----------------------------------------------------------------------
diff --git a/ambari-client/python-client/src/main/python/ambari_client/model/host.py b/ambari-client/python-client/src/main/python/ambari_client/model/host.py
index 05bdf6e..f6c39d6 100644
--- a/ambari-client/python-client/src/main/python/ambari_client/model/host.py
+++ b/ambari-client/python-client/src/main/python/ambari_client/model/host.py
@@ -219,8 +219,11 @@ def _bootstrap_hosts(root_resource, hosts_list, ssh_key, ssh_user):
     @param hosts_list list of host_names.
     @return: A  StatusModel object.
     """
-    payload_dic = {"verbose":True, "sshKey": ssh_key.encode(
-        'string_escape')  , "hosts":str(hosts_list) , "user": ssh_user }
+    payload_dic = {
+        "verbose": True,
+        "sshKey": ssh_key,
+        "hosts": str(hosts_list),
+        "user": ssh_user}
     resp = root_resource.post(
         paths.BOOTSTRAP_PATH,
         payload_dic,

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-client/python-client/src/main/python/ambari_client/model/paths.py
----------------------------------------------------------------------
diff --git a/ambari-client/python-client/src/main/python/ambari_client/model/paths.py b/ambari-client/python-client/src/main/python/ambari_client/model/paths.py
index 3643129..e111824 100644
--- a/ambari-client/python-client/src/main/python/ambari_client/model/paths.py
+++ b/ambari-client/python-client/src/main/python/ambari_client/model/paths.py
@@ -40,6 +40,7 @@ HOSTS_ASSIGN_ROLE = "/clusters/%s/hosts?Hosts/host_name=%s"
 BOOTSTRAP_PATH = "/bootstrap"
 REQUEST_STATUS_PATH = "/clusters/%s/requests/%s?fields=tasks/Tasks/status"
 REQUEST_PATH = "clusters/%s/requests/%s"
+REQUEST_N_PATH = "clusters/%s/requests?to=end&page_size=%s&fields=Requests"
 
 CONFIGURATION_PATH = "/clusters/%s/configurations?type=%s&tag=%s"
 CONFIGURATION_ALL_PATH = "/clusters/%s/configurations?type=%s"
@@ -57,3 +58,4 @@ TASKS_PATH = "clusters/%s/requests/%s/tasks?fields=*"
 
 BLUEPRINT_ALL_PATH = "blueprints?fields=*"
 BLUEPRINT_PATH = "blueprints/%s"
+BLUEPRINT_CLUSTER_PATH = "clusters/%s?format=blueprint"

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-client/python-client/src/main/python/ambari_client/model/status.py
----------------------------------------------------------------------
diff --git a/ambari-client/python-client/src/main/python/ambari_client/model/status.py b/ambari-client/python-client/src/main/python/ambari_client/model/status.py
index 37ca8fd..8ef1140 100644
--- a/ambari-client/python-client/src/main/python/ambari_client/model/status.py
+++ b/ambari-client/python-client/src/main/python/ambari_client/model/status.py
@@ -15,7 +15,7 @@
 #  limitations under the License.
 
 import logging
-from ambari_client.model.base_model import BaseModel
+from ambari_client.model.base_model import BaseModel, ModelList
 from ambari_client.model import paths, utils
 
 
@@ -32,7 +32,7 @@ class StatusModel(BaseModel):
     REF_ATTR = ('cluster_name',)
 
     def __init__(self, resource_root, status, requestId=None, message=None):
-        #BaseModel.__init__(self, **locals())
+        # BaseModel.__init__(self, **locals())
         utils.retain_self_helper(BaseModel, **locals())
 
     def __str__(self):
@@ -72,3 +72,41 @@ class StatusModel(BaseModel):
             return self.status
         else:
             None
+
+
+def _get_N_requests(resource_root, cluster_name, noOfrequest):
+    """
+    Get all services in a cluster.
+    @param cluster_name :Cluster name.
+    @return: A  ModelList object.
+    """
+    path = paths.REQUEST_N_PATH % (cluster_name, noOfrequest)
+    dic = resource_root.get(path)
+    return utils.ModelUtils.get_model_list(
+        ModelList,
+        RequestModel,
+        dic,
+        resource_root,
+        "Requests")
+
+
+class RequestModel(BaseModel):
+
+    """
+    The RequestModel class
+    """
+    RO_ATTR = ("request_context",)
+    RW_ATTR = ('id', 'request_status')
+    REF_ATTR = ('cluster_name',)
+
+    def __init__(self, resource_root, id, request_status=None):
+        # BaseModel.__init__(self, **locals())
+        utils.retain_self_helper(BaseModel, **locals())
+
+    def __str__(self):
+        return "<<RequestModel>> id = %s ; request_status = %s" % (
+            self.id, self.request_status)
+
+    def is_error(self):
+        return (
+            self.status != 200 and self.status != 201 and self.status != 202)

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-client/python-client/src/main/python/ambari_client/model/utils.py
----------------------------------------------------------------------
diff --git a/ambari-client/python-client/src/main/python/ambari_client/model/utils.py b/ambari-client/python-client/src/main/python/ambari_client/model/utils.py
index e1f1479..65dd153 100644
--- a/ambari-client/python-client/src/main/python/ambari_client/model/utils.py
+++ b/ambari-client/python-client/src/main/python/ambari_client/model/utils.py
@@ -162,12 +162,20 @@ class ModelUtils(object):
         rw_dict = {}
         LOG.debug("model_dict =   " + str(model_dict))
 
+        # extract model /keyword
         if isinstance(model_dict, dict) and RESOURCE_KEY_WORD in model_dict:
             model_dict = model_dict[RESOURCE_KEY_WORD]
-            LOG.debug(
-                "model_dict has %s ;subset = %s" %
-                (RESOURCE_KEY_WORD, str(
-                    model_dict.items())))
+            if not isinstance(model_dict, list):
+                LOG.debug(
+                    "model_dict has %s ;subset = %s" %
+                    (RESOURCE_KEY_WORD, str(
+                        model_dict.items())))
+            else:
+                LOG.debug(
+                    "model_dict is list and has %s ;subset = %s" %
+                    (RESOURCE_KEY_WORD, str(
+                        model_dict)))
+        # check for Requests
         if isinstance(model_dict, dict) and "Requests" in model_dict:
             model_dict = model_dict["Requests"]
             LOG.debug(
@@ -175,12 +183,17 @@ class ModelUtils(object):
                 (str(
                     model_dict.items())))
 
-        for k, v in model_dict.items():
-            LOG.debug("key = %s ; value = %s " % (str(k), str(v)))
-            if k in model_cls.RW_ATTR:
-                LOG.debug(k + " is there in RW_ATTR")
-                rw_dict[k] = v
-                del model_dict[k]
+        # check for composition i.e list of Models
+        if isinstance(model_dict, list):
+            LOG.debug(
+                "model_dict is list")
+        else:
+            for k, v in model_dict.items():
+                LOG.debug("key = %s ; value = %s " % (str(k), str(v)))
+                if k in model_cls.RW_ATTR:
+                    LOG.debug(k + " is there in RW_ATTR")
+                    rw_dict[k] = v
+                    del model_dict[k]
 
         rw_dict = get_unicode_kw(rw_dict)
         obj = model_cls(resource_root, **rw_dict)
@@ -238,7 +251,7 @@ def get_REF_object(ref_class_name):
 
 
 def get_unicode(v):
-    #import unicodedata
+    # import unicodedata
     if v:
         if isinstance(v, unicode):
             v = unicodedata.normalize('NFKD', v).encode('ascii', 'ignore')
@@ -249,8 +262,8 @@ def get_unicode(v):
 
 
 def retain_self_helper(memclass, self=None, **kwargs):
-        # print locals()
-        #from ambari_client.model.base_model import  BaseModel
+    # print locals()
+        # from ambari_client.model.base_model import  BaseModel
     memclass.__init__(self, **kwargs)
 
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-groovy-shell/pom.xml
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-groovy-shell/pom.xml b/ambari-shell/ambari-groovy-shell/pom.xml
new file mode 100644
index 0000000..a1acf8b
--- /dev/null
+++ b/ambari-shell/ambari-groovy-shell/pom.xml
@@ -0,0 +1,142 @@
+<?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>
+    <groupId>org.apache.ambari</groupId>
+    <artifactId>ambari-shell</artifactId>
+    <version>1.3.0-SNAPSHOT</version>
+    <relativePath>../../ambari-shell</relativePath>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.apache.ambari</groupId>
+  <artifactId>ambari-groovy-shell</artifactId>
+  <packaging>jar</packaging>
+  <name>Ambari Groovy Shell</name>
+  <version>1.3.0-SNAPSHOT</version>
+  <description>Ambari Groovy Shell</description>
+   <properties>
+    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    <start-class>org.apache.ambari.shell.AmbariShell</start-class>
+  </properties>
+  <dependencies>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework.shell</groupId>
+      <artifactId>spring-shell</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework.boot</groupId>
+      <artifactId>spring-boot-starter</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework.boot</groupId>
+      <artifactId>spring-boot-starter-test</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>com.github.lalyos</groupId>
+      <artifactId>jfiglet</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>commons-io</groupId>
+      <artifactId>commons-io</artifactId>
+      <version>2.3</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.ambari</groupId>
+      <artifactId>groovy-client</artifactId>
+      <version>1.3.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-core</artifactId>
+      <version>1.9.5</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>jline</groupId>
+      <artifactId>jline</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.codehaus.jackson</groupId>
+      <artifactId>jackson-mapper-asl</artifactId>
+    </dependency>
+  </dependencies>
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <version>3.0</version>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.rat</groupId>
+        <artifactId>apache-rat-plugin</artifactId>
+        <configuration>
+          <excludes>
+            <exclude>src/main/resources/elephant.txt</exclude>
+            <exclude>src/test/resources/2columns</exclude>
+            <exclude>src/test/resources/3columns</exclude>
+            <exclude>src/test/resources/testBlueprint.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>
+      <plugin>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-maven-plugin</artifactId>
+        <version>1.0.2.RELEASE</version>
+        <executions>
+          <execution>
+            <goals>
+              <goal>repackage</goal>
+            </goals>
+          </execution>
+        </executions>
+        <configuration>
+          <mainClass>${start-class}</mainClass>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.vafer</groupId>
+        <artifactId>jdeb</artifactId>
+        <version>1.0.1</version>
+        <executions>
+          <execution>
+            <phase>none</phase>
+            <goals>
+              <goal>jdeb</goal>
+            </goals>
+          </execution>
+        </executions>
+        <configuration>
+          <controlDir>${basedir}/../../ambari-project/src/main/package/deb/control</controlDir>
+          <skip>true</skip>
+          <submodules>false</submodules>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/AmbariShell.java
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/AmbariShell.java b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/AmbariShell.java
new file mode 100644
index 0000000..e842620
--- /dev/null
+++ b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/AmbariShell.java
@@ -0,0 +1,111 @@
+/**
+ * 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.shell;
+
+import org.apache.ambari.groovy.client.AmbariClient;
+import org.apache.ambari.shell.model.AmbariContext;
+import org.apache.ambari.shell.model.Hints;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.CommandLineRunner;
+import org.springframework.boot.builder.SpringApplicationBuilder;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.shell.CommandLine;
+import org.springframework.shell.core.JLineShellComponent;
+import org.springframework.shell.event.ShellStatus;
+import org.springframework.shell.event.ShellStatusListener;
+
+/**
+ * Shell bootstrap.
+ */
+@Configuration
+@ComponentScan(basePackageClasses = {AmbariShell.class})
+public class AmbariShell implements CommandLineRunner, ShellStatusListener {
+
+  @Autowired
+  private CommandLine commandLine;
+  @Autowired
+  private JLineShellComponent shell;
+  @Autowired
+  private AmbariContext context;
+  @Autowired
+  private AmbariClient client;
+
+  @Override
+  public void run(String... arg) throws Exception {
+    String[] shellCommandsToExecute = commandLine.getShellCommandsToExecute();
+    if (shellCommandsToExecute != null) {
+      for (String cmd : shellCommandsToExecute) {
+        if (!shell.executeScriptLine(cmd)) {
+          break;
+        }
+      }
+      System.exit(0);
+    } else {
+      shell.addShellStatusListener(this);
+      shell.start();
+      shell.promptLoop();
+      shell.waitForComplete();
+    }
+  }
+
+  @Override
+  public void onShellStatusChange(ShellStatus oldStatus, ShellStatus newStatus) {
+    if (newStatus.getStatus() == ShellStatus.Status.STARTED) {
+      try {
+        String cluster = client.getClusterName();
+        boolean available = client.isBlueprintAvailable();
+        if (cluster == null) {
+          if (available) {
+            context.setHint(Hints.BUILD_CLUSTER);
+          } else {
+            context.setHint(Hints.ADD_BLUEPRINT);
+          }
+        } else {
+          context.setHint(Hints.PROGRESS);
+        }
+        context.setCluster(cluster);
+        context.setBlueprintsAvailable(available);
+      } catch (Exception e) {
+        System.out.println(e.getMessage());
+        shell.executeCommand("quit");
+      }
+    }
+  }
+
+
+  public static void main(String[] args) {
+    if (args.length == 0) {
+      System.out.println(
+        "\nAmbari Shell: Interactive command line tool for managing Apache Ambari.\n\n" +
+          "Usage:\n" +
+          "  java -jar ambari-shell.jar                  : Starts Ambari Shell in interactive mode.\n" +
+          "  java -jar ambari-shell.jar --cmdfile=<FILE> : Ambari Shell executes commands read from the file.\n\n" +
+          "Options:\n" +
+          "  --ambari.host=<HOSTNAME>       Hostname of the Ambari Server [default: localhost].\n" +
+          "  --ambari.port=<PORT>           Port of the Ambari Server [default: 8080].\n" +
+          "  --ambari.user=<USER>           Username of the Ambari admin [default: admin].\n" +
+          "  --ambari.password=<PASSWORD>   Password of the Ambari admin [default: admin].\n\n" +
+          "Note:\n" +
+          "  At least one option is mandatory."
+      );
+      System.exit(1);
+    }
+    new SpringApplicationBuilder(AmbariShell.class).showBanner(false).run(args);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/commands/BasicCommands.java
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/commands/BasicCommands.java b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/commands/BasicCommands.java
new file mode 100644
index 0000000..9babe12
--- /dev/null
+++ b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/commands/BasicCommands.java
@@ -0,0 +1,207 @@
+/**
+ * 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.shell.commands;
+
+import static org.apache.ambari.shell.support.TableRenderer.renderMapValueMap;
+import static org.apache.ambari.shell.support.TableRenderer.renderSingleMap;
+
+import org.apache.ambari.groovy.client.AmbariClient;
+import org.apache.ambari.shell.model.AmbariContext;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.shell.core.CommandMarker;
+import org.springframework.shell.core.annotation.CliAvailabilityIndicator;
+import org.springframework.shell.core.annotation.CliCommand;
+import org.springframework.shell.core.annotation.CliOption;
+import org.springframework.stereotype.Component;
+
+/**
+ * Basic commands used in the shell. Delegating the commands
+ * to the Ambari Server via a Groovy based client.
+ *
+ * @see org.apache.ambari.groovy.client.AmbariClient
+ */
+@Component
+public class BasicCommands implements CommandMarker {
+
+  private AmbariClient client;
+  private AmbariContext context;
+
+  @Autowired
+  public BasicCommands(AmbariClient client, AmbariContext context) {
+    this.client = client;
+    this.context = context;
+  }
+
+  /**
+   * Checks whether the tasks command is available or not.
+   *
+   * @return true if its available false otherwise
+   */
+  @CliAvailabilityIndicator("tasks")
+  public boolean isTasksCommandAvailable() {
+    return context.isConnectedToCluster();
+  }
+
+  /**
+   * Prints the tasks of the Ambari Server.
+   *
+   * @param id id of the request
+   * @return task list
+   */
+  @CliCommand(value = "tasks", help = "Lists the Ambari tasks")
+  public String tasks(
+    @CliOption(key = "id", mandatory = false, help = "Id of the request; default is: 1", unspecifiedDefaultValue = "1") String id) {
+    return renderSingleMap(client.getTaskMap(id), "TASK", "STATUS");
+  }
+
+  /**
+   * Checks whether the service list command is available or not.
+   *
+   * @return true if available false otherwise
+   */
+  @CliAvailabilityIndicator("services list")
+  public boolean isServiceListCommandAvailable() {
+    return context.isConnectedToCluster();
+  }
+
+  /**
+   * Prints the available service list of the Ambari Server.
+   *
+   * @return service list
+   */
+  @CliCommand(value = "services list", help = "Lists the available services")
+  public String servicesList() {
+    return renderSingleMap(client.getServicesMap(), "SERVICE", "STATE");
+  }
+
+  /**
+   * Checks whether the service components command is available or not.
+   *
+   * @return true if available false otherwise
+   */
+  @CliAvailabilityIndicator("services components")
+  public boolean isServiceComponentsCommandAvailable() {
+    return context.isConnectedToCluster();
+  }
+
+  /**
+   * Prints the service components of the Ambari Server.
+   *
+   * @return service component list
+   */
+  @CliCommand(value = "services components", help = "Lists all services with their components")
+  public String serviceComponents() {
+    return renderMapValueMap(client.getServiceComponentsMap(), "SERVICE", "COMPONENT", "STATE");
+  }
+
+  /**
+   * Checks whether the debug on command is available or not.
+   *
+   * @return true if available false otherwise
+   */
+  @CliAvailabilityIndicator("debug on")
+  public boolean isDebugOnCommandAvailable() {
+    return !client.isDebugEnabled();
+  }
+
+  /**
+   * Turns the debug on. From now on users will see the URLs of the API calls.
+   *
+   * @return status message
+   */
+  @CliCommand(value = "debug on", help = "Shows the URL of the API calls")
+  public String debugOn() {
+    client.setDebugEnabled(true);
+    return "debug enabled";
+  }
+
+  /**
+   * Checks whether the debug off command is available or not.
+   *
+   * @return true if available false otherwise
+   */
+  @CliAvailabilityIndicator("debug off")
+  public boolean isDebugOffCommandAvailable() {
+    return client.isDebugEnabled();
+  }
+
+  /**
+   * Turns the debug off. URLs are not visible anymore.
+   *
+   * @return status message
+   */
+  @CliCommand(value = "debug off", help = "Stops showing the URL of the API calls")
+  public String debugOff() {
+    client.setDebugEnabled(false);
+    return "debug disabled";
+  }
+
+  /**
+   * Checks whether the hint command is available or not.
+   *
+   * @return true if available false otherwise
+   */
+  @CliAvailabilityIndicator("hint")
+  public boolean isHintCommandAvailable() {
+    return true;
+  }
+
+  /**
+   * Provides some hints what you can do in the current context.
+   *
+   * @return hint message
+   */
+  @CliCommand(value = "hint", help = "Shows some hints")
+  public String hint() {
+    return context.getHint();
+  }
+
+  @CliAvailabilityIndicator("services stop")
+  public boolean isServiceStopCommandAvailable() {
+    return context.isConnectedToCluster();
+  }
+
+  @CliCommand(value = "services stop", help = "Stops all the running services")
+  public String stopServices() {
+    String message;
+    try {
+      client.stopAllServices();
+      message = "Stopping all services..";
+    } catch (Exception e) {
+      message = "Cannot stop services";
+    }
+    return String.format("%s\n\n%s", message, servicesList());
+  }
+
+  @CliAvailabilityIndicator("services start")
+  public boolean isServiceStartCommandAvailable() {
+    return context.isConnectedToCluster();
+  }
+
+  @CliCommand(value = "services start", help = "Starts all the services")
+  public String startServices() {
+    String message;
+    try {
+      client.startAllServices();
+      message = "Starting all services..";
+    } catch (Exception e) {
+      message = "Cannot start services";
+    }
+    return String.format("%s\n\n%s", message, servicesList());
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/commands/BlueprintCommands.java
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/commands/BlueprintCommands.java b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/commands/BlueprintCommands.java
new file mode 100644
index 0000000..73000d0
--- /dev/null
+++ b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/commands/BlueprintCommands.java
@@ -0,0 +1,198 @@
+/**
+ * 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.shell.commands;
+
+import static org.apache.ambari.shell.support.TableRenderer.renderMultiValueMap;
+import static org.apache.ambari.shell.support.TableRenderer.renderSingleMap;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.net.URL;
+
+import org.apache.ambari.groovy.client.AmbariClient;
+import org.apache.ambari.shell.completion.Blueprint;
+import org.apache.ambari.shell.model.AmbariContext;
+import org.apache.ambari.shell.model.Hints;
+import org.apache.commons.io.IOUtils;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.shell.core.CommandMarker;
+import org.springframework.shell.core.annotation.CliAvailabilityIndicator;
+import org.springframework.shell.core.annotation.CliCommand;
+import org.springframework.shell.core.annotation.CliOption;
+import org.springframework.stereotype.Component;
+
+/**
+ * Blueprint related commands used in the shell.
+ *
+ * @see org.apache.ambari.groovy.client.AmbariClient
+ */
+@Component
+public class BlueprintCommands implements CommandMarker {
+
+  private AmbariClient client;
+  private AmbariContext context;
+  private ObjectMapper jsonMapper;
+
+  @Autowired
+  public BlueprintCommands(AmbariClient client, AmbariContext context, ObjectMapper jsonMapper) {
+    this.client = client;
+    this.context = context;
+    this.jsonMapper = jsonMapper;
+  }
+
+  /**
+   * Checks whether the blueprints command is available or not.
+   *
+   * @return true if available false otherwise
+   */
+  @CliAvailabilityIndicator("blueprint list")
+  public boolean isBlueprintListCommandAvailable() {
+    return context.areBlueprintsAvailable();
+  }
+
+  /**
+   * Prints all the blueprints.
+   *
+   * @return list of blueprints
+   */
+  @CliCommand(value = "blueprint list", help = "Lists all known blueprints")
+  public String listBlueprints() {
+    return renderSingleMap(client.getBlueprintsMap(), "BLUEPRINT", "STACK");
+  }
+
+  /**
+   * Checks whether the blueprint show command is available or not.
+   *
+   * @return true if available false otherwise
+   */
+  @CliAvailabilityIndicator(value = "blueprint show")
+  public boolean isBlueprintShowCommandAvailable() {
+    return context.areBlueprintsAvailable();
+  }
+
+  /**
+   * Shows the requested blueprint's details.
+   *
+   * @param id id of the blueprint
+   * @return blueprint as formatted table
+   */
+  @CliCommand(value = "blueprint show", help = "Shows the blueprint by its id")
+  public String showBlueprint(
+    @CliOption(key = "id", mandatory = true, help = "Id of the blueprint") Blueprint id) {
+    return renderMultiValueMap(client.getBlueprintMap(id.getName()), "HOSTGROUP", "COMPONENT");
+  }
+
+  /**
+   * Checks whether the blueprint add command is available or not.
+   *
+   * @return true if available false otherwise
+   */
+  @CliAvailabilityIndicator(value = "blueprint add")
+  public boolean isBlueprintAddCommandAvailable() {
+    return true;
+  }
+
+  /**
+   * Adds a blueprint to the Ambari server either through an URL or from a file.
+   * If both specified the file takes precedence.
+   *
+   * @param url  -optional, URL containing the blueprint json
+   * @param file - optional, file containing the blueprint json
+   * @return status message
+   */
+  @CliCommand(value = "blueprint add", help = "Add a new blueprint with either --url or --file")
+  public String addBlueprint(
+    @CliOption(key = "url", mandatory = false, help = "URL of the blueprint to download from") String url,
+    @CliOption(key = "file", mandatory = false, help = "File which contains the blueprint") File file) {
+    String message;
+    try {
+      String json = file == null ? readContent(url) : readContent(file);
+      if (json != null) {
+        client.addBlueprint(json);
+        context.setHint(Hints.BUILD_CLUSTER);
+        context.setBlueprintsAvailable(true);
+        message = String.format("Blueprint: '%s' has been added", getBlueprintName(json));
+      } else {
+        message = "No blueprint specified";
+      }
+    } catch (Exception e) {
+      message = "Cannot add blueprint: " + e.getMessage();
+    }
+    return message;
+  }
+
+  /**
+   * Checks whether the blueprint defaults command is available or not.
+   *
+   * @return true if available false otherwise
+   */
+  @CliAvailabilityIndicator(value = "blueprint defaults")
+  public boolean isBlueprintDefaultsAddCommandAvailable() {
+    return !context.areBlueprintsAvailable();
+  }
+
+  /**
+   * Adds two default blueprints to the Ambari server.
+   *
+   * @return status message
+   */
+  @CliCommand(value = "blueprint defaults", help = "Adds the default blueprints to Ambari")
+  public String addBlueprint() {
+    String message = "Default blueprints added";
+    try {
+      client.addDefaultBlueprints();
+      context.setHint(Hints.BUILD_CLUSTER);
+      context.setBlueprintsAvailable(true);
+    } catch (Exception e) {
+      message = "Failed to add the default blueprints: " + e.getMessage();
+    }
+    return message;
+  }
+
+  private String readContent(File file) {
+    String content = null;
+    try {
+      content = IOUtils.toString(new FileInputStream(file));
+    } catch (IOException e) {
+      // not important
+    }
+    return content;
+  }
+
+  private String readContent(String url) {
+    String content = null;
+    try {
+      content = IOUtils.toString(new URL(url));
+    } catch (IOException e) {
+      // not important
+    }
+    return content;
+  }
+
+  private String getBlueprintName(String json) {
+    String result = "";
+    try {
+      result = jsonMapper.readTree(json.getBytes()).get("Blueprints").get("blueprint_name").asText();
+    } catch (IOException e) {
+      // not important
+    }
+    return result;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/commands/ClusterCommands.java
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/commands/ClusterCommands.java b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/commands/ClusterCommands.java
new file mode 100644
index 0000000..dafdb85
--- /dev/null
+++ b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/commands/ClusterCommands.java
@@ -0,0 +1,294 @@
+/**
+ * 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.shell.commands;
+
+import static org.apache.ambari.shell.support.TableRenderer.renderMultiValueMap;
+import static org.apache.ambari.shell.support.TableRenderer.renderSingleMap;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.ambari.groovy.client.AmbariClient;
+import org.apache.ambari.shell.completion.Blueprint;
+import org.apache.ambari.shell.completion.Host;
+import org.apache.ambari.shell.flash.FlashService;
+import org.apache.ambari.shell.model.AmbariContext;
+import org.apache.ambari.shell.model.FocusType;
+import org.apache.ambari.shell.model.Hints;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.shell.core.CommandMarker;
+import org.springframework.shell.core.annotation.CliAvailabilityIndicator;
+import org.springframework.shell.core.annotation.CliCommand;
+import org.springframework.shell.core.annotation.CliOption;
+import org.springframework.stereotype.Component;
+
+import groovyx.net.http.HttpResponseException;
+
+/**
+ * Cluster related commands used in the shell.
+ *
+ * @see org.apache.ambari.groovy.client.AmbariClient
+ */
+@Component
+public class ClusterCommands implements CommandMarker {
+
+  private AmbariClient client;
+  private AmbariContext context;
+  private FlashService flashService;
+  private Map<String, List<String>> hostGroups;
+
+  @Autowired
+  public ClusterCommands(AmbariClient client, AmbariContext context, FlashService flashService) {
+    this.client = client;
+    this.context = context;
+    this.flashService = flashService;
+  }
+
+  /**
+   * Checks whether the cluster build command is available or not.
+   *
+   * @return true if available false otherwise
+   */
+  @CliAvailabilityIndicator("cluster build")
+  public boolean isClusterBuildCommandAvailable() {
+    return !context.isConnectedToCluster() && !context.isFocusOnClusterBuild() && context.areBlueprintsAvailable();
+  }
+
+  /**
+   * Sets the focus on cluster building. Takes a blueprint id, if it does not exists it wont focus.
+   * After focus the users are able to assign hosts to host groups.
+   *
+   * @param id id of the blueprint
+   * @return prints the blueprint as formatted table if exists, otherwise error message
+   */
+  @CliCommand(value = "cluster build", help = "Starts to build a cluster")
+  public String buildCluster(
+    @CliOption(key = "blueprint", mandatory = true, help = "Id of the blueprint, use 'blueprints' command to see the list") Blueprint id) {
+    String message;
+    String blueprint = id.getName();
+    if (client.doesBlueprintExist(blueprint)) {
+      context.setFocus(blueprint, FocusType.CLUSTER_BUILD);
+      context.setHint(Hints.ASSIGN_HOSTS);
+      message = String.format("%s\n%s",
+        renderSingleMap(client.getHostNames(), "HOSTNAME", "STATE"),
+        renderMultiValueMap(client.getBlueprintMap(blueprint), "HOSTGROUP", "COMPONENT"));
+      createNewHostGroups();
+    } else {
+      message = "Not a valid blueprint id";
+    }
+    return message;
+  }
+
+  /**
+   * Checks whether the cluster assign command is available or not.
+   *
+   * @return true if available false otherwise
+   */
+  @CliAvailabilityIndicator("cluster assign")
+  public boolean isAssignCommandAvailable() {
+    return context.isFocusOnClusterBuild();
+  }
+
+  /**
+   * Assign hosts to host groups provided in the blueprint.
+   *
+   * @param host  host to assign
+   * @param group which host group to
+   * @return status message
+   */
+  @CliCommand(value = "cluster assign", help = "Assign host to host group")
+  public String assign(
+    @CliOption(key = "host", mandatory = true, help = "Fully qualified host name") Host host,
+    @CliOption(key = "hostGroup", mandatory = true, help = "Host group which to assign the host") String group) {
+    String message;
+    String hostName = host.getName();
+    if (client.getHostNames().keySet().contains(hostName)) {
+      if (addHostToGroup(hostName, group)) {
+        context.setHint(Hints.CREATE_CLUSTER);
+        message = String.format("%s has been added to %s", hostName, group);
+      } else {
+        message = String.format("%s is not a valid host group", group);
+      }
+    } else {
+      message = String.format("%s is not a valid hostname", hostName);
+    }
+    return message;
+  }
+
+  /**
+   * Checks whether the cluster auto command is available or not.
+   *
+   * @return true if available false otherwise
+   */
+  @CliAvailabilityIndicator(value = "cluster autoAssign")
+  public boolean isClusterAutoAssignAvailable() {
+    return context.isFocusOnClusterBuild() && !isHostAssigned();
+  }
+
+  /**
+   * Tries to auto associate hosts to host groups.
+   *
+   * @return prints the auto assignments
+   */
+  @CliCommand(value = "cluster autoAssign", help = "Automatically assigns hosts to different host groups base on the provided strategy")
+  public String autoAssign() {
+    Map<String, List<String>> assignments = client.recommendAssignments(context.getFocusValue());
+    if (!assignments.isEmpty()) {
+      hostGroups = assignments;
+      context.setHint(Hints.CREATE_CLUSTER);
+    }
+    return showAssignments();
+  }
+
+  /**
+   * Checks whether the cluster preview command is available or not.
+   *
+   * @return true if available false otherwise
+   */
+  @CliAvailabilityIndicator("cluster preview")
+  public boolean isClusterPreviewCommandAvailable() {
+    return context.isFocusOnClusterBuild() && isHostAssigned();
+  }
+
+  /**
+   * Shows the currently assigned hosts.
+   *
+   * @return formatted host - host group table
+   */
+  @CliCommand(value = "cluster preview", help = "Shows the currently assigned hosts")
+  public String showAssignments() {
+    return renderMultiValueMap(hostGroups, "HOSTGROUP", "HOST");
+  }
+
+  /**
+   * Checks whether the cluster create command is available or not.
+   *
+   * @return true if available false otherwise
+   */
+  @CliAvailabilityIndicator("cluster create")
+  public boolean isCreateClusterCommandAvailable() {
+    return context.isFocusOnClusterBuild() && isHostAssigned();
+  }
+
+  /**
+   * Creates a new cluster based on the provided host - host group associations and the selected blueprint.
+   * If the cluster creation fails, deletes the cluster.
+   *
+   * @return status message
+   */
+  @CliCommand(value = "cluster create", help = "Create a cluster based on current blueprint and assigned hosts")
+  public String createCluster(
+    @CliOption(key = "exitOnFinish", mandatory = false, help = "Quits the shell when the cluster creation finishes") Boolean exit) {
+    String message = "Successfully created the cluster";
+    String blueprint = context.getFocusValue();
+    try {
+      client.createCluster(blueprint, blueprint, hostGroups);
+      context.setCluster(blueprint);
+      context.resetFocus();
+      context.setHint(Hints.PROGRESS);
+      flashService.showInstallProgress(exit == null ? false : exit);
+    } catch (HttpResponseException e) {
+      createNewHostGroups();
+      message = "Failed to create the cluster: " + e.getMessage();
+      try {
+        deleteCluster(blueprint);
+      } catch (HttpResponseException e1) {
+        message += ". Failed to cleanup cluster creation: " + e1.getMessage();
+      }
+    }
+    return message;
+  }
+
+  /**
+   * Checks whether the cluster delete command is available or not.
+   *
+   * @return true if available false otherwise
+   */
+  @CliAvailabilityIndicator("cluster delete")
+  public boolean isDeleteClusterCommandAvailable() {
+    return context.isConnectedToCluster();
+  }
+
+  /**
+   * Deletes the cluster.
+   *
+   * @return status message
+   */
+  @CliCommand(value = "cluster delete", help = "Delete the cluster")
+  public String deleteCluster() {
+    String message = "Successfully deleted the cluster";
+    try {
+      deleteCluster(context.getCluster());
+    } catch (HttpResponseException e) {
+      message = "Could not delete the cluster: " + e.getMessage();
+    }
+    return message;
+  }
+
+  /**
+   * Checks whether the cluster reset command is available or not.
+   *
+   * @return true if available false otherwise
+   */
+  @CliAvailabilityIndicator(value = "cluster reset")
+  public boolean isClusterResetCommandAvailable() {
+    return context.isFocusOnClusterBuild() && isHostAssigned();
+  }
+
+  @CliCommand(value = "cluster reset", help = "Clears the host - host group assignments")
+  public void reset() {
+    context.setHint(Hints.ASSIGN_HOSTS);
+    createNewHostGroups();
+  }
+
+  private void deleteCluster(String id) throws HttpResponseException {
+    client.deleteCluster(id);
+  }
+
+  private void createNewHostGroups() {
+    Map<String, List<String>> groups = new HashMap<String, List<String>>();
+    for (String hostGroup : client.getHostGroups(context.getFocusValue())) {
+      groups.put(hostGroup, new ArrayList<String>());
+    }
+    this.hostGroups = groups;
+  }
+
+  private boolean addHostToGroup(String host, String group) {
+    boolean result = true;
+    List<String> hosts = hostGroups.get(group);
+    if (hosts == null) {
+      result = false;
+    } else {
+      hosts.add(host);
+    }
+    return result;
+  }
+
+  private boolean isHostAssigned() {
+    boolean result = false;
+    for (String group : hostGroups.keySet()) {
+      if (!hostGroups.get(group).isEmpty()) {
+        result = true;
+        break;
+      }
+    }
+    return result;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/commands/ElephantCommand.java
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/commands/ElephantCommand.java b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/commands/ElephantCommand.java
new file mode 100644
index 0000000..a236054
--- /dev/null
+++ b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/commands/ElephantCommand.java
@@ -0,0 +1,53 @@
+/**
+ * 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.shell.commands;
+
+import java.io.IOException;
+
+import org.apache.commons.io.IOUtils;
+import org.springframework.shell.core.CommandMarker;
+import org.springframework.shell.core.annotation.CliAvailabilityIndicator;
+import org.springframework.shell.core.annotation.CliCommand;
+import org.springframework.stereotype.Component;
+
+/**
+ * Draws an elephant to the console.
+ */
+@Component
+public class ElephantCommand implements CommandMarker {
+
+  /**
+   * Checks whether the hello command is available or not.
+   *
+   * @return true if available false otherwise
+   */
+  @CliAvailabilityIndicator("hello")
+  public boolean isCommandAvailable() {
+    return true;
+  }
+
+  /**
+   * Prints an elephant to the console.
+   *
+   * @return elephant
+   */
+  @CliCommand(value = "hello", help = "Prints a simple elephant to the console")
+  public String elephant() throws IOException {
+    return IOUtils.toString(getClass().getResourceAsStream("/elephant.txt"));
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/commands/HostCommands.java
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/commands/HostCommands.java b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/commands/HostCommands.java
new file mode 100644
index 0000000..dd3c775
--- /dev/null
+++ b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/commands/HostCommands.java
@@ -0,0 +1,119 @@
+/**
+ * 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.shell.commands;
+
+import static org.apache.ambari.shell.support.TableRenderer.renderSingleMap;
+
+import org.apache.ambari.groovy.client.AmbariClient;
+import org.apache.ambari.shell.completion.Host;
+import org.apache.ambari.shell.model.AmbariContext;
+import org.apache.ambari.shell.model.FocusType;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.shell.core.CommandMarker;
+import org.springframework.shell.core.annotation.CliAvailabilityIndicator;
+import org.springframework.shell.core.annotation.CliCommand;
+import org.springframework.shell.core.annotation.CliOption;
+import org.springframework.stereotype.Component;
+
+/**
+ * Host related commands used in the shell.
+ *
+ * @see org.apache.ambari.groovy.client.AmbariClient
+ */
+@Component
+public class HostCommands implements CommandMarker {
+
+  private AmbariClient client;
+  private AmbariContext context;
+
+  @Autowired
+  public HostCommands(AmbariClient client, AmbariContext context) {
+    this.client = client;
+    this.context = context;
+  }
+
+  /**
+   * Checks whether the host list command is available or not.
+   *
+   * @return true if available false otherwise
+   */
+  @CliAvailabilityIndicator("host list")
+  public boolean isHostsCommandAvailable() {
+    return true;
+  }
+
+  /**
+   * Prints the available hosts of the Ambari Server.
+   *
+   * @return host list
+   */
+  @CliCommand(value = "host list", help = "Lists the available hosts")
+  public String hosts() {
+    return client.showHostList();
+  }
+
+  /**
+   * Checks whether the host focus command is available or not.
+   *
+   * @return true if available false otherwise
+   */
+  @CliAvailabilityIndicator("host focus")
+  public boolean isFocusHostCommandAvailable() {
+    return context.isConnectedToCluster();
+  }
+
+  /**
+   * Sets the focus to the specified host.
+   *
+   * @param host the host to set the focus to
+   * @return status message
+   */
+  @CliCommand(value = "host focus", help = "Sets the useHost to the specified host")
+  public String focusHost(
+    @CliOption(key = "host", mandatory = true, help = "hostname") Host host) {
+    String message;
+    String hostName = host.getName();
+    if (client.getHostNames().keySet().contains(hostName)) {
+      context.setFocus(hostName, FocusType.HOST);
+      message = "Focus set to: " + hostName;
+    } else {
+      message = hostName + " is not a valid host name";
+    }
+    return message;
+  }
+
+  /**
+   * Checks whether the host components command is available or not.
+   *
+   * @return true if available false otherwise
+   */
+  @CliAvailabilityIndicator("host components")
+  public boolean isHostComponentsCommandAvailable() {
+    return context.isFocusOnHost();
+  }
+
+  /**
+   * Prints the components which belongs to the host being focused on.
+   *
+   * @return list of host components
+   */
+  @CliCommand(value = "host components", help = "Lists the components assigned to the selected host")
+  public String hostComponents() {
+    return renderSingleMap(client.getHostComponentsMap(context.getFocusValue()), "COMPONENT", "STATE");
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/completion/Blueprint.java
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/completion/Blueprint.java b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/completion/Blueprint.java
new file mode 100644
index 0000000..4eec7b1
--- /dev/null
+++ b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/completion/Blueprint.java
@@ -0,0 +1,34 @@
+/**
+ * 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.shell.completion;
+
+/**
+ * Wrapper class for TAB completion to blueprint names.
+ */
+public class Blueprint {
+
+  private final String name;
+
+  public Blueprint(String name) {
+    this.name = name;
+  }
+
+  public String getName() {
+    return name;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/completion/Host.java
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/completion/Host.java b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/completion/Host.java
new file mode 100644
index 0000000..f64e97b
--- /dev/null
+++ b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/completion/Host.java
@@ -0,0 +1,34 @@
+/**
+ * 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.shell.completion;
+
+/**
+ * Wrapper class for TAB completion to host names.
+ */
+public class Host {
+
+  private final String name;
+
+  public Host(String name) {
+    this.name = name;
+  }
+
+  public String getName() {
+    return name;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/configuration/ConverterConfiguration.java
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/configuration/ConverterConfiguration.java b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/configuration/ConverterConfiguration.java
new file mode 100644
index 0000000..049c52f
--- /dev/null
+++ b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/configuration/ConverterConfiguration.java
@@ -0,0 +1,142 @@
+/**
+ * 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.shell.configuration;
+
+import org.apache.ambari.groovy.client.AmbariClient;
+import org.apache.ambari.shell.converter.BlueprintConverter;
+import org.apache.ambari.shell.converter.HostConverter;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.shell.converters.AvailableCommandsConverter;
+import org.springframework.shell.converters.BigDecimalConverter;
+import org.springframework.shell.converters.BigIntegerConverter;
+import org.springframework.shell.converters.BooleanConverter;
+import org.springframework.shell.converters.CharacterConverter;
+import org.springframework.shell.converters.DateConverter;
+import org.springframework.shell.converters.DoubleConverter;
+import org.springframework.shell.converters.EnumConverter;
+import org.springframework.shell.converters.FloatConverter;
+import org.springframework.shell.converters.IntegerConverter;
+import org.springframework.shell.converters.LocaleConverter;
+import org.springframework.shell.converters.LongConverter;
+import org.springframework.shell.converters.ShortConverter;
+import org.springframework.shell.converters.SimpleFileConverter;
+import org.springframework.shell.converters.StaticFieldConverterImpl;
+import org.springframework.shell.converters.StringConverter;
+import org.springframework.shell.core.Converter;
+
+/**
+ * Configures the converters used by the shell.
+ */
+@Configuration
+public class ConverterConfiguration {
+
+  @Autowired
+  private AmbariClient client;
+
+  @Bean
+  Converter simpleFileConverter() {
+    return new SimpleFileConverter();
+  }
+
+  @Bean
+  Converter stringConverter() {
+    return new StringConverter();
+  }
+
+  @Bean
+  Converter availableCommandsConverter() {
+    return new AvailableCommandsConverter();
+  }
+
+  @Bean
+  Converter bigDecimalConverter() {
+    return new BigDecimalConverter();
+  }
+
+  @Bean
+  Converter bigIntegerConverter() {
+    return new BigIntegerConverter();
+  }
+
+  @Bean
+  Converter booleanConverter() {
+    return new BooleanConverter();
+  }
+
+  @Bean
+  Converter characterConverter() {
+    return new CharacterConverter();
+  }
+
+  @Bean
+  Converter dateConverter() {
+    return new DateConverter();
+  }
+
+  @Bean
+  Converter doubleConverter() {
+    return new DoubleConverter();
+  }
+
+  @Bean
+  Converter enumConverter() {
+    return new EnumConverter();
+  }
+
+  @Bean
+  Converter floatConverter() {
+    return new FloatConverter();
+  }
+
+  @Bean
+  Converter integerConverter() {
+    return new IntegerConverter();
+  }
+
+  @Bean
+  Converter localeConverter() {
+    return new LocaleConverter();
+  }
+
+  @Bean
+  Converter longConverter() {
+    return new LongConverter();
+  }
+
+  @Bean
+  Converter shortConverter() {
+    return new ShortConverter();
+  }
+
+  @Bean
+  Converter staticFieldConverterImpl() {
+    return new StaticFieldConverterImpl();
+  }
+
+  @Bean
+  Converter blueprintConverter() {
+    return new BlueprintConverter(client);
+  }
+
+  @Bean
+  Converter hostConverter() {
+    return new HostConverter(client);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/configuration/ShellConfiguration.java
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/configuration/ShellConfiguration.java b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/configuration/ShellConfiguration.java
new file mode 100644
index 0000000..4c493b0
--- /dev/null
+++ b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/configuration/ShellConfiguration.java
@@ -0,0 +1,114 @@
+/**
+ * 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.shell.configuration;
+
+import org.apache.ambari.groovy.client.AmbariClient;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
+import org.springframework.scheduling.concurrent.ThreadPoolExecutorFactoryBean;
+import org.springframework.shell.CommandLine;
+import org.springframework.shell.SimpleShellCommandLineOptions;
+import org.springframework.shell.commands.ExitCommands;
+import org.springframework.shell.commands.HelpCommands;
+import org.springframework.shell.commands.ScriptCommands;
+import org.springframework.shell.commands.VersionCommands;
+import org.springframework.shell.core.CommandMarker;
+import org.springframework.shell.core.JLineShellComponent;
+import org.springframework.shell.plugin.HistoryFileNameProvider;
+import org.springframework.shell.plugin.support.DefaultHistoryFileNameProvider;
+
+/**
+ * Spring bean definitions.
+ */
+@Configuration
+public class ShellConfiguration {
+
+  @Value("${ambari.host:localhost}")
+  private String host;
+
+  @Value("${ambari.port:8080}")
+  private String port;
+
+  @Value("${ambari.user:admin}")
+  private String user;
+
+  @Value("${ambari.password:admin}")
+  private String password;
+
+  @Value("${cmdfile:}")
+  private String cmdFile;
+
+  @Bean
+  AmbariClient createAmbariClient() {
+    return new AmbariClient(host, port, user, password);
+  }
+
+  @Bean
+  static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() {
+    return new PropertySourcesPlaceholderConfigurer();
+  }
+
+  @Bean
+  HistoryFileNameProvider defaultHistoryFileNameProvider() {
+    return new DefaultHistoryFileNameProvider();
+  }
+
+  @Bean(name = "shell")
+  JLineShellComponent shell() {
+    return new JLineShellComponent();
+  }
+
+  @Bean
+  CommandLine commandLine() throws Exception {
+    String[] args = cmdFile.length() > 0 ? new String[]{"--cmdfile", cmdFile} : new String[0];
+    return SimpleShellCommandLineOptions.parseCommandLine(args);
+  }
+
+  @Bean
+  ThreadPoolExecutorFactoryBean getThreadPoolExecutorFactoryBean() {
+    return new ThreadPoolExecutorFactoryBean();
+  }
+
+  @Bean
+  ObjectMapper getObjectMapper() {
+    return new ObjectMapper();
+  }
+
+  @Bean
+  CommandMarker exitCommand() {
+    return new ExitCommands();
+  }
+
+  @Bean
+  CommandMarker versionCommands() {
+    return new VersionCommands();
+  }
+
+  @Bean
+  CommandMarker helpCommands() {
+    return new HelpCommands();
+  }
+
+  @Bean
+  CommandMarker scriptCommands() {
+    return new ScriptCommands();
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/converter/BlueprintConverter.java
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/converter/BlueprintConverter.java b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/converter/BlueprintConverter.java
new file mode 100644
index 0000000..7984e7f
--- /dev/null
+++ b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/converter/BlueprintConverter.java
@@ -0,0 +1,58 @@
+/**
+ * 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.shell.converter;
+
+import java.util.List;
+import java.util.Set;
+
+import org.apache.ambari.groovy.client.AmbariClient;
+import org.apache.ambari.shell.completion.Blueprint;
+import org.springframework.shell.core.Completion;
+import org.springframework.shell.core.Converter;
+import org.springframework.shell.core.MethodTarget;
+
+/**
+ * Converter used to complete blueprint names.
+ */
+public class BlueprintConverter implements Converter<Blueprint> {
+
+  private AmbariClient client;
+
+  public BlueprintConverter(AmbariClient client) {
+    this.client = client;
+  }
+
+  @Override
+  public boolean supports(Class<?> type, String optionContext) {
+    return Blueprint.class.isAssignableFrom(type);
+  }
+
+  @Override
+  public Blueprint convertFromText(String value, Class<?> targetType, String optionContext) {
+    return new Blueprint(value);
+  }
+
+  @Override
+  public boolean getAllPossibleValues(List<Completion> completions, Class<?> targetType, String existingData, String optionContext, MethodTarget target) {
+    Set<String> blueprints = client.getBlueprintsMap().keySet();
+    for (String blueprint : blueprints) {
+      completions.add(new Completion(blueprint));
+    }
+    return true;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/converter/HostConverter.java
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/converter/HostConverter.java b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/converter/HostConverter.java
new file mode 100644
index 0000000..39aa6e9
--- /dev/null
+++ b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/converter/HostConverter.java
@@ -0,0 +1,58 @@
+/**
+ * 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.shell.converter;
+
+import java.util.List;
+import java.util.Set;
+
+import org.apache.ambari.groovy.client.AmbariClient;
+import org.apache.ambari.shell.completion.Host;
+import org.springframework.shell.core.Completion;
+import org.springframework.shell.core.Converter;
+import org.springframework.shell.core.MethodTarget;
+
+/**
+ * Converter used to complete host names.
+ */
+public class HostConverter implements Converter<Host> {
+
+  private AmbariClient client;
+
+  public HostConverter(AmbariClient client) {
+    this.client = client;
+  }
+
+  @Override
+  public boolean supports(Class<?> type, String optionContext) {
+    return Host.class.isAssignableFrom(type);
+  }
+
+  @Override
+  public Host convertFromText(String value, Class<?> targetType, String optionContext) {
+    return new Host(value);
+  }
+
+  @Override
+  public boolean getAllPossibleValues(List<Completion> completions, Class<?> targetType, String existingData, String optionContext, MethodTarget target) {
+    Set<String> hosts = client.getHostNames().keySet();
+    for (String host : hosts) {
+      completions.add(new Completion(host));
+    }
+    return true;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/customization/AmbariBanner.java
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/customization/AmbariBanner.java b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/customization/AmbariBanner.java
new file mode 100644
index 0000000..f97ef59
--- /dev/null
+++ b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/customization/AmbariBanner.java
@@ -0,0 +1,50 @@
+/**
+ * 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.shell.customization;
+
+import org.springframework.shell.plugin.BannerProvider;
+import org.springframework.stereotype.Component;
+
+import com.github.lalyos.jfiglet.FigletFont;
+
+/**
+ * Prints the banner when the user starts the shell.
+ */
+@Component
+public class AmbariBanner implements BannerProvider {
+
+  @Override
+  public String getProviderName() {
+    return "AmbariShell";
+  }
+
+  @Override
+  public String getBanner() {
+    return FigletFont.convertOneLine("AmbariShell");
+  }
+
+  @Override
+  public String getVersion() {
+    return getClass().getPackage().getImplementationVersion();
+  }
+
+  @Override
+  public String getWelcomeMessage() {
+    return "Welcome to Ambari Shell. For command and param completion press TAB, for assistance type 'hint'.";
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/customization/AmbariHistory.java
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/customization/AmbariHistory.java b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/customization/AmbariHistory.java
new file mode 100644
index 0000000..c23fc9a
--- /dev/null
+++ b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/customization/AmbariHistory.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.shell.customization;
+
+import org.springframework.shell.plugin.HistoryFileNameProvider;
+import org.springframework.stereotype.Component;
+
+/**
+ * Specifies the name of the Ambari command log. Later this log can be used
+ * to re-execute the commands with either the --cmdfile option at startup
+ * or with the script --file command.
+ */
+@Component
+public class AmbariHistory implements HistoryFileNameProvider {
+
+  @Override
+  public String getHistoryFileName() {
+    return "ambari-log.ash";
+  }
+
+  @Override
+  public String getProviderName() {
+    return "AmbariShell";
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/customization/AmbariPrompt.java
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/customization/AmbariPrompt.java b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/customization/AmbariPrompt.java
new file mode 100644
index 0000000..b91e76e
--- /dev/null
+++ b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/customization/AmbariPrompt.java
@@ -0,0 +1,43 @@
+/**
+ * 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.shell.customization;
+
+import org.apache.ambari.shell.model.AmbariContext;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.shell.plugin.PromptProvider;
+import org.springframework.stereotype.Component;
+
+/**
+ * Manages the text of the shell's prompt.
+ */
+@Component
+public class AmbariPrompt implements PromptProvider {
+
+  @Autowired
+  private AmbariContext context;
+
+  @Override
+  public String getProviderName() {
+    return AmbariPrompt.class.getSimpleName();
+  }
+
+  @Override
+  public String getPrompt() {
+    return context.getPrompt();
+  }
+}