From 7b33afc2e9104f7719786f9528ddf6819e95d28a Mon Sep 17 00:00:00 2001 From: Dean Troyer Date: Wed, 16 Apr 2014 01:08:00 -0500 Subject: [PATCH] Add some sample scripts This is a very basic starting point for working code example usage of the SDK. The common module includes an argument parser that recognizes the common authentication arguments so setting up auth against a running OpenStack cloud is the same as the library CLIs. The inital example for Transport is a couple of simple GETs that also shows the connection pooling. Change-Id: I07de2888471a39cbc43daedded36ad683d02a472 --- examples/__init__.py | 0 examples/common.py | 237 ++++++++++++++++++++++++++++++++++++++++++ examples/transport.py | 64 ++++++++++++ 3 files changed, 301 insertions(+) create mode 100644 examples/__init__.py create mode 100755 examples/common.py create mode 100755 examples/transport.py diff --git a/examples/__init__.py b/examples/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/examples/common.py b/examples/common.py new file mode 100755 index 000000000..6c7bed270 --- /dev/null +++ b/examples/common.py @@ -0,0 +1,237 @@ +#!/usr/bin/env python +# common.py - Common bits for SDK examples + +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +""" +SDK Examples + +This is a collection of common functions used by the example scripts. +It may also be run as a script to do the most basic check of creating +a Transport object. + +common.object_parser() provides the common set of command-line arguments +used in the library CLIs for setting up authentication. This should make +playing with the example scripts against a running OpenStack simpler. + +""" + +import argparse +import logging +import os +import subprocess +import sys +import traceback + +from openstack import transport + +CONSOLE_MESSAGE_FORMAT = '%(levelname)s: %(name)s %(message)s' +DEFAULT_VERBOSE_LEVEL = 1 +USER_AGENT = 'qwiktest' + + +_logger = logging.getLogger(__name__) + + +def get_open_fds(): + '''Return the open file descriptors for current process + + .. warning: will only work on UNIX-like os-es. + ''' + pid = os.getpid() + procs = subprocess.check_output( + ["lsof", '-w', '-Fftn0', "-p", str(pid)] + ) + print('procs: %s' % procs) + print('netstat: %s' % subprocess.check_output(['netstat', '-nlt'])) + procs_list = filter( + lambda s: s and s[0] == 'f' and s[1].isdigit(), + procs.split('\n') + ) + return [d.replace('\000', '|') for d in procs_list] + + +def make_transport(opts): + """Create a transport given some options.""" + + # Certificate verification - defaults to True + if opts.os_cacert: + verify = opts.os_cacert + else: + verify = not opts.insecure + + trans = transport.Transport( + verify=verify, + user_agent=USER_AGENT, + ) + return trans + + +def run(opts): + print("start fds: %s" % get_open_fds()) + + # Set up common client transport + trans = make_transport(opts) + + # Do something interesting here? + print("transport: %s" % trans) + + print("end fds: %s" % get_open_fds()) + + +def env(*vars, **kwargs): + """Search for the first defined of possibly many env vars + + Returns the first environment variable defined in vars, or + returns the default defined in kwargs. + + """ + for v in vars: + value = os.environ.get(v, None) + if value: + return value + return kwargs.get('default', '') + + +def option_parser(): + """Set up some of the common CLI options + + These are the basic options that match the library CLIs so + command-line/environment setups for those also work with these + demonstration programs. + + """ + + parser = argparse.ArgumentParser( + description='A demonstration framework') + # Global arguments + parser.add_argument( + '--os-auth-url', + metavar='', + default=env('OS_AUTH_URL'), + help='Authentication URL (Env: OS_AUTH_URL)', + ) + parser.add_argument( + '--os-project-name', + metavar='', + default=env('OS_PROJECT_NAME', default=env('OS_TENANT_NAME')), + help='Project name of the requested project-level' + 'authorization scope (Env: OS_PROJECT_NAME)', + ) + parser.add_argument( + '--os-username', + metavar='', + default=env('OS_USERNAME'), + help='Authentication username (Env: OS_USERNAME)', + ) + parser.add_argument( + '--os-password', + metavar='', + default=env('OS_PASSWORD'), + help='Authentication password (Env: OS_PASSWORD)', + ) + parser.add_argument( + '--os-cacert', + metavar='', + default=env('OS_CACERT'), + help='CA certificate bundle file (Env: OS_CACERT)', + ) + verify_group = parser.add_mutually_exclusive_group() + verify_group.add_argument( + '--verify', + action='store_true', + help='Verify server certificate (default)', + ) + verify_group.add_argument( + '--insecure', + action='store_true', + help='Disable server certificate verification', + ) + parser.add_argument( + '--os-identity-api-version', + metavar='', + default=env( + 'OS_IDENTITY_API_VERSION', + default=None), + help='Force Identity API version (Env: OS_IDENTITY_API_VERSION)', + ) + parser.add_argument( + '--os-token', + metavar='', + default=env('OS_TOKEN'), + help='Defaults to env[OS_TOKEN]', + ) + parser.add_argument( + '--os-url', + metavar='', + default=env('OS_URL'), + help='Defaults to env[OS_URL]', + ) + parser.add_argument( + '-v', '--verbose', + action='count', + dest='verbose_level', + default=1, + help='Increase verbosity of output. Can be repeated.', + ) + parser.add_argument( + '--debug', + default=False, + action='store_true', + help='show tracebacks on errors', + ) + return parser + + +def configure_logging(opts): + """Typical app logging setup + + Based on OSC/cliff + + """ + + root_logger = logging.getLogger('') + + # Always send higher-level messages to the console via stderr + console = logging.StreamHandler(sys.stderr) + formatter = logging.Formatter(CONSOLE_MESSAGE_FORMAT) + console.setFormatter(formatter) + root_logger.addHandler(console) + + if opts.debug: + root_logger.setLevel(logging.DEBUG) + else: + root_logger.setLevel(logging.WARNING) + return + + +def setup(): + opts = option_parser().parse_args() + configure_logging(opts) + return opts + + +def main(opts, run): + try: + return run(opts) + except Exception as e: + if opts.debug: + _logger.error(traceback.format_exc(e)) + else: + _logger.error('Exception raised: ' + str(e)) + return 1 + + +if __name__ == "__main__": + opts = setup() + sys.exit(main(opts, run)) diff --git a/examples/transport.py b/examples/transport.py new file mode 100755 index 000000000..bac4b8d94 --- /dev/null +++ b/examples/transport.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python +# transport.py - Example transport usage + +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +""" +SDK Transport Examples + +This script shows the basic use of the Transport class in making +REST API calls. + +""" + +import sys + +from examples import common + + +def do_transport(opts): + trans = common.make_transport(opts) + + # Get the version data from the auth URL + resp = trans.get(opts.os_auth_url).json() + ver = resp['version'] + print("\nAuth URL: %s" % opts.os_auth_url) + print(" version: %s" % ver['id']) + print(" status: %s" % ver['status']) + + # Do a basic call to somewhere fun + url = 'https://api.github.com/users/openstack' + resp = trans.get(url).json() + print("\nGitHub API URL: %s" % url) + print(" gists: %s" % resp['gists_url']) + print(" repos: %s" % resp['public_repos']) + + url = 'https://api.github.com/users/openstack-dev' + resp = trans.get(url).json() + print("\nGitHub API URL: %s" % url) + print(" gists: %s" % resp['gists_url']) + print(" repos: %s" % resp['public_repos']) + + # stats + print('\nTransport connection pools:') + print(" http pool: %s" % ( + trans.adapters['http://'].poolmanager.pools.keys(), + )) + print(" https pool: %s" % ( + trans.adapters['https://'].poolmanager.pools.keys(), + )) + + +if __name__ == "__main__": + opts = common.setup() + sys.exit(common.main(opts, do_transport))