ambari-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From su...@apache.org
Subject [2/4] AMBARI-6176. Integrate python shell into Ambari-shell module(subin)
Date Wed, 02 Jul 2014 17:36:50 GMT
http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/ambari_shell.py
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/ambari_shell.py b/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/ambari_shell.py
new file mode 100644
index 0000000..79af1a6
--- /dev/null
+++ b/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/ambari_shell.py
@@ -0,0 +1,412 @@
+#!/usr/bin/env python
+#
+#  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.
+
+
+import logging
+import logging.handlers
+import sys
+import signal
+import json
+import time
+import pdb
+import os
+import stat
+import cmd
+import string
+import bz2
+import datetime
+# import traceback
+import getpass
+import argparse
+import readline
+import ConfigParser
+import StringIO
+import subprocess
+import textwrap
+
+import utils.displayutils
+import utils.osutils
+import utils.pluginutils
+from ambari_client.ambari_api import AmbariClient
+
+
+configFile = "/etc/ambari-shell/conf/ambari-shell.ini"
+
+
+formatstr = "%(levelname)s %(asctime)s %(filename)s:%(lineno)d - %(message)s"
+LOG_MAX_BYTES = 10000000
+LOG_BACKUP = 2
+
+SHELL_CONFIG = {
+    'clustername': None,
+    'hostname': 'localhost',
+    'port': 8080,
+    'username': 'admin',
+    'password': 'admin',
+    'display_type': 'table',
+    'client': None,
+    'configFile': configFile}
+
+########################################################################
+#
+# Utility methods
+#
+########################################################################
+
+
+def exit_gracefully(signum, frame):
+    # restore the original signal handler as otherwise evil things will happen
+    # in raw_input when CTRL+C is pressed, and our signal handler is not
+    # re-entrant
+    signal.signal(signal.SIGINT, original_sigint)
+    print "\nExiting"
+    sys.exit(1)
+
+    # restore the exit gracefully handler here
+    signal.signal(signal.SIGINT, exit_gracefully)
+
+
+def exit_gracefully1(signum, frame):
+    # restore the original signal handler as otherwise evil things will happen
+    # in raw_input when CTRL+C is pressed, and our signal handler is not
+    # re-entrant
+    signal.signal(signal.SIGQUIT, original_sigint)
+    print "\nExiting"
+    sys.exit(1)
+
+    # restore the exit gracefully handler here
+    signal.signal(signal.SIGQUIT, exit_gracefully)
+
+
+def resolve_config():
+    try:
+        config = ConfigParser.RawConfigParser()
+        if os.path.exists(configFile):
+            print "looking  from " + configFile
+            config.read(configFile)
+        else:
+            raise Exception("No config found")
+    except Exception as err:
+        logging.warn(err)
+    print "found " + configFile
+    return config
+
+
+def get_log_level(loglevel):
+    loglev = loglevel.upper()
+    if loglev == "DEBUG":
+        return logging.DEBUG
+    elif loglev == "INFO":
+        return logging.INFO
+    elif loglev == "WARNING":
+        return logging.WARNING
+    elif loglev == "CRITICAL":
+        return logging.CRITICAL
+    elif loglev == "ERROR":
+        return logging.ERROR
+    elif loglev == "FATAL":
+        return logging.FATAL
+    else:
+        return logging.NOTSET
+
+
+def setup_logging(loglevel, logPath="./"):
+    try:
+        logging.root
+        curTimestamp = str(datetime.datetime.now())
+        ct = curTimestamp.split('.')[0]
+        curTime = ct.replace(':', '-')
+        datee = curTime.split(' ')[0]
+        timee = curTime.split(' ')[1]
+        # Set Log directory and log file name. Each run generates a new log
+        # file
+
+        logFile = logPath + 'ambaricli_' + datee + "_" + timee + '.log'
+        fh = open(logFile, 'w')
+        fh.write('*****************************************************\n')
+        fh.write('                Amabri Python CLI Log\n')
+        t = '                Timestamp: ' + ct + '\n'
+        fh.write(t)
+        fh.write('*****************************************************\n\n\n')
+        fh.close()
+        # Set the config for logging
+        logging.basicConfig(
+            filename=logFile,
+            format='%(asctime)s : %(levelname)s: %(message)s',
+            level=get_log_level(loglevel))
+    except IOError as e:
+        errStr = "  I/O error({0}): {1}".format(e.errno, e.strerror)
+        print errStr
+        sys.exit(1)
+    except Exception as exception:
+        print exception
+        sys.exit(1)
+
+
+def getLogLevel(configg):
+    loglevel = "debug"
+    try:
+        loglevel = configg.get('python_shell', 'loglevel')
+    except Exception:
+        logging.error("No loglevel found ")
+        return loglevel
+    return loglevel
+
+
+def getLogPath(configg):
+    logPath = "./"
+    try:
+        logPath = configg.get('python_shell', 'log_folder')
+    except Exception:
+        logging.error("No log_folder found")
+        return logPath
+    return logPath
+
+
+def getPluginPath(configg):
+    cliplugin_path = "./"
+    try:
+        cliplugin_path = configg.get('python_shell', 'cliplugin_folder')
+    except Exception:
+        logging.error("No cliplugin_folder found")
+        return cliplugin_path
+    return cliplugin_path
+
+
+def getDefaultPluginPath(configg):
+    cliplugin_path = "./"
+    try:
+        cliplugin_path = configg.get('python_shell', 'default_plugin_folder')
+    except Exception:
+        logging.error("No default_plugin_folder found")
+        return cliplugin_path
+    return cliplugin_path
+
+
+def getCommandsDict(ppath, cliplugin_path):
+    default_dictt = utils.pluginutils.getPlugins(ppath)
+    logging.debug("pluginutils returned default plugins >> %s ", default_dictt)
+    dictt = utils.pluginutils.getPlugins(cliplugin_path)
+    logging.debug("pluginutils returned >> %s ", dictt)
+    if(not set(default_dictt).isdisjoint(set(dictt))):
+        common_commands = set(default_dictt).intersection(set(dictt))
+        common_commands = " & ".join(str(x) for x in common_commands)
+        logging.error(
+            "ERROR :plugins folder has duplicate commands already present in default commands")
+        logging.error(common_commands)
+        print "ERROR :plugins folder has duplicate command already present in default commands"
+        print "pls remove following commands from plugin folder >" + str(common_commands)
+        sys.exit(1)
+    default_dictt.update(dictt)
+    return default_dictt
+
+
+class CmdBase(cmd.Cmd):
+
+    """CLI .
+    """
+
+    intro = utils.displayutils.shellBanner()
+    prompt = 'ambari>'
+    http_proxy = ''
+    https_proxy = ''
+    # headers
+    doc_header = "Commands"
+    undoc_header = "Other Commands"
+
+    def __init__(self):
+        cmd.Cmd.__init__(self)
+
+    def do_EOF(self, line):
+        logging.info("====== do_EOF ======")
+        return True
+
+    def do_exit(self, line):
+        logging.info("====== do_exit ======")
+        return True
+
+    def postloop(self):
+        logging.info("====== exit ======")
+
+#    def parseline(self, line):
+#        print 'parseline(%s) =>' % line,
+#        ret = cmd.Cmd.parseline(self, line)
+#        print ret
+#        return ret
+
+    def emptyline(self):
+        # print 'emptyline()'
+        # return cmd.Cmd.emptyline(self)
+        return
+
+    def default(self, line):
+        """Called on an input line when the command prefix is not recognized.
+
+        If this method is not overridden, it prints an error message and
+        returns.
+
+        """
+        self.stdout.write(
+            '*** Unknown command *** : %s \n type "help" to list all commands \n' %
+            line)
+
+
+class AmbariShell(CmdBase):
+
+    COMPONENTS = {}
+    SERVICES = None
+    CLUSTERS = None
+
+    def __init__(self):
+        CmdBase.__init__(self)
+        self.config = None
+        self.global_shell_config = SHELL_CONFIG
+
+    def preloop(self):
+        "Checks if the cluster was pre-defined"
+        self._set_prompt()
+
+    def _set_prompt(self):
+        if self.global_shell_config['clustername']:
+            self.prompt = "ambari-" + \
+                str(self.global_shell_config['clustername']) + ">"
+            logging.debug("found a cluster >" +
+                          str(self.global_shell_config['clustername']))
+        else:
+            self.prompt = 'ambari>'
+
+    def postcmd(self, stop, line):
+        # print 'postcmd(%s, %s)' % (stop, line)
+        self._set_prompt()
+        return cmd.Cmd.postcmd(self, stop, line)
+
+    def setConfig(self, customConfig):
+        self.config = customConfig
+
+    # core code should begin here
+
+    def generate_output(self, headers, rows):
+        if self.global_shell_config['display_type'] == "table":
+            print utils.displayutils.display_table(headers, rows)
+
+        if self.global_shell_config['display_type'] == "csv":
+            utils.displayutils.createCSV(headers, rows)
+
+        if self.global_shell_config['display_type'] == "xml":
+            print utils.displayutils.createXML(headers, rows)
+
+#
+# The "main" function
+
+
+def main():
+    parser = argparse.ArgumentParser(description='Ambari CLI')
+    parser.add_argument('-H', '--host', action='store', dest='host')
+    parser.add_argument(
+        '-p',
+        '--port',
+        action='store',
+        dest='port',
+        type=int,
+        default=8080)
+    parser.add_argument(
+        '-u',
+        '--user',
+        action='store',
+        dest='user',
+        default='admin')
+    parser.add_argument(
+        '-c',
+        '--clustername',
+        action='store',
+        dest='clustername')
+    parser.add_argument(
+        '--password',
+        action='store',
+        dest='password',
+        default='admin')
+    parser.add_argument(
+        '-d',
+        '--display_type',
+        action='store',
+        dest='display_type',
+        default='table')
+    parser.add_argument('-r', '--run', action='store', dest='run')
+    args = parser.parse_args()
+
+    # Check if a username was suplied, if not, prompt the user
+    if not args.host:
+        args.host = raw_input("Enter Ambari Server host: ")
+
+    if args.host:
+        SHELL_CONFIG['hostname'] = args.host
+    if args.clustername:
+        SHELL_CONFIG['clustername'] = args.clustername
+    if args.display_type:
+        SHELL_CONFIG['display_type'] = args.display_type
+
+    headers_dict = {'X-Requested-By': 'mycompany'}
+    client = AmbariClient(
+        SHELL_CONFIG['hostname'],
+        SHELL_CONFIG['port'],
+        SHELL_CONFIG['username'],
+        SHELL_CONFIG['password'],
+        version=1,
+        http_header=headers_dict)
+    SHELL_CONFIG['client'] = client
+
+    # do some plumbing
+    config = resolve_config()
+    logPath = getLogPath(config)
+    loglevel = getLogLevel(config)
+    cliplugin_path = getPluginPath(config)
+    dpath = getDefaultPluginPath(config)
+    setup_logging(loglevel, logPath)
+    # get ready to create a shell
+    utils.osutils.doclearScreen()
+    shell = AmbariShell()
+    logging.info("cliplugin_folder =  %s", getPluginPath(config))
+    logging.info("SHELL_CONFIG =  %s", str(SHELL_CONFIG))
+    # Get all commands
+
+    commands_dictt = getCommandsDict(dpath, cliplugin_path)
+    for k, v in commands_dictt.items():
+        setattr(AmbariShell, str(k), v)
+    shell.setConfig(config)
+
+    # Check if user is attempting non-interactive shell
+    if args.run:
+        print args.run
+        for command in args.run.split(';'):
+            shell.onecmd(command)
+            sys.exit(0)
+    else:
+        try:
+            shell.cmdloop()
+        except KeyboardInterrupt:
+            sys.stdout.write("\n")
+            sys.exit(0)
+    logging.info("finished")
+
+
+if __name__ == '__main__':
+    original_sigint = signal.getsignal(signal.SIGINT)
+    signal.signal(signal.SIGINT, exit_gracefully)
+    signal.signal(signal.SIGQUIT, exit_gracefully1)
+    signal.signal(signal.SIGTERM, exit_gracefully1)
+    main()

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/plugins/__init__.py
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/plugins/__init__.py b/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/plugins/__init__.py
new file mode 100644
index 0000000..278df2e
--- /dev/null
+++ b/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/plugins/__init__.py
@@ -0,0 +1,16 @@
+#
+#  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.

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/plugins/blueprint.py
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/plugins/blueprint.py b/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/plugins/blueprint.py
new file mode 100644
index 0000000..4d65163
--- /dev/null
+++ b/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/plugins/blueprint.py
@@ -0,0 +1,21 @@
+#!/usr/bin/env python
+#
+#  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.
+import logging
+import textwrap
+
+LOG = logging.getLogger(__name__)

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/plugins/connect_cluster.py
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/plugins/connect_cluster.py b/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/plugins/connect_cluster.py
new file mode 100644
index 0000000..c28d493
--- /dev/null
+++ b/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/plugins/connect_cluster.py
@@ -0,0 +1,81 @@
+#!/usr/bin/env python
+#
+#  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.
+import logging
+import textwrap
+
+LOG = logging.getLogger(__name__)
+
+
+def do_connect_cluster(self, cluster):
+
+    if not cluster:
+        self.help_connect_cluster()
+        return None
+
+    if not self.CLUSTERS:
+        clusters = [str(c.cluster_name).encode('ascii', 'ignore')
+                    for c in self.global_shell_config['client'].get_all_clusters()]
+        self.CLUSTERS = clusters
+
+    if cluster not in self.CLUSTERS:
+        print "ERROR ! cluster %s not found " % str(cluster)
+        print "        valid clusters are " + str(self.CLUSTERS)
+        return None
+    if self.global_shell_config['clustername']:
+        LOG.debug("old cluster = " + self.global_shell_config['clustername'])
+        self.global_shell_config['clustername'] = str(cluster)
+    else:
+        self.global_shell_config['clustername'] = cluster
+    self.prompt = "ambari-" + \
+        str(self.global_shell_config['clustername']) + ">"
+
+
+def help_connect_cluster(self):
+    print '\n'.join([' Usage:', '     connect_cluster <cluster_name>'])
+
+
+def do_disconnect_cluster(self, line):
+
+    if self.global_shell_config['clustername']:
+        LOG.debug("old cluster = " + self.global_shell_config['clustername'])
+    self.global_shell_config['clustername'] = None
+    self.prompt = "ambari>"
+
+
+def help_disconnect_cluster(self):
+    print '\n'.join([' Usage:', '     disconnect_cluster'])
+
+
+def complete_connect_cluster(self, pattern, line, start_index, end_index):
+    if not self.CLUSTERS:
+        clusters = [
+            (c.cluster_name).encode(
+                'ascii',
+                'ignore') for c in self.global_shell_config['client'].get_all_clusters()]
+        self.CLUSTERS = clusters
+
+    LOG.debug(
+        ("self.CLUSTERS = %s pattern = %s ") %
+        (str(
+            self.CLUSTERS),
+            pattern))
+    if pattern:
+        return [
+            c for c in self.CLUSTERS if c.startswith(pattern)]
+    else:
+        return self.CLUSTERS

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/plugins/create_cluster.py
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/plugins/create_cluster.py b/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/plugins/create_cluster.py
new file mode 100644
index 0000000..f9947d7
--- /dev/null
+++ b/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/plugins/create_cluster.py
@@ -0,0 +1,34 @@
+#!/usr/bin/env python
+#
+#  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.
+
+
+import logging
+import textwrap
+
+
+LOG = logging.getLogger(__name__)
+
+
+def do_create_cluster(self, line):
+    #  logging = self.LOG
+    print "TODO"
+    self.prompt = "ambari>"
+
+
+def help_create_cluster(self):
+    print '\n'.join([' Usage:', '     create_cluster <cluster_name>'])

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/plugins/service.py
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/plugins/service.py b/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/plugins/service.py
new file mode 100644
index 0000000..d44769a
--- /dev/null
+++ b/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/plugins/service.py
@@ -0,0 +1,125 @@
+#!/usr/bin/env python
+#
+#  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.
+
+
+import logging
+import textwrap
+
+
+LOG = logging.getLogger(__name__)
+
+
+def do_start_service(self, service):
+    if not service:
+        self.help_stop_service()
+        return None
+    clustername = self.global_shell_config['clustername']
+    if not clustername:
+        print("Error! No cluster currently selected")
+        return None
+
+    if self.t_service_action(service=service, action="start"):
+        print("%s is being started" % (service))
+    else:
+        print("Error! cannot start service")
+    return
+
+
+def do_stop_service(self, service):
+    if not service:
+        self.help_start_service()
+        return None
+
+    clustername = self.global_shell_config['clustername']
+    if not clustername:
+        print("Error! No cluster currently selected")
+        return None
+
+    if self.t_service_action(service=service, action="stop"):
+        print("%s is being stopped" % (service))
+    else:
+        print("Error! cannot stop service")
+        return
+
+
+def help_stop_service(self):
+    print textwrap.dedent("""
+    Usage:
+        > stop_service <service_name>
+    """)
+
+
+def help_start_service(self):
+    print textwrap.dedent("""
+    Usage:
+        > start_service <service_name>
+    """)
+
+
+def complete_start_service(self, pattern, line, start_index, end_index):
+    return self.services_complete(pattern, line, start_index, end_index)
+
+
+def complete_stop_service(self, pattern, line, start_index, end_index):
+    client = self.global_shell_config['client']
+    clustername = self.global_shell_config['clustername']
+    if not clustername:
+        return None
+    else:
+        if not self.SERVICES:
+            services = [
+                s.service_name for s in client.get_cluster(clustername).get_all_services()]
+            self.SERVICES = services
+
+    if pattern:
+        return [s for s in self.SERVICES if s.startswith(pattern)]
+    else:
+        return self.SERVICES
+
+
+def services_complete(self, pattern, line, start_index, end_index, append=[]):
+    client = self.global_shell_config['client']
+    clustername = self.global_shell_config['clustername']
+    if not clustername:
+        return None
+    else:
+        if not self.SERVICES:
+            services = [
+                s.service_name for s in client.get_cluster(clustername).get_all_services()]
+            self.SERVICES = services
+
+    if pattern:
+        return [s for s in self.SERVICES + append if s.startswith(pattern)]
+    else:
+        return self.SERVICES + append
+
+
+def t_service_action(self, service, action):
+    try:
+        client = self.global_shell_config['client']
+        cluster = self.global_shell_config['clustername']
+        service = client.get_cluster(cluster).get_service(service)
+    except Exception:
+        print("Service not found")
+        return None
+
+    if action == "start":
+        service.start(message='started by Ambari python CLI')
+    if action == "stop":
+        service.stop(message='stopped by Ambari python CLI')
+    return True

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/plugins/shell_config.py
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/plugins/shell_config.py b/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/plugins/shell_config.py
new file mode 100644
index 0000000..2facd02
--- /dev/null
+++ b/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/plugins/shell_config.py
@@ -0,0 +1,77 @@
+#!/usr/bin/env python
+#
+#  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.
+import logging
+import textwrap
+
+LOG = logging.getLogger(__name__)
+
+
+def do_get_shell_config(self, config_name):
+    rows = []
+    headers = ["KEY", "VAlUE"]
+    if not config_name:
+        for i in self.global_shell_config.items():
+            rows.append([i[0], i[1]])
+    else:
+        if config_name in self.global_shell_config.keys():
+            rows.append([config_name, self.global_shell_config[config_name]])
+
+    self.generate_output(headers, rows)
+
+
+def do_set_shell_config(self, config=None):
+    kv = config.split(" ")
+    if len(kv) != 2:
+        self.help_set_shell_config()
+        return
+    config_name = kv[0]
+    config_value = kv[1]
+    if config_name in self.global_shell_config.keys():
+        self.global_shell_config[config_name] = config_value
+
+    self.do_get_shell_config(config_name=None)
+
+
+def help_get_shell_config(self):
+    print textwrap.dedent("""
+    Usage:
+        > get_shell_config <config_name>     get all shell config
+    """)
+
+
+def help_set_shell_config(self):
+    print textwrap.dedent("""
+    Usage:
+        > set_shell_config <config_name> <config_value>     sets shell config
+    """)
+
+
+def complete_get_shell_config(self, pattern, line, start_index, end_index):
+    if pattern:
+        return [
+            c for c in self.global_shell_config.keys() if c.startswith(pattern)]
+    else:
+        return self.CLUSTERS
+
+
+def complete_set_shell_config(self, pattern, line, start_index, end_index):
+    if pattern:
+        return [
+            c for c in self.global_shell_config.keys() if c.startswith(pattern)]
+    else:
+        return self.CLUSTERS

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/plugins/show.py
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/plugins/show.py b/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/plugins/show.py
new file mode 100644
index 0000000..584b40a
--- /dev/null
+++ b/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/plugins/show.py
@@ -0,0 +1,155 @@
+#!/usr/bin/env python
+#
+#  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.
+
+
+import logging
+import textwrap
+
+LOG = logging.getLogger(__name__)
+
+
+def help_show(self):
+    print textwrap.dedent("""
+    Usage:
+        > show clusters     list clusters
+        > show hosts        list hosts
+        > show stacks       list stacks
+        > show services     list services
+        > show requests     list previous requests
+        > show blueprints   list blueprints
+    """)
+
+
+def do_show(self, option):
+    """
+    Usage:
+        > show clusters     list clusters
+        > show hosts        list hosts
+        > show stacks       list stacks
+        > show services     list services
+        > show requests     list previous requests
+        > show blueprints   list blueprints
+    """
+    headers = []
+    rows = []
+    options = [
+        "clusters",
+        "stacks",
+        "status",
+        "services",
+        "hosts",
+        "requests",
+        "blueprints"]
+
+    if not option:
+        self.help_show()
+        return
+
+    if option not in options:
+        self.default(option)
+        return
+
+    client = self.global_shell_config['client']
+    clustername = self.global_shell_config['clustername']
+    # show clusters
+    if option == "clusters":
+        "Display list of clusters on system"
+        headers = ["CLUSTER NAME"]
+        clusters = client.get_all_clusters()
+        for cluster in clusters:
+            rows.append([cluster.cluster_name])
+
+    # show clusters
+    if option == "stacks":
+        "Display list of stacks on system"
+        headers = ["STACK NAME"]
+        stacks = client.get_stacks(True)
+        for stack in stacks:
+            rows.append([stack.stack_version])
+
+    if option == "blueprints":
+        "Display list of blueprints on system"
+        headers = ["BLUEPRINT NAME", "VERSION"]
+        blues = client.get_blueprint()
+        for b in blues:
+            rows.append([b.blueprint_name, b.stack_version])
+
+    if option == "status":
+        "Display list of stacks on system"
+        headers = ["HOST_NAME", "ROLE", "STATUS"]
+        if not clustername:
+            print("Error! No cluster currently selected")
+            return
+        else:
+            tasks = client.get_task_status(clustername, 2)
+            for task in tasks:
+                rows.append([task.host_name, task.role, task.status])
+
+    # show hosts
+    if option == "hosts":
+        "Display a list of hosts avaiable on the system"
+        headers = ["HOSTNAME", "IP ADDRESS"]
+        if not clustername:
+            for host in client.get_all_hosts():
+                rows.append([host.host_name, host.ip])
+        else:
+            c = client.get_cluster(clustername)
+            for host in c.get_all_hosts():
+                rows.append([host.host_name, host.ip])
+
+    if option == "requests":
+        headers = ["REQUEST-ID", "STATUS"]
+        if not clustername:
+            print("Error! No cluster currently selected")
+            return
+        else:
+            c = client.get_cluster(clustername)
+            for req in client.get_requests(clustername):
+                rows.append([req.id, req.request_status])
+
+    # show services
+    if option == "services":
+        "Show list of services on the cluster"
+        headers = ["SERVICE", "STATUS"]
+
+        if not clustername:
+            print("Error! No cluster currently selected")
+            return
+        else:
+            c = client.get_cluster(clustername)
+            for service in c.get_all_services():
+                rows.append([service.service_name, service.state])
+
+    self.generate_output(headers, rows)
+
+
+def complete_show(self, pattern, line, start_index, end_index):
+    show_commands = [
+        "clusters",
+        "hosts",
+        "services",
+        "stacks",
+        "blueprints",
+        "requests"]
+    if pattern:
+        return [c for c in show_commands if c.startswith(pattern)]
+    else:
+        return show_commands
+
+if __name__ == '__main__':
+    do_show(None, None)

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/utils/__init__.py
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/utils/__init__.py b/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/utils/__init__.py
new file mode 100644
index 0000000..278df2e
--- /dev/null
+++ b/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/utils/__init__.py
@@ -0,0 +1,16 @@
+#
+#  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.

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/utils/displayutils.py
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/utils/displayutils.py b/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/utils/displayutils.py
new file mode 100644
index 0000000..3c45e7f
--- /dev/null
+++ b/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/utils/displayutils.py
@@ -0,0 +1,128 @@
+#!/usr/bin/env python
+#
+#  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.
+
+import logging
+import textwrap
+import cStringIO
+import operator
+from xml.etree import ElementTree as etree
+from functools import reduce
+
+
+LOG = logging.getLogger(__name__)
+
+
+class bcolors:
+    HEADER = '\033[95m'
+    OKBLUE = '\033[94m'
+    OKGREEN = '\033[92m'
+    WARNING = '\033[93m'
+    FAIL = '\033[91m'
+    ENDC = '\033[0m'
+
+    def disable(self):
+        self.HEADER = ''
+        self.OKBLUE = ''
+        self.OKGREEN = ''
+        self.WARNING = ''
+        self.FAIL = ''
+
+
+__header__ = textwrap.dedent("""
+   ___         __            _
+  / _ | __ _  / /  ___ _____(_)
+ / __ |/  ' \/ _ \/ _ `/ __/ /
+/_/ |_/_/_/_/_.__/\_,_/_/ /_/  CLI v%s
+""" % str(1))
+
+
+def shellBanner():
+    """
+     Prints the CLI Banner.
+    """
+    return __header__ + textwrap.dedent(
+        """
+    ====================================
+        Welcome to Ambari python CLI
+        type 'help' to list all commands..
+    ====================================
+    """)
+
+
+def createXML(headers, rows):
+    root = etree.Element('xmloutput')
+    for r in rows:
+        for h, relemt in zip(headers, r):
+
+            child = etree.Element(h.lower().replace(' ', '_'))
+            child.text = str(relemt)
+            root.append(child)
+
+    # pretty string
+    s = etree.tostring(root)
+    return s
+
+
+def createCSV(headers, rows):
+    headers = [x.lower().replace(' ', '_') for x in headers]
+    print(','.join(headers))
+    for r in rows:
+        print(','.join(r))
+
+
+def display_table(headers, rows):
+
+    delimiter = '='
+    delimiter1 = ' | '
+    output = cStringIO.StringIO()
+    temp_rows = [tuple(headers)] + rows
+    row_tuple = [(row,) for row in temp_rows]
+    # get max width
+    verticalrows = map(None, *reduce(operator.add, row_tuple))
+
+    if not rows:
+        widthList = [len(str(x)) for x in headers]
+        row_width = sum(widthList)
+    else:
+        widthList = [max([len(str(x)) for x in column])
+                     for column in verticalrows]
+        row_width = sum(widthList)
+    header_line = delimiter * \
+        (row_width + len(delimiter1) * (len(widthList) - 1))
+
+    i = 0
+    for rr in row_tuple:
+        for row in rr:
+            print >> output, delimiter1.join(
+                [(str(x)).ljust(width) for (x, width) in zip(row, widthList)])
+        if i == 0:
+            print >> output, header_line
+            i = 9999
+    return output.getvalue()
+
+
+if __name__ == '__main__':
+    print createXML(['STACK NAME', ], [[u'HDP']])
+    createCSV(['STACK NAME', ], [[u'HDP']])
+    headers = ['First Name', 'Last Name', 'Age']
+    data = \
+        '''Sam ,Browne,21
+       Jhon,Browne,23
+       Adam,senio,21'''
+    rows = [row.strip().split(',') for row in data.splitlines()]
+    print display_table(headers, rows)

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/utils/osutils.py
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/utils/osutils.py b/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/utils/osutils.py
new file mode 100644
index 0000000..8aeaa34
--- /dev/null
+++ b/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/utils/osutils.py
@@ -0,0 +1,69 @@
+#!/usr/bin/env python
+#
+#  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.
+
+import logging
+import os
+import sys
+import platform
+
+LOG = logging.getLogger(__name__)
+
+
+def clearScreen(operatingSys):
+    """
+    Function to clear the screen
+    Input   : OS
+    """
+    logging.info('Entering..')
+
+    if operatingSys == 'Windows':
+        cmdClear = 'CLS'
+    elif operatingSys == 'Linux':
+        cmdClear = 'clear'
+    elif operatingSys == 'Darwin':
+        cmdClear = 'clear'
+    logging.debug('Running command : %s', cmdClear)
+    os.system(cmdClear)
+    logging.info('Exiting..')
+
+
+def getOperatingSystem():
+    logging.info('Entering..')
+    operatingSys = platform.system()
+    # sprint operatingSys
+    if not operatingSys:
+        logging.error('Operating system is NULL.')
+        return False, ''
+    else:
+        logging.debug('Got operating system : %s', operatingSys)
+        logging.info('Exiting..')
+        return True, operatingSys
+
+
+def doclearScreen():
+    # Determine the OS
+    result, operatingSys = getOperatingSystem()
+    if not result:
+        logging.error('Failed to determine Operating System. Exiting.')
+        sys.exit(1)
+    # clear the Screen
+    clearScreen(operatingSys)
+
+
+if __name__ == '__main__':
+    pass

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/utils/pluginutils.py
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/utils/pluginutils.py b/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/utils/pluginutils.py
new file mode 100644
index 0000000..fdcb97c
--- /dev/null
+++ b/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/utils/pluginutils.py
@@ -0,0 +1,100 @@
+#!/usr/bin/env python
+#
+#  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.
+
+import logging
+import os
+import sys
+import inspect
+
+LOG = logging.getLogger(__name__)
+#------------------------------------------------------------------------------
+'''
+Function that searches for all plugins from a file
+Input   : folder
+Output  : dict
+'''
+#------------------------------------------------------------------------------
+
+
+def get_plugins(module):
+    logging.debug('[Module: %s]\n' % module.__name__)
+
+    plugin_method_map = {}
+    count = 0
+
+    for name in dir(module):
+        obj = getattr(module, name)
+        if inspect.isclass(obj):
+            count += 1
+        elif (inspect.ismethod(obj) or inspect.isfunction(obj)):
+            if obj.__name__.startswith("do_") or obj.__name__.startswith(
+                    "help_") or obj.__name__.startswith("complete_") or obj.__name__.startswith("t_"):
+                logging.debug("%s ,%s ", obj.__name__, obj)
+                plugin_method_map.update({obj.__name__: obj})
+                count += 1
+            elif inspect.isbuiltin(obj):
+                count += 1
+    logging.debug(plugin_method_map)
+    if count == 0:
+        logging.debug('(No members)')
+
+    return plugin_method_map
+
+
+def import_modules(dirr):
+    module_list = []
+    for f in os.listdir(os.path.abspath(dirr)):
+        module_name, ext = os.path.splitext(f)
+        if ext == '.py' and module_name != "ambari_shell":
+            logging.debug('imported module: %s' % (module_name))
+            module = __import__(module_name)
+            module_list.append(module)
+
+    return module_list
+
+
+def getPlugins(foldername):
+    if os.path.isdir(foldername):
+        sys.path.append(foldername)
+        logging.debug('%s is a directory!' % (foldername))
+
+    mod_list = import_modules(foldername)
+    logging.debug(mod_list)
+
+    plugin_method_map = {}
+    for m in mod_list:
+        dictt = get_plugins(m)
+        if dictt:
+            plugin_method_map.update(dictt)
+
+    return plugin_method_map
+
+
+def getPluginsFromModules(modulename):
+    module = __import__(modulename)
+    logging.debug(module)
+
+    plugin_method_map = {}
+    dictt = get_plugins(module)
+    if dictt:
+        plugin_method_map.update(dictt)
+
+    return plugin_method_map
+
+if __name__ == "__main__":
+    print getPlugins("plug")

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-python-shell/src/main/python/setup.py
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-python-shell/src/main/python/setup.py b/ambari-shell/ambari-python-shell/src/main/python/setup.py
new file mode 100755
index 0000000..b67d872
--- /dev/null
+++ b/ambari-shell/ambari-python-shell/src/main/python/setup.py
@@ -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.
+
+
+from setuptools import setup, find_packages
+
+from sys import version_info, platform
+
+if version_info[:2] > (2, 5):
+    install_requires = []
+else:
+    install_requires = ['simplejson >= 2.0.0']
+
+# Python 2.6 and below requires argparse
+if version_info[:2] < (2, 7):
+    install_requires += ['argparse']
+
+install_requires += ['ambari_client']
+setup(
+  name='ambari_shell',
+  author_email="ambari-dev@incubator.apache.org",
+  version="1.6.0-SNAPSHOT",
+  packages=['ambari_shell'],
+  install_requires=install_requires,
+  description='Ambari Python Shell',
+  license='Apache License 2.0'
+)

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-python-shell/src/packages/tarball/all.xml
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-python-shell/src/packages/tarball/all.xml b/ambari-shell/ambari-python-shell/src/packages/tarball/all.xml
new file mode 100755
index 0000000..0e4f34b
--- /dev/null
+++ b/ambari-shell/ambari-python-shell/src/packages/tarball/all.xml
@@ -0,0 +1,34 @@
+<?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 xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.1"
+          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+          xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.1 http://maven.apache.org/xsd/assembly-1.1.1.xsd">
+  <!--This 'all' id is not appended to the produced bundle because we do this:
+    http://maven.apache.org/plugins/maven-assembly-plugin/faq.html#required-classifiers
+  -->
+  <formats>
+    <format>dir</format>
+  </formats>
+  <includeBaseDirectory>false</includeBaseDirectory>
+  <fileSets>
+    <fileSet>
+      <directory>src/main/python</directory>
+      <outputDirectory>/</outputDirectory>
+    </fileSet>
+  </fileSets>
+</assembly>

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/assemblies/client.xml
----------------------------------------------------------------------
diff --git a/ambari-shell/assemblies/client.xml b/ambari-shell/assemblies/client.xml
new file mode 100644
index 0000000..20670cd
--- /dev/null
+++ b/ambari-shell/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/c8eceafc/ambari-shell/pom.xml
----------------------------------------------------------------------
diff --git a/ambari-shell/pom.xml b/ambari-shell/pom.xml
index a7e3400..947c9b9 100644
--- a/ambari-shell/pom.xml
+++ b/ambari-shell/pom.xml
@@ -1,14 +1,23 @@
 <?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">
