From 13ef6ede7616d792e0f9449bd926da3c812fee87 Mon Sep 17 00:00:00 2001 From: amcrn Date: Tue, 14 Jan 2014 14:07:47 -0800 Subject: [PATCH] initial commit --- .gitignore | 6 + LICENSE | 176 ++++++++++++++++ README.md | 20 +- accounts_python_troveclient_ext.py | 88 ++++++++ diagnostics_python_troveclient_ext.py | 52 +++++ hosts_python_troveclient_ext.py | 105 +++++++++ hwinfo_python_troveclient_ext.py | 49 +++++ management_flavor_python_troveclient_ext.py | 85 ++++++++ management_python_troveclient_ext.py | 222 ++++++++++++++++++++ quota_python_troveclient_ext.py | 73 +++++++ setup.py | 33 +++ storage_python_troveclient_ext.py | 58 +++++ 12 files changed, 965 insertions(+), 2 deletions(-) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 accounts_python_troveclient_ext.py create mode 100644 diagnostics_python_troveclient_ext.py create mode 100644 hosts_python_troveclient_ext.py create mode 100644 hwinfo_python_troveclient_ext.py create mode 100644 management_flavor_python_troveclient_ext.py create mode 100644 management_python_troveclient_ext.py create mode 100644 quota_python_troveclient_ext.py create mode 100644 setup.py create mode 100644 storage_python_troveclient_ext.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8179add --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +*.pyc +.venv +.DS_STORE +mgmt_python_troveclient_ext.egg-info/ +dist +build diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..68c771a --- /dev/null +++ b/LICENSE @@ -0,0 +1,176 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + diff --git a/README.md b/README.md index 535e8a1..8d761a9 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,20 @@ +============================= mgmt_python_troveclient_ext -=========================== +============================= -management api extensions for python-troveclient +Management API extensions for python-troveclient (v1.0+). + +Setup: + +``` +$ git clone git://github.com/openstack/python-troveclient.git +$ git clone git://github.com/amcrn/mgmt_python_troveclient_ext.git +$ cd python-troveclient +$ pip install -r requirements.txt +$ python setup.py develop +# fetch extensions fix, see https://review.openstack.org/#/c/65758/ +$ git fetch https://review.openstack.org/openstack/python-troveclient refs/changes/58/65758/4 && git cherry-pick FETCH_HEAD +$ cd ../mgmt_python_troveclient_ext +$ python setup.py develop +$ trove +``` diff --git a/accounts_python_troveclient_ext.py b/accounts_python_troveclient_ext.py new file mode 100644 index 0000000..4387fcc --- /dev/null +++ b/accounts_python_troveclient_ext.py @@ -0,0 +1,88 @@ +# Copyright 2011 OpenStack Foundation +# Copyright 2013 Rackspace Hosting +# All Rights Reserved. +# +# 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. + +from troveclient import base +from troveclient import common +from troveclient import utils + + +class Account(base.Resource): + """ + Account is an opaque instance used to hold account information. + """ + def __repr__(self): + return "" % self.name + + +class Accounts(base.ManagerWithFind): + """ + Manage :class:`Account` information. + """ + + resource_class = Account + + def _list(self, url, response_key): + resp, body = self.api.client.get(url) + if not body: + raise Exception("Call to " + url + " did not return a body.") + return [self.resource_class(self, res) for res in body[response_key]] + + def index(self): + """List all accounts with non-terminated instances""" + + url = "/mgmt/accounts" + resp, body = self.api.client.get(url) + common.check_for_exceptions(resp, body) + if not body: + raise Exception("Call to " + url + " did not return a body.") + return [self.resource_class(self, res) for res in body['accounts']] + + def show(self, account): + """ + Get a list of instances associated with an account + + :rtype: :class:`Account`. + """ + + acct_name = self._get_account_name(account) + return self._list("/mgmt/accounts/%s" % acct_name, 'account') + + # Appease the abc gods + def list(self): + pass + + @staticmethod + def _get_account_name(account): + try: + if account.name: + return account.name + except AttributeError: + return account + + +@utils.service_type('database') +def do_mgmt_account_list(cs, args): + """List all accounts with non-terminated instances""" + accounts = cs.accounts_python_troveclient_ext.index() + utils.print_list(accounts, ['id', 'num_instances']) + + +@utils.arg('account', metavar='', help='Name of the account.') +@utils.service_type('database') +def do_mgmt_account_show(cs, args): + """Get a list of instances associated with an account""" + account = cs.accounts_python_troveclient_ext.show(args.account) + utils.print_dict(account) diff --git a/diagnostics_python_troveclient_ext.py b/diagnostics_python_troveclient_ext.py new file mode 100644 index 0000000..0ac9cb5 --- /dev/null +++ b/diagnostics_python_troveclient_ext.py @@ -0,0 +1,52 @@ +# Copyright 2011 OpenStack Foundation +# Copyright 2013 Rackspace Hosting +# All Rights Reserved. +# +# 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. + +from troveclient import base +from troveclient import utils + + +class Diagnostics(base.Resource): + """ + Account is an opaque instance used to hold account information. + """ + def __repr__(self): + return "" % self.version + + +class DiagnosticsInterrogator(base.ManagerWithFind): + """ + Manager class for Interrogator resource + """ + resource_class = Diagnostics + + def get(self, instance): + """ + Get the diagnostics of the guest on an instance. + """ + return self._get("/mgmt/instances/%s/diagnostics" % + base.getid(instance), "diagnostics") + + # Appease the abc gods + def list(self): + pass + + +@utils.arg('instance', metavar='', help='ID of the instance.') +@utils.service_type('database') +def do_mgmt_diagnostics_show(cs, args): + """Get the diagnostics of the guest on an instance""" + hosts = cs.diagnostics_python_troveclient_ext.get(args.instance) + utils.print_dict(hosts) diff --git a/hosts_python_troveclient_ext.py b/hosts_python_troveclient_ext.py new file mode 100644 index 0000000..26dfef8 --- /dev/null +++ b/hosts_python_troveclient_ext.py @@ -0,0 +1,105 @@ +# Copyright 2011 OpenStack Foundation +# Copyright 2013 Rackspace Hosting +# All Rights Reserved. +# +# 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. + +from troveclient import base +from troveclient import common +from troveclient import utils + + +class Host(base.Resource): + """ + A Hosts is an opaque instance used to store Host instances. + """ + def __repr__(self): + return "" % self.name + + +class Hosts(base.ManagerWithFind): + """ + Manage :class:`Host` resources. + """ + resource_class = Host + + def _list(self, url, response_key): + resp, body = self.api.client.get(url) + if not body: + raise Exception("Call to " + url + " did not return a body.") + return [self.resource_class(self, res) for res in body[response_key]] + + def _action(self, host_id, body): + """ + Perform a host "action" -- update + """ + url = "/mgmt/hosts/%s/instances/action" % host_id + resp, body = self.api.client.post(url, body=body) + common.check_for_exceptions(resp, body) + + def update_all(self, host_id): + """ + Update all instances on a host. + """ + body = {'update': ''} + self._action(host_id, body) + + def index(self): + """ + List all hosts + + :rtype: list of :class:`Hosts`. + """ + return self._list("/mgmt/hosts", "hosts") + + def get(self, host): + """ + Show details of a host + + :rtype: :class:`host` + """ + return self._get("/mgmt/hosts/%s" % self._get_host_name(host), "host") + + @staticmethod + def _get_host_name(host): + try: + if host.name: + return host.name + except AttributeError: + return host + + # Appease the abc gods + def list(self): + pass + + +@utils.service_type('database') +def do_mgmt_host_list(cs, args): + """List all hosts""" + hosts = cs.hosts.index() + utils.print_list(hosts) + + +@utils.arg('host', metavar='', help='Name of the host.') +@utils.service_type('database') +def do_mgmt_host_show(cs, args): + """Show details of a host""" + host = cs.hosts_python_troveclient_ext.get(args.host) + utils.print_dict(host) + + +@utils.arg('host', metavar='', help='ID of the host.') +@utils.service_type('database') +def do_mgmt_host_update_all(cs, args): + """Update all instances on a host""" + result = cs.hosts_python_troveclient_ext.update_all(args.host) diff --git a/hwinfo_python_troveclient_ext.py b/hwinfo_python_troveclient_ext.py new file mode 100644 index 0000000..e415695 --- /dev/null +++ b/hwinfo_python_troveclient_ext.py @@ -0,0 +1,49 @@ +# Copyright 2011 OpenStack Foundation +# Copyright 2013 Rackspace Hosting +# All Rights Reserved. +# +# 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. + +from troveclient import base +from troveclient import utils + + +class HwInfo(base.Resource): + + def __repr__(self): + return "" % self.version + + +class HwInfoInterrogator(base.ManagerWithFind): + """ + Manager class for HwInfo + """ + resource_class = HwInfo + + def get(self, instance): + """ + Get the hardware information of an instance. + """ + return self._get("/mgmt/instances/%s/hwinfo" % base.getid(instance)) + + # Appease the abc gods + def list(self): + pass + + +@utils.arg('instance', metavar='', help='ID of the instance.') +@utils.service_type('database') +def do_mgmt_hwinfo_show(cs, args): + """Get the hardware information of an instance""" + hosts = cs.hwinfo_python_troveclient_ext.get(args.instance) + utils.print_dict(hosts) diff --git a/management_flavor_python_troveclient_ext.py b/management_flavor_python_troveclient_ext.py new file mode 100644 index 0000000..21782ba --- /dev/null +++ b/management_flavor_python_troveclient_ext.py @@ -0,0 +1,85 @@ +# Copyright 2011 OpenStack Foundation +# Copyright 2013 Rackspace Hosting +# All Rights Reserved. +# +# 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. + +from troveclient import base +from troveclient import utils +from troveclient.v1 import flavors + + +class MgmtFlavor(base.ManagerWithFind): + """ + Manage :class:`Flavor` resources. + """ + resource_class = flavors.Flavor + + def __repr__(self): + return "" % id(self) + + # Appease the abc gods + def list(self): + pass + + def create(self, name, ram, disk, vcpus, + flavorid="auto", ephemeral=None, swap=None, rxtx_factor=None, + service_type=None): + """ + Create a new flavor. + """ + body = {"flavor": { + "flavor_id": flavorid, + "name": name, + "ram": ram, + "disk": disk, + "vcpu": vcpus, + "ephemeral": 0, + "swap": 0, + "rxtx_factor": "1.0", + "is_public": "True" + }} + if ephemeral: + body["flavor"]["ephemeral"] = ephemeral + if swap: + body["flavor"]["swap"] = swap + if rxtx_factor: + body["flavor"]["rxtx_factor"] = rxtx_factor + if service_type: + body["flavor"]["service_type"] = service_type + + return self._create("/mgmt/flavors", body, "flavor") + + +@utils.arg('name', metavar='', help='Name of the new flavor') +@utils.arg('ram', metavar='', help='Memory size in MB') +@utils.arg('disk', metavar='', help='Disk size in GB') +@utils.arg('vcpus', metavar='', help='Number of vcpus') +@utils.arg('--flavorid', metavar='', default="auto", + help='Unique ID (integer or UUID) for the new flavor.') +@utils.arg('--ephemeral', metavar='', default=None, + help='Ephemeral space size in GB (default 0)') +@utils.arg('--swap', metavar='', default=None, + help='Swap space size in MB (default 0)') +@utils.arg('--rxtx_factor', metavar='', default=None, + help='RX/TX factor (default 1)') +@utils.arg('--service_type', metavar='', default=None, + help='The service type') +@utils.service_type('database') +def do_mgmt_flavor_create(cs, args): + """Create a new flavor""" + ext = cs.management_flavor_python_troveclient_ext + flavor = ext.create(args.name, args.ram, args.disk, args.vcpus, + args.flavorid, args.ephemeral, args.swap, + args.rxtx_factor, args.service_type) + utils.print_dict(flavor) diff --git a/management_python_troveclient_ext.py b/management_python_troveclient_ext.py new file mode 100644 index 0000000..012861a --- /dev/null +++ b/management_python_troveclient_ext.py @@ -0,0 +1,222 @@ +# Copyright 2011 OpenStack Foundation +# Copyright 2013 Rackspace Hosting +# All Rights Reserved. +# +# 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. + +from troveclient import base +from troveclient import common +from troveclient import utils +from troveclient.v1 import instances + + +class RootHistory(base.Resource): + def __repr__(self): + return ("" + % (self.id, self.created, self.user)) + + +class Management(base.ManagerWithFind): + """ + Manage :class:`Instances` resources. + """ + resource_class = instances.Instance + + # Appease the abc gods + def list(self): + pass + + def show(self, instance): + """ + Get details of one instance. + + :rtype: :class:`Instance`. + """ + + return self._get("/mgmt/instances/%s" % base.getid(instance), + 'instance') + + def index(self, deleted=None, limit=None, marker=None): + """ + Show an overview of all local instances. + Optionally, filter by deleted status. + + :rtype: list of :class:`Instance`. + """ + form = '' + if deleted is not None: + if deleted in ('true', 'True', '1'): + form = "?deleted=true" + else: + form = "?deleted=false" + + url = "/mgmt/instances%s" % form + return self._paginated(url, "instances", limit, marker) + + def root_enabled_history(self, instance): + """ + Get root access history of one instance. + + """ + url = "/mgmt/instances/%s/root" % base.getid(instance) + resp, body = self.api.client.get(url) + if not body: + raise Exception("Call to " + url + " did not return a body.") + return body['root_history'] + + def _action(self, instance_id, body): + """ + Perform a server "action" -- reboot/rebuild/resize/etc. + """ + url = "/mgmt/instances/%s/action" % instance_id + resp, body = self.api.client.post(url, body=body) + common.check_for_exceptions(resp, body) + if body: + return self.resource_class(self, body, loaded=True) + return body + + def stop(self, instance_id): + """ + Stop the database on an instance + """ + body = {'stop': {}} + self._action(instance_id, body) + + def reboot(self, instance_id): + """ + Reboot the underlying OS. + + :param instance_id: The :class:`Instance` (or its ID) to share onto. + """ + body = {'reboot': {}} + self._action(instance_id, body) + + def migrate(self, instance_id, host=None): + """ + Migrate the instance. + + :param instance_id: The :class:`Instance` (or its ID) to share onto. + """ + if host: + body = {'migrate': {'host': host}} + else: + body = {'migrate': {}} + self._action(instance_id, body) + + def update(self, instance_id): + """ + Update the guest agent via apt-get. + """ + body = {'update': {}} + self._action(instance_id, body) + + def reset_task_status(self, instance_id): + """ + Set the task status to NONE. + """ + body = {'reset-task-status': {}} + self._action(instance_id, body) + + +def _print_instance(instance): + if instance._info.get('links'): + del(instance._info['links']) + utils.print_dict(instance._info) + + +@utils.arg('instance', metavar='', help='ID of the instance.') +@utils.service_type('database') +def do_mgmt_show(cs, args): + """Show details of an instance""" + instance = cs.management.show(args.instance) + instance._info['flavor'] = instance.flavor['id'] + if hasattr(instance, 'volume'): + instance._info['volume'] = instance.volume['size'] + if 'id' in instance.volume: + instance._info['volume_id'] = instance.volume['id'] + if 'used' in instance.volume: + instance._info['volume_used'] = instance.volume['used'] + if 'status' in instance.volume: + instance._info['volume_status'] = instance.volume['status'] + + if hasattr(instance, 'ip'): + instance._info['ip'] = ', '.join(instance.ip) + if hasattr(instance, 'datastore'): + instance._info['datastore'] = instance.datastore['type'] + instance._info['datastore_version'] = instance.datastore['version'] + if hasattr(instance, 'guest_status'): + description = instance.guest_status['state_description'] + instance._info['guest_status'] = description + _print_instance(instance) + + +@utils.arg('--deleted', metavar='', default=None, + help='Optional. Filter instances on deleted.') +@utils.service_type('database') +def do_mgmt_list(cs, args): + """List all instances""" + instances = cs.management.index(deleted=args.deleted) + for instance in instances: + setattr(instance, 'flavor_id', instance.flavor['id']) + if hasattr(instance, 'volume'): + setattr(instance, 'size', instance.volume['size']) + if hasattr(instance, 'datastore'): + setattr(instance, 'datastore_version', + instance.datastore['version']) + setattr(instance, 'datastore', instance.datastore['type']) + utils.print_list(instances, + ['id', 'name', 'tenant_id', 'flavor_id', 'size', + 'datastore', 'datastore_version', 'status', 'created', + 'deleted_at']) + + +@utils.arg('instance', metavar='', help='ID of the instance.') +@utils.service_type('database') +def do_mgmt_root_history(cs, args): + """Get the root enabled history of an instance""" + ext = cs.management_python_troveclient_ext + history = ext.root_enabled_history(args.instance) + utils.print_dict(history) + + +@utils.arg('instance', metavar='', help='ID of the instance.') +def do_mgmt_stop(cs, args): + """Stop the database on an instance""" + cs.management_python_troveclient_ext.stop(args.instance) + + +@utils.arg('instance', metavar='', help='ID of the instance.') +def do_mgmt_reboot(cs, args): + """Soft reboot an instance""" + cs.management_python_troveclient_ext.reboot(args.instance) + + +@utils.arg('instance', metavar='', help='ID of the instance.') +@utils.arg('--host', metavar='', default=None, + help='Optional. Name of the host.') +def do_mgmt_migrate(cs, args): + """Migrate an instance""" + ext = cs.management_python_troveclient_ext + ext.migrate(args.instance, host=args.host) + + +@utils.arg('instance', metavar='', help='ID of the instance.') +def do_mgmt_update(cs, args): + """Update an instance""" + cs.management_python_troveclient_ext.update(args.instance) + + +@utils.arg('instance', metavar='', help='ID of the instance.') +def do_mgmt_reset_task_status(cs, args): + """Update the task status to None for an instance""" + cs.management_python_troveclient_ext.reset_task_status(args.instance) diff --git a/quota_python_troveclient_ext.py b/quota_python_troveclient_ext.py new file mode 100644 index 0000000..f89d259 --- /dev/null +++ b/quota_python_troveclient_ext.py @@ -0,0 +1,73 @@ +# Copyright 2011 OpenStack Foundation +# Copyright 2013 Rackspace Hosting +# Copyright 2013 Hewlett-Packard Development Company, L.P. +# All Rights Reserved. +# +# 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. + +import json +from troveclient import base +from troveclient import common +from troveclient import utils + + +class Quotas(base.ManagerWithFind): + """ + Manage :class:`Quota` information. + """ + + resource_class = base.Resource + + def show(self, tenant_id): + """Get a list of quota limits for a tenant""" + url = "/mgmt/quotas/%s" % tenant_id + resp, body = self.api.client.get(url) + common.check_for_exceptions(resp, body) + if not body: + raise Exception("Call to " + url + " did not return a body.") + if 'quotas' not in body: + raise Exception("Missing key value 'quotas' in response body.") + return body['quotas'] + + def update(self, id, quotas): + """Update the quota limits for a tenant""" + url = "/mgmt/quotas/%s" % id + body = {"quotas": json.loads(quotas)} + resp, body = self.api.client.put(url, body=body) + common.check_for_exceptions(resp, body) + if not body: + raise Exception("Call to " + url + " did not return a body.") + if 'quotas' not in body: + raise Exception("Missing key value 'quotas' in response body.") + return body['quotas'] + + # Appease the abc gods + def list(self): + pass + + +@utils.arg('tenant', metavar='', help='ID of the tenant.') +@utils.service_type('database') +def do_mgmt_quota_show(cs, args): + """Get a list of quota limits for a tenant""" + hosts = cs.quota_python_troveclient_ext.show(args.tenant) + utils.print_dict(hosts) + + +@utils.arg('tenant', metavar='', help='ID of the tenant.') +@utils.arg('quotas', metavar='', help='Dict of quotas.') +@utils.service_type('database') +def do_mgmt_quota_update(cs, args): + """Update quota limits for a tenant""" + quotas = cs.quota_python_troveclient_ext.update(args.tenant, args.quotas) + utils.print_dict(quotas) diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..f8e03a4 --- /dev/null +++ b/setup.py @@ -0,0 +1,33 @@ +# Copyright 2014 eBay Software Foundation +# +# 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. + +import setuptools + + +setuptools.setup( + name="mgmt_python_troveclient_ext", + version="0.0.1", + author="eBay Software Foundation", + author_email="amcreynolds@ebaysf.com", + description="Management extension for python-troveclient", + license="Apache License, Version 2.0", + classifiers=[ + "Development Status :: 4 - Beta", + "Intended Audience :: Developers", + "Intended Audience :: Information Technology", + "License :: OSI Approved :: Apache Software License", + "Operating System :: OS Independent", + "Programming Language :: Python", + ] +) diff --git a/storage_python_troveclient_ext.py b/storage_python_troveclient_ext.py new file mode 100644 index 0000000..3c08760 --- /dev/null +++ b/storage_python_troveclient_ext.py @@ -0,0 +1,58 @@ +# Copyright 2011 OpenStack Foundation +# Copyright 2013 Rackspace Hosting +# All Rights Reserved. +# +# 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. + +from troveclient import base +from troveclient import utils + + +class Device(base.Resource): + """ + Storage is an opaque instance used to hold storage information. + """ + def __repr__(self): + return "" % self.name + + +class StorageInfo(base.ManagerWithFind): + """ + Manage :class:`Storage` resources. + """ + resource_class = Device + + def _list(self, url, response_key): + resp, body = self.api.client.get(url) + if not body: + raise Exception("Call to " + url + " did not return a body.") + return [self.resource_class(self, res) for res in body[response_key]] + + def index(self): + """ + List all storage devices + + :rtype: list of :class:`Storages`. + """ + return self._list("/mgmt/storage", "devices") + + # Appease the abc gods + def list(self): + pass + + +@utils.service_type('database') +def do_mgmt_storage_list(cs, args): + """List all storage devices""" + storage_list = cs.storage_python_troveclient_ext.index() + utils.print_list(storage_list)