Thomas Maddox 05b4f117bb CLI and client support for get/set/delete of resource vars
Functionality is supported both	for the	Python client:

host = craton.hosts.get(item_id=8)
host.variables.update(x='foo', y={'a': 47, 'b': True}, z='baz')
host.variables.delete("foo", "bar", "baz")

As well	as for the CLI:

craton host-vars-get 1
craton host-vars-set 3 x=true y=47 z=foo/bar w=3.14159
cat <<EOF | craton host-vars-set 13
{
    "glance_default_store": "not-so-swift",
    "neutron_l2_population": false,
    "make_stuff_up": true,
    "some/namespaced/variable": {"a": 1, "b": 2}
}
EOF
craton --format json host-vars-get 13 | jq -C
craton host-vars-delete 13 make_stuff_up
craton host-vars-set 13 x= y=42   # deletes x

This patch implements the basis for supporting this
in other resources as well, however we only address
hosts here as an initial implementation. We will
fast-follow with support in other resources.

Partial-Bug: 1659110
Change-Id: Id30188937518d7103d6f943cf1d038b039dc30cc
2017-03-06 14:27:35 +00:00

108 lines
3.6 KiB
Python

# 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.
"""Base class implementation for formatting plugins."""
class Formatter(object):
"""Class that defines the formatter interface.
Instead of having to override and call up to this class's ``__init__``
method, we also provide an ``after_init`` method that can be implemented
to extend what happens on initialization.
.. attribute:: args
Parsed command-line arguments stored as an instance of
:class:`argparse.Namespace`.
"""
def __init__(self, parsed_args):
"""Instantiate our formatter with the parsed CLI arguments.
:param parsed_args:
The CLI arguments parsed by :mod:`argparse`.
:type parsed_args:
argparse.Namespace
"""
self.args = parsed_args
self.after_init()
def after_init(self):
"""Initialize the object further after ``__init__``."""
pass
def configure(self, *args, **kwargs):
"""Optional configuration of the plugin after instantiation."""
return self
def handle(self, item_to_format):
"""Handle a returned item from the cratonclient API.
cratonclient's API produces both single Resource objects as well as
generators of those objects. This method should be capable of handling
both.
Based on the type, this will either call ``handle_generator`` or
``handle_instance``. Subclasses must implement both of those methods.
:returns:
None
:rtype:
None
:raises ValueError:
If the item provided is not a subclass of
:class:`~cratonclient.crud.Resource` or an iterable class then
we will not know how to handle it. In that case, we will raise a
ValueError.
"""
to_dict = getattr(item_to_format, 'to_dict', None)
if to_dict is not None:
self.handle_instance(item_to_format)
return
try:
self.handle_generator(item_to_format)
except TypeError as err:
raise ValueError(
"Expected an iterable object but instead received something "
"of type: %s. Received a TypeError: %s" % (
type(item_to_format),
err
)
)
def handle_instance(self, instance):
"""Format and print the instance provided.
:param instance:
The instance retrieved from the API that needs to be formatted.
:type instance:
cratonclient.crud.Resource
"""
raise NotImplementedError(
"A formatter plugin subclassed Formatter but did not implement"
" the handle_instance method."
)
def handle_generator(self, generator):
"""Format and print the instance provided.
:param generator:
The generator retrieved from the API whose items need to be
formatted.
"""
raise NotImplementedError(
"A formatter plugin subclassed Formatter but did not implement"
" the handle_generator method."
)