+  <!--
+   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.
+-->
+
   <parent>
     <groupId>org.apache.ambari</groupId>
     <artifactId>ambari-project</artifactId>
@@ -18,106 +27,33 @@
   <modelVersion>4.0.0</modelVersion>
   <groupId>org.apache.ambari</groupId>
   <artifactId>ambari-shell</artifactId>
-  <packaging>jar</packaging>
-  <name>Ambari Shell</name>
+  <packaging>pom</packaging>
   <version>1.3.0-SNAPSHOT</version>
+  <name>Ambari Shell</name>
   <description>Ambari 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>
+  <modules>
+    <module>ambari-python-shell</module>
+    <module>ambari-groovy-shell</module>
+  </modules>
   <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>
+          <tarLongFileMode>gnu</tarLongFileMode>
+          <descriptors>
+            <descriptor>assemblies/client.xml</descriptor>
+          </descriptors>
         </configuration>
-      </plugin>
-      <plugin>
-        <groupId>org.springframework.boot</groupId>
-        <artifactId>spring-boot-maven-plugin</artifactId>
-        <version>1.0.2.RELEASE</version>
         <executions>
           <execution>
+            <id>build-tarball</id>
+            <phase>prepare-package</phase>
             <goals>
-              <goal>repackage</goal>
+              <goal>single</goal>
             </goals>
           </execution>
         </executions>
