Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 20 additions & 5 deletions openstack_interpreter/common/output.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
"""
This module is all about text formatting and output. Make text pretty!
This module is all about text formatting and output.

It is suggested you use tab autocomplete to list the available functions
in this class, and inspect them for their docstrings.

E.g.:
In [1]: output.print_styled?
"""

from fcntl import ioctl
Expand Down Expand Up @@ -38,6 +44,8 @@ def style_text(text, styles):

:param text: Text to style
:param styles: list of styles
For available style see:
In [1]: output.available_text_styles?
"""
if sys.stdout.isatty() and not os.getenv('ANSI_COLORS_DISABLED'):
style_codes = []
Expand All @@ -55,6 +63,8 @@ def print_styled(text, styles):

:param text: Text to style
:param styles: list of styles
For available style see:
In [1]: output.available_text_styles?
"""
print(style_text(text, styles))

Expand Down Expand Up @@ -157,14 +167,21 @@ def print_object(obj, formatters=None, wrap=None,
:param sortby: column of the table to sort by, defaults to 'Property'
.
"""

fields = []
for field in dir(obj):
if field.startswith("_") or callable(getattr(obj, field)):
continue
fields.append(field)

if not wrap:
# 2 columns padded by 1 on each side = 4
# 3 x '|' as border and separator = 3
# total non-content padding = 7
padding = 7
# Now we need to find what the longest key is
longest_key = 0
for key in obj.__dict__.keys():
for key in fields:
if not key.startswith("_") and len(key) > longest_key:
longest_key = len(key)
# the wrap for the value column is based on
Expand All @@ -177,9 +194,7 @@ def print_object(obj, formatters=None, wrap=None,
caching=False, print_empty=False)
pt.align = 'l'

for field in obj.__dict__.keys():
if field.startswith("_"):
continue
for field in fields:
if field in formatters:
value = formatters[field](getattr(obj, field), wrap=wrap)
pt.add_row([field, value])
Expand Down
10 changes: 9 additions & 1 deletion openstack_interpreter/common/profile.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@

from contextlib import contextmanager
from datetime import datetime


@contextmanager
def timed(desc):
"""
A useful context manager for timing how long something took

Example use:
In [1]: with timed("getting server list:"):
...: oi.sdk.connection.compute.servers()
...:
getting server list: took: 0:00:00.001366
"""
start = datetime.utcnow()
yield
end = datetime.utcnow()
Expand Down
12 changes: 12 additions & 0 deletions openstack_interpreter/common/prompt.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,18 @@
"""
This module is focused on adding a prompt to some action where you want to be
able to have something stop, and ask for input before moving on.

It is suggested you use tab autocomplete to list the available functions
in this class, and inspect them for their docstrings.

An example use case:
In [1]: for server in oi.sdk.connection.compute.servers():
...: if server.status == "ERROR":
...: if prompt.prompt_yes_no(
...: "Do you wish to delete server '%s'" % server.name):
...: server.delete()
...: else:
...: print(server.name)
"""


Expand Down
16 changes: 8 additions & 8 deletions openstack_interpreter/v1/clients.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,19 +51,19 @@ class ClientManager(object):
normal setup, and in some case constructor differences.

To get a list of what services the ClientManager has been setup for:
In [1]: interpreter.clients.available_services
In [1]: oi.clients.available_services

Default versions for services:
In [2]: interpreter.clients.available_services
In [2]: oi.clients.available_services

To get a client (replace <service_type> with the service you want):
In [3]: interpreter.clients.<service_type>
In [3]: oi.clients.<service_type>

Get novaclient in your configured region:
In [4]: novaclient = interpreter.clients.compute
In [4]: novaclient = oi.clients.compute

Get novaclient in a specific region:
In [5]: novaclient = interpreter.clients.get_client(
In [5]: novaclient = oi.clients.get_client(
'compute', region="RegionOne")

The python clients themselves have reasonably useful docstrings,
Expand All @@ -86,10 +86,10 @@ def get_client(self, service, version=None, region=None):
Get an OpenStack client, in a given version, in a given region.

examples:
In [1]: novaclient = interpreter.clients.get_client('compute')
In [2]: novaclient = interpreter.clients.get_client(
In [1]: novaclient = oi.clients.get_client('compute')
In [2]: novaclient = oi.clients.get_client(
'compute', region="RegionOne")
In [3]: novaclient = interpreter.clients.get_client(
In [3]: novaclient = oi.clients.get_client(
'compute', version="1")
"""
try:
Expand Down
55 changes: 49 additions & 6 deletions openstack_interpreter/v1/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,62 @@
from openstack_interpreter.v1.interpreter import OpenStackInterpreter


def _format_example(line_num, command):
return (
output.style_text('In [', ['green']) +
output.style_text(line_num, ['green-bright', 'bold']) +
output.style_text(']:', ['green']) +
command
)


welcome_msg = """
%(title)s

This is a command added to the OpenStackClient that gives you
quick and easy access to a ipython interpreter that has some
pre-built classes and tools for python development on OpenStack
which are built on top of your authenticated session.

To get started you will probably want to inspect the '%(oi_object)s' object:
%(example_1)s

Most of the objects exposed by the OpenStackInterpreter have useful docstrings
as do some of the underlying libraries and tools such as the OpenStackSDK.

Other useful tools provided along with the OpenStackInterpreter that are
worth inspecting:
%(example_2)s
%(example_3)s
%(example_4)s

And don't forget: %(tab_complete)s

""" % {
'title': output.style_text(
"Welcome to the OpenStackInterpreter.", ['bold']),
'oi_object': output.style_text('oi', ['green']),
'example_1': _format_example(1, " oi?"),
'example_2': _format_example(2, " output?"),
'example_3': _format_example(3, " timed?"),
'example_4': _format_example(4, " prompt?"),
'tab_complete': output.style_text(
"The ipython interpreter supports tab completion!", ['bold']),
}


class SetupOpenStackInterpreter(command.Command):
"""
Command to setup the interpreter object and drop you into an
ipython interpreter. You will be authenticated using
your specificed auth credentials, and the interpreter will be
setup with your session.

Your starting interaction will be with the 'interpreter' object.
Your starting interaction will be with the 'oi' object.
You should also use the help and functionality provided by ipython.

To get some basic help:
In [1]: interpreter?
In [1]: oi?

Most objects or functions have help and docstrings built in. As such
using ipython's built in <object>? and <object>?? to see help is useful.
Expand Down Expand Up @@ -59,8 +103,7 @@ def _check_auth_url(self):

def take_action(self, parsed_args):
self._check_auth_url()
interpreter = OpenStackInterpreter(
session=self.app.client_manager.session,
default_region=self.app.client_manager.region_name,
)
interpreter = OpenStackInterpreter(self) # noqa
oi = interpreter # noqa
print(welcome_msg)
embed()
16 changes: 11 additions & 5 deletions openstack_interpreter/v1/interpreter.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@


from openstack_interpreter.v1.clients import ClientManager
from openstack_interpreter.v1.sdk import SDKManager


class OpenStackInterpreter(object):
Expand All @@ -9,19 +9,25 @@ class OpenStackInterpreter(object):
python clients and SDKs.

Additional client help is found at:
In [1]: interpreter.clients?
In [1]: oi.sdk?
In [2]: oi.clients?

fields:
- session
Your keystoneauth session object to reuse as needed.
- clients
The interpreter ClientManager. A useful construct to help
you access all the various python clients.
- sdk
The interpreter SDKManager. A wrapper around the openstack sdk
with some helper functions for setup.

"""

def __init__(self, session, default_region):
self.session = session
def __init__(self, command):
self._session = command.app.client_manager.session
self.clients = ClientManager(
session=session, default_region=default_region,
session=self._session,
default_region=command.app.client_manager.region_name,
)
self.sdk = SDKManager(session=self._session)
59 changes: 59 additions & 0 deletions openstack_interpreter/v1/sdk.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
from openstack import connection


class SDKManager(object):
"""A wrapper around the openstackSDK

Your primary interaction will be with the connection itself and
the various services it exposes. A connection is an authenticated
object representing a connection to a given cloud region.

Example get servers:
In [1]: servers = list(oi.sdk.connection.compute.servers())

All list methods in the SDK return a generator, so if you don't
want to act on them in a for loop, you need to explictly ask
for a list().

Your best bet to understand what is possible with the connection
object is to use tab autocomplete and inspect the docstrings of
the functions themselves.

fields:
- connection
An instance of the openstacksdk connection object built
from the same session as the openstack interpreter was
setup via the openstackclient.

methods:
- get_connection
Get a connection object with user defined config.
For help do:
In [1]: oi.sdk.get_connection?
"""

def __init__(self, session):
self.connection = connection.Connection(session=session)
self._session = session

def get_connection(self, **kwargs):
"""Get a connection object with user defined config

This is mostly used to get a connection to a specific region
or with specific versions of services.

All config values will otherwise default to your current
interpreter session unless overridden. The function takes
arbitrary kwargs and passes those to the config class.

The majority of the parameters that will be useful to you
here are:
- region_name
- <service_type>_api_version

examples:
In [1]: conn_r2 = oi.sdk.get_connection(region='RegionTwo')
In [2]: conn_c1 = oi.sdk.get_connection(
compute_api_version='2')
"""
return connection.Connection(session=self._session, **kwargs)
30 changes: 15 additions & 15 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
pbr>=3.0.0
babel!=2.4.0,>=2.3.4
pbr>=3.1.1
babel>=2.5.1

keystoneauth1>=2.12.1
osc-lib>=1.5.1
openstacksdk>=0.9.5
python-ceilometerclient>=2.6.1
python-cinderclient>=1.9.0
python-glanceclient>=2.5.0
python-heatclient>=1.4.0
python-keystoneclient>=3.5.0
python-neutronclient>=6.0.0
python-novaclient>=6.0.0
python-openstackclient>=3.3.0 # Apache-2.0
python-swiftclient>=2.2.0 # Apache-2.0
ipython>=5.3.0
keystoneauth1>=3.3.0
osc-lib>=1.8.0
openstacksdk>=0.11.1
python-ceilometerclient==2.9.0
python-cinderclient>=3.4.0
python-glanceclient>=2.9.0
python-heatclient>=1.13.0
python-keystoneclient>=3.14.0
python-neutronclient>=6.6.0
python-novaclient>=9.1.1
python-openstackclient>=3.13.0
python-swiftclient>=3.4.0
ipython>=5.5.0