You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by bh...@apache.org on 2013/07/28 19:23:55 UTC

git commit: updated refs/heads/master to 6f84e74

Updated Branches:
  refs/heads/master 76c90efa4 -> 6f84e74a6


tools: Remove cloudmonkey, add info in INSTALL.md

After some discussion on the dev ML[1], we decided to move tools/cli which
contained cloudmonkey to a new git repository [2]. We did that by retaining
its history. In this commit, we remove tools/cli and add information on where
to find cloudmonkey. This is help us speed up cloudmonkey's development and
releases, now that with ApiDiscovery it's completely independent of any other
CloudStack modules.

[1] http://markmail.org/message/tjlr753xfhpw4uk4
[2] https://git-wip-us.apache.org/repos/asf?p=cloudstack-cloudmonkey.git

Signed-off-by: Rohit Yadav <bh...@apache.org>


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

Branch: refs/heads/master
Commit: 6f84e74a68d78705a06fe58f7927f42f61453a16
Parents: 76c90ef
Author: Rohit Yadav <bh...@apache.org>
Authored: Sun Jul 28 22:49:17 2013 +0530
Committer: Rohit Yadav <bh...@apache.org>
Committed: Sun Jul 28 22:53:12 2013 +0530

----------------------------------------------------------------------
 INSTALL.md                           |   7 +
 tools/cli/README                     |   1 +
 tools/cli/cloudmonkey/__init__.py    |  23 --
 tools/cli/cloudmonkey/cachemaker.py  | 181 ----------
 tools/cli/cloudmonkey/cloudmonkey.py | 538 ------------------------------
 tools/cli/cloudmonkey/config.py      | 122 -------
 tools/cli/cloudmonkey/printer.py     | 120 -------
 tools/cli/cloudmonkey/requester.py   | 165 ---------
 tools/cli/pom.xml                    |  73 ----
 tools/cli/setup.py                   |  68 ----
 tools/pom.xml                        |   1 -
 11 files changed, 8 insertions(+), 1291 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/6f84e74a/INSTALL.md
----------------------------------------------------------------------
diff --git a/INSTALL.md b/INSTALL.md
index b0e1a761..37415dc 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -213,6 +213,13 @@ Install needed packages:
     $ yum install cloud-agent                        # agent (kvm)
     $ yum install cloud-usage                        # usage server
 