-        <configuration>
-          <mainClass>${start-class}</mainClass>
-        </configuration>
       </plugin>
       <plugin>
         <groupId>org.vafer</groupId>
@@ -132,9 +68,7 @@
           </execution>
         </executions>
         <configuration>
-          <controlDir>${basedir}/../../ambari-project/src/main/package/deb/control</controlDir>
-          <skip>true</skip>
-          <submodules>false</submodules>
+          <controlDir>${basedir}/../ambari-project/src/main/package/deb/control</controlDir>
         </configuration>
       </plugin>
     </plugins>

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/src/main/java/org/apache/ambari/shell/AmbariShell.java
----------------------------------------------------------------------
diff --git a/ambari-shell/src/main/java/org/apache/ambari/shell/AmbariShell.java b/ambari-shell/src/main/java/org/apache/ambari/shell/AmbariShell.java
deleted file mode 100644
index e842620..0000000
--- a/ambari-shell/src/main/java/org/apache/ambari/shell/AmbariShell.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.ambari.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/src/main/java/org/apache/ambari/shell/commands/BasicCommands.java
----------------------------------------------------------------------
diff --git a/ambari-shell/src/main/java/org/apache/ambari/shell/commands/BasicCommands.java b/ambari-shell/src/main/java/org/apache/ambari/shell/commands/BasicCommands.java
deleted file mode 100644
index 9babe12..0000000
--- a/ambari-shell/src/main/java/org/apache/ambari/shell/commands/BasicCommands.java
+++ /dev/null
@@ -1,207 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.ambari.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/src/main/java/org/apache/ambari/shell/commands/BlueprintCommands.java
----------------------------------------------------------------------
diff --git a/ambari-shell/src/main/java/org/apache/ambari/shell/commands/BlueprintCommands.java b/ambari-shell/src/main/java/org/apache/ambari/shell/commands/BlueprintCommands.java
deleted file mode 100644
index 73000d0..0000000
--- a/ambari-shell/src/main/java/org/apache/ambari/shell/commands/BlueprintCommands.java
+++ /dev/null
@@ -1,198 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.ambari.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/src/main/java/org/apache/ambari/shell/commands/ClusterCommands.java
----------------------------------------------------------------------
diff --git a/ambari-shell/src/main/java/org/apache/ambari/shell/commands/ClusterCommands.java b/ambari-shell/src/main/java/org/apache/ambari/shell/commands/ClusterCommands.java
deleted file mode 100644
index dafdb85..0000000
--- a/ambari-shell/src/main/java/org/apache/ambari/shell/commands/ClusterCommands.java
+++ /dev/null
@@ -1,294 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.ambari.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/src/main/java/org/apache/ambari/shell/commands/ElephantCommand.java
----------------------------------------------------------------------
diff --git a/ambari-shell/src/main/java/org/apache/ambari/shell/commands/ElephantCommand.java b/ambari-shell/src/main/java/org/apache/ambari/shell/commands/ElephantCommand.java
deleted file mode 100644
index a236054..0000000
--- a/ambari-shell/src/main/java/org/apache/ambari/shell/commands/ElephantCommand.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.ambari.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


Mime
View raw message