From d69be912e3a47234846b04d5e385fa75ecbebc5e Mon Sep 17 00:00:00 2001 From: Clark Perkins Date: Mon, 8 Feb 2016 16:03:38 -0600 Subject: [PATCH 01/19] Updating version for 0.8 --- stackdio/client/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stackdio/client/version.py b/stackdio/client/version.py index f36a786..2c6a193 100644 --- a/stackdio/client/version.py +++ b/stackdio/client/version.py @@ -29,7 +29,7 @@ except Exception: pass -VERSION = (0, 7, 0, 'dev', 0) +VERSION = (0, 8, 0, 'dev', 0) def get_version(version): From afa420d2b47a8b5021a482902a55d6251e2544c6 Mon Sep 17 00:00:00 2001 From: Clark Perkins Date: Mon, 8 Feb 2016 16:25:35 -0600 Subject: [PATCH 02/19] Converted README to rst --- README.md => README.rst | 96 ++++++++++++++++++++++++++++++----------- setup.py | 2 +- 2 files changed, 71 insertions(+), 27 deletions(-) rename README.md => README.rst (59%) diff --git a/README.md b/README.rst similarity index 59% rename from README.md rename to README.rst index 9cf19a1..e475fa0 100644 --- a/README.md +++ b/README.rst @@ -1,12 +1,14 @@ stackdio-python-client ====================== -[![Build Status](https://travis-ci.org/stackdio/stackdio-python-client.svg?branch=master)](https://travis-ci.org/stackdio/stackdio-python-client) +|Travis CI| The canonical Python client and cli for the stackd.io API -## Overview +Overview +-------- + This is a small set of tools for internal use of stackd.io. After cloning this repo, you should be able to quickly get up and running with your own stacks. @@ -14,92 +16,134 @@ stacks. Advanced usage like creating custom blueprints or writing your own formulas is beyond the scope of this. -## Installation -We recommend using virtualenv via [virtualenvwrapper] to install this in a +Installation +------------ + +We recommend using virtualenv via `virtualenvwrapper`_ to install this in a virtualenv. If you consider yourself a knowledgeable Pythonista, feel free to install this however you'd like, but this document will assume that you are -using virtualenvwrapper. See the full [virtualenvwrapper] docs for details, +using virtualenvwrapper. See the full `virtualenvwrapper`_ docs for details, but in short you can install it on most systems like: +.. code:: bash + pip install virtualenvwrapper Once you've got it, installing this tool goes something like: +.. code:: bash + mkvirtualenv stackdio-client - # assuming you are in whatever dir you cloned this repo to: - pip install . + pip install stackdio You'll see a few things scrolling by, but should be set after this. To use this later, you'll need to re-activate the virtualenv like: +.. code:: bash + workon stackdio-client -Whenever it's activated, `stackdio-cli` should be on your path. +Whenever it's activated, ``stackdio-cli`` should be on your path. + +First Use +--------- -## First Use -The first time that you fire up `stackdio-cli`, you'll need to run the -`initial_setup` command. This will prompt you for your LDAP username and +The first time that you fire up ``stackdio-cli``, you'll need to run the +``configure`` command. This will prompt you for your LDAP username and password, and store them securely in your OS keychain for later use. It will import some standard formula, and create a few commonly used blueprints. +.. code:: bash + $ stackdio-cli None @ None - > initial_setup + > configure # YOU WILL BE WALKED THROUGH A SIMPLE SET OF QUESTIONS -## Stack Operations -All of the following assume that you have run `initial_setup` successfully. To +Stack Operations +---------------- + +All of the following assume that you have run ``initial_setup`` successfully. To launch the cli, simply type: +.. code:: bash + $ stackdio-cli -You can run `help` at any point to see available commands. For details on a -specific command you can run `help COMMAND`, e.g. `help stacks`. The rest of +You can run ``help`` at any point to see available commands. For details on a +specific command you can run ``help COMMAND``, e.g. ``help stacks``. The rest of these commands assume you have the cli running. -### Launching Stacks +Launching Stacks +~~~~~~~~~~~~~~~~ Stacks are launched from blueprints. To launch the 3 node HBase stack that's included with this you do: +.. code:: bash + > stacks launch cdh450-ipa-3 MYSTACKNAME -**NOTE:** To avoid DNS namespace collisions, the stack name needs to be unique. -An easy way to ensure this is to include your name in the stack name. -### Deleting Stacks +.. note:: + + To avoid DNS namespace collisions, the stack name needs to be unique. + An easy way to ensure this is to include your name in the stack name. + +Deleting Stacks +~~~~~~~~~~~~~~~ + When you are done with a stack you can delete it. This is destructive and cannot be recovered from, so think carefully before deleting your stack! +.. code:: bash + > stacks delete STACK_NAME -Alternatively you can `terminate` a stack which will terminate all instances, +Alternatively you can ``terminate`` a stack which will terminate all instances, but leave the stack definition in place. -### Provisioning Stacks +Provisioning Stacks +~~~~~~~~~~~~~~~~~~~ + Occassionally something will go wrong when launching your stack, e.g. network connections may flake out causing some package installations to fail. If this happens you can manually provision your stack, causing everything to be brought back up to date: +.. code:: bash + > stacks provision STACK_NAME -### Stack Info +Stack Info +~~~~~~~~~~ + Once you have launched a stack, you can then monitor the status of it like: +.. code:: bash + > stacks history STACK_NAME This displays the top level information for a stack. You can supply additional arguments to pull back additional info about a stack. For example, to get a list of FQDNs (aka hostnames) for a stack: +.. code:: bash + > stacks hostnames STACK_NAME -There are various logs available that you can access with the `stacks logs` +There are various logs available that you can access with the ``stacks logs`` command. -## What's Next? +What's Next? +------------ + For anything not covered by this tool, you'll need to use the stackdio-server web UI or API directly. For more information on that, check out http://docs.stackd.io. -[virtualenvwrapper]: https://pypi.python.org/pypi/virtualenvwrapper + +.. |Travis CI| image:: https://travis-ci.org/stackdio/stackdio-python-client.svg?branch=master + :target: https://travis-ci.org/stackdio/stackdio-python-client + :alt: Build Status + +.. _virtualenvwrapper: https://pypi.python.org/pypi/virtualenvwrapper diff --git a/setup.py b/setup.py index 32376ed..7015fe8 100644 --- a/setup.py +++ b/setup.py @@ -41,7 +41,7 @@ def test_python_version(): 'platform for everyone.') # Use the README.md as the long description -with open('README.md') as f: +with open('README.rst') as f: LONG_DESCRIPTION = f.read() requirements = [ From 69814b4fd94580f46f79f86ca030504eb08da6ca Mon Sep 17 00:00:00 2001 From: Clark Perkins Date: Mon, 11 Apr 2016 17:06:34 -0500 Subject: [PATCH 03/19] Allow 0.8.x servers --- stackdio/client/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stackdio/client/__init__.py b/stackdio/client/__init__.py index 1c4bc42..faba27f 100644 --- a/stackdio/client/__init__.py +++ b/stackdio/client/__init__.py @@ -64,9 +64,9 @@ def __init__(self, url=None, username=None, password=None, verify=True, cfg_file except MissingUrlException: self.version = None - if self.version and (self.version[0] != 0 or self.version[1] != 7): + if self.version and (self.version[0] != 0 or self.version[1] != 8): raise IncompatibleVersionException('Server version {0}.{1}.{2} not ' - 'supported.'.format(**self.version)) + 'supported.'.format(*self.version)) @property def url(self): From 7da7c87b88b0cb0fddbde8b591efe8a40da73f75 Mon Sep 17 00:00:00 2001 From: Clark Perkins Date: Sun, 24 Apr 2016 22:23:15 -0500 Subject: [PATCH 04/19] Accidentally committed bad version --- stackdio/client/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stackdio/client/__init__.py b/stackdio/client/__init__.py index 763d27f..f10bcb8 100644 --- a/stackdio/client/__init__.py +++ b/stackdio/client/__init__.py @@ -99,7 +99,7 @@ def __init__(self, url=None, username=None, password=None, verify=True, cfg_file raw_version = None self.version = None - if self.version and (self.version[0] != 0 or self.version[1] != 7): + if self.version and (self.version[0] != 0 or self.version[1] != 8): raise IncompatibleVersionException( 'Server version {0} not supported. Please upgrade ' 'stackdio-cli to {1}.{2}.0 or higher.'.format(raw_version, *self.version) From e7168a34d31f1421043e71aa2e9b3e4478b2c328 Mon Sep 17 00:00:00 2001 From: Clark Perkins Date: Tue, 1 Nov 2016 12:12:22 -0500 Subject: [PATCH 05/19] Fixed version parsing --- stackdio/client/__init__.py | 43 ++++++------------------------------- 1 file changed, 6 insertions(+), 37 deletions(-) diff --git a/stackdio/client/__init__.py b/stackdio/client/__init__.py index f10bcb8..877a189 100644 --- a/stackdio/client/__init__.py +++ b/stackdio/client/__init__.py @@ -15,8 +15,11 @@ # limitations under the License. # +from __future__ import unicode_literals + import logging +from pkg_resources import parse_version from .account import AccountMixin from .blueprint import BlueprintMixin from .config import StackdioConfig @@ -37,44 +40,10 @@ logger.addHandler(logging.NullHandler()) -def _get_server_version_info(version_str): - basic_info = version_str.split('.') - - major = int(basic_info[0]) - minor = int(basic_info[1]) - - version_type = 'final' - extra_id = 0 - - try: - patch_v = int(basic_info[2]) - except ValueError: - for vtype in ('a', 'b', 'rc'): - if vtype in basic_info[2]: - version_type = vtype - idx = basic_info[2].find(vtype) - patch_v = int(basic_info[:idx]) - extra_id = int(basic_info[2][idx + len(vtype):]) - - if version_type == 'final': - raise ValueError('Invalid version: {}'.format(version_str)) - - if len(basic_info) > 3: - for vtype in ('dev', 'post'): - if basic_info[3].startswith(vtype): - version_type = vtype - extra_id = int(basic_info[3][len(vtype):]) - - if version_type == 'final': - raise ValueError('Invalid version: {}'.format(version_str)) - - return major, minor, patch_v, version_type, extra_id - - class StackdioClient(BlueprintMixin, FormulaMixin, AccountMixin, ImageMixin, RegionMixin, StackMixin, SettingsMixin, HttpMixin): - def __init__(self, url=None, username=None, password=None, verify=True, cfg_file=None): + def __init__(self, url=None, username=None, password=None, verify=None, cfg_file=None): self.config = StackdioConfig(cfg_file) self._password = self.config.get_password() @@ -94,12 +63,12 @@ def __init__(self, url=None, username=None, password=None, verify=True, cfg_file if self.usable(): try: raw_version = self.get_version(raise_for_status=False) - self.version = _get_server_version_info(raw_version) + self.version = parse_version(raw_version) except MissingUrlException: raw_version = None self.version = None - if self.version and (self.version[0] != 0 or self.version[1] != 8): + if self.version and not self.version.base_version.startswith('0.8'): raise IncompatibleVersionException( 'Server version {0} not supported. Please upgrade ' 'stackdio-cli to {1}.{2}.0 or higher.'.format(raw_version, *self.version) From 1cc82c42fe0b5875b29aa264ae64373674e6d837 Mon Sep 17 00:00:00 2001 From: Clark Perkins Date: Tue, 1 Nov 2016 12:13:56 -0500 Subject: [PATCH 06/19] parse_version sometimes returns a tuple? --- stackdio/client/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stackdio/client/__init__.py b/stackdio/client/__init__.py index 877a189..4ce2cea 100644 --- a/stackdio/client/__init__.py +++ b/stackdio/client/__init__.py @@ -68,7 +68,7 @@ def __init__(self, url=None, username=None, password=None, verify=None, cfg_file raw_version = None self.version = None - if self.version and not self.version.base_version.startswith('0.8'): + if self.version and (int(self.version[0]) != 0 or int(self.version[1]) != 8): raise IncompatibleVersionException( 'Server version {0} not supported. Please upgrade ' 'stackdio-cli to {1}.{2}.0 or higher.'.format(raw_version, *self.version) From 5e630488cf194a55bd4e5b081d8e0aaebb686a52 Mon Sep 17 00:00:00 2001 From: Clark Perkins Date: Tue, 1 Nov 2016 12:22:30 -0500 Subject: [PATCH 07/19] Removed search_* methods, just pass kwargs to list_* methods instead --- stackdio/cli/mixins/blueprints.py | 2 +- stackdio/cli/mixins/formulas.py | 2 +- stackdio/cli/mixins/stacks.py | 4 ++-- stackdio/client/account.py | 14 ++------------ stackdio/client/blueprint.py | 6 +----- stackdio/client/formula.py | 7 +------ stackdio/client/image.py | 7 +------ stackdio/client/region.py | 12 ++---------- stackdio/client/stack.py | 11 +++++------ 9 files changed, 16 insertions(+), 49 deletions(-) diff --git a/stackdio/cli/mixins/blueprints.py b/stackdio/cli/mixins/blueprints.py index b8c3e88..5d8fab2 100644 --- a/stackdio/cli/mixins/blueprints.py +++ b/stackdio/cli/mixins/blueprints.py @@ -181,7 +181,7 @@ def create_all_blueprints(client): def get_blueprint_id(client, blueprint_title): - found_blueprints = client.search_blueprints(title=blueprint_title) + found_blueprints = client.list_blueprints(title=blueprint_title) if len(found_blueprints) == 0: raise click.Abort('Blueprint "{0}" does not exist'.format(blueprint_title)) diff --git a/stackdio/cli/mixins/formulas.py b/stackdio/cli/mixins/formulas.py index 2fcb748..ec4d47c 100644 --- a/stackdio/cli/mixins/formulas.py +++ b/stackdio/cli/mixins/formulas.py @@ -43,7 +43,7 @@ def import_formula(client, uri, username, password): def get_formula_id(client, formula_uri): - found_formulas = client.search_formulas(uri=formula_uri) + found_formulas = client.list_formulas(uri=formula_uri) if len(found_formulas) == 0: raise click.Abort('Formula "{0}" does not exist'.format(formula_uri)) diff --git a/stackdio/cli/mixins/stacks.py b/stackdio/cli/mixins/stacks.py index a1fa3f1..cea0c30 100644 --- a/stackdio/cli/mixins/stacks.py +++ b/stackdio/cli/mixins/stacks.py @@ -52,7 +52,7 @@ def launch_stack(client, blueprint_title, stack_title): def get_stack_id(client, stack_title): - found_stacks = client.search_stacks(title=stack_title) + found_stacks = client.list_stacks(title=stack_title) if len(found_stacks) == 0: raise click.Abort('Stack "{0}" does not exist'.format(stack_title)) @@ -73,7 +73,7 @@ def stack_history(client, stack_title, length): stack_id = get_stack_id(client, stack_title) history = client.get_stack_history(stack_id) for event in history[0:min(length, len(history))]: - click.echo('[{created}] {level} // {event} // {status}'.format(**event)) + click.echo('[{created}] {message}'.format(**event)) @stacks.command(name='hostnames') diff --git a/stackdio/client/account.py b/stackdio/client/account.py index 928105f..f43b522 100644 --- a/stackdio/client/account.py +++ b/stackdio/client/account.py @@ -21,15 +21,10 @@ class AccountMixin(HttpMixin): @get('cloud/providers/', paginate=True) - def list_providers(self): + def list_providers(self, **kwargs): """List all providers""" pass - @get('cloud/providers/', paginate=True) - def search_providers(self, **kwargs): - """Search for a provider""" - pass - @post('cloud/accounts/') def create_account(self, **kwargs): """Create an account""" @@ -53,7 +48,7 @@ def create_account(self, **kwargs): return form_data @get('cloud/accounts/', paginate=True) - def list_accounts(self): + def list_accounts(self, **kwargs): """List all account""" pass @@ -62,11 +57,6 @@ def get_account(self, account_id): """Return the account that matches the given id""" pass - @get('cloud/accounts/') - def search_accounts(self, **kwargs): - """List all accounts""" - pass - @delete('cloud/accounts/{account_id}/') def delete_account(self, account_id): """List all accounts""" diff --git a/stackdio/client/blueprint.py b/stackdio/client/blueprint.py index f684bb6..e9e9f2e 100644 --- a/stackdio/client/blueprint.py +++ b/stackdio/client/blueprint.py @@ -56,17 +56,13 @@ def create_blueprint(self, blueprint): return blueprint @get('blueprints/', paginate=True) - def list_blueprints(self): + def list_blueprints(self, **kwargs): pass @get('blueprints/{blueprint_id}/') def get_blueprint(self, blueprint_id): pass - @get('blueprints/', paginate=True) - def search_blueprints(self, **kwargs): - pass - @delete('blueprints/{blueprint_id}/') def delete_blueprint(self, blueprint_id): pass diff --git a/stackdio/client/formula.py b/stackdio/client/formula.py index 5e30935..3d819b7 100644 --- a/stackdio/client/formula.py +++ b/stackdio/client/formula.py @@ -37,7 +37,7 @@ def import_formula(self, formula_uri, git_username=None, git_password=None, acce return data @get('formulas/', paginate=True) - def list_formulas(self): + def list_formulas(self, **kwargs): """Return all formulas""" pass @@ -50,11 +50,6 @@ def get_formula(self, formula_id): def list_components_for_version(self, formula_id, version): pass - @get('formulas/', paginate=True) - def search_formulas(self, **kwargs): - """Get a formula with matching id""" - pass - @delete('formulas/{formula_id}/') def delete_formula(self, formula_id): """Delete formula with matching id""" diff --git a/stackdio/client/image.py b/stackdio/client/image.py index 8af4f15..80402f2 100644 --- a/stackdio/client/image.py +++ b/stackdio/client/image.py @@ -32,7 +32,7 @@ def create_image(self, title, image_id, ssh_user, cloud_provider, default_instan } @get('cloud/images/', paginate=True) - def list_images(self): + def list_images(self, **kwargs): """List all images""" pass @@ -41,11 +41,6 @@ def get_image(self, image_id): """Return the image that matches the given id""" pass - @get('cloud/images/', paginate=True) - def search_images(self, **kwargs): - """List all images""" - pass - @delete('cloud/images/{image_id}/') def delete_image(self, image_id): """Delete the image with the given id""" diff --git a/stackdio/client/region.py b/stackdio/client/region.py index 2689d8b..e69237a 100644 --- a/stackdio/client/region.py +++ b/stackdio/client/region.py @@ -20,25 +20,17 @@ class RegionMixin(HttpMixin): @get('cloud/providers/{provider_name}/regions/', paginate=True) - def list_regions(self, provider_name): + def list_regions(self, provider_name, **kwargs): pass @get('cloud/providers/{provider_name}/regions/{region_id}/') def get_region(self, provider_name, region_id): pass - @get('cloud/providers/{provider_name}/regions/', paginate=True) - def search_regions(self, provider_name, **kwargs): - pass - @get('cloud/providers/{provider_name}/zones/', paginate=True) - def list_zones(self): + def list_zones(self, provider_name, **kwargs): pass @get('cloud/providers/{provider_name}/zones/{zone_id}') def get_zone(self, provider_name, zone_id): pass - - @get('cloud/providers/{provider_name}/zones/', paginate=True) - def search_zones(self, provider_name, **kwargs): - pass diff --git a/stackdio/client/stack.py b/stackdio/client/stack.py index 0308f25..1daef54 100644 --- a/stackdio/client/stack.py +++ b/stackdio/client/stack.py @@ -33,7 +33,7 @@ def create_stack(self, stack_data): return stack_data @get('stacks/', paginate=True) - def list_stacks(self): + def list_stacks(self, **kwargs): """Return a list of all stacks""" pass @@ -42,11 +42,6 @@ def get_stack(self, stack_id): """Get stack info""" pass - @get('stacks/', paginate=True) - def search_stacks(self, **kwargs): - """Search for stacks that match the given criteria""" - pass - @delete('stacks/{stack_id}/') def delete_stack(self, stack_id): """Destructively delete a stack forever.""" @@ -100,6 +95,10 @@ def get_stack_history(self, stack_id): """Get stack info""" pass + @get_stack_history.response + def get_stack_history(self, resp): + return list(reversed(resp)) + @get('stacks/{stack_id}/hosts/', paginate=True) def get_stack_hosts(self, stack_id): """Get a list of all stack hosts""" From 57f8e6fbaa309cd9840e411cc639d96c83ef8830 Mon Sep 17 00:00:00 2001 From: Clark Perkins Date: Tue, 1 Nov 2016 12:28:59 -0500 Subject: [PATCH 08/19] Make travis upload to pypi --- .travis.yml | 43 ++++++++++++++++++++++++------------------- setup.py | 8 +++----- 2 files changed, 27 insertions(+), 24 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6b4d5c0..5dbb743 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,20 +2,13 @@ language: python python: - "2.7" - - "3.3" - "3.4" + - "3.5" cache: directories: - $HOME/.cache/pip -# Set up our environment -env: - NOSE_WITH_XUNIT: 1 - NOSE_WITH_COVERAGE: 1 - NOSE_COVER_BRANCHES: 1 - NOSE_COVER_INCLUSIVE: 1 - # So that we get a docker container sudo: false @@ -37,18 +30,30 @@ script: # Only build artifacts on success after_success: - coveralls - - export STACKDIO_VERSION=`python setup.py --version` - python setup.py sdist - python setup.py bdist_wheel deploy: - provider: releases - api_key: - secure: T4jI1aZQ+wDJBgGxcbdrtLz3zpXA9yZwmrsm8d3GqEGxApMtkKLWq0uqf86C8VkqaY6p4Nm1a/PTApV1isbuSoJbdeMVJA1MlYB/G7QMK7eI8nFqkw7Q4jzuOdEC0D1CPZx7ZWBn0bYxSRTcSeQSnGeGDy2KxekGSZFfIxe4APo= - file: - - dist/stackdio-${STACKDIO_VERSION}.tar.gz - - dist/stackdio-${STACKDIO_VERSION}-py2.py3-none-any.whl - skip_cleanup: true - on: - tags: true - repo: stackdio/stackdio-python-client + - provider: releases + api_key: + secure: T4jI1aZQ+wDJBgGxcbdrtLz3zpXA9yZwmrsm8d3GqEGxApMtkKLWq0uqf86C8VkqaY6p4Nm1a/PTApV1isbuSoJbdeMVJA1MlYB/G7QMK7eI8nFqkw7Q4jzuOdEC0D1CPZx7ZWBn0bYxSRTcSeQSnGeGDy2KxekGSZFfIxe4APo= + file: + - dist/stackdio-${TRAVIS_TAG}.tar.gz + - dist/stackdio-${TRAVIS_TAG}-py2.py3-none-any.whl + skip_cleanup: true + on: + tags: true + repo: stackdio/stackdio-python-client + python: "2.7" + + # Upload to pypi. Do this instead of the pypi provider so that we + # ensure the exact same artifact is uploaded to github and pypi. + # The pypi provider will re-build the 2 artifacts, which is not ideal. + # This requires setting TWINE_USERNAME and TWINE_PASSWORD in travis. + - provider: script + script: twine upload dist/stackdio-${TRAVIS_TAG}.tar.gz dist/stackdio-${TRAVIS_TAG}-py2.py3-none-any.whl + skip_cleanup: true + on: + tags: true + repo: stackdio/stackdio-python-client + python: "2.7" diff --git a/setup.py b/setup.py index 3c460a0..f8869f0 100644 --- a/setup.py +++ b/setup.py @@ -15,7 +15,6 @@ # limitations under the License. # -import os import sys from setuptools import setup, find_packages @@ -25,9 +24,9 @@ def test_python_version(): major = sys.version_info[0] minor = sys.version_info[1] micro = sys.version_info[2] - if float('%d.%d' % (major, minor)) < 2.6: + if (major, minor) < (2, 7): err_msg = ('Your Python version {0}.{1}.{2} is not supported.\n' - 'stackdio-server requires Python 2.6 or newer.\n'.format(major, minor, micro)) + 'stackdio-server requires Python 2.7 or newer.\n'.format(major, minor, micro)) sys.stderr.write(err_msg) sys.exit(1) @@ -85,7 +84,6 @@ def test_python_version(): 'console_scripts': [ 'stackdio-cli=stackdio.cli:main', 'blueprint-generator=stackdio.cli.blueprints:main', - 'stackdio-config-convert=stackdio.client.config:main', ], }, classifiers=[ @@ -99,8 +97,8 @@ def test_python_version(): 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.3', 'Programming Language :: Python :: 3.4', + 'Programming Language :: Python :: 3.5', 'Topic :: System :: Clustering', 'Topic :: System :: Distributed Computing', ] From 2de64767b13a3a15b229a571e01052ace059bdd7 Mon Sep 17 00:00:00 2001 From: Clark Perkins Date: Tue, 1 Nov 2016 12:34:37 -0500 Subject: [PATCH 09/19] Removed search method --- stackdio/client/snapshot.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/stackdio/client/snapshot.py b/stackdio/client/snapshot.py index 5cda87a..6264f8b 100644 --- a/stackdio/client/snapshot.py +++ b/stackdio/client/snapshot.py @@ -26,17 +26,13 @@ def create_snapshot(self, snapshot): return snapshot @get('cloud/snapshots/', paginate=True) - def list_snapshots(self): + def list_snapshots(self, **kwargs): pass @get('cloud/snapshots/{snapshot_id}/') def get_snapshot(self, snapshot_id): pass - @get('cloud/snapshots/', paginate=True) - def search_snapshots(self, **kwargs): - pass - @delete('cloud/snapshots/{snapshot_id}/') def delete_snapshot(self, snapshot_id): pass From 674dc7069b8de851e482a5d671808caba06da377 Mon Sep 17 00:00:00 2001 From: Clark Perkins Date: Tue, 1 Nov 2016 15:34:29 -0500 Subject: [PATCH 10/19] Updating version for 0.8.0b1 --- stackdio/client/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stackdio/client/version.py b/stackdio/client/version.py index 73cb64f..bcee887 100644 --- a/stackdio/client/version.py +++ b/stackdio/client/version.py @@ -27,7 +27,7 @@ except Exception: pass -VERSION = (0, 8, 0, 'dev', 0) +VERSION = (0, 8, 0, 'b', 1) def get_version(version): From 0099f9d5838c98d287c6e8931e1dd53dc3cc574d Mon Sep 17 00:00:00 2001 From: Clark Perkins Date: Tue, 1 Nov 2016 15:34:51 -0500 Subject: [PATCH 11/19] Updating version for 0.8.0 development --- stackdio/client/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stackdio/client/version.py b/stackdio/client/version.py index bcee887..73cb64f 100644 --- a/stackdio/client/version.py +++ b/stackdio/client/version.py @@ -27,7 +27,7 @@ except Exception: pass -VERSION = (0, 8, 0, 'b', 1) +VERSION = (0, 8, 0, 'dev', 0) def get_version(version): From 0dcb4cd66e873672aa1a2b539516fbf88592c5f5 Mon Sep 17 00:00:00 2001 From: Clark Perkins Date: Tue, 1 Nov 2016 15:38:26 -0500 Subject: [PATCH 12/19] Install twine --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 5dbb743..8b9c997 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,6 +16,7 @@ sudo: false install: - pip install -U pip - pip install -U wheel + - pip install -U twine - pip install -U -e .[testing] ## Customize test commands From 2e7d1c1398f86596c4f7d61188d5d4bbd75b2e1c Mon Sep 17 00:00:00 2001 From: Clark Perkins Date: Wed, 5 Jul 2017 14:14:59 -0500 Subject: [PATCH 13/19] Support yaml blueprint templates --- stackdio/cli/blueprints/generator.py | 37 +++++++++++++++++----------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/stackdio/cli/blueprints/generator.py b/stackdio/cli/blueprints/generator.py index efef425..b59c935 100644 --- a/stackdio/cli/blueprints/generator.py +++ b/stackdio/cli/blueprints/generator.py @@ -1,15 +1,15 @@ -from __future__ import print_function +from __future__ import print_function, unicode_literals -import sys -import os import json +import os +import sys import click import yaml from jinja2 import Environment, FileSystemLoader, StrictUndefined, meta from jinja2.exceptions import TemplateNotFound, TemplateSyntaxError, UndefinedError -from jinja2.nodes import Assign, Block, Const, If, Not from jinja2.filters import do_replace, evalcontextfilter +from jinja2.nodes import Assign, Block, Const, If, Not class BlueprintException(Exception): @@ -232,12 +232,12 @@ def generate(self, template_file, var_files=(), variables=None, if prompt: # Prompt for missing vars for var in sorted(missing_vars): - context[var] = self.prompt('{0}: '.format(var)) + context[var] = self.prompt('{}: '.format(var)) else: # Print an error error_str = 'Missing variables:\n' for var in sorted(missing_vars): - error_str += ' {0}\n'.format(var) + error_str += ' {}\n'.format(var) self.error_exit(error_str, 0) # Find the set of optional variables (ones inside of a 'if is not undefined' @@ -259,14 +259,14 @@ def generate(self, template_file, var_files=(), variables=None, if null_vars and not suppress_warnings: warn_str = '\nWARNING: Null variables (replaced with empty string):\n' for var in null_vars: - warn_str += ' {0}\n'.format(var) + warn_str += ' {}\n'.format(var) self.warning(warn_str, 0) # Print a warning if there's unset optional variables if optional_vars and not suppress_warnings: warn_str = '\nWARNING: Missing optional variables:\n' for var in sorted(optional_vars): - warn_str += ' {0}\n'.format(var) + warn_str += ' {}\n'.format(var) self.warning(warn_str, 0) # Generate the blueprint @@ -276,24 +276,31 @@ def generate(self, template_file, var_files=(), variables=None, set_vars.update(context) context = set_vars - template_json = template.render(**context) + rendered_template = template.render(**context) if debug: click.echo('\n') - click.echo(template_json) + click.echo(rendered_template) click.echo('\n') - # Return a dict object rather than a string - return json.loads(template_json) + template_extension = template_file.split('.')[-1] + + if template_extension in ('json',): + # Return a dict object rather than a string + return json.loads(rendered_template) + elif template_extension in ('yaml', 'yml'): + return yaml.safe_load(rendered_template) + else: + self.error_exit('Template extension {} is not valid.'.format(template_extension)) except TemplateNotFound: - self.error_exit('Your template file {0} was not found.'.format(template_file)) + self.error_exit('Your template file {} was not found.'.format(template_file)) except TemplateSyntaxError as e: - self.error_exit('Invalid template error at line {0}:\n{1}'.format( + self.error_exit('Invalid template error at line {}:\n{}'.format( e.lineno, str(e) )) except UndefinedError as e: - self.error_exit('Missing variable: {0}'.format(str(e))) + self.error_exit('Missing variable: {}'.format(str(e))) # except ValueError: # self.error_exit('Invalid JSON. Check your template file.') From a0aae18720c0ba553d77b40eab02f9b621a8742e Mon Sep 17 00:00:00 2001 From: Clark Perkins Date: Tue, 15 May 2018 11:52:03 -0500 Subject: [PATCH 14/19] Readability changes --- stackdio/client/http.py | 5 +---- stackdio/client/stack.py | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/stackdio/client/http.py b/stackdio/client/http.py index 4eb3d4d..35e2bf7 100644 --- a/stackdio/client/http.py +++ b/stackdio/client/http.py @@ -95,10 +95,7 @@ def __init__(self, dfunc=None, rfunc=None, quiet=False): self.obj = None self.data_func = dfunc - self.response_func = rfunc - - if self.response_func is None: - self.response_func = default_response + self.response_func = rfunc or default_response self.quiet = quiet diff --git a/stackdio/client/stack.py b/stackdio/client/stack.py index 1daef54..396fe3d 100644 --- a/stackdio/client/stack.py +++ b/stackdio/client/stack.py @@ -97,7 +97,7 @@ def get_stack_history(self, stack_id): @get_stack_history.response def get_stack_history(self, resp): - return list(reversed(resp)) + return reversed(resp) @get('stacks/{stack_id}/hosts/', paginate=True) def get_stack_hosts(self, stack_id): From 7889c765218d78c3d398a683228cc2b875c7d61e Mon Sep 17 00:00:00 2001 From: Clark Perkins Date: Tue, 15 May 2018 11:53:15 -0500 Subject: [PATCH 15/19] Updating version for 0.8.0b2 --- stackdio/client/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stackdio/client/version.py b/stackdio/client/version.py index 73cb64f..5687339 100644 --- a/stackdio/client/version.py +++ b/stackdio/client/version.py @@ -27,7 +27,7 @@ except Exception: pass -VERSION = (0, 8, 0, 'dev', 0) +VERSION = (0, 8, 0, 'b', 2) def get_version(version): From 3b4782648670eed7d0e385d4aa6918a297a56451 Mon Sep 17 00:00:00 2001 From: Clark Perkins Date: Tue, 15 May 2018 11:54:11 -0500 Subject: [PATCH 16/19] Updating version for 0.8.0 development --- stackdio/client/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stackdio/client/version.py b/stackdio/client/version.py index 5687339..73cb64f 100644 --- a/stackdio/client/version.py +++ b/stackdio/client/version.py @@ -27,7 +27,7 @@ except Exception: pass -VERSION = (0, 8, 0, 'b', 2) +VERSION = (0, 8, 0, 'dev', 0) def get_version(version): From fce41a067c23775f6fca93e4a06faa993d9b5469 Mon Sep 17 00:00:00 2001 From: Clark Perkins Date: Tue, 15 May 2018 12:05:55 -0500 Subject: [PATCH 17/19] Fixing travis deploy --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 8b9c997..619765d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -37,7 +37,7 @@ after_success: deploy: - provider: releases api_key: - secure: T4jI1aZQ+wDJBgGxcbdrtLz3zpXA9yZwmrsm8d3GqEGxApMtkKLWq0uqf86C8VkqaY6p4Nm1a/PTApV1isbuSoJbdeMVJA1MlYB/G7QMK7eI8nFqkw7Q4jzuOdEC0D1CPZx7ZWBn0bYxSRTcSeQSnGeGDy2KxekGSZFfIxe4APo= + secure: WDRJ+QYPfAMuH8sEFPTTEHabaEtfvLWvHiXi69NA3lruIlKr0Id5gpF/Bqr5VfHiz9jdHuBRdVLgYRYVXAVsRkw13N1YlHgR4j4oi61fMugwDTC820Jnf8EDpuvXys8TPiPRh7Xe2XTGc4HMO0moGz6gp9gH4OAsxGgLPNLmiDA= file: - dist/stackdio-${TRAVIS_TAG}.tar.gz - dist/stackdio-${TRAVIS_TAG}-py2.py3-none-any.whl From ac17d07a7b42aea3c753d3543133aaa94385acfd Mon Sep 17 00:00:00 2001 From: Clark Perkins Date: Tue, 15 May 2018 12:08:00 -0500 Subject: [PATCH 18/19] Updating version for 0.8.0b2 --- stackdio/client/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stackdio/client/version.py b/stackdio/client/version.py index 73cb64f..5687339 100644 --- a/stackdio/client/version.py +++ b/stackdio/client/version.py @@ -27,7 +27,7 @@ except Exception: pass -VERSION = (0, 8, 0, 'dev', 0) +VERSION = (0, 8, 0, 'b', 2) def get_version(version): From 9a74959fa19494f1a840920bcaa413ff7c042b6a Mon Sep 17 00:00:00 2001 From: Clark Perkins Date: Tue, 15 May 2018 12:08:32 -0500 Subject: [PATCH 19/19] Updating version for 0.8.0 development --- stackdio/client/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stackdio/client/version.py b/stackdio/client/version.py index 5687339..73cb64f 100644 --- a/stackdio/client/version.py +++ b/stackdio/client/version.py @@ -27,7 +27,7 @@ except Exception: pass -VERSION = (0, 8, 0, 'b', 2) +VERSION = (0, 8, 0, 'dev', 0) def get_version(version):