This is an automated email from the ASF dual-hosted git repository. rohit pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/cloudstack-cloudmonkey.git
commit 7b55fb417ac6788b009c1caf040f2a9dbb6e0031 Author: Rohit Yadav <ro...@apache.org> AuthorDate: Wed Apr 11 04:02:40 2018 +0530 cloudmonkey: purge legacy files Signed-off-by: Rohit Yadav <ro...@apache.org> --- .gitignore | 28 -- Dockerfile | 36 -- Makefile | 41 -- cloudmonkey/__init__.py | 23 -- cloudmonkey/cachemaker.py | 182 --------- cloudmonkey/cloudmonkey.py | 937 -------------------------------------------- cloudmonkey/config.py | 209 ---------- cloudmonkey/precache.py | 19 - cloudmonkey/printer.py | 124 ------ cloudmonkey/requester.py | 335 ---------------- config.docker | 25 -- docs/.gitignore | 1 - docs/Makefile | 177 --------- docs/source/cloudmonkey.rst | 62 --- docs/source/conf.py | 262 ------------- docs/source/index.rst | 37 -- docs/source/modules.rst | 7 - setup.cfg | 7 - setup.py | 86 ---- 19 files changed, 2598 deletions(-) diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 63c8cd1..0000000 --- a/.gitignore +++ /dev/null @@ -1,28 +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. - -dist/ -*~ -*.log -*.pyc -*.egginfo/ -*.egg-info/ -.DS_Store -*.swp -build/ -.* -!.gitignore diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 696974d..0000000 --- a/Dockerfile +++ /dev/null @@ -1,36 +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. -# -# -FROM python:2 - -MAINTAINER "Apache CloudStack" <d...@cloudstack.apache.org> -LABEL Description="Apache CloudStack CloudMonkey; Python based CloudStack command line interface" -LABEL Vendor="Apache.org" -LABEL License=ApacheV2 -LABEL Version=5.3.3 - -COPY . /cloudstack-cloudmonkey -RUN pip install requests -RUN (cd /cloudstack-cloudmonkey; python setup.py build) -RUN (cd /cloudstack-cloudmonkey; python setup.py install) - -RUN mkdir -p /cloudmonkey -WORKDIR /cloudmonkey -COPY config.docker /cloudmonkey/config - -ENTRYPOINT ["cloudmonkey", "-c", "/cloudmonkey/config"] \ No newline at end of file diff --git a/Makefile b/Makefile deleted file mode 100644 index 182cbce..0000000 --- a/Makefile +++ /dev/null @@ -1,41 +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. - -all: clean buildwithcache - -runtests: - nosetests -v --verbosity=3 - -buildwithcache: buildcache build - -build: - python setup.py build - python setup.py sdist - -check: - pep8 cloudmonkey/*.py - -buildcache: - python cloudmonkey/cachemaker.py - mv -f precache.py cloudmonkey/ - -install: clean - python setup.py sdist - pip install --upgrade dist/cloudmonkey-*.tar.gz - -clean: - rm -frv build dist *egg-info diff --git a/cloudmonkey/__init__.py b/cloudmonkey/__init__.py deleted file mode 100644 index cf689e7..0000000 --- a/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 diff --git a/cloudmonkey/cachemaker.py b/cloudmonkey/cachemaker.py deleted file mode 100644 index 2f2fa87..0000000 --- a/cloudmonkey/cachemaker.py +++ /dev/null @@ -1,182 +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 - apidict['response'] = getvalue(api, 'response') - 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" diff --git a/cloudmonkey/cloudmonkey.py b/cloudmonkey/cloudmonkey.py deleted file mode 100644 index b106362..0000000 --- a/cloudmonkey/cloudmonkey.py +++ /dev/null @@ -1,937 +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 argcomplete - import argparse - import atexit - import cmd - import csv - import copy - import json - import logging - import os - import shlex - import sys - import time - import types - - from cachemaker import loadcache, savecache, monkeycache, splitverbsubject - from config import __version__, __description__, __projecturl__ - from config import display_types - from config import read_config, write_config, config_file, default_profile - from dicttoxml import dicttoxml - from optparse import OptionParser - from prettytable import PrettyTable - from printer import monkeyprint - from requester import monkeyrequest - from requester import login - from requester import logout - from urlparse import urlparse - from xml.dom.minidom import parseString -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': []} - -normal_readline = True -# Fix terminal env before importing readline -# Without it, char ESC[?1034h gets printed in output -# There is not TERM variable in some environment such as Docker. -if 'TERM' not in os.environ or os.environ['TERM'].startswith('xterm'): - os.environ['TERM'] = 'vt100' -try: - import readline -except ImportError, e: - print("Module readline not found, autocompletions will fail", e) -else: - import rlcompleter - readline_doc = getattr(readline, '__doc__', '') - if readline_doc is not None and 'libedit' in readline_doc: - readline.parse_and_bind("bind ^I rl_complete") - readline.parse_and_bind("bind ^R em-inc-search-prev") - normal_readline = False - 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 = [] - profile_names = [] - verbs = [] - interpreterMode = False - error_on_last_command = False - param_cache = {} - prompt = "🐵 > " - protocol = "http" - host = "localhost" - port = "8080" - path = "/client/api" - hook_count = 0 - - def __init__(self, pname, cfile): - self.default_apis = self.completenames('') - 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.init_credential_store() - 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(u"Error: Unable to read history. " + unicode(e)) - atexit.register(readline.write_history_file, self.history_file) - - def init_credential_store(self): - self.credentials = {'apikey': self.apikey, 'secretkey': self.secretkey, - 'domain': self.domain, 'username': self.username, - 'password': self.password, - 'signatureversion': self.signatureversion} - parsed_url = urlparse(self.url) - self.protocol = "http" if not parsed_url.scheme else parsed_url.scheme - self.host = parsed_url.netloc - self.port = "8080" if not parsed_url.port else parsed_url.port - self.path = parsed_url.path - self.set_prompt() - - def get_prompt(self): - return self.prompt.split(") ")[-1] - - def set_prompt(self): - self.prompt = "(%s) %s" % (self.profile, self.get_prompt()) - - 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): - self.interpreterMode = True - print(self.intro) - print "Using management server profile:", self.profile, "\n" - while True: - try: - super(CloudMonkeyShell, self).cmdloop(intro="") - except KeyboardInterrupt: - print("^C") - - def precmd(self, line): - self.hook_count -= 1 - if self.hook_count <= 0: - self.hook_count = 0 - readline.set_startup_hook() - return line - - 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: - handler_name = "do_" + str(verb) - handler_doc = str("%ss resources" % verb.capitalize()) - - if hasattr(self, handler_name) and getattr(self, handler_name).__doc__ == handler_doc: - continue - - def add_grammar(verb): - default_handler = None - if self.default_apis.__contains__(verb): - default_handler = getattr(self, handler_name) - - def grammar_closure(self, args): - if not args: - if default_handler: - default_handler(args) - return - args = args.decode("utf-8") - if self.pipe_runner(u"{0} {1}".format(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: - if default_handler: - default_handler(args) - else: - self.monkeyprint("Error: invalid %s api arg " % verb, - str(e)) - return - self.default(u"{0} {1}".format(cmd, args)) - return grammar_closure - - grammar_handler = add_grammar(verb) - grammar_handler.__doc__ = handler_doc - grammar_handler.__name__ = handler_name - setattr(self.__class__, grammar_handler.__name__, grammar_handler) - - def monkeyprint(self, *args): - output = u"" - try: - for arg in args: - if isinstance(type(arg), types.NoneType) or not arg: - continue - if not (isinstance(arg, str) or isinstance(arg, unicode)): - arg = unicode(arg) - output += arg - except Exception, e: - print(str(e)) - - output = output.encode("utf-8") - if self.color == 'true': - monkeyprint(output) - else: - if output.startswith("Error"): - sys.stderr.write(output + "\n") - sys.stderr.flush() - else: - print output - - def print_result(self, result, result_filter=[]): - if not result or len(result) == 0: - return - - filtered_result = copy.deepcopy(result) - if result_filter and isinstance(result_filter, list) \ - and len(result_filter) > 0: - tfilter = {} # temp var to hold a dict of the filters - tresult = filtered_result # dupe the result to filter - if result_filter: - for res in result_filter: - tfilter[res] = 1 - for okey, oval in result.iteritems(): - if isinstance(oval, dict): - for tkey in oval: - if tkey not in tfilter: - try: - del(tresult[okey][oval][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 - filtered_result = tresult - - def print_result_json(result): - self.monkeyprint(json.dumps(result, - sort_keys=True, - indent=2, - ensure_ascii=False, - separators=(',', ': '))) - - def print_result_xml(result): - custom_root = "CloudStack-%s" % self.profile.replace(" ", "_") - xml = dicttoxml(result, attr_type=False, custom_root=custom_root) - self.monkeyprint(parseString(xml).toprettyxml()) - - def print_result_csv(result): - if "count" in result: - result.pop("count") - - if len(result.keys()) == 1: - item = result[result.keys()[0]] - if isinstance(item, list): - result = item - elif isinstance(item, dict): - result = [item] - - if isinstance(result, list) and len(result) > 0: - if isinstance(result[0], dict): - keys = result[0].keys() - writer = csv.DictWriter(sys.stdout, keys) - print ','.join(keys) - for item in result: - row = {} - for k in keys: - if k not in item: - row[k] = None - else: - if type(item[k]) is unicode: - row[k] = item[k].encode('utf8') - else: - row[k] = item[k] - writer.writerow(row) - elif isinstance(result, dict): - keys = result.keys() - writer = csv.DictWriter(sys.stdout, keys) - print ','.join(keys) - writer.writerow(result) - - def print_result_tabular(result): - def print_table(printer, toprow): - if printer: - self.monkeyprint(printer.get_string()) - return PrettyTable(toprow) - printer = None - toprow = [] - if not result: - return - toprow = set(reduce(lambda x, y: x + y, map(lambda x: x.keys(), - filter(lambda x: isinstance(x, dict), result)))) - printer = print_table(printer, toprow) - for node in result: - if not node: - continue - for key in toprow: - if key not in node: - node[key] = '' - row = map(lambda x: node[x], toprow) - if printer and row: - printer.add_row(row) - print_table(printer, toprow) - - def print_result_as_dict(result): - for key in sorted(result.keys(), key=lambda x: - x not in ['id', 'count', 'name'] and x): - if isinstance(result[key], list): - self.monkeyprint(key + ":") - print_result_as_list(result[key]) - elif isinstance(result[key], dict): - self.monkeyprint(key + ":") - print_result_as_dict(result[key]) - else: - value = unicode(result[key]) - self.monkeyprint(key, " = ", value) - - def print_result_as_list(result): - for idx, node in enumerate(result): - if isinstance(node, dict): - if self.display == 'table': - print_result_tabular(result) - break - print_result_as_dict(node) - elif isinstance(node, list): - print_result_as_list(node) - else: - self.monkeyprint(filtered_result) - if result and node and (idx+1) < len(result): - self.monkeyprint(self.ruler * 80) - - if self.display == "json": - print_result_json(filtered_result) - return - - if self.display == "xml": - print_result_xml(filtered_result) - return - - if self.display == "csv": - print_result_csv(filtered_result) - return - - if isinstance(filtered_result, dict): - print_result_as_dict(filtered_result) - elif isinstance(filtered_result, list): - print_result_as_list(filtered_result) - else: - self.monkeyprint(filtered_result) - - def make_request(self, command, args={}, isasync=False): - self.error_on_last_command = False - response, error = monkeyrequest(command, args, isasync, - self.asyncblock, logger, - self.url, self.credentials, - self.timeout, self.expires, - self.verifysslcert == 'true', - self.signatureversion) - if error: - self.monkeyprint(u"Error {0}".format(error)) - self.error_on_last_command = True - return response - - def update_param_cache(self, api, result={}): - if not api: - return - logger.debug("Updating param cache for %s API" % api) - responsekey = filter(lambda x: 'response' in x, result.keys())[0] - result = result[responsekey] - options = [] - uuids = [] - for key in result.keys(): - if isinstance(result[key], list): - for element in result[key]: - if 'id' in element.keys(): - uuid = unicode(element['id']) - name = "" - keyspace = ["name", "displayname", - "username", "description"] - for name_key in keyspace: - if name_key in element.keys(): - name = element[name_key] - break - options.append((uuid, name,)) - uuids.append(uuid) - self.param_cache[api] = {} - self.param_cache[api]["ts"] = int(time.time()) - self.param_cache[api]["options"] = sorted(options) - return sorted(uuids) - - def default(self, args): - try: - args = args.strip() - args.decode("utf-8") - except UnicodeError, ignore: - args = args.encode("utf-8") - - if self.pipe_runner(args): - return - - apiname = args.partition(' ')[0] - verb, subject = splitverbsubject(apiname) - - lexp = shlex.shlex(args) - lexp.whitespace = " " - lexp.whitespace_split = True - lexp.posix = True - args = [] - while True: - try: - next_val = lexp.next() - if not next_val: - break - next_val = next_val.decode("utf-8") - args.append(next_val.replace(u'\x00', u'')) - except ValueError, err: - self.monkeyprint("Command parsing error: ", err) - return - - args_dict = dict(map(lambda x: [x.partition("=")[0], - x.partition("=")[2]], - args[1:])[x] for x in range(len(args) - 1)) - - field_filter = [] - if 'filter' in args_dict: - field_filter = filter(lambda x: x.strip() != '', - args_dict.pop('filter').split(',')) - field_filter = list(set(field_filter)) - - missing = [] - if verb in self.apicache and subject in self.apicache[verb]: - missing = filter(lambda x: x not in [key.split('[')[0].lower() - for key in args_dict], - self.apicache[verb][subject]['requiredparams']) - - if len(missing) > 0: - self.monkeyprint("Missing arguments: ", ' '.join(missing)) - return - - isasync = False - if 'asyncapis' in self.apicache: - if apiname.decode("utf-8") in self.apicache["asyncapis"]: - isasync = True - - result = self.make_request(apiname, args_dict, isasync) - - if not result or not isinstance(result, dict): - if isinstance(result, unicode): - result = result.decode("utf-8") - logger.debug("Invalid command result: %s" % result) - return - - try: - responsekeys = filter(lambda x: 'response' in x, result.keys()) - for responsekey in responsekeys: - self.print_result(result[responsekey], field_filter) - if apiname.startswith("list") and "id" not in args_dict: - self.update_param_cache(apiname, result) - except Exception as e: - self.monkeyprint("Error on parsing and printing ", e) - - def completedefault(self, text, line, begidx, endidx): - partitions = line[:endidx].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 = map(lambda x: x + " ", - 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[:endidx].split(" ")[-1] - idx = param.find("=") - value = param[idx + 1:] - param = param[:idx] - if param == "filter": - response_params = self.apicache[verb][subject]["response"] - used = filter(lambda x: x.strip() != "", - value.split(",")[:-1]) - unused = map(lambda x: x['name'] + ",", filter(lambda x: - "name" in x and x["name"] not in used, - response_params)) - last_value = value.split(",")[-1] - if last_value: - unused = filter(lambda x: x.startswith(last_value), - unused) - suffix = ",".join(used) - if suffix: - suffix += "," - global normal_readline - if normal_readline: - return filter(lambda x: x.startswith(last_value), - map(lambda x: x, unused)) - else: # OSX fix - return filter(lambda x: x.startswith(value), - map(lambda x: suffix + x, unused)) - elif len(value) < 36 and idx != -1: - api = None - logger.debug("[Paramcompl] For %s %s %s=" % (verb, subject, - param)) - if "id" in param: - logger.debug("[Paramcompl] Using 'list' heuristics") - if param == "id" or param == "ids": - entity = subject - else: - entity = param.replace("id", "") - apis = [] - for resource in self.apicache["list"]: - if resource.startswith(entity): - api = self.apicache["list"][resource]['name'] - if (entity + "s") == resource.lower(): - break - apis.append(api) - api = None - if len(apis) > 0 and not api: - logger.debug("[Paramcompl] APIs: %s" % apis) - api = min(apis, key=len) - logger.debug("[Paramcompl] Possible API: %s" % api) - if not api: - logger.debug("[Paramcompl] Using relative approx") - params = self.apicache[verb][subject]['params'] - arg = filter(lambda x: x['name'] == param, params)[0] - if "type" in arg and arg["type"] == "boolean": - return filter(lambda x: x.startswith(value), - ["true ", "false "]) - related = arg['related'] - apis = filter(lambda x: 'list' in x, related) - logger.debug("[Paramcompl] Related APIs: %s" % apis) - if len(apis) > 0: - api = apis[0] - else: - if param == "account": - api = "listAccounts" - else: - return - uuids = [] - cache_burst_ts = int(time.time()) - 900 - logger.debug("Trying paramcompletion using API: %s" % api) - if api in self.param_cache.keys() and \ - len(self.param_cache[api]["options"]) > 0 and \ - self.param_cache[api]["ts"] > cache_burst_ts: - for option in self.param_cache[api]["options"]: - uuid = option[0] - if uuid.startswith(value): - uuids.append(uuid) - else: - api_args = {'listall': 'true', 'templatefilter': 'all'} - response = self.make_request(api, args=api_args) - if not response: - return - uuids = self.update_param_cache(api, response) - if len(uuids) > 1: - print - options = sorted(self.param_cache[api]["options"], - key=lambda x: x[1]) - for option in options: - uuid = option[0] - name = option[1] - if uuid.startswith(value): - print uuid, name - autocompletions = map(lambda x: x + " ", uuids) - search_string = value - - if subject != "" and line.split(" ")[-1].find('=') == -1: - 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 not response: - 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: - url, auth, log_file, history_file - You may also edit your ~/.cloudmonkey_config instead of using set. - - Example: - set url http://localhost:8080/client/api - set prompt 🐵 cloudmonkey> - set log_file /var/log/cloudmonkey.log - """ - args = args.strip().partition(" ") - key, value = (args[0].strip(), args[2].strip()) - if not key: - return - allowed_blank_keys = ["username", "password", "apikey", "secretkey", - "domain"] - if key not in allowed_blank_keys and not value: - print "Blank value of %s is not allowed" % key - return - - self.prompt = self.get_prompt() - setattr(self, key, value) - if key in ['host', 'port', 'path', 'protocol']: - key = 'url' - self.url = "%s://%s:%s%s" % (self.protocol, self.host, - self.port, self.path) - print "This option has been deprecated, please set 'url' instead" - print "This server url will be used:", self.url - write_config(self.get_attr, self.config_file) - read_config(self.get_attr, self.set_attr, self.config_file) - self.init_credential_store() - if key.strip() == 'profile' and self.interpreterMode: - print "\nLoaded server profile '%s' with options:" % value - for option in default_profile.keys(): - value = self.get_attr(option) - if option in ["password", "apikey", "secretkey"] and value: - value = value[:2] + "XXX" + value[4:6] + "YYY...(hidden)" - print " %s = %s" % (option, value) - print - - def complete_set(self, text, line, begidx, endidx): - mline = line.partition(" ")[2].lstrip().partition(" ") - option = mline[0].strip() - separator = mline[1] - value = mline[2].lstrip() - if separator == "": - return [s for s in self.config_options if s.startswith(option)] + self.completedefault(text, line, begidx, endidx) - elif option == "profile": - return [s for s in self.profile_names if s.startswith(value)] - elif option == "display": - return [s for s in display_types - if s.startswith(value)] - elif option in ["asyncblock", "color", "paramcompletion", - "verifysslcert"]: - return [s for s in ["true", "false"] if s.startswith(value)] - elif "set" in self.apicache["verbs"]: - return self.completedefault(text, line, begidx, endidx) - - return [] - - def do_login(self, args): - """ - Login using stored credentials. Starts a session to be reused for - subsequent api calls - """ - try: - session, sessionkey = login(self.url, self.username, self.password) - self.credentials['session'] = session - self.credentials['sessionkey'] = sessionkey - except Exception, e: - self.monkeyprint("Error: Login failed to the server: ", unicode(e)) - - def do_logout(self, args): - """ - Logout of session started with login with username and password - """ - try: - logout(self.url, self.credentials.get('session')) - except Exception, e: - pass - self.credentials['session'] = None - self.credentials['sessionkey'] = None - - def pipe_runner(self, args): - if args.find(" |") > -1: - pname = self.program_name - if '.py' in pname: - pname = "python " + pname - if isinstance(args, str): - self.do_shell("{0} {1}".format(pname, args)) - else: - self.do_shell(u"{0} {1}".format(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=t...@test.tt firstname=user$i lastname=user$i \ - password=password username=user$i; done - """ - if args.isdigit(): - self.do_history("!" + args) - return - if isinstance(args, str): - os.system(args) - else: - os.system(args.encode("utf-8")) - - def do_history(self, args): - """ - Prints cloudmonkey history - """ - if self.pipe_runner("history " + args): - return - startIdx = 1 - endIdx = readline.get_current_history_length() - numLen = len(str(endIdx)) - historyArg = args.split(' ')[0] - if historyArg.isdigit(): - startIdx = endIdx - long(historyArg) - if startIdx < 1: - startIdx = 1 - elif historyArg == "clear" or historyArg == "c": - readline.clear_history() - print "CloudMonkey history cleared" - return - elif len(historyArg) > 1 and historyArg[0] == "!" and historyArg[1:].isdigit(): - command = readline.get_history_item(long(historyArg[1:])) - readline.set_startup_hook(lambda: readline.insert_text(command)) - self.hook_count = 1 - return - for idx in xrange(startIdx, endIdx): - self.monkeyprint("%s %s" % (str(idx).rjust(numLen), - readline.get_history_item(idx))) - - 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 - """ - self.do_logout(None) - 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) - - -def main(): - parser = argparse.ArgumentParser(usage="cloudmonkey [options] [commands]", - description=__description__, - epilog="Try cloudmonkey [help|?]") - - parser.add_argument("-v", "--version", action="version", - default=argparse.SUPPRESS, - version="cloudmonkey %s" % __version__, - help="show CloudMonkey's version and exit") - - parser.add_argument("-c", "--config-file", - dest="configFile", default=config_file, - help="config file for cloudmonkey", metavar="FILE") - - parser.add_argument("-b", "--block-async", action="store_true", - help="block and poll result on async API calls") - - parser.add_argument("-n", "--noblock-async", action="store_true", - help="do not block on async API calls") - - parser.add_argument("-d", "--display-type", - dest="displayType", default=None, - help="output displays: json, xml, table or default", - choices=tuple(display_types)) - - parser.add_argument("-p", "--profile", - dest="serverProfile", default=None, - help="server profile to load") - - parser.add_argument("commands", nargs=argparse.REMAINDER, - help="API commands") - - argcomplete.autocomplete(parser) - args = parser.parse_args() - - shell = CloudMonkeyShell(sys.argv[0], args.configFile) - - if args.displayType and args.displayType in display_types: - shell.set_attr("display", args.displayType) - - if args.noblock_async: - shell.set_attr("asyncblock", "false") - - if args.block_async: - shell.set_attr("asyncblock", "true") - - if args.serverProfile and args.serverProfile.strip() != '': - shell.do_set("profile %s" % args.serverProfile) - - if len(args.commands) > 0: - shell.set_attr("color", "false") - commands = [] - for command in args.commands: - split_command = command.split("=", 1) - if len(split_command) > 1: - key = split_command[0] - value = split_command[1] - if " " not in value or \ - (value.startswith("\"") and value.endswith("\"")) or \ - (value.startswith("\'") and value.endswith("\'")): - commands.append(command) - else: - commands.append("%s=\"%s\"" % (key, value)) - else: - commands.append(command) - shell.onecmd(" ".join(commands)) - if shell.error_on_last_command: - sys.exit(1) - else: - shell.cmdloop() - - try: - sys.stdout.close() - except: - pass - try: - sys.stderr.close() - except: - pass - - -if __name__ == "__main__": - main() diff --git a/cloudmonkey/config.py b/cloudmonkey/config.py deleted file mode 100644 index c5faec2..0000000 --- a/cloudmonkey/config.py +++ /dev/null @@ -1,209 +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. - -__version__ = "5.3.3" -__description__ = "Command Line Interface for Apache CloudStack" -__maintainer__ = "The Apache CloudStack Team" -__maintaineremail__ = "d...@cloudstack.apache.org" -__project__ = "The Apache CloudStack Team" -__projectemail__ = "d...@cloudstack.apache.org" -__projecturl__ = "http://cloudstack.apache.org" - -try: - import os - import sys - - from ConfigParser import ConfigParser - 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'] - -# cloudmonkey display types -display_types = ["json", "xml", "csv", "table", "default"] - -config_dir = expanduser('~/.cloudmonkey') -config_file = expanduser(config_dir + '/config') - -# cloudmonkey config fields -mandatory_sections = ['core', 'ui'] -default_profile_name = 'local' -config_fields = {'core': {}, 'ui': {}} - -# core -config_fields['core']['asyncblock'] = 'true' -config_fields['core']['paramcompletion'] = 'true' -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') -config_fields['core']['profile'] = default_profile_name - -# ui -config_fields['ui']['color'] = 'true' -config_fields['ui']['prompt'] = '🐵 > ' -config_fields['ui']['display'] = 'default' - -# default profile -default_profile = {} -default_profile['url'] = 'http://localhost:8080/client/api' -default_profile['timeout'] = '3600' -default_profile['expires'] = '600' -default_profile['username'] = 'admin' -default_profile['password'] = 'password' -default_profile['domain'] = '/' -default_profile['apikey'] = '' -default_profile['secretkey'] = '' -default_profile['verifysslcert'] = 'true' -default_profile['signatureversion'] = '3' - - -def write_config(get_attr, config_file): - global config_fields, mandatory_sections - global default_profile, default_profile_name - config = ConfigParser() - if os.path.exists(config_file): - try: - with open(config_file, 'r') as cfg: - config.readfp(cfg) - except IOError, e: - print "Error: config_file not found", e - - profile = None - try: - profile = get_attr('profile') - except AttributeError, e: - pass - if profile is None or profile == '': - profile = default_profile_name - if profile in mandatory_sections: - print "Server profile name cannot be '%s'" % profile - sys.exit(1) - - has_profile_changed = False - profile_in_use = default_profile_name - try: - profile_in_use = config.get('core', 'profile') - except Exception: - pass - if profile_in_use != profile: - has_profile_changed = True - - for section in (mandatory_sections + [profile]): - if not config.has_section(section): - try: - config.add_section(section) - if section not in mandatory_sections: - for key in default_profile.keys(): - config.set(section, key, default_profile[key]) - else: - for key in config_fields[section].keys(): - config.set(section, key, config_fields[section][key]) - except ValueError, e: - print "Server profile name cannot be", profile - sys.exit(1) - if section in mandatory_sections: - section_keys = config_fields[section].keys() - else: - section_keys = default_profile.keys() - for key in section_keys: - try: - if not (has_profile_changed and section == profile): - config.set(section, key, get_attr(key)) - except Exception: - pass - 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, mandatory_sections - global default_profile, default_profile_name - 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())) - config_options += default_profile.keys() - - config = ConfigParser() - if os.path.exists(config_file): - 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) - print "Welcome! Use the `set` command to configure options" - print "Config file:", config_file - print "After setting up, run the `sync` command to sync apis\n" - - missing_keys = [] - if config.has_option('core', 'profile'): - profile = config.get('core', 'profile') - else: - global default_profile_name - profile = default_profile_name - - if profile is None or profile == '' or profile in mandatory_sections: - print "Server profile cannot be", profile - sys.exit(1) - - set_attr("profile_names", filter(lambda x: x != "core" and x != "ui", - config.sections())) - - if not config.has_section(profile): - print ("Selected profile (%s) does not exist," + - " using default values") % profile - try: - config.add_section(profile) - except ValueError, e: - print "Server profile name cannot be", profile - sys.exit(1) - for key in default_profile.keys(): - config.set(profile, key, default_profile[key]) - - for section in (mandatory_sections + [profile]): - if section in mandatory_sections: - section_keys = config_fields[section].keys() - else: - section_keys = default_profile.keys() - for key in section_keys: - try: - set_attr(key, config.get(section, key)) - except Exception, e: - if section in mandatory_sections: - set_attr(key, config_fields[section][key]) - else: - set_attr(key, default_profile[key]) - missing_keys.append("%s = %s" % (key, get_attr(key))) - # Cosmetic fix for prompt - if key == 'prompt': - set_attr(key, get_attr('prompt').strip() + " ") - - if len(missing_keys) > 0: - print "Missing configuration was set using default values for keys:" - print "`%s` in %s" % (', '.join(missing_keys), config_file) - write_config(get_attr, config_file) - - return config_options diff --git a/cloudmonkey/precache.py b/cloudmonkey/precache.py deleted file mode 100644 index ac7d880..0000000 --- a/cloudmonkey/precache.py +++ /dev/null @@ -1,19 +0,0 @@ -# -*- 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. -apicache = {u'authorize': {u'securitygroupingress': {u'name': u'authorizeSecurityGroupIngress', u'related': [u'authorizeSecurityGroupEgress'], u'isasync': True, u'params': [{u'name': u'projectid', u'required': False, u'related': [u'listProjectAccounts', u'listProjects', u'activateProject', u'createProject', u'updateProject'], u'length': 255, u'type': u'uuid', u'description': u'an optional project of the security group'}, {u'name': u'cidrlist', u'required': False, u'related': [], u'length [...] \ No newline at end of file diff --git a/cloudmonkey/printer.py b/cloudmonkey/printer.py deleted file mode 100644 index 29d5903..0000000 --- a/cloudmonkey/printer.py +++ /dev/null @@ -1,124 +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.lexer import bygroups, 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]*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+]{5}' - - def makelistre(lis): - return r'(' + r'|'.join(lis) + r')' - - tokens = { - 'root': [ - (r' ', Whitespace), - (date_rgx, Number), - (r'"' + date_rgx + r'"', Number), - (uuid_rgx, Literal), - (r'"' + uuid_rgx + r'"', 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' - if text.startswith("Error"): - highlight(text, lexer, fmter, sys.stderr) - else: - highlight(text, lexer, fmter, sys.stdout) diff --git a/cloudmonkey/requester.py b/cloudmonkey/requester.py deleted file mode 100644 index 914854f..0000000 --- a/cloudmonkey/requester.py +++ /dev/null @@ -1,335 +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 itertools - import json - import requests - import ssl - import sys - import time - import urllib - import urllib2 - - from datetime import datetime, timedelta - from requests_toolbelt import SSLAdapter - from urllib2 import HTTPError, URLError -except ImportError, e: - print "Import error in %s : %s" % (__name__, e) - import sys - sys.exit() - - -# Disable HTTPS verification warnings. -from requests.packages import urllib3 -urllib3.disable_warnings() - - -def logger_debug(logger, message): - if logger is not None: - logger.debug(message) - - -def writeError(msg): - sys.stderr.write(msg) - sys.stderr.write("\n") - sys.stderr.flush() - - -def login(url, username, password, domain="/", verifysslcert=False): - """ - Login and obtain a session to be used for subsequent API calls - Wrong username/password leads to HTTP error code 531 - """ - args = {} - - args["command"] = 'login' - args["username"] = username - args["password"] = password - args["domain"] = domain - args["response"] = "json" - - sessionkey = '' - session = requests.Session() - session.mount('https://', SSLAdapter(ssl.PROTOCOL_TLSv1)) - - try: - resp = session.post(url, params=args, verify=verifysslcert) - except requests.exceptions.ConnectionError, e: - writeError("Connection refused by server: %s" % e) - return None, None - - if resp.status_code == 200: - sessionkey = resp.json()['loginresponse']['sessionkey'] - elif resp.status_code == 405: - writeError("Method not allowed, unauthorized access on URL: %s" % url) - session = None - sessionkey = None - elif resp.status_code == 531: - writeError("Error authenticating at %s using username: %s" - ", password: %s, domain: %s" % (url, username, password, - domain)) - session = None - sessionkey = None - else: - resp.raise_for_status() - - return session, sessionkey - - -def logout(url, session): - if not session: - return - session.get(url, params={'command': 'logout'}) - - -def make_request_with_password(command, args, logger, url, credentials, - verifysslcert=False): - error = None - args = args.copy() - username = credentials['username'] - password = credentials['password'] - domain = credentials['domain'] - - if not (username and password): - error = "Username and password cannot be empty" - result = None - return result, error - - tries = 0 - retry = True - - while tries < 2 and retry: - sessionkey = credentials.get('sessionkey') - session = credentials.get('session') - tries += 1 - - # obtain a valid session if not supplied - if not (session and sessionkey): - session, sessionkey = login(url, username, password, domain, - verifysslcert) - if not (session and sessionkey): - return None, 'Authentication failed' - credentials['session'] = session - credentials['sessionkey'] = sessionkey - - args['sessionkey'] = sessionkey - - # make the api call - resp = session.get(url, params=args, verify=verifysslcert) - result = resp.text - logger_debug(logger, "Response received: %s" % resp.text) - - if resp.status_code == 200: # success - retry = False - break - if resp.status_code == 401: # sessionkey is wrong - credentials['session'] = None - credentials['sessionkey'] = None - continue - - if resp.status_code != 200 and resp.status_code != 401: - error_message = resp.headers.get('X-Description') - if not error_message: - error_message = resp.text - error = "{0}: {1}".format(resp.status_code, error_message) - result = None - retry = False - - return result, error - - -def make_request(command, args, logger, url, credentials, expires, - verifysslcert=False, signatureversion=3): - result = None - error = None - - if not url.startswith('http'): - error = "Server URL should start with 'http' or 'https', " + \ - "please check and fix the url" - return None, error - - if not args: - args = {} - - args = args.copy() - args["command"] = command - args["response"] = "json" - signatureversion = int(signatureversion) - if signatureversion >= 3: - args["signatureversion"] = signatureversion - if not expires: - expires = 600 - expirationtime = datetime.utcnow() + timedelta(seconds=int(expires)) - args["expires"] = expirationtime.strftime('%Y-%m-%dT%H:%M:%S+0000') - - for key in args.keys(): - value = args[key] - if isinstance(value, unicode): - value = value.encode("utf-8") - args[key] = value - if not key: - args.pop(key) - - # try to use the apikey/secretkey method by default - # followed by trying to check if we're using integration port - # finally use the username/password method - if not credentials['apikey'] and not ("8096" in url): - try: - return make_request_with_password(command, args, logger, url, - credentials, verifysslcert) - except (requests.exceptions.ConnectionError, Exception), e: - return None, e - - def sign_request(params, secret_key): - request = zip(params.keys(), params.values()) - request.sort(key=lambda x: x[0].lower()) - hash_str = "&".join( - ["=".join( - [r[0].lower(), - urllib.quote_plus(str(r[1]), safe="*").lower() - .replace("+", "%20").replace("%3A", ":")] - ) for r in request] - ) - return base64.encodestring(hmac.new(secret_key, hash_str, - hashlib.sha1).digest()).strip() - - args['apiKey'] = credentials['apikey'] - args["signature"] = sign_request(args, credentials['secretkey']) - - session = requests.Session() - session.mount('https://', SSLAdapter(ssl.PROTOCOL_TLSv1)) - - try: - response = session.get(url, params=args, verify=verifysslcert) - logger_debug(logger, "Request sent: %s" % response.url) - result = response.text - - if response.status_code == 200: # success - error = None - elif response.status_code == 401: # auth issue - error = "401 Authentication error" - elif response.status_code != 200 and response.status_code != 401: - error = "{0}: {1}".format(response.status_code, - response.headers.get('X-Description')) - except requests.exceptions.ConnectionError, e: - return None, "Connection refused by server: %s" % e - except Exception, pokemon: - error = pokemon.message - - logger_debug(logger, "Response received: %s" % result) - if error is not None: - logger_debug(logger, "Error: %s" % (error)) - return result, error - - return result, error - - -def monkeyrequest(command, args, isasync, asyncblock, logger, url, - credentials, timeout, expires, verifysslcert=False, - signatureversion=3): - 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, url, - credentials, expires, verifysslcert, - signatureversion) - - logger_debug(logger, "======== END Request ========\n") - - if error is not None and not response: - return response, error - - def process_json(response): - try: - response = json.loads(response, "utf-8") - except ValueError, e: - logger_debug(logger, "Error processing json: %s" % e) - writeError("Error processing json: %s" % e) - response = None - error = e - return response - - response = process_json(response) - if not response or not isinstance(response, dict): - return response, error - - m = list(v for v in response.keys() if 'response' in v.lower()) - if not m: - return response, 'Invalid response received: %s' % response - - isasync = isasync and (asyncblock == "true" or 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} - if not timeout: - timeout = 3600 - timeout = int(timeout) - cursor = itertools.cycle([u'|', u'/', u'-', u'\\']) - while timeout > 0: - interval = 2 - while interval > 0: - sys.stdout.write(u"%s\r" % cursor.next()) - sys.stdout.flush() - time.sleep(0.1) - interval -= 0.1 - timeout = timeout - 2 - logger_debug(logger, "Job %s to timeout in %ds" % (jobid, timeout)) - - response, error = make_request(command, request, logger, url, - credentials, expires, verifysslcert) - if error and not response: - 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]] - if "errorcode" in result or "errortext" in result: - return response, error - - 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: - sys.stdout.write(u"\r \n") - sys.stdout.flush() - return response, error - elif jobstatus == 0: - pass # Job in progress - 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 diff --git a/config.docker b/config.docker deleted file mode 100644 index 17c536a..0000000 --- a/config.docker +++ /dev/null @@ -1,25 +0,0 @@ -[core] -profile = container -asyncblock = true -paramcompletion = true -history_file = /cloudmonkey/history -log_file = /cloudmonkey/log -cache_file = /cloudmonkey/cache - - -[ui] -color = true -prompt = > -display = default - -[container] -url = http://cloudstack:8080/client/api -username = admin -password = password -apikey = -secretkey = -timeout = 3600 -expires = 600 -verifysslcert = false -signatureversion = 3 -domain = / \ No newline at end of file diff --git a/docs/.gitignore b/docs/.gitignore deleted file mode 100644 index e35d885..0000000 --- a/docs/.gitignore +++ /dev/null @@ -1 +0,0 @@ -_build diff --git a/docs/Makefile b/docs/Makefile deleted file mode 100644 index 681b3a3..0000000 --- a/docs/Makefile +++ /dev/null @@ -1,177 +0,0 @@ -# Makefile for Sphinx documentation -# - -# You can set these variables from the command line. -SPHINXOPTS = -SPHINXBUILD = sphinx-build -PAPER = -BUILDDIR = build - -# User-friendly check for sphinx-build -ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) -$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) -endif - -# Internal variables. -PAPEROPT_a4 = -D latex_paper_size=a4 -PAPEROPT_letter = -D latex_paper_size=letter -ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source -# the i18n builder cannot share the environment and doctrees with the others -I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source - -.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext - -help: - @echo "Please use \`make <target>' where <target> is one of" - @echo " html to make standalone HTML files" - @echo " dirhtml to make HTML files named index.html in directories" - @echo " singlehtml to make a single large HTML file" - @echo " pickle to make pickle files" - @echo " json to make JSON files" - @echo " htmlhelp to make HTML files and a HTML help project" - @echo " qthelp to make HTML files and a qthelp project" - @echo " devhelp to make HTML files and a Devhelp project" - @echo " epub to make an epub" - @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" - @echo " latexpdf to make LaTeX files and run them through pdflatex" - @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" - @echo " text to make text files" - @echo " man to make manual pages" - @echo " texinfo to make Texinfo files" - @echo " info to make Texinfo files and run them through makeinfo" - @echo " gettext to make PO message catalogs" - @echo " changes to make an overview of all changed/added/deprecated items" - @echo " xml to make Docutils-native XML files" - @echo " pseudoxml to make pseudoxml-XML files for display purposes" - @echo " linkcheck to check all external links for integrity" - @echo " doctest to run all doctests embedded in the documentation (if enabled)" - -clean: - rm -rf $(BUILDDIR)/* - -html: - $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." - -dirhtml: - $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." - -singlehtml: - $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml - @echo - @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." - -pickle: - $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle - @echo - @echo "Build finished; now you can process the pickle files." - -json: - $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json - @echo - @echo "Build finished; now you can process the JSON files." - -htmlhelp: - $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp - @echo - @echo "Build finished; now you can run HTML Help Workshop with the" \ - ".hhp project file in $(BUILDDIR)/htmlhelp." - -qthelp: - $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp - @echo - @echo "Build finished; now you can run "qcollectiongenerator" with the" \ - ".qhcp project file in $(BUILDDIR)/qthelp, like this:" - @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/ApacheCloudStackCloudMonkey.qhcp" - @echo "To view the help file:" - @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/ApacheCloudStackCloudMonkey.qhc" - -devhelp: - $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp - @echo - @echo "Build finished." - @echo "To view the help file:" - @echo "# mkdir -p $$HOME/.local/share/devhelp/ApacheCloudStackCloudMonkey" - @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/ApacheCloudStackCloudMonkey" - @echo "# devhelp" - -epub: - $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub - @echo - @echo "Build finished. The epub file is in $(BUILDDIR)/epub." - -latex: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo - @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." - @echo "Run \`make' in that directory to run these through (pdf)latex" \ - "(use \`make latexpdf' here to do that automatically)." - -latexpdf: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo "Running LaTeX files through pdflatex..." - $(MAKE) -C $(BUILDDIR)/latex all-pdf - @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." - -latexpdfja: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo "Running LaTeX files through platex and dvipdfmx..." - $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja - @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." - -text: - $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text - @echo - @echo "Build finished. The text files are in $(BUILDDIR)/text." - -man: - $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man - @echo - @echo "Build finished. The manual pages are in $(BUILDDIR)/man." - -texinfo: - $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo - @echo - @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." - @echo "Run \`make' in that directory to run these through makeinfo" \ - "(use \`make info' here to do that automatically)." - -info: - $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo - @echo "Running Texinfo files through makeinfo..." - make -C $(BUILDDIR)/texinfo info - @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." - -gettext: - $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale - @echo - @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." - -changes: - $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes - @echo - @echo "The overview file is in $(BUILDDIR)/changes." - -linkcheck: - $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck - @echo - @echo "Link check complete; look for any errors in the above output " \ - "or in $(BUILDDIR)/linkcheck/output.txt." - -doctest: - $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest - @echo "Testing of doctests in the sources finished, look at the " \ - "results in $(BUILDDIR)/doctest/output.txt." - -xml: - $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml - @echo - @echo "Build finished. The XML files are in $(BUILDDIR)/xml." - -pseudoxml: - $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml - @echo - @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." diff --git a/docs/source/cloudmonkey.rst b/docs/source/cloudmonkey.rst deleted file mode 100644 index 22bf625..0000000 --- a/docs/source/cloudmonkey.rst +++ /dev/null @@ -1,62 +0,0 @@ -cloudmonkey package -=================== - -Submodules ----------- - -cloudmonkey.cachemaker module ------------------------------ - -.. automodule:: cloudmonkey.cachemaker - :members: - :undoc-members: - :show-inheritance: - -cloudmonkey.cloudmonkey module ------------------------------- - -.. automodule:: cloudmonkey.cloudmonkey - :members: - :undoc-members: - :show-inheritance: - -cloudmonkey.config module -------------------------- - -.. automodule:: cloudmonkey.config - :members: - :undoc-members: - :show-inheritance: - -cloudmonkey.precache module ---------------------------- - -.. automodule:: cloudmonkey.precache - :members: - :undoc-members: - :show-inheritance: - -cloudmonkey.printer module --------------------------- - -.. automodule:: cloudmonkey.printer - :members: - :undoc-members: - :show-inheritance: - -cloudmonkey.requester module ----------------------------- - -.. automodule:: cloudmonkey.requester - :members: - :undoc-members: - :show-inheritance: - - -Module contents ---------------- - -.. automodule:: cloudmonkey - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/source/conf.py b/docs/source/conf.py deleted file mode 100644 index 9c30ccb..0000000 --- a/docs/source/conf.py +++ /dev/null @@ -1,262 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Apache CloudStack CloudMonkey documentation build configuration file, created by -# sphinx-quickstart on Tue Sep 24 13:08:09 2013. -# -# This file is execfile()d with the current directory set to its -# containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. - -import sys -import os - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -#sys.path.insert(0, os.path.abspath('.')) - -# -- General configuration ------------------------------------------------ - -# If your documentation needs a minimal Sphinx version, state it here. -#needs_sphinx = '1.0' - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. -extensions = [ - 'sphinx.ext.autodoc', - 'sphinx.ext.coverage', - 'sphinx.ext.viewcode', -] - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# The suffix of source filenames. -source_suffix = '.rst' - -# The encoding of source files. -#source_encoding = 'utf-8-sig' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = u'Apache CloudStack CloudMonkey' -copyright = u'2012-2014, The Apache Software Foundation' - -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -# -# The short X.Y version. -version = '5.3.3' -# The full version, including alpha/beta/rc tags. -release = version - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -#language = None - -# There are two options for replacing |today|: either, you set today to some -# non-false value, then it is used: -#today = '' -# Else, today_fmt is used as the format for a strftime call. -#today_fmt = '%B %d, %Y' - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -exclude_patterns = [] - -# The reST default role (used for this markup: `text`) to use for all -# documents. -#default_role = None - -# If true, '()' will be appended to :func: etc. cross-reference text. -#add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -#add_module_names = True - -# If true, sectionauthor and moduleauthor directives will be shown in the -# output. They are ignored by default. -#show_authors = False - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - -# A list of ignored prefixes for module index sorting. -#modindex_common_prefix = [] - -# If true, keep warnings as "system message" paragraphs in the built documents. -#keep_warnings = False - - -# -- Options for HTML output ---------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -html_theme = 'default' - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -#html_theme_options = {} - -# Add any paths that contain custom themes here, relative to this directory. -#html_theme_path = [] - -# The name for this set of Sphinx documents. If None, it defaults to -# "<project> v<release> documentation". -#html_title = None - -# A shorter title for the navigation bar. Default is the same as html_title. -#html_short_title = None - -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -#html_logo = None - -# The name of an image file (within the static path) to use as favicon of the -# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 -# pixels large. -#html_favicon = None - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] - -# Add any extra paths that contain custom files (such as robots.txt or -# .htaccess) here, relative to this directory. These files are copied -# directly to the root of the documentation. -#html_extra_path = [] - -# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, -# using the given strftime format. -#html_last_updated_fmt = '%b %d, %Y' - -# If true, SmartyPants will be used to convert quotes and dashes to -# typographically correct entities. -#html_use_smartypants = True - -# Custom sidebar templates, maps document names to template names. -#html_sidebars = {} - -# Additional templates that should be rendered to pages, maps page names to -# template names. -#html_additional_pages = {} - -# If false, no module index is generated. -#html_domain_indices = True - -# If false, no index is generated. -#html_use_index = True - -# If true, the index is split into individual pages for each letter. -#html_split_index = False - -# If true, links to the reST sources are added to the pages. -#html_show_sourcelink = True - -# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -#html_show_sphinx = True - -# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -#html_show_copyright = True - -# If true, an OpenSearch description file will be output, and all pages will -# contain a <link> tag referring to it. The value of this option must be the -# base URL from which the finished HTML is served. -#html_use_opensearch = '' - -# This is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = None - -# Output file base name for HTML help builder. -htmlhelp_basename = 'ApacheCloudStackCloudMonkeydoc' - - -# -- Options for LaTeX output --------------------------------------------- - -latex_elements = { -# The paper size ('letterpaper' or 'a4paper'). -#'papersize': 'letterpaper', - -# The font size ('10pt', '11pt' or '12pt'). -#'pointsize': '10pt', - -# Additional stuff for the LaTeX preamble. -#'preamble': '', -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, -# author, documentclass [howto/manual]). -latex_documents = [ - ('index', 'ApacheCloudStackCloudMonkey.tex', u'Apache CloudStack CloudMonkey Documentation', - u'The Apache Software Foundation', 'manual'), -] - -# The name of an image file (relative to this directory) to place at the top of -# the title page. -#latex_logo = None - -# For "manual" documents, if this is true, then toplevel headings are parts, -# not chapters. -#latex_use_parts = False - -# If true, show page references after internal links. -#latex_show_pagerefs = False - -# If true, show URL addresses after external links. -#latex_show_urls = False - -# Documents to append as an appendix to all manuals. -#latex_appendices = [] - -# If false, no module index is generated. -#latex_domain_indices = True - - -# -- Options for manual page output --------------------------------------- - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [ - ('index', 'apachecloudstackcloudmonkey', u'Apache CloudStack CloudMonkey Documentation', - [u'The Apache Software Foundation'], 1) -] - -# If true, show URL addresses after external links. -#man_show_urls = False - - -# -- Options for Texinfo output ------------------------------------------- - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) -texinfo_documents = [ - ('index', 'ApacheCloudStackCloudMonkey', u'Apache CloudStack CloudMonkey Documentation', - u'The Apache Software Foundation', 'ApacheCloudStackCloudMonkey', 'One line description of project.', - 'Miscellaneous'), -] - -# Documents to append as an appendix to all manuals. -#texinfo_appendices = [] - -# If false, no module index is generated. -#texinfo_domain_indices = True - -# How to display URL addresses: 'footnote', 'no', or 'inline'. -#texinfo_show_urls = 'footnote' - -# If true, do not generate a @detailmenu in the "Top" node's menu. -#texinfo_no_detailmenu = False diff --git a/docs/source/index.rst b/docs/source/index.rst deleted file mode 100644 index bbb18ed..0000000 --- a/docs/source/index.rst +++ /dev/null @@ -1,37 +0,0 @@ -Apache CloudStack CloudMonkey -============================= - -The Apache CloudStack CloudMonkey is a command line interface (CLI) tool for CloudStack written in Python. cloudmonkey -can be use both as an interactive shell and as a command line tool which simplifies CS configuration and management. - -**Features** - -#. Usable as a command line tool and interactive shell -#. All commands are lowercase unlike API -#. Api Discovery using sync feature, with build time api precaching for failsafe sync -#. Raw api execution support -#. Auto-completion via double <tab> -#. Reverse search using Ctrl+R -#. Emacs compatible keybindings -#. Pipeable output -#. Unix shell execution -#. Support to handle async jobs using user defined blocking or non-blocking way -#. Tabular or JSON output with filtering of table columns -#. Colored output -#. Api parameter value completion (based on predication, fuzzy results may fail sometimes) -#. Use apikey and secretkey or username/password - -Instructions for working with CloudMonkey can be found here: - -https://cwiki.apache.org/confluence/display/CLOUDSTACK/CloudStack+cloudmonkey+CLI - -.. toctree:: - :maxdepth: 2 - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` - diff --git a/docs/source/modules.rst b/docs/source/modules.rst deleted file mode 100644 index 2b7efb5..0000000 --- a/docs/source/modules.rst +++ /dev/null @@ -1,7 +0,0 @@ -cloudmonkey -=========== - -.. toctree:: - :maxdepth: 4 - - cloudmonkey diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 649ed60..0000000 --- a/setup.cfg +++ /dev/null @@ -1,7 +0,0 @@ -[build_sphinx] -source-dir = docs/source -build-dir = docs/build -all_files = 1 - -[upload_sphinx] -upload-dir = docs/build/html diff --git a/setup.py b/setup.py deleted file mode 100644 index 4422328..0000000 --- a/setup.py +++ /dev/null @@ -1,86 +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 - -import sys - -from cloudmonkey import __version__, __description__ -from cloudmonkey import __maintainer__, __maintaineremail__ -from cloudmonkey import __project__, __projecturl__, __projectemail__ - -requires = [ - 'Pygments>=1.5', - 'argcomplete', - 'dicttoxml', - 'prettytable>=0.6', - 'requests', - 'requests-toolbelt', - ] - -try: - import readline -except ImportError: - platform = str(sys.platform).lower() - if 'win32' in platform or 'win64' in platform: - requires.append('pyreadline') - else: - requires.append('readline') - -# Upgrade notes for 5.3.0 -print "If you're upgrading, run the following to enable parameter completion:" -print " cloudmonkey sync" -print " cloudmonkey set paramcompletion true" -print "Parameter completion may fail, if the above is not run!" - -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 = requires, - 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 - """, -) -- To stop receiving notification emails like this one, please contact ro...@apache.org.