+## Installing CloudMonkey CLI
+
+CloudMonkey is a CLI for Apache CloudStack. It was earlier in `tools/cli` within
+the source code but now it has its own repository:
+
+    https://git-wip-us.apache.org/repos/asf?p=cloudstack-cloudmonkey.git
+
 ## Notes
 
 If you will be using Xen as your hypervisor, please download [vhd-util](http://download.cloud.com.s3.amazonaws.com/tools/vhd-util)

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/6f84e74a/tools/cli/README
----------------------------------------------------------------------
diff --git a/tools/cli/README b/tools/cli/README
new file mode 100644
index 0000000..f8bfebe
--- /dev/null
+++ b/tools/cli/README
@@ -0,0 +1 @@
+Moved to https://git-wip-us.apache.org/repos/asf?p=cloudstack-cloudmonkey.git

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/6f84e74a/tools/cli/cloudmonkey/__init__.py
----------------------------------------------------------------------
diff --git a/tools/cli/cloudmonkey/__init__.py b/tools/cli/cloudmonkey/__init__.py
deleted file mode 100644
index cf689e7..0000000
--- a/tools/cli/cloudmonkey/__init__.py
+++ /dev/null
@@ -1,23 +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.
-
-try:
-    from config import __version__, __description__
-    from config import __maintainer__, __maintaineremail__
-    from config import __project__, __projecturl__, __projectemail__
-except ImportError, e:
-    print e

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/6f84e74a/tools/cli/cloudmonkey/cachemaker.py
----------------------------------------------------------------------
diff --git a/tools/cli/cloudmonkey/cachemaker.py b/tools/cli/cloudmonkey/cachemaker.py
deleted file mode 100644
index 47749e5..0000000
--- a/tools/cli/cloudmonkey/cachemaker.py
+++ /dev/null
@@ -1,181 +0,0 @@
-# -*- coding: utf-8 -*-
-# 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.
-
-try:
-    import json
-    import os
-    import types
-
-    from config import config_fields
-except ImportError, e:
-    import sys
-    print "ImportError", e
-    sys.exit(1)
-
-
-def getvalue(dictionary, key):
-    if key in dictionary:
-        return dictionary[key]
-    else:
-        return None
-
-
-def splitcsvstring(string):
-    if string is not None:
-        return filter(lambda x: x.strip() != '', string.split(','))
-    else:
-        return []
-
-
-def splitverbsubject(string):
-    idx = 0
-    for char in string:
-        if char.islower():
-            idx += 1
-        else:
-            break
-    return string[:idx].lower(), string[idx:].lower()
-
-
-def savecache(apicache, json_file):
-    """
-    Saves apicache dictionary as json_file, returns dictionary as indented str
-    """
-    if apicache is None or apicache is {}:
-        return ""
-    apicachestr = json.dumps(apicache, indent=2)
-    with open(json_file, 'w') as cache_file:
-        cache_file.write(apicachestr)
-    return apicachestr
-
-
-def loadcache(json_file):
-    """
-    Loads json file as dictionary, feeds it to monkeycache and spits result
-    """
-    f = open(json_file, 'r')
-    data = f.read()
-    f.close()
-    try:
-        apicache = json.loads(data)
-    except ValueError, e:
-        print "Error processing json:", json_file, e
-        return {}
-    return apicache
-
-
-def monkeycache(apis):
-    """
-    Feed this a dictionary of api bananas, it spits out processed cache
-    """
-    if isinstance(type(apis), types.NoneType) or apis is None:
-        return {}
-
-    responsekey = filter(lambda x: 'response' in x, apis.keys())
-
-    if len(responsekey) == 0:
-        print "[monkeycache] Invalid dictionary, has no response"
-        return None
-    if len(responsekey) != 1:
-        print "[monkeycache] Multiple responsekeys, chosing first one"
-
-    responsekey = responsekey[0]
-    verbs = set()
-    cache = {}
-    cache['count'] = getvalue(apis[responsekey], 'count')
-    cache['asyncapis'] = []
-
-    apilist = getvalue(apis[responsekey], 'api')
-    if apilist is None:
-        print "[monkeycache] Server response issue, no apis found"
-
-    for api in apilist:
-        name = getvalue(api, 'name')
-        verb, subject = splitverbsubject(name)
-
-        apidict = {}
-        apidict['name'] = name
-        apidict['description'] = getvalue(api, 'description')
-        apidict['isasync'] = getvalue(api, 'isasync')
-        if apidict['isasync']:
-            cache['asyncapis'].append(name)
-        apidict['related'] = splitcsvstring(getvalue(api, 'related'))
-
-        required = []
-        apiparams = []
-        for param in getvalue(api, 'params'):
-            apiparam = {}
-            apiparam['name'] = getvalue(param, 'name')
-            apiparam['description'] = getvalue(param, 'description')
-            apiparam['required'] = (getvalue(param, 'required') is True)
-            apiparam['length'] = int(getvalue(param, 'length'))
-            apiparam['type'] = getvalue(param, 'type')
-            apiparam['related'] = splitcsvstring(getvalue(param, 'related'))
-            if apiparam['required']:
-                required.append(apiparam['name'])
-            apiparams.append(apiparam)
-
-        apidict['requiredparams'] = required
-        apidict['params'] = apiparams
-        if verb not in cache:
-            cache[verb] = {}
-        cache[verb][subject] = apidict
-        verbs.add(verb)
-
-    cache['verbs'] = list(verbs)
-    return cache
-
-
-def main(json_file):
-    """
-    cachemaker.py creates a precache datastore of all available apis of
-    CloudStack and dumps the precache dictionary in an
-    importable python module. This way we cheat on the runtime overhead of
-    completing commands and help docs. This reduces the overall search and
-    cache_miss (computation) complexity from O(n) to O(1) for any valid cmd.
-    """
-    f = open("precache.py", "w")
-    f.write("""# -*- coding: utf-8 -*-
-# Auto-generated code by cachemaker.py
-# 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.""")
-    f.write("\napicache = %s" % loadcache(json_file))
-    f.close()
-
-if __name__ == "__main__":
-    cache_file = config_fields['core']['cache_file']
-    print "[cachemaker] Pre-caching using user's cloudmonkey cache", cache_file
-    if os.path.exists(cache_file):
-        main(cache_file)
-    else:
-        print "[cachemaker] Unable to cache apis, file not found", cache_file
-        print "[cachemaker] Run cloudmonkey sync to generate cache"

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/6f84e74a/tools/cli/cloudmonkey/cloudmonkey.py
----------------------------------------------------------------------
diff --git a/tools/cli/cloudmonkey/cloudmonkey.py b/tools/cli/cloudmonkey/cloudmonkey.py
deleted file mode 100644
index 13f54ad..0000000
--- a/tools/cli/cloudmonkey/cloudmonkey.py
+++ /dev/null
@@ -1,538 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-# 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.
-
-try:
-    import atexit
-    import cmd
-    import json
-    import logging
-    import os
-    import pdb
-    import shlex
-    import sys
-    import types
-    import copy
-
-    from cachemaker import loadcache, savecache, monkeycache, splitverbsubject
-    from config import __version__, __description__, __projecturl__
-    from config import read_config, write_config, config_file
-    from optparse import OptionParser
-    from prettytable import PrettyTable
-    from printer import monkeyprint
-    from requester import monkeyrequest
-except ImportError, e:
-    print("Import error in %s : %s" % (__name__, e))
-    import sys
-    sys.exit()
-
-try:
-    from precache import apicache
-except ImportError:
-    apicache = {'count': 0, 'verbs': [], 'asyncapis': []}
-
-try:
-    import readline
-except ImportError, e:
-    print("Module readline not found, autocompletions will fail", e)
-else:
-    import rlcompleter
-    if 'libedit' in readline.__doc__:
-        readline.parse_and_bind("bind ^I rl_complete")
-    else:
-        readline.parse_and_bind("tab: complete")
-
-log_fmt = '%(asctime)s - %(filename)s:%(lineno)s - [%(levelname)s] %(message)s'
-logger = logging.getLogger(__name__)
-
-
-class CloudMonkeyShell(cmd.Cmd, object):
-    intro = ("☁ Apache CloudStack 🐵 cloudmonkey " + __version__ +
-             ". Type help or ? to list commands.\n")
-    ruler = "="
-    config_options = []
-    verbs = []
-
-    def __init__(self, pname, cfile):
-        self.program_name = pname
-        self.config_file = cfile
-        self.config_options = read_config(self.get_attr, self.set_attr,
-                                          self.config_file)
-        self.loadcache()
-        self.prompt = self.prompt.strip() + " "  # Cosmetic fix for prompt
-
-        logging.basicConfig(filename=self.log_file,
-                            level=logging.DEBUG, format=log_fmt)
-        logger.debug("Loaded config fields:\n%s" % map(lambda x: "%s=%s" %
-                                                       (x, getattr(self, x)),
-                                                       self.config_options))
-        cmd.Cmd.__init__(self)
-
-        try:
-            if os.path.exists(self.history_file):
-                readline.read_history_file(self.history_file)
-        except IOError, e:
-            logger.debug("Error: Unable to read history. " + str(e))
-        atexit.register(readline.write_history_file, self.history_file)
-
-    def get_attr(self, field):
-        return getattr(self, field)
-
-    def set_attr(self, field, value):
-        return setattr(self, field, value)
-
-    def emptyline(self):
-        pass
-
-    def cmdloop(self, intro=None):
-        print(self.intro)
-        while True:
-            try:
-                super(CloudMonkeyShell, self).cmdloop(intro="")
-                self.postloop()
-            except KeyboardInterrupt:
-                print("^C")
-
-    def loadcache(self):
-        if os.path.exists(self.cache_file):
-            self.apicache = loadcache(self.cache_file)
-        else:
-            self.apicache = apicache
-        if 'verbs' in self.apicache:
-            self.verbs = self.apicache['verbs']
-
-        for verb in self.verbs:
-            def add_grammar(verb):
-                def grammar_closure(self, args):
-                    if self.pipe_runner("%s %s" % (verb, args)):
-                        return
-                    if ' --help' in args or ' -h' in args:
-                        self.do_help("%s %s" % (verb, args))
-                        return
-                    try:
-                        args_partition = args.partition(" ")
-                        cmd = self.apicache[verb][args_partition[0]]['name']
-                        args = args_partition[2]
-                    except KeyError, e:
-                        self.monkeyprint("Error: invalid %s api arg" % verb, e)
-                        return
-                    self.default("%s %s" % (cmd, args))
-                return grammar_closure
-
-            grammar_handler = add_grammar(verb)
-            grammar_handler.__doc__ = "%ss resources" % verb.capitalize()
-            grammar_handler.__name__ = 'do_' + str(verb)
-            setattr(self.__class__, grammar_handler.__name__, grammar_handler)
-
-    def monkeyprint(self, *args):
-        output = ""
-        try:
-            for arg in args:
-                if isinstance(type(arg), types.NoneType):
-                    continue
-                output += str(arg)
-        except Exception, e:
-            print(e)
-
-        if self.color == 'true':
-            monkeyprint(output)
-        else:
-            print(output)
-
-    def print_result(self, result, result_filter=None):
-        if result is None or len(result) == 0:
-            return
-
-        def printer_helper(printer, toprow):
-            if printer:
-                self.monkeyprint(printer)
-            return PrettyTable(toprow)
-
-        def print_result_json(result, result_filter=None):
-            tfilter = {}  # temp var to hold a dict of the filters
-            tresult = copy.deepcopy(result)  # dupe the result to filter
-            if result_filter is not None:
-                for res in result_filter:
-                    tfilter[res] = 1
-                myresults = {}
-                for okey, oval in result.iteritems():
-                    if isinstance(oval, dict):
-                        for tkey in x:
-                            if tkey not in tfilter:
-                                try:
-                                    del(tresult[okey][x][tkey])
-                                except:
-                                    pass
-                    elif isinstance(oval, list):
-                        for x in range(len(oval)):
-                            if isinstance(oval[x], dict):
-                                for tkey in oval[x]:
-                                    if tkey not in tfilter:
-                                        try:
-                                            del(tresult[okey][x][tkey])
-                                        except:
-                                            pass
-                            else:
-                                try:
-                                    del(tresult[okey][x])
-                                except:
-                                    pass
-            print json.dumps(tresult,
-                             sort_keys=True,
-                             indent=2,
-                             separators=(',', ': '))
-
-        def print_result_tabular(result, result_filter=None):
-            toprow = None
-            printer = None
-            for node in result:
-                if toprow != node.keys():
-                    if result_filter is not None and len(result_filter) != 0:
-                        commonkeys = filter(lambda x: x in node.keys(),
-                                            result_filter)
-                        if commonkeys != toprow:
-                            toprow = commonkeys
-                            printer = printer_helper(printer, toprow)
-                    else:
-                        toprow = node.keys()
-                        printer = printer_helper(printer, toprow)
-                row = map(lambda x: node[x], toprow)
-                if printer and row:
-                    printer.add_row(row)
-            if printer:
-                self.monkeyprint(printer)
-
-        def print_result_as_dict(result, result_filter=None):
-            if self.display == "json":
-                print_result_json(result, result_filter)
-                return
-
-            for key in sorted(result.keys(), key=lambda x:
-                              x not in ['id', 'count', 'name'] and x):
-                if not (isinstance(result[key], list) or
-                        isinstance(result[key], dict)):
-                    self.monkeyprint("%s = %s" % (key, result[key]))
-                else:
-                    self.monkeyprint(key + ":")
-                    self.print_result(result[key], result_filter)
-
-        def print_result_as_list(result, result_filter=None):
-            for node in result:
-                if isinstance(node, dict) and self.display == 'table':
-                    print_result_tabular(result, result_filter)
-                    break
-                self.print_result(node)
-                if len(result) > 1:
-                    self.monkeyprint(self.ruler * 80)
-
-        if isinstance(result, dict):
-            print_result_as_dict(result, result_filter)
-        elif isinstance(result, list):
-            print_result_as_list(result, result_filter)
-        elif isinstance(result, str):
-            print result
-        elif not (str(result) is None):
-            self.monkeyprint(result)
-
-    def make_request(self, command, args={}, isasync=False):
-        response, error = monkeyrequest(command, args, isasync,
-                                        self.asyncblock, logger,
-                                        self.host, self.port,
-                                        self.apikey, self.secretkey,
-                                        self.timeout, self.protocol, self.path)
-        if error is not None:
-            self.monkeyprint(error)
-        return response
-
-    def default(self, args):
-        if self.pipe_runner(args):
-            return
-
-        apiname = args.partition(' ')[0]
-        verb, subject = splitverbsubject(apiname)
-
-        lexp = shlex.shlex(args.strip())
-        lexp.whitespace = " "
-        lexp.whitespace_split = True
-        lexp.posix = True
-        args = []
-        while True:
-            next_val = lexp.next()
-            if next_val is None:
-                break
-            args.append(next_val.replace('\x00', ''))
-
-        args_dict = dict(map(lambda x: [x.partition("=")[0],
-                                        x.partition("=")[2]],
-                             args[1:])[x] for x in range(len(args) - 1))
-        field_filter = None
-        if 'filter' in args_dict:
-            field_filter = filter(lambda x: x is not '',
-                                  map(lambda x: x.strip(),
-                                      args_dict.pop('filter').split(',')))
-
-        missing = []
-        if verb in self.apicache and subject in self.apicache[verb]:
-            missing = filter(lambda x: x not in args_dict.keys(),
-                             self.apicache[verb][subject]['requiredparams'])
-
-        if len(missing) > 0:
-            self.monkeyprint("Missing arguments: ", ' '.join(missing))
-            return
-
-        isasync = False
-        if 'asyncapis' in self.apicache:
-            isasync = apiname in self.apicache['asyncapis']
-
-        result = self.make_request(apiname, args_dict, isasync)
-
-        if result is None:
-            return
-        try:
-            responsekeys = filter(lambda x: 'response' in x, result.keys())
-            for responsekey in responsekeys:
-                self.print_result(result[responsekey], field_filter)
-            print
-        except Exception as e:
-            self.monkeyprint("🙈  Error on parsing and printing", e)
-
-    def completedefault(self, text, line, begidx, endidx):
-        partitions = line.partition(" ")
-        verb = partitions[0].strip()
-        rline = partitions[2].lstrip().partition(" ")
-        subject = rline[0]
-        separator = rline[1]
-        params = rline[2].lstrip()
-
-        if verb not in self.verbs:
-            return []
-
-        autocompletions = []
-        search_string = ""
-
-        if separator != " ":   # Complete verb subjects
-            autocompletions = self.apicache[verb].keys()
-            search_string = subject
-        else:                  # Complete subject params
-            autocompletions = map(lambda x: x + "=",
-                                  map(lambda x: x['name'],
-                                      self.apicache[verb][subject]['params']))
-            search_string = text
-            if self.paramcompletion == 'true':
-                param = line.split(" ")[-1]
-                idx = param.find("=")
-                value = param[idx + 1:]
-                param = param[:idx]
-                if len(value) < 36 and idx != -1:
-                    params = self.apicache[verb][subject]['params']
-                    related = filter(lambda x: x['name'] == param,
-                                     params)[0]['related']
-                    api = min(filter(lambda x: 'list' in x, related), key=len)
-                    response = self.make_request(api, args={'listall': 'true'})
-                    responsekey = filter(lambda x: 'response' in x,
-                                         response.keys())[0]
-                    result = response[responsekey]
-                    uuids = []
-                    for key in result.keys():
-                        if isinstance(result[key], list):
-                            for element in result[key]:
-                                if 'id' in element.keys():
-                                    uuids.append(element['id'])
-                    autocompletions = uuids
-                    search_string = value
-
-        if subject != "" and (self.display == "table" or
-                              self.display == "json"):
-            autocompletions.append("filter=")
-        return [s for s in autocompletions if s.startswith(search_string)]
-
-    def do_sync(self, args):
-        """
-        Asks cloudmonkey to discovery and sync apis available on user specified
-        CloudStack host server which has the API discovery plugin, on failure
-        it rollbacks last datastore or api precached datastore.
-        """
-        response = self.make_request("listApis")
-        if response is None:
-            monkeyprint("Failed to sync apis, please check your config?")
-            monkeyprint("Note: `sync` requires api discovery service enabled" +
-                        " on the CloudStack management server")
-            return
-        self.apicache = monkeycache(response)
-        savecache(self.apicache, self.cache_file)
-        monkeyprint("%s APIs discovered and cached" % self.apicache["count"])
-        self.loadcache()
-
-    def do_api(self, args):
-        """
-        Make raw api calls. Syntax: api <apiName> <args>=<values>.
-
-        Example:
-        api listAccount listall=true
-        """
-        if len(args) > 0:
-            return self.default(args)
-        else:
-            self.monkeyprint("Please use a valid syntax")
-
-    def do_set(self, args):
-        """
-        Set config for cloudmonkey. For example, options can be:
-        host, port, apikey, secretkey, log_file, history_file
-        You may also edit your ~/.cloudmonkey_config instead of using set.
-
-        Example:
-        set host 192.168.56.2
-        set prompt 🐵 cloudmonkey>
-        set log_file /var/log/cloudmonkey.log
-        """
-        args = args.strip().partition(" ")
-        key, value = (args[0], args[2])
-        setattr(self, key, value)  # keys and attributes should have same names
-        self.prompt = self.prompt.strip() + " "  # prompt fix
-        write_config(self.get_attr, self.config_file)
-
-    def complete_set(self, text, line, begidx, endidx):
-        mline = line.partition(" ")[2]
-        offs = len(mline) - len(text)
-        return [s[offs:] for s in self.config_options
-                if s.startswith(mline)]
-
-    def pipe_runner(self, args):
-        if args.find(' |') > -1:
-            pname = self.program_name
-            if '.py' in pname:
-                pname = "python " + pname
-            self.do_shell("%s %s" % (pname, args))
-            return True
-        return False
-
-    def do_shell(self, args):
-        """
-        Execute shell commands using shell <command> or !<command>
-
-        Example:
-        !ls
-        shell ls
-        !for((i=0; i<10; i++)); do cloudmonkey create user account=admin \
-            email=test@test.tt firstname=user$i lastname=user$i \
-            password=password username=user$i; done
-        """
-        os.system(args)
-
-    def do_help(self, args):
-        """
-        Show help docs for various topics
-
-        Example:
-        help list
-        help list users
-        ?list
-        ?list users
-        """
-        fields = args.partition(" ")
-        if fields[2] == "":
-            cmd.Cmd.do_help(self, args)
-        else:
-            verb = fields[0]
-            subject = fields[2].partition(" ")[0]
-            if subject in self.apicache[verb]:
-                api = self.apicache[verb][subject]
-                helpdoc = "(%s) %s" % (api['name'], api['description'])
-                if api['isasync']:
-                    helpdoc += "\nThis API is asynchronous."
-                required = api['requiredparams']
-                if len(required) > 0:
-                    helpdoc += "\nRequired params are %s" % ' '.join(required)
-                helpdoc += "\nParameters\n" + "=" * 10
-                for param in api['params']:
-                    helpdoc += "\n%s = (%s) %s" % (param['name'],
-                               param['type'], param['description'])
-                self.monkeyprint(helpdoc)
-            else:
-                self.monkeyprint("Error: no such api (%s) on %s" %
-                                 (subject, verb))
-
-    def complete_help(self, text, line, begidx, endidx):
-        fields = line.partition(" ")
-        subfields = fields[2].partition(" ")
-
-        if subfields[1] != " ":
-            return cmd.Cmd.complete_help(self, text, line, begidx, endidx)
-        else:
-            line = fields[2]
-            text = subfields[2]
-            return self.completedefault(text, line, begidx, endidx)
-
-    def do_EOF(self, args):
-        """
-        Quit on Ctrl+d or EOF
-        """
-        sys.exit()
-
-    def do_exit(self, args):
-        """
-        Quit CloudMonkey CLI
-        """
-        return self.do_quit(args)
-
-    def do_quit(self, args):
-        """
-        Quit CloudMonkey CLI
-        """
-        self.monkeyprint("Bye!")
-        return self.do_EOF(args)
-
-
-class MonkeyParser(OptionParser):
-    def format_help(self, formatter=None):
-        if formatter is None:
-            formatter = self.formatter
-        result = []
-        if self.usage:
-            result.append("Usage: cloudmonkey [options] [cmds] [params]\n\n")
-        if self.description:
-            result.append(self.format_description(formatter) + "\n")
-        result.append(self.format_option_help(formatter))
-        result.append("\nTry cloudmonkey [help|?]\n")
-        return "".join(result)
-
-
-def main():
-    parser = MonkeyParser()
-    parser.add_option("-c", "--config-file",
-                      dest="cfile", default=config_file,
-                      help="config file for cloudmonkey", metavar="FILE")
-    parser.add_option("-v", "--version",
-                      action="store_true", dest="version", default=False,
-                      help="prints cloudmonkey version information")
-
-    (options, args) = parser.parse_args()
-    if options.version:
-        print "cloudmonkey", __version__
-        print __description__, "(%s)" % __projecturl__
-        sys.exit(0)
-
-    shell = CloudMonkeyShell(sys.argv[0], options.cfile)
-    if len(args) > 0:
-        shell.onecmd(' '.join(args))
-    else:
-        shell.cmdloop()
-
-if __name__ == "__main__":
-    main()

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/6f84e74a/tools/cli/cloudmonkey/config.py
----------------------------------------------------------------------
diff --git a/tools/cli/cloudmonkey/config.py b/tools/cli/cloudmonkey/config.py
deleted file mode 100644
index 36f7e77..0000000
--- a/tools/cli/cloudmonkey/config.py
+++ /dev/null
@@ -1,122 +0,0 @@
-# -*- coding: utf-8 -*-
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License.  You may obtain a copy of the License at
-#
-#   http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied.  See the License for the
-# specific language governing permissions and limitations
-# under the License.
-
-# Use following rules for versioning:
-# <cloudstack version>-<cli increment, starts from 0>
-__version__ = "4.2.0-0"
-__description__ = "Command Line Interface for Apache CloudStack"
-__maintainer__ = "Rohit Yadav"
-__maintaineremail__ = "bhaisaab@apache.org"
-__project__ = "The Apache CloudStack Team"
-__projectemail__ = "dev@cloudstack.apache.org"
-__projecturl__ = "http://cloudstack.apache.org"
-
-try:
-    import os
-    import sys
-
-    from ConfigParser import ConfigParser, SafeConfigParser
-    from os.path import expanduser
-except ImportError, e:
-    print "ImportError", e
-
-param_type = ['boolean', 'date', 'float', 'integer', 'short', 'list',
-              'long', 'object', 'map', 'string', 'tzdate', 'uuid']
-
-iterable_type = ['set', 'list', 'object']
-
-config_dir = expanduser('~/.cloudmonkey')
-config_file = expanduser(config_dir + '/config')
-
-# cloudmonkey config fields
-config_fields = {'core': {}, 'server': {}, 'user': {}, 'ui': {}}
-
-# core
-config_fields['core']['asyncblock'] = 'true'
-config_fields['core']['paramcompletion'] = 'false'
-config_fields['core']['cache_file'] = expanduser(config_dir + '/cache')
-config_fields['core']['history_file'] = expanduser(config_dir + '/history')
-config_fields['core']['log_file'] = expanduser(config_dir + '/log')
-
-# ui
-config_fields['ui']['color'] = 'true'
-config_fields['ui']['prompt'] = '> '
-config_fields['ui']['display'] = 'default'
-
-# server
-config_fields['server']['host'] = 'localhost'
-config_fields['server']['path'] = '/client/api'
-config_fields['server']['port'] = '8080'
-config_fields['server']['protocol'] = 'http'
-config_fields['server']['timeout'] = '3600'
-
-# user
-config_fields['user']['apikey'] = ''
-config_fields['user']['secretkey'] = ''
-
-
-def write_config(get_attr, config_file, first_time=False):
-    global config_fields
-    config = ConfigParser()
-    for section in config_fields.keys():
-        config.add_section(section)
-        for key in config_fields[section].keys():
-            if first_time:
-                config.set(section, key, config_fields[section][key])
-            else:
-                config.set(section, key, get_attr(key))
-    with open(config_file, 'w') as cfg:
-        config.write(cfg)
-    return config
-
-
-def read_config(get_attr, set_attr, config_file):
-    global config_fields, config_dir
-    if not os.path.exists(config_dir):
-        os.makedirs(config_dir)
-
-    config_options = reduce(lambda x, y: x + y, map(lambda x:
-                            config_fields[x].keys(), config_fields.keys()))
-
-    if os.path.exists(config_file):
-        config = ConfigParser()
-        try:
-            with open(config_file, 'r') as cfg:
-                config.readfp(cfg)
-        except IOError, e:
-            print "Error: config_file not found", e
-    else:
-        config = write_config(get_attr, config_file, True)
-        print "Welcome! Using `set` configure the necessary settings:"
-        print " ".join(sorted(config_options))
-        print "Config file:", config_file
-        print "After setting up, run the `sync` command to sync apis\n"
-
-    missing_keys = []
-    for section in config_fields.keys():
-        for key in config_fields[section].keys():
-            try:
-                set_attr(key, config.get(section, key))
-            except Exception:
-                missing_keys.append(key)
-
-    if len(missing_keys) > 0:
-        print "Please fix `%s` in %s" % (', '.join(missing_keys), config_file)
-        sys.exit()
-
-    return config_options

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/6f84e74a/tools/cli/cloudmonkey/printer.py
----------------------------------------------------------------------
diff --git a/tools/cli/cloudmonkey/printer.py b/tools/cli/cloudmonkey/printer.py
deleted file mode 100644
index 925e765..0000000
--- a/tools/cli/cloudmonkey/printer.py
+++ /dev/null
@@ -1,120 +0,0 @@
-# -*- coding: utf-8 -*-
-# 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.
-
-try:
-    from pygments import highlight
-    from pygments.console import ansiformat
-    from pygments.formatter import Formatter
-    from pygments.formatters import Terminal256Formatter
-    from pygments.lexer import bygroups, include, RegexLexer
-    from pygments.token import *
-
-    import sys
-except ImportError, e:
-    print e
-
-
-MONKEY_COLORS = {
-    Token:          '',
-    Whitespace:     'reset',
-    Text:           'reset',
-
-    Name:           'green',
-    Operator:       'teal',
-    Operator.Word:  'lightgray',
-    String:         'purple',
-
-    Keyword:        '_red_',
-    Error:          'red',
-    Literal:        'yellow',
-    Number:         'blue',
-}
-
-
-def get_colorscheme():
-    return MONKEY_COLORS
-
-
-class MonkeyLexer(RegexLexer):
-    keywords = ['[a-z]*id', '^[a-z A-Z]*:']
-    attributes = ['[Tt]rue', '[Ff]alse']
-    params = ['[a-z]*[Nn]ame', 'type', '[Ss]tate']
-
-    uuid_rgx = r'[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}'
-    date_rgx = r'[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9:]{8}-[0-9]{4}'
-
-    def makelistre(lis):
-        return r'(' + r'|'.join(lis) + r')'
-
-    tokens = {
-        'root': [
-            (r' ', Whitespace),
-            (date_rgx, Number),
-            (uuid_rgx, Literal),
-            (r'(?:\b\d+\b(?:-\b\d+|%)?)', Number),
-            (r'^[-=]*\n', Operator.Word),
-            (r'Error', Error),
-            (makelistre(attributes), Literal),
-            (makelistre(params) + r'( = )(.*)', bygroups(Name, Operator,
-                                                         String)),
-            (makelistre(keywords), Keyword),
-            (makelistre(params), Name),
-            (r'(^[a-zA-Z]* )(=)', bygroups(Name, Operator)),
-            (r'\S+', Text),
-        ]
-    }
-
-    def analyse_text(text):
-        npos = text.find('\n')
-        if npos < 3:
-            return False
-        return text[0] == '[' and text[npos - 1] == ']'
-
-
-class MonkeyFormatter(Formatter):
-    def __init__(self, **options):
-        Formatter.__init__(self, **options)
-        self.colorscheme = get_colorscheme()
-
-    def format(self, tokensource, outfile):
-        return Formatter.format(self, tokensource, outfile)
-
-    def format_unencoded(self, tokensource, outfile):
-        for ttype, value in tokensource:
-            color = self.colorscheme.get(ttype)
-            while color is None:
-                ttype = ttype[:-1]
-                color = self.colorscheme.get(ttype)
-            if color:
-                spl = value.split('\n')
-                for line in spl[:-1]:
-                    if line:
-                        outfile.write(ansiformat(color, line))
-                    outfile.write('\n')
-                if spl[-1]:
-                    outfile.write(ansiformat(color, spl[-1]))
-            else:
-                outfile.write(value)
-
-
-def monkeyprint(text):
-    fmter = MonkeyFormatter()
-    lexer = MonkeyLexer()
-    lexer.encoding = 'utf-8'
-    fmter.encoding = 'utf-8'
-    highlight(text, lexer, fmter, sys.stdout)

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/6f84e74a/tools/cli/cloudmonkey/requester.py
----------------------------------------------------------------------
diff --git a/tools/cli/cloudmonkey/requester.py b/tools/cli/cloudmonkey/requester.py
deleted file mode 100644
index b06e1fc..0000000
--- a/tools/cli/cloudmonkey/requester.py
+++ /dev/null
@@ -1,165 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-# 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.
-
-try:
-    import base64
-    import hashlib
-    import hmac
-    import httplib
-    import json
-    import os
-    import pdb
-    import re
-    import shlex
-    import sys
-    import time
-    import types
-    import urllib
-    import urllib2
-    from urllib2 import urlopen, HTTPError, URLError
-
-except ImportError, e:
-    print "Import error in %s : %s" % (__name__, e)
-    import sys
-    sys.exit()
-
-
-def logger_debug(logger, message):
-    if logger is not None:
-        logger.debug(message)
-
-
-def make_request(command, args, logger, host, port,
-                 apikey, secretkey, protocol, path):
-    response = None
-    error = None
-
-    if protocol != 'http' and protocol != 'https':
-        error = "Protocol must be 'http' or 'https'"
-        return None, error
-
-    if args is None:
-        args = {}
-
-    args["command"] = command
-    args["apiKey"] = apikey
-    args["response"] = "json"
-    request = zip(args.keys(), args.values())
-    request.sort(key=lambda x: x[0].lower())
-
-    request_url = "&".join(["=".join([r[0], urllib.quote_plus(str(r[1]))])
-                           for r in request])
-    hashStr = "&".join(["=".join([r[0].lower(),
-                       str.lower(urllib.quote_plus(str(r[1]))).replace("+",
-                       "%20")]) for r in request])
-
-    sig = urllib.quote_plus(base64.encodestring(hmac.new(secretkey, hashStr,
-                            hashlib.sha1).digest()).strip())
-    request_url += "&signature=%s" % sig
-    request_url = "%s://%s:%s%s?%s" % (protocol, host, port, path, request_url)
-
-    try:
-        logger_debug(logger, "Request sent: %s" % request_url)
-        connection = urllib2.urlopen(request_url)
-        response = connection.read()
-    except HTTPError, e:
-        error = "%s: %s" % (e.msg, e.info().getheader('X-Description'))
-    except URLError, e:
-        error = e.reason
-
-    logger_debug(logger, "Response received: %s" % response)
-    if error is not None:
-        logger_debug(logger, "Error: %s" % (error))
-        return response, error
-
-    return response, error
-
-
-def monkeyrequest(command, args, isasync, asyncblock, logger, host, port,
-                  apikey, secretkey, timeout, protocol, path):
-    response = None
-    error = None
-    logger_debug(logger, "======== START Request ========")
-    logger_debug(logger, "Requesting command=%s, args=%s" % (command, args))
-    response, error = make_request(command, args, logger, host, port,
-                                   apikey, secretkey, protocol, path)
-    logger_debug(logger, "======== END Request ========\n")
-
-    if error is not None:
-        return response, error
-
-    def process_json(response):
-        try:
-            response = json.loads(str(response))
-        except ValueError, e:
-            error = "Error processing json response, %s" % e
-            logger_debug(logger, "Error processing json: %s" % e)
-
-        return response
-
-    response = process_json(response)
-    if response is None:
-        return response, error
-
-    isasync = isasync and (asyncblock == "true")
-    responsekey = filter(lambda x: 'response' in x, response.keys())[0]
-
-    if isasync and 'jobid' in response[responsekey]:
-        jobid = response[responsekey]['jobid']
-        command = "queryAsyncJobResult"
-        request = {'jobid': jobid}
-        timeout = int(timeout)
-        pollperiod = 2
-        progress = 1
-        while timeout > 0:
-            print '\r' + '.' * progress,
-            sys.stdout.flush()
-            time.sleep(pollperiod)
-            timeout = timeout - pollperiod
-            progress += 1
-            logger_debug(logger, "Job %s to timeout in %ds" % (jobid, timeout))
-            response, error = make_request(command, request, logger,
-                                           host, port, apikey, secretkey,
-                                           protocol, path)
-            if error is not None:
-                return response, error
-
-            response = process_json(response)
-            responsekeys = filter(lambda x: 'response' in x, response.keys())
-
-            if len(responsekeys) < 1:
-                continue
-
-            result = response[responsekeys[0]]
-            jobstatus = result['jobstatus']
-            if jobstatus == 2:
-                jobresult = result["jobresult"]
-                error = "\rAsync job %s failed\nError %s, %s" % (jobid,
-                        jobresult["errorcode"], jobresult["errortext"])
-                return response, error
-            elif jobstatus == 1:
-                print "\r" + " " * progress,
-                return response, error
-            else:
-                logger_debug(logger, "We should not arrive here!")
-                sys.stdout.flush()
-
-        error = "Error: Async query timeout occurred for jobid %s" % jobid
-
-    return response, error

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/6f84e74a/tools/cli/pom.xml
----------------------------------------------------------------------
diff --git a/tools/cli/pom.xml b/tools/cli/pom.xml
deleted file mode 100644
index b4820cd..0000000
--- a/tools/cli/pom.xml
+++ /dev/null
@@ -1,73 +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.
--->
-<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">
-  <modelVersion>4.0.0</modelVersion>
-  <artifactId>cloud-cli</artifactId>
-  <name>Apache CloudStack cloudmonkey cli</name>
-  <packaging>pom</packaging>
-  <parent>
-    <groupId>org.apache.cloudstack</groupId>
-    <artifactId>cloud-tools</artifactId>
-    <version>4.2.0-SNAPSHOT</version>
-    <relativePath>../pom.xml</relativePath>
-  </parent>
-
-  <build>
-    <defaultGoal>install</defaultGoal>
-    <plugins>
-      <plugin>
-        <groupId>org.codehaus.mojo</groupId>
-        <artifactId>exec-maven-plugin</artifactId>
-        <version>1.2.1</version>
-        <executions>
-          <execution>
-            <id>cachemaker</id>
-            <phase>compile</phase>
-            <goals>
-              <goal>exec</goal>
-            </goals>
-            <configuration>
-              <workingDirectory>${basedir}/cloudmonkey</workingDirectory>
-              <executable>python</executable>
-              <arguments>
-                  <argument>cachemaker.py</argument>
-              </arguments>
-            </configuration>
-          </execution>
-          <execution>
-            <id>package</id>
-            <phase>compile</phase>
-            <goals>
-              <goal>exec</goal>
-            </goals>
-            <configuration>
-              <workingDirectory>${basedir}</workingDirectory>
-              <executable>python</executable>
-              <arguments>
-                  <argument>setup.py</argument>
-                  <argument>sdist</argument>
-              </arguments>
-            </configuration>
-          </execution>
-        </executions>
-      </plugin>
-    </plugins>
-  </build>
-</project>

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/6f84e74a/tools/cli/setup.py
----------------------------------------------------------------------
diff --git a/tools/cli/setup.py b/tools/cli/setup.py
deleted file mode 100644
index 4c7b297..0000000
--- a/tools/cli/setup.py
+++ /dev/null
@@ -1,68 +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.
-
-try:
-    from setuptools import setup, find_packages
-except ImportError:
-    from distribute_setup import use_setuptools
-    use_setuptools()
-    from setuptools import setup, find_packages
-
-from cloudmonkey import __version__, __description__
-from cloudmonkey import __maintainer__, __maintaineremail__
-from cloudmonkey import __project__, __projecturl__, __projectemail__
-
-try:
-    import readline
-except ImportError:
-    requires.append('readline')
-
-setup(
-    name = 'cloudmonkey',
-    version = __version__,
-    author = __project__,
-    author_email = __projectemail__,
-    maintainer = __maintainer__,
-    maintainer_email = __maintaineremail__,
-    url = __projecturl__,
-    description = __description__,
-    long_description = "cloudmonkey is a CLI for Apache CloudStack",
-    platforms = ("Any",),
-    license = 'ASL 2.0',
-    packages = find_packages(),
-    install_requires = [
-        'Pygments>=1.5',
-        'prettytable>=0.6',
-    ],
-    include_package_data = True,
-    zip_safe = False,
-    classifiers = [
-        "Development Status :: 5 - Production/Stable",
-        "Environment :: Console",
-        "Intended Audience :: Developers",
-        "Intended Audience :: End Users/Desktop",
-        "Operating System :: OS Independent",
-        "Programming Language :: Python",
-        "Topic :: Software Development :: Testing",
-        "Topic :: Software Development :: Interpreters",
-        "Topic :: Utilities",
-    ],
-    entry_points="""
-    [console_scripts]
-    cloudmonkey = cloudmonkey.cloudmonkey:main
-    """,
-)

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/6f84e74a/tools/pom.xml
----------------------------------------------------------------------
diff --git a/tools/pom.xml b/tools/pom.xml
index 09961bb..49cf135 100644
--- a/tools/pom.xml
+++ b/tools/pom.xml
@@ -37,7 +37,6 @@
     <modules>
         <module>apidoc</module>
         <module>marvin</module>
-        <module>cli</module>
         <module>devcloud</module>
         <module>devcloud-kvm</module>
     </modules>