Retire shade
Change-Id: I6742309f6454417485742d53fd24dc1b66a7538b Signed-off-by: Stephen Finucane <stephenfin@redhat.com> Depends-on: https://review.opendev.org/c/openstack/project-config/+/961522
This commit is contained in:
1 parent
b9dc7d04cc
commit
dbf80ad2d8
341 files changed
+7
-51514
No files matched your search
@@ -1,7 +0,0 @@
|
||||
[run]
|
||||
branch = True
|
||||
source = shade
|
||||
omit = shade/tests/*
|
||||
|
||||
[report]
|
||||
ignore_errors = True
|
||||
-54
@@ -1,54 +0,0 @@
|
||||
*.py[cod]
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Packages
|
||||
.eggs
|
||||
*.egg
|
||||
*.egg-info
|
||||
dist
|
||||
build
|
||||
eggs
|
||||
parts
|
||||
bin
|
||||
var
|
||||
sdist
|
||||
develop-eggs
|
||||
.installed.cfg
|
||||
lib
|
||||
lib64
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
.coverage
|
||||
cover
|
||||
.tox
|
||||
nosetests.xml
|
||||
.testrepository
|
||||
.stestr
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
|
||||
# Mr Developer
|
||||
.mr.developer.cfg
|
||||
.project
|
||||
.pydevproject
|
||||
|
||||
# Complexity
|
||||
output/*.html
|
||||
output/*/index.html
|
||||
|
||||
# Sphinx
|
||||
doc/build
|
||||
|
||||
# pbr generates these
|
||||
AUTHORS
|
||||
ChangeLog
|
||||
|
||||
# Editors
|
||||
*~
|
||||
.*.swp
|
||||
@@ -1,3 +0,0 @@
|
||||
[DEFAULT]
|
||||
test_path=./shade/tests/unit
|
||||
top_dir=./
|
||||
-210
@@ -1,210 +0,0 @@
|
||||
- job:
|
||||
name: shade-tox-py38-tips
|
||||
parent: openstack-tox-py38
|
||||
description: |
|
||||
Run tox python 38 unittests against master of important libs
|
||||
vars:
|
||||
tox_install_siblings: true
|
||||
zuul_work_dir: src/opendev.org/openstack/shade
|
||||
# shade in required-projects so that os-client-config and keystoneauth
|
||||
# can add the job as well
|
||||
required-projects:
|
||||
- openstack/shade
|
||||
- openstack/keystoneauth
|
||||
- openstack/openstacksdk
|
||||
- openstack/os-client-config
|
||||
|
||||
- project-template:
|
||||
name: shade-tox-tips
|
||||
check:
|
||||
jobs:
|
||||
- shade-tox-py38-tips
|
||||
gate:
|
||||
jobs:
|
||||
- shade-tox-py38-tips
|
||||
|
||||
- job:
|
||||
name: shade-functional-devstack-base
|
||||
parent: devstack-tox-functional-consumer
|
||||
description: |
|
||||
Base job for shade devstack-based functional tests
|
||||
post-run: playbooks/devstack/post.yaml
|
||||
required-projects:
|
||||
# These jobs will DTRT when shade triggers them, but we want to make
|
||||
# sure stable branches of shade never get cloned by other people,
|
||||
# since stable branches of shade are, well, not actually things.
|
||||
- name: openstack/shade
|
||||
override-checkout: master
|
||||
- name: openstack/heat
|
||||
- name: openstack/swift
|
||||
timeout: 9000
|
||||
vars:
|
||||
devstack_local_conf:
|
||||
post-config:
|
||||
$CINDER_CONF:
|
||||
DEFAULT:
|
||||
osapi_max_limit: 6
|
||||
devstack_services:
|
||||
ceilometer-acentral: false
|
||||
ceilometer-acompute: false
|
||||
ceilometer-alarm-evaluator: false
|
||||
ceilometer-alarm-notifier: false
|
||||
ceilometer-anotification: false
|
||||
ceilometer-api: false
|
||||
ceilometer-collector: false
|
||||
s-account: true
|
||||
s-container: true
|
||||
s-object: true
|
||||
s-proxy: true
|
||||
devstack_plugins:
|
||||
heat: https://opendev.org/openstack/heat
|
||||
tox_environment:
|
||||
# Do we really need to set this? It's cargo culted
|
||||
PYTHONUNBUFFERED: 'true'
|
||||
# Is there a way we can query the localconf variable to get these
|
||||
# rather than setting them explicitly?
|
||||
SHADE_HAS_DESIGNATE: 0
|
||||
SHADE_HAS_HEAT: 1
|
||||
SHADE_HAS_MAGNUM: 0
|
||||
SHADE_HAS_NEUTRON: 1
|
||||
SHADE_HAS_SWIFT: 1
|
||||
tox_install_siblings: false
|
||||
tox_envlist: functional
|
||||
zuul_work_dir: src/opendev.org/openstack/shade
|
||||
|
||||
- job:
|
||||
name: shade-functional-devstack-legacy
|
||||
parent: shade-functional-devstack-base
|
||||
description: |
|
||||
Run shade functional tests against a legacy devstack
|
||||
# TODO(mordred): This does not seem to work
|
||||
voting: false
|
||||
vars:
|
||||
devstack_localrc:
|
||||
ENABLE_IDENTITY_V2: true
|
||||
FLAT_INTERFACE: br_flat
|
||||
PUBLIC_INTERFACE: br_pub
|
||||
tox_environment:
|
||||
SHADE_USE_KEYSTONE_V2: 1
|
||||
SHADE_HAS_NEUTRON: 0
|
||||
override-checkout: stable/newton
|
||||
|
||||
- job:
|
||||
name: shade-functional-devstack
|
||||
parent: shade-functional-devstack-base
|
||||
description: |
|
||||
Run shade functional tests against a master devstack
|
||||
vars:
|
||||
devstack_localrc:
|
||||
Q_SERVICE_PLUGIN_CLASSES: qos
|
||||
Q_ML2_PLUGIN_EXT_DRIVERS: qos,port_security
|
||||
tox_environment:
|
||||
SHADE_TOX_PYTHON: python3
|
||||
|
||||
- job:
|
||||
name: shade-functional-devstack-python3
|
||||
parent: shade-functional-devstack
|
||||
description: |
|
||||
Run shade functional tests using python3 against a master devstack
|
||||
|
||||
- job:
|
||||
name: shade-functional-devstack-tips-python3
|
||||
parent: shade-functional-devstack
|
||||
description: |
|
||||
Run shade functional tests with tips of library dependencies using
|
||||
python3 against a master devstack.
|
||||
required-projects:
|
||||
- name: openstack/keystoneauth
|
||||
- name: openstack/openstacksdk
|
||||
- name: openstack/os-client-config
|
||||
vars:
|
||||
tox_install_siblings: true
|
||||
tox_environment:
|
||||
SHADE_TOX_PYTHON: python3
|
||||
|
||||
- job:
|
||||
name: shade-functional-devstack-magnum
|
||||
parent: shade-functional-devstack
|
||||
description: |
|
||||
Run shade functional tests against a master devstack with magnum
|
||||
required-projects:
|
||||
- openstack/magnum
|
||||
- openstack/python-magnumclient
|
||||
vars:
|
||||
devstack_plugins:
|
||||
magnum: https://opendev.org/openstack/magnum
|
||||
devstack_localrc:
|
||||
MAGNUM_GUEST_IMAGE_URL: https://tarballs.openstack.org/magnum/images/fedora-atomic-f23-dib.qcow2
|
||||
MAGNUM_IMAGE_NAME: fedora-atomic-f23-dib
|
||||
devstack_services:
|
||||
s-account: false
|
||||
s-container: false
|
||||
s-object: false
|
||||
s-proxy: false
|
||||
tox_environment:
|
||||
SHADE_HAS_SWIFT: 0
|
||||
SHADE_HAS_MAGNUM: 1
|
||||
voting: false
|
||||
|
||||
- job:
|
||||
name: shade-ansible-functional-devstack
|
||||
parent: shade-functional-devstack
|
||||
description: |
|
||||
Run shade ansible functional tests against a master devstack
|
||||
using released version of ansible.
|
||||
vars:
|
||||
tox_envlist: ansible
|
||||
|
||||
- job:
|
||||
name: shade-ansible-stable-2.5-functional-devstack
|
||||
parent: shade-ansible-functional-devstack
|
||||
description: |
|
||||
Run shade ansible functional tests against a master devstack
|
||||
using git devel branch version of ansible.
|
||||
branches: ^(devel|master)$
|
||||
required-projects:
|
||||
- name: github.com/ansible/ansible
|
||||
override-checkout: stable-2.5
|
||||
- name: openstack/shade
|
||||
override-checkout: master
|
||||
- name: openstack/devstack
|
||||
override-checkout: master
|
||||
vars:
|
||||
# test-matrix grabs branch from the zuul branch setting. If the job
|
||||
# is triggered by ansible, that branch will be stable-2.5 which doesn't
|
||||
# make sense to devstack. Override so that we run the right thing.
|
||||
test_matrix_branch: master
|
||||
tox_install_siblings: true
|
||||
|
||||
- project-template:
|
||||
name: shade-functional-tips
|
||||
check:
|
||||
jobs:
|
||||
- shade-functional-devstack-tips-python3
|
||||
gate:
|
||||
jobs:
|
||||
- shade-functional-devstack-tips-python3
|
||||
|
||||
- project:
|
||||
templates:
|
||||
- check-requirements
|
||||
- openstack-lower-constraints-jobs
|
||||
- openstack-python-jobs
|
||||
- openstack-python3-victoria-jobs
|
||||
- publish-openstack-docs-pti
|
||||
- release-notes-jobs-python3
|
||||
- shade-functional-tips
|
||||
- shade-tox-tips
|
||||
check:
|
||||
jobs:
|
||||
- bifrost-integration-tinyipa:
|
||||
voting: false
|
||||
- shade-ansible-stable-2.5-functional-devstack:
|
||||
voting: false
|
||||
- shade-ansible-functional-devstack
|
||||
- shade-functional-devstack-magnum
|
||||
- shade-functional-devstack-python3
|
||||
gate:
|
||||
jobs:
|
||||
- shade-ansible-functional-devstack
|
||||
- shade-functional-devstack-python3
|
||||
@@ -1,43 +0,0 @@
|
||||
.. _contributing:
|
||||
|
||||
=====================
|
||||
Contributing to shade
|
||||
=====================
|
||||
|
||||
If you're interested in contributing to the shade project,
|
||||
the following will help get you started.
|
||||
|
||||
Contributor License Agreement
|
||||
-----------------------------
|
||||
|
||||
.. index::
|
||||
single: license; agreement
|
||||
|
||||
In order to contribute to the shade project, you need to have
|
||||
signed OpenStack's contributor's agreement.
|
||||
|
||||
.. seealso::
|
||||
|
||||
* https://wiki.openstack.org/wiki/How_To_Contribute
|
||||
|
||||
Project Hosting Details
|
||||
-------------------------
|
||||
|
||||
Project Documentation
|
||||
https://docs.openstack.org/shade/latest/
|
||||
|
||||
Bug tracker
|
||||
https://storyboard.openstack.org/#!/project/openstack/shade
|
||||
|
||||
Mailing list (prefix subjects with ``[shade]`` for faster responses)
|
||||
http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-discuss
|
||||
|
||||
Code Hosting
|
||||
https://opendev.org/openstack/shade
|
||||
|
||||
Code Review
|
||||
https://review.opendev.org/#/q/status:open+project:openstack/shade,n,z
|
||||
|
||||
Please read `GerritWorkflow`_ before sending your first patch for review.
|
||||
|
||||
.. _GerritWorkflow: https://wiki.openstack.org/wiki/GerritWorkflow
|
||||
-49
@@ -1,49 +0,0 @@
|
||||
shade Style Commandments
|
||||
========================
|
||||
|
||||
Read the OpenStack Style Commandments
|
||||
https://docs.openstack.org/hacking/latest/
|
||||
|
||||
Indentation
|
||||
-----------
|
||||
|
||||
PEP-8 allows for 'visual' indentation. Do not use it. Visual indentation looks
|
||||
like this:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
return_value = self.some_method(arg1, arg1,
|
||||
arg3, arg4)
|
||||
|
||||
Visual indentation makes refactoring the code base unneccesarily hard.
|
||||
|
||||
Instead of visual indentation, use this:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
return_value = self.some_method(
|
||||
arg1, arg1, arg3, arg4)
|
||||
|
||||
That way, if some_method ever needs to be renamed, the only line that needs
|
||||
to be touched is the line with some_method. Additionaly, if you need to
|
||||
line break at the top of a block, please indent the continuation line
|
||||
an additional 4 spaces, like this:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
for val in self.some_method(
|
||||
arg1, arg1, arg3, arg4):
|
||||
self.do_something_awesome()
|
||||
|
||||
Neither of these are 'mandated' by PEP-8. However, they are prevailing styles
|
||||
within this code base.
|
||||
|
||||
Unit Tests
|
||||
----------
|
||||
|
||||
Unit tests should be virtually instant. If a unit test takes more than 1 second
|
||||
to run, it is a bad unit test. Honestly, 1 second is too slow.
|
||||
|
||||
All unit test classes should subclass `shade.tests.unit.base.BaseTestCase`. The
|
||||
base TestCase class takes care of properly creating `OpenStackCloud` objects
|
||||
in a way that protects against local environment.
|
||||
@@ -1,175 +0,0 @@
|
||||
|
||||
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.
|
||||
@@ -1,6 +0,0 @@
|
||||
include AUTHORS
|
||||
include ChangeLog
|
||||
exclude .gitignore
|
||||
exclude .gitreview
|
||||
|
||||
global-exclude *.pyc
|
||||
+7
-92
@@ -1,92 +1,7 @@
|
||||
Introduction
|
||||
============
|
||||
|
||||
.. warning::
|
||||
|
||||
shade has been superceded by `openstacksdk`_ and no longer takes new
|
||||
features. The existing code will continue to be maintained indefinitely
|
||||
for bugfixes as necessary, but improvements will be deferred to
|
||||
`openstacksdk`_. Please update your applications to use `openstacksdk`_
|
||||
directly.
|
||||
|
||||
shade is a simple client library for interacting with OpenStack clouds. The
|
||||
key word here is *simple*. Clouds can do many many many things - but there are
|
||||
probably only about 10 of them that most people care about with any
|
||||
regularity. If you want to do complicated things, you should probably use
|
||||
the lower level client libraries - or even the REST API directly. However,
|
||||
if what you want is to be able to write an application that talks to clouds
|
||||
no matter what crazy choices the deployer has made in an attempt to be
|
||||
more hipster than their self-entitled narcissist peers, then shade is for you.
|
||||
|
||||
shade started its life as some code inside of ansible. ansible has a bunch
|
||||
of different OpenStack related modules, and there was a ton of duplicated
|
||||
code. Eventually, between refactoring that duplication into an internal
|
||||
library, and adding logic and features that the OpenStack Infra team had
|
||||
developed to run client applications at scale, it turned out that we'd written
|
||||
nine-tenths of what we'd need to have a standalone library.
|
||||
|
||||
.. _usage_example:
|
||||
|
||||
Example
|
||||
=======
|
||||
|
||||
Sometimes an example is nice.
|
||||
|
||||
#. Create a ``clouds.yml`` file::
|
||||
|
||||
clouds:
|
||||
mordred:
|
||||
region_name: RegionOne
|
||||
auth:
|
||||
username: 'mordred'
|
||||
password: XXXXXXX
|
||||
project_name: 'shade'
|
||||
auth_url: 'https://montytaylor-sjc.openstack.blueboxgrid.com:5001/v2.0'
|
||||
|
||||
Please note: *os-client-config* will look for a file called ``clouds.yaml``
|
||||
in the following locations:
|
||||
|
||||
* Current Directory
|
||||
* ``~/.config/openstack``
|
||||
* ``/etc/openstack``
|
||||
|
||||
More information at https://pypi.org/project/os-client-config
|
||||
|
||||
|
||||
#. Create a server with *shade*, configured with the ``clouds.yml`` file::
|
||||
|
||||
import shade
|
||||
|
||||
# Initialize and turn on debug logging
|
||||
shade.simple_logging(debug=True)
|
||||
|
||||
# Initialize cloud
|
||||
# Cloud configs are read with os-client-config
|
||||
cloud = shade.openstack_cloud(cloud='mordred')
|
||||
|
||||
# Upload an image to the cloud
|
||||
image = cloud.create_image(
|
||||
'ubuntu-trusty', filename='ubuntu-trusty.qcow2', wait=True)
|
||||
|
||||
# Find a flavor with at least 512M of RAM
|
||||
flavor = cloud.get_flavor_by_ram(512)
|
||||
|
||||
# Boot a server, wait for it to boot, and then do whatever is needed
|
||||
# to get a public ip for it.
|
||||
cloud.create_server(
|
||||
'my-server', image=image, flavor=flavor, wait=True, auto_ip=True)
|
||||
|
||||
|
||||
Links
|
||||
=====
|
||||
|
||||
* `Issue Tracker <https://storyboard.openstack.org/#!/project/760>`_
|
||||
* `Code Review <https://review.openstack.org/#/q/status:open+project:openstack/shade,n,z>`_
|
||||
* `Documentation <https://docs.openstack.org/shade/latest/>`_
|
||||
* `Source <https://opendev.org/openstack/shade>`_
|
||||
* `PyPI <https://pypi.org/project/shade/>`_
|
||||
* `Mailing list <http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack>`_
|
||||
* `Release notes <https://docs.openstack.org/releasenotes/shade>`_
|
||||
* `Contributing <https://docs.openstack.org/shade/latest/contributor/index.html>`_
|
||||
|
||||
.. _openstacksdk: https://docs.openstack.org/openstacksdk/latest/user/
|
||||
This project is no longer maintained.
|
||||
The contents of this repository are still available in the Git
|
||||
source code management system. To see the contents of this
|
||||
repository before it reached its end of life, please check out the
|
||||
previous commit with "git checkout HEAD^1".
|
||||
For any further questions, please email
|
||||
openstack-discuss@lists.openstack.org.
|
||||
@@ -1,8 +0,0 @@
|
||||
# This is a cross-platform list tracking distribution packages needed by tests;
|
||||
# see http://docs.openstack.org/infra/bindep/ for additional information.
|
||||
|
||||
build-essential [platform:dpkg]
|
||||
python-dev [platform:dpkg]
|
||||
python-devel [platform:rpm]
|
||||
libffi-dev [platform:dpkg]
|
||||
libffi-devel [platform:rpm]
|
||||
@@ -1,54 +0,0 @@
|
||||
# Install and configure **shade** library in devstack
|
||||
#
|
||||
# To enable shade in devstack add an entry to local.conf that looks like
|
||||
#
|
||||
# [[local|localrc]]
|
||||
# enable_plugin shade https://opendev.org/openstack/shade
|
||||
|
||||
function preinstall_shade {
|
||||
:
|
||||
}
|
||||
|
||||
function install_shade {
|
||||
if use_library_from_git "shade"; then
|
||||
# don't clone, it'll be done by the plugin install
|
||||
setup_dev_lib "shade"
|
||||
else
|
||||
pip_install "shade"
|
||||
fi
|
||||
}
|
||||
|
||||
function configure_shade {
|
||||
:
|
||||
}
|
||||
|
||||
function initialize_shade {
|
||||
:
|
||||
}
|
||||
|
||||
function unstack_shade {
|
||||
:
|
||||
}
|
||||
|
||||
function clean_shade {
|
||||
:
|
||||
}
|
||||
|
||||
# This is the main for plugin.sh
|
||||
if [[ "$1" == "stack" && "$2" == "pre-install" ]]; then
|
||||
preinstall_shade
|
||||
elif [[ "$1" == "stack" && "$2" == "install" ]]; then
|
||||
install_shade
|
||||
elif [[ "$1" == "stack" && "$2" == "post-config" ]]; then
|
||||
configure_shade
|
||||
elif [[ "$1" == "stack" && "$2" == "extra" ]]; then
|
||||
initialize_shade
|
||||
fi
|
||||
|
||||
if [[ "$1" == "unstack" ]]; then
|
||||
unstack_shade
|
||||
fi
|
||||
|
||||
if [[ "$1" == "clean" ]]; then
|
||||
clean_shade
|
||||
fi
|
||||
@@ -1,6 +0,0 @@
|
||||
# The order of packages is significant, because pip processes them in the order
|
||||
# of appearance. Changing the order has an impact on the overall integration
|
||||
# process, which may cause wedges in the gate later.
|
||||
sphinx>=2.0.0,!=2.1.0 # BSD
|
||||
openstackdocstheme>=2.2.1 # Apache-2.0
|
||||
reno>=3.1.0 # Apache-2.0
|
||||
@@ -1,46 +0,0 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.insert(0, os.path.abspath('../..'))
|
||||
|
||||
extensions = [
|
||||
'sphinx.ext.autodoc',
|
||||
'openstackdocstheme',
|
||||
'reno.sphinxext'
|
||||
]
|
||||
|
||||
# openstackdocstheme options
|
||||
openstackdocs_repo_name = 'openstack/shade'
|
||||
openstackdocs_auto_name = False
|
||||
openstackdocs_use_storyboard = True
|
||||
html_theme = 'openstackdocs'
|
||||
|
||||
# The suffix of source filenames.
|
||||
source_suffix = '.rst'
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = u'shade'
|
||||
copyright = u'2014 Hewlett-Packard Development Company, L.P.'
|
||||
|
||||
# If true, '()' will be appended to :func: etc. cross-reference text.
|
||||
add_function_parentheses = True
|
||||
|
||||
# If true, the current module name will be prepended to all description
|
||||
# unit titles (such as .. function::).
|
||||
add_module_names = True
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = '%sdoc' % project
|
||||
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title, author, documentclass
|
||||
# [howto/manual]).
|
||||
latex_documents = [
|
||||
('index',
|
||||
'%s.tex' % project,
|
||||
u'%s Documentation' % project,
|
||||
u'Monty Taylor', 'manual'),
|
||||
]
|
||||
@@ -1,116 +0,0 @@
|
||||
********************************
|
||||
Shade Developer Coding Standards
|
||||
********************************
|
||||
|
||||
In the beginning, there were no guidelines. And it was good. But that
|
||||
didn't last long. As more and more people added more and more code,
|
||||
we realized that we needed a set of coding standards to make sure that
|
||||
the shade API at least *attempted* to display some form of consistency.
|
||||
|
||||
Thus, these coding standards/guidelines were developed. Note that not
|
||||
all of shade adheres to these standards just yet. Some older code has
|
||||
not been updated because we need to maintain backward compatibility.
|
||||
Some of it just hasn't been changed yet. But be clear, all new code
|
||||
*must* adhere to these guidelines.
|
||||
|
||||
Below are the patterns that we expect Shade developers to follow.
|
||||
|
||||
Release Notes
|
||||
=============
|
||||
|
||||
Shade uses `reno <https://docs.openstack.org/reno/latest/>`_ for
|
||||
managing its release notes. A new release note should be added to
|
||||
your contribution anytime you add new API calls, fix significant bugs,
|
||||
add new functionality or parameters to existing API calls, or make any
|
||||
other significant changes to the code base that we should draw attention
|
||||
to for the user base.
|
||||
|
||||
It is *not* necessary to add release notes for minor fixes, such as
|
||||
correction of documentation typos, minor code cleanup or reorganization,
|
||||
or any other change that a user would not notice through normal usage.
|
||||
|
||||
API Methods
|
||||
===========
|
||||
|
||||
- When an API call acts on a resource that has both a unique ID and a
|
||||
name, that API call should accept either identifier with a name_or_id
|
||||
parameter.
|
||||
|
||||
- All resources should adhere to the get/list/search interface that
|
||||
control retrieval of those resources. E.g., `get_image()`, `list_images()`,
|
||||
`search_images()`.
|
||||
|
||||
- Resources should have `create_RESOURCE()`, `delete_RESOURCE()`,
|
||||
`update_RESOURCE()` API methods (as it makes sense).
|
||||
|
||||
- For those methods that should behave differently for omitted or None-valued
|
||||
parameters, use the `_utils.valid_kwargs` decorator. Notably: all Neutron
|
||||
`update_*` functions.
|
||||
|
||||
- Deleting a resource should return True if the delete succeeded, or False
|
||||
if the resource was not found.
|
||||
|
||||
Exceptions
|
||||
==========
|
||||
|
||||
All underlying client exceptions must be captured and converted to an
|
||||
`OpenStackCloudException` or one of its derivatives.
|
||||
|
||||
REST Calls
|
||||
============
|
||||
|
||||
All interactions with the cloud should be done with direct REST using
|
||||
the appropriate `keystoneauth1.adapter.Adapter`. See Glance and Swift
|
||||
calls for examples.
|
||||
|
||||
Returned Resources
|
||||
==================
|
||||
|
||||
Complex objects returned to the caller must be a `munch.Munch` type. The
|
||||
`shade._adapter.Adapter` class makes resources into `munch.Munch`.
|
||||
|
||||
All objects should be normalized. It is shade's purpose in life to make
|
||||
OpenStack consistent for end users, and this means not trusting the clouds
|
||||
to return consistent objects. There should be a normalize function in
|
||||
`shade/_normalize.py` that is applied to objects before returning them to
|
||||
the user. See :doc:`../user/model` for further details on object model
|
||||
requirements.
|
||||
|
||||
Fields should not be in the normalization contract if we cannot commit to
|
||||
providing them to all users.
|
||||
|
||||
Fields should be renamed in normalization to be consistent with
|
||||
the rest of shade. For instance, nothing in shade exposes the legacy OpenStack
|
||||
concept of "tenant" to a user, but instead uses "project" even if the
|
||||
cloud uses tenant.
|
||||
|
||||
Nova vs. Neutron
|
||||
================
|
||||
|
||||
- Recognize that not all cloud providers support Neutron, so never
|
||||
assume it will be present. If a task can be handled by either
|
||||
Neutron or Nova, code it to be handled by either.
|
||||
|
||||
- For methods that accept either a Nova pool or Neutron network, the
|
||||
parameter should just refer to the network, but documentation of it
|
||||
should explain about the pool. See: `create_floating_ip()` and
|
||||
`available_floating_ip()` methods.
|
||||
|
||||
Tests
|
||||
=====
|
||||
|
||||
- New API methods *must* have unit tests!
|
||||
|
||||
- New unit tests should only mock at the REST layer using `requests_mock`.
|
||||
Any mocking of shade itself or of legacy client libraries should be
|
||||
considered legacy and to be avoided.
|
||||
|
||||
- Functional tests should be added, when possible.
|
||||
|
||||
- In functional tests, always use unique names (for resources that have this
|
||||
attribute) and use it for clean up (see next point).
|
||||
|
||||
- In functional tests, always define cleanup functions to delete data added
|
||||
by your test, should something go wrong. Data removal should be wrapped in
|
||||
a try except block and try to delete as many entries added by the test as
|
||||
possible.
|
||||
@@ -1 +0,0 @@
|
||||
.. include:: ../../../CONTRIBUTING.rst
|
||||
@@ -1,9 +0,0 @@
|
||||
=========================
|
||||
Shade Contributor Guide
|
||||
=========================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
contributing
|
||||
coding
|
||||
@@ -1,31 +0,0 @@
|
||||
.. shade documentation master file, created by
|
||||
sphinx-quickstart on Tue Jul 9 22:26:36 2013.
|
||||
You can adapt this file completely to your liking, but it should at least
|
||||
contain the root `toctree` directive.
|
||||
|
||||
=================================
|
||||
Welcome to shade's documentation!
|
||||
=================================
|
||||
|
||||
Contents:
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
install/index
|
||||
user/index
|
||||
contributor/index
|
||||
|
||||
.. releasenotes contains a lot of sections, toctree with maxdepth 1 is used.
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
releasenotes/index
|
||||
|
||||
.. include:: ../../README.rst
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
|
||||
* :ref:`genindex`
|
||||
* :ref:`search`
|
||||
@@ -1,12 +0,0 @@
|
||||
============
|
||||
Installation
|
||||
============
|
||||
|
||||
At the command line::
|
||||
|
||||
$ pip install shade
|
||||
|
||||
Or, if you have virtualenv wrapper installed::
|
||||
|
||||
$ mkvirtualenv shade
|
||||
$ pip install shade
|
||||
@@ -1,5 +0,0 @@
|
||||
=============
|
||||
Release Notes
|
||||
=============
|
||||
|
||||
.. release-notes::
|
||||
@@ -1,13 +0,0 @@
|
||||
import shade
|
||||
|
||||
# Initialize and turn on debug logging
|
||||
shade.simple_logging(debug=True)
|
||||
|
||||
for cloud_name, region_name in [
|
||||
('my-vexxhost', 'ca-ymq-1'),
|
||||
('my-citycloud', 'Buf1'),
|
||||
('my-internap', 'ams01')]:
|
||||
# Initialize cloud
|
||||
cloud = shade.openstack_cloud(cloud=cloud_name, region_name=region_name)
|
||||
for server in cloud.search_servers('my-server'):
|
||||
cloud.delete_server(server, wait=True, delete_ips=True)
|
||||
@@ -1,22 +0,0 @@
|
||||
import shade
|
||||
|
||||
# Initialize and turn on debug logging
|
||||
shade.simple_logging(debug=True)
|
||||
|
||||
for cloud_name, region_name, image, flavor_id in [
|
||||
('my-vexxhost', 'ca-ymq-1', 'Ubuntu 16.04.1 LTS [2017-03-03]',
|
||||
'5cf64088-893b-46b5-9bb1-ee020277635d'),
|
||||
('my-citycloud', 'Buf1', 'Ubuntu 16.04 Xenial Xerus',
|
||||
'0dab10b5-42a2-438e-be7b-505741a7ffcc'),
|
||||
('my-internap', 'ams01', 'Ubuntu 16.04 LTS (Xenial Xerus)',
|
||||
'A1.4')]:
|
||||
# Initialize cloud
|
||||
cloud = shade.openstack_cloud(cloud=cloud_name, region_name=region_name)
|
||||
|
||||
# Boot a server, wait for it to boot, and then do whatever is needed
|
||||
# to get a public ip for it.
|
||||
server = cloud.create_server(
|
||||
'my-server', image=image, flavor=dict(id=flavor_id),
|
||||
wait=True, auto_ip=True)
|
||||
# Delete it - this is a demo
|
||||
cloud.delete_server(server, wait=True, delete_ips=True)
|
||||
@@ -1,25 +0,0 @@
|
||||
import shade
|
||||
|
||||
# Initialize and turn on debug logging
|
||||
shade.simple_logging(debug=True)
|
||||
|
||||
for cloud_name, region_name, image, flavor in [
|
||||
('my-vexxhost', 'ca-ymq-1',
|
||||
'Ubuntu 16.04.1 LTS [2017-03-03]', 'v1-standard-4'),
|
||||
('my-citycloud', 'Buf1',
|
||||
'Ubuntu 16.04 Xenial Xerus', '4C-4GB-100GB'),
|
||||
('my-internap', 'ams01',
|
||||
'Ubuntu 16.04 LTS (Xenial Xerus)', 'A1.4')]:
|
||||
# Initialize cloud
|
||||
cloud = shade.openstack_cloud(cloud=cloud_name, region_name=region_name)
|
||||
cloud.delete_server('my-server', wait=True, delete_ips=True)
|
||||
|
||||
# Boot a server, wait for it to boot, and then do whatever is needed
|
||||
# to get a public ip for it.
|
||||
server = cloud.create_server(
|
||||
'my-server', image=image, flavor=flavor, wait=True, auto_ip=True)
|
||||
print(server.name)
|
||||
print(server['name'])
|
||||
cloud.pprint(server)
|
||||
# Delete it - this is a demo
|
||||
cloud.delete_server(server, wait=True, delete_ips=True)
|
||||
@@ -1,6 +0,0 @@
|
||||
import shade
|
||||
shade.simple_logging(debug=True)
|
||||
|
||||
cloud = shade.openstack_cloud(
|
||||
cloud='my-vexxhost', region_name='ca-ymq-1')
|
||||
cloud.get_image('Ubuntu 16.04.1 LTS [2017-03-03]')
|
||||
@@ -1,7 +0,0 @@
|
||||
import shade
|
||||
shade.simple_logging()
|
||||
|
||||
cloud = shade.openstack_cloud(cloud='fuga', region_name='cystack')
|
||||
cloud.pprint([
|
||||
image for image in cloud.list_images()
|
||||
if 'ubuntu' in image.name.lower()])
|
||||
@@ -1,6 +0,0 @@
|
||||
import shade
|
||||
shade.simple_logging(http_debug=True)
|
||||
|
||||
cloud = shade.openstack_cloud(
|
||||
cloud='my-vexxhost', region_name='ca-ymq-1')
|
||||
cloud.get_image('Ubuntu 16.04.1 LTS [2017-03-03]')
|
||||
@@ -1,7 +0,0 @@
|
||||
import shade
|
||||
shade.simple_logging(debug=True)
|
||||
|
||||
cloud = shade.openstack_cloud(cloud='ovh', region_name='SBG1')
|
||||
image = cloud.get_image('Ubuntu 16.10')
|
||||
print(image.name)
|
||||
print(image['name'])
|
||||
@@ -1,7 +0,0 @@
|
||||
import shade
|
||||
shade.simple_logging()
|
||||
|
||||
cloud = shade.openstack_cloud(cloud='fuga', region_name='cystack')
|
||||
image = cloud.get_image(
|
||||
'Ubuntu 16.04 LTS - Xenial Xerus - 64-bit - Fuga Cloud Based Image')
|
||||
cloud.pprint(image)
|
||||
@@ -1,23 +0,0 @@
|
||||
import shade
|
||||
shade.simple_logging(debug=True)
|
||||
|
||||
cloud = shade.openstack_cloud(cloud='my-citycloud', region_name='Buf1')
|
||||
try:
|
||||
server = cloud.create_server(
|
||||
'my-server', image='Ubuntu 16.04 Xenial Xerus',
|
||||
flavor=dict(id='0dab10b5-42a2-438e-be7b-505741a7ffcc'),
|
||||
wait=True, auto_ip=True)
|
||||
|
||||
print("\n\nFull Server\n\n")
|
||||
cloud.pprint(server)
|
||||
|
||||
print("\n\nTurn Detailed Off\n\n")
|
||||
cloud.pprint(cloud.get_server('my-server', detailed=False))
|
||||
|
||||
print("\n\nBare Server\n\n")
|
||||
cloud.pprint(cloud.get_server('my-server', bare=True))
|
||||
|
||||
finally:
|
||||
# Delete it - this is a demo
|
||||
cloud.delete_server(server, wait=True, delete_ips=True)
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
import shade
|
||||
shade.simple_logging(debug=True)
|
||||
|
||||
cloud = shade.openstack_cloud(cloud='rax', region_name='DFW')
|
||||
print(cloud.has_service('network'))
|
||||
@@ -1,6 +0,0 @@
|
||||
import shade
|
||||
shade.simple_logging(debug=True)
|
||||
|
||||
cloud = shade.openstack_cloud(cloud='kiss', region_name='region1')
|
||||
print(cloud.has_service('network'))
|
||||
print(cloud.has_service('container-orchestration'))
|
||||
@@ -1,8 +0,0 @@
|
||||
import shade
|
||||
shade.simple_logging()
|
||||
|
||||
cloud = shade.openstack_cloud(
|
||||
cloud='fuga', region_name='cystack', strict=True)
|
||||
image = cloud.get_image(
|
||||
'Ubuntu 16.04 LTS - Xenial Xerus - 64-bit - Fuga Cloud Based Image')
|
||||
cloud.pprint(image)
|
||||
@@ -1,10 +0,0 @@
|
||||
import shade
|
||||
shade.simple_logging(debug=True)
|
||||
|
||||
cloud = shade.openstack_cloud(cloud='ovh', region_name='SBG1')
|
||||
cloud.create_object(
|
||||
container='my-container', name='my-object',
|
||||
filename='/home/mordred/briarcliff.sh3d',
|
||||
segment_size=1000000)
|
||||
cloud.delete_object('my-container', 'my-object')
|
||||
cloud.delete_container('my-container')
|
||||
@@ -1,10 +0,0 @@
|
||||
import shade
|
||||
shade.simple_logging(debug=True)
|
||||
|
||||
cloud = shade.openstack_cloud(cloud='ovh', region_name='SBG1')
|
||||
cloud.create_object(
|
||||
container='my-container', name='my-object',
|
||||
filename='/home/mordred/briarcliff.sh3d',
|
||||
segment_size=1000000)
|
||||
cloud.delete_object('my-container', 'my-object')
|
||||
cloud.delete_container('my-container')
|
||||
@@ -1,6 +0,0 @@
|
||||
import shade
|
||||
shade.simple_logging(http_debug=True)
|
||||
|
||||
cloud = shade.openstack_cloud(
|
||||
cloud='datacentred', app_name='AmazingApp', app_version='1.0')
|
||||
cloud.list_networks()
|
||||
@@ -1,19 +0,0 @@
|
||||
==================
|
||||
Shade User Guide
|
||||
==================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
usage
|
||||
logging
|
||||
model
|
||||
microversions
|
||||
|
||||
Presentations
|
||||
=============
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
multi-cloud-demo
|
||||
@@ -1,93 +0,0 @@
|
||||
=======
|
||||
Logging
|
||||
=======
|
||||
|
||||
`shade` uses `Python Logging`_. As `shade` is a library, it does not
|
||||
configure logging handlers automatically, expecting instead for that to be
|
||||
the purview of the consuming application.
|
||||
|
||||
Simple Usage
|
||||
------------
|
||||
|
||||
For consumers who just want to get a basic logging setup without thinking
|
||||
about it too deeply, there is a helper method. If used, it should be called
|
||||
before any other `shade` functionality.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import shade
|
||||
shade.simple_logging()
|
||||
|
||||
`shade.simple_logging` takes two optional boolean arguments:
|
||||
|
||||
debug
|
||||
Turns on debug logging.
|
||||
|
||||
http_debug
|
||||
Turns on debug logging as well as debug logging of the underlying HTTP calls.
|
||||
|
||||
`shade.simple_logging` also sets up a few other loggers and squelches some
|
||||
warnings or log messages that are otherwise uninteresting or unactionable by
|
||||
a `shade` user.
|
||||
|
||||
Advanced Usage
|
||||
--------------
|
||||
|
||||
`shade` logs to a set of different named loggers.
|
||||
|
||||
Most of the logging is set up to log to the root `shade` logger. There are
|
||||
additional sub-loggers that are used at times, primarily so that a user can
|
||||
decide to turn on or off a specific type of logging. They are listed below.
|
||||
|
||||
shade.task_manager
|
||||
`shade` uses a Task Manager to perform remote calls. The `shade.task_manager`
|
||||
logger emits messages at the start and end of each Task announging what
|
||||
it is going to run and then what it ran and how long it took. Logging
|
||||
`shade.task_manager` is a good way to get a trace of external actions shade
|
||||
is taking without full `HTTP Tracing`_.
|
||||
|
||||
shade.request_ids
|
||||
The `shade.request_ids` logger emits a log line at the end of each HTTP
|
||||
interaction with the OpenStack Request ID associated with the interaction.
|
||||
This can be be useful for tracking action taken on the server-side if one
|
||||
does not want `HTTP Tracing`_.
|
||||
|
||||
shade.iterate_timeout
|
||||
When `shade` needs to poll a resource, it does so in a loop that waits
|
||||
between iterations and ultimately timesout. The `shade.iterate_timeout`
|
||||
logger emits messages for each iteration indicating it is waiting and for
|
||||
how long. These can be useful to see for long running tasks so that one
|
||||
can know things are not stuck, but can also be noisy.
|
||||
|
||||
shade.http
|
||||
`shade` will sometimes log additional information about HTTP interactions
|
||||
to the `shade.http` logger. This can be verbose, as it sometimes logs
|
||||
entire response bodies.
|
||||
|
||||
shade.fnmatch
|
||||
`shade` will try to use `fnmatch`_ on given `name_or_id` arguments. It's a
|
||||
best effort attempt, so pattern misses are logged to `shade.fnmatch`. A user
|
||||
may not be intending to use an fnmatch pattern - such as if they are trying
|
||||
to find an image named ``Fedora 24 [official]``, so these messages are
|
||||
logged separately.
|
||||
|
||||
.. _fnmatch: https://pymotw.com/2/fnmatch/
|
||||
|
||||
HTTP Tracing
|
||||
------------
|
||||
|
||||
HTTP Interactions are handled by `keystoneauth`. If you want to enable HTTP
|
||||
tracing while using `shade` and are not using `shade.simple_logging`,
|
||||
set the log level of the `keystoneauth` logger to `DEBUG`.
|
||||
|
||||
Python Logging
|
||||
--------------
|
||||
|
||||
Python logging is a standard feature of Python and is documented fully in the
|
||||
Python Documentation, which varies by version of Python.
|
||||
|
||||
For more information on Python Logging for Python v2, see
|
||||
https://docs.python.org/2/library/logging.html.
|
||||
|
||||
For more information on Python Logging for Python v3, see
|
||||
https://docs.python.org/3/library/logging.html.
|
||||
@@ -1,75 +0,0 @@
|
||||
=============
|
||||
Microversions
|
||||
=============
|
||||
|
||||
As shade rolls out support for consuming microversions, it will do so on a
|
||||
call by call basis as needed. Just like with major versions, shade should have
|
||||
logic to handle each microversion for a given REST call it makes, with the
|
||||
following rules in mind:
|
||||
|
||||
* If an activity shade performs can be done differently or more efficiently
|
||||
with a new microversion, the support should be added to shade.
|
||||
|
||||
* shade should always attempt to use the latest microversion it is aware of
|
||||
for a given call, unless a microversion removes important data.
|
||||
|
||||
* Microversion selection should under no circumstances be exposed to the user,
|
||||
except in the case of missing feature error messages.
|
||||
|
||||
* If a feature is only exposed for a given microversion and cannot be simulated
|
||||
for older clouds without that microversion, it is ok to add it to shade but
|
||||
a clear error message should be given to the user that the given feature is
|
||||
not available on their cloud. (A message such as "This cloud only supports
|
||||
a maximum microversion of XXX for service YYY and this feature only exists
|
||||
on clouds with microversion ZZZ. Please contact your cloud provider for
|
||||
information about when this feature might be available")
|
||||
|
||||
* When adding a feature to shade that only exists behind a new microversion,
|
||||
every effort should be made to figure out how to provide the same
|
||||
functionality if at all possible, even if doing so is inefficient. If an
|
||||
inefficient workaround is employed, a warning should be provided to the
|
||||
user. (the user's workaround to skip the inefficient behavior would be to
|
||||
stop using that shade API call)
|
||||
|
||||
* If shade is aware of logic for more than one microversion, it should always
|
||||
attempt to use the latest version available for the service for that call.
|
||||
|
||||
* Objects returned from shade should always go through normalization and thus
|
||||
should always conform to shade's documented data model and should never look
|
||||
different to the shade user regardless of the microversion used for the REST
|
||||
call.
|
||||
|
||||
* If a microversion adds new fields to an object, those fields should be
|
||||
added to shade's data model contract for that object and the data should
|
||||
either be filled in by performing additional REST calls if the data is
|
||||
available that way, or the field should have a default value of None which
|
||||
the user can be expected to test for when attempting to use the new value.
|
||||
|
||||
* If a microversion removes fields from an object that are part of shade's
|
||||
existing data model contract, care should be taken to not use the new
|
||||
microversion for that call unless forced to by lack of availablity of the
|
||||
old microversion on the cloud in question. In the case where an old
|
||||
microversion is no longer available, care must be taken to either find the
|
||||
data from another source and fill it in, or to put a value of None into the
|
||||
field and document for the user that on some clouds the value may not exist.
|
||||
|
||||
* If a microversion removes a field and the outcome is particularly intractable
|
||||
and impossible to work around without fundamentally breaking shade's users,
|
||||
an issue should be raised with the service team in question. Hopefully a
|
||||
resolution can be found during the period while clouds still have the old
|
||||
microversion.
|
||||
|
||||
* As new calls or objects are added to shade, it is important to check in with
|
||||
the service team in question on the expected stability of the object. If
|
||||
there are known changes expected in the future, even if they may be a few
|
||||
years off, shade should take care to not add committments to its data model
|
||||
for those fields/features. It is ok for shade to not have something.
|
||||
|
||||
..note::
|
||||
shade does not currently have any sort of "experimental" opt-in API that
|
||||
would allow a shade to expose things to a user that may not be supportable
|
||||
under shade's normal compatibility contract. If a conflict arises in the
|
||||
future where there is a strong desire for a feature but also a lack of
|
||||
certainty about its stability over time, an experimental API may want to
|
||||
be explored ... but concrete use cases should arise before such a thing
|
||||
is started.
|
||||
@@ -1,533 +0,0 @@
|
||||
==========
|
||||
Data Model
|
||||
==========
|
||||
|
||||
shade has a very strict policy on not breaking backwards compatability ever.
|
||||
However, with the data structures returned from OpenStack, there are places
|
||||
where the resource structures from OpenStack are returned to the user somewhat
|
||||
directly, leaving a shade user open to changes/differences in result content.
|
||||
|
||||
To combat that, shade 'normalizes' the return structure from OpenStack in many
|
||||
places, and the results of that normalization are listed below. Where shade
|
||||
performs normalization, a user can count on any fields declared in the docs
|
||||
as being completely safe to use - they are as much a part of shade's API
|
||||
contract as any other Python method.
|
||||
|
||||
Some OpenStack objects allow for arbitrary attributes at
|
||||
the root of the object. shade will pass those through so as not to break anyone
|
||||
who may be counting on them, but as they are arbitrary shade can make no
|
||||
guarantees as to their existence. As part of normalization, shade will put any
|
||||
attribute from an OpenStack resource that is not in its data model contract
|
||||
into an attribute called 'properties'. The contents of properties are
|
||||
defined to be an arbitrary collection of key value pairs with no promises as
|
||||
to any particular key ever existing.
|
||||
|
||||
If a user passes `strict=True` to the shade constructor, shade will not pass
|
||||
through arbitrary objects to the root of the resource, and will instead only
|
||||
put them in the properties dict. If a user is worried about accidentally
|
||||
writing code that depends on an attribute that is not part of the API contract,
|
||||
this can be a useful tool. Keep in mind all data can still be accessed via
|
||||
the properties dict, but any code touching anything in the properties dict
|
||||
should be aware that the keys found there are highly user/cloud specific.
|
||||
Any key that is transformed as part of the shade data model contract will
|
||||
not wind up with an entry in properties - only keys that are unknown.
|
||||
|
||||
Location
|
||||
--------
|
||||
|
||||
A Location defines where a resource lives. It includes a cloud name and a
|
||||
region name, an availability zone as well as information about the project
|
||||
that owns the resource.
|
||||
|
||||
The project information may contain a project id, or a combination of one or
|
||||
more of a project name with a domain name or id. If a project id is present,
|
||||
it should be considered correct.
|
||||
|
||||
Some resources do not carry ownership information with them. For those, the
|
||||
project information will be filled in from the project the user currently
|
||||
has a token for.
|
||||
|
||||
Some resources do not have information about availability zones, or may exist
|
||||
region wide. Those resources will have None as their availability zone.
|
||||
|
||||
If all of the project information is None, then
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
Location = dict(
|
||||
cloud=str(),
|
||||
region=str(),
|
||||
zone=str() or None,
|
||||
project=dict(
|
||||
id=str() or None,
|
||||
name=str() or None,
|
||||
domain_id=str() or None,
|
||||
domain_name=str() or None))
|
||||
|
||||
|
||||
Resources
|
||||
=========
|
||||
|
||||
Flavor
|
||||
------
|
||||
|
||||
A flavor for a Nova Server.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
Flavor = dict(
|
||||
location=Location(),
|
||||
id=str(),
|
||||
name=str(),
|
||||
is_public=bool(),
|
||||
is_disabled=bool(),
|
||||
ram=int(),
|
||||
vcpus=int(),
|
||||
disk=int(),
|
||||
ephemeral=int(),
|
||||
swap=int(),
|
||||
rxtx_factor=float(),
|
||||
extra_specs=dict(),
|
||||
properties=dict())
|
||||
|
||||
|
||||
Flavor Access
|
||||
-------------
|
||||
|
||||
An access entry for a Nova Flavor.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
FlavorAccess = dict(
|
||||
flavor_id=str(),
|
||||
project_id=str())
|
||||
|
||||
|
||||
Image
|
||||
-----
|
||||
|
||||
A Glance Image.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
Image = dict(
|
||||
location=Location(),
|
||||
id=str(),
|
||||
name=str(),
|
||||
min_ram=int(),
|
||||
min_disk=int(),
|
||||
size=int(),
|
||||
virtual_size=int(),
|
||||
container_format=str(),
|
||||
disk_format=str(),
|
||||
checksum=str(),
|
||||
created_at=str(),
|
||||
updated_at=str(),
|
||||
owner=str(),
|
||||
is_public=bool(),
|
||||
is_protected=bool(),
|
||||
visibility=str(),
|
||||
status=str(),
|
||||
locations=list(),
|
||||
direct_url=str() or None,
|
||||
tags=list(),
|
||||
properties=dict())
|
||||
|
||||
|
||||
Keypair
|
||||
-------
|
||||
|
||||
A keypair for a Nova Server.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
Keypair = dict(
|
||||
location=Location(),
|
||||
name=str(),
|
||||
id=str(),
|
||||
public_key=str(),
|
||||
fingerprint=str(),
|
||||
type=str(),
|
||||
user_id=str(),
|
||||
private_key=str() or None
|
||||
properties=dict())
|
||||
|
||||
|
||||
Security Group
|
||||
--------------
|
||||
|
||||
A Security Group from either Nova or Neutron
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
SecurityGroup = dict(
|
||||
location=Location(),
|
||||
id=str(),
|
||||
name=str(),
|
||||
description=str(),
|
||||
security_group_rules=list(),
|
||||
properties=dict())
|
||||
|
||||
Security Group Rule
|
||||
-------------------
|
||||
|
||||
A Security Group Rule from either Nova or Neutron
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
SecurityGroupRule = dict(
|
||||
location=Location(),
|
||||
id=str(),
|
||||
direction=str(), # oneof('ingress', 'egress')
|
||||
ethertype=str(),
|
||||
port_range_min=int() or None,
|
||||
port_range_max=int() or None,
|
||||
protocol=str() or None,
|
||||
remote_ip_prefix=str() or None,
|
||||
security_group_id=str() or None,
|
||||
remote_group_id=str() or None
|
||||
properties=dict())
|
||||
|
||||
Server
|
||||
------
|
||||
|
||||
A Server from Nova
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
Server = dict(
|
||||
location=Location(),
|
||||
id=str(),
|
||||
name=str(),
|
||||
image=dict() or str(),
|
||||
flavor=dict(),
|
||||
volumes=list(), # Volume
|
||||
interface_ip=str(),
|
||||
has_config_drive=bool(),
|
||||
accessIPv4=str(),
|
||||
accessIPv6=str(),
|
||||
addresses=dict(), # string, list(Address)
|
||||
created=str(),
|
||||
created_at=str(),
|
||||
key_name=str(),
|
||||
metadata=dict(), # string, string
|
||||
private_v4=str(),
|
||||
progress=int(),
|
||||
public_v4=str(),
|
||||
public_v6=str(),
|
||||
security_groups=list(), # SecurityGroup
|
||||
status=str(),
|
||||
updated=str(),
|
||||
user_id=str(),
|
||||
host_id=str() or None,
|
||||
power_state=str() or None,
|
||||
task_state=str() or None,
|
||||
vm_state=str() or None,
|
||||
launched_at=str() or None,
|
||||
terminated_at=str() or None,
|
||||
task_state=str() or None,
|
||||
properties=dict())
|
||||
|
||||
ComputeLimits
|
||||
-------------
|
||||
|
||||
Limits and current usage for a project in Nova
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
ComputeLimits = dict(
|
||||
location=Location(),
|
||||
max_personality=int(),
|
||||
max_personality_size=int(),
|
||||
max_server_group_members=int(),
|
||||
max_server_groups=int(),
|
||||
max_server_meta=int(),
|
||||
max_total_cores=int(),
|
||||
max_total_instances=int(),
|
||||
max_total_keypairs=int(),
|
||||
max_total_ram_size=int(),
|
||||
total_cores_used=int(),
|
||||
total_instances_used=int(),
|
||||
total_ram_used=int(),
|
||||
total_server_groups_used=int(),
|
||||
properties=dict())
|
||||
|
||||
ComputeUsage
|
||||
------------
|
||||
|
||||
Current usage for a project in Nova
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
ComputeUsage = dict(
|
||||
location=Location(),
|
||||
started_at=str(),
|
||||
stopped_at=str(),
|
||||
server_usages=list(),
|
||||
max_personality=int(),
|
||||
max_personality_size=int(),
|
||||
max_server_group_members=int(),
|
||||
max_server_groups=int(),
|
||||
max_server_meta=int(),
|
||||
max_total_cores=int(),
|
||||
max_total_instances=int(),
|
||||
max_total_keypairs=int(),
|
||||
max_total_ram_size=int(),
|
||||
total_cores_used=int(),
|
||||
total_hours=int(),
|
||||
total_instances_used=int(),
|
||||
total_local_gb_usage=int(),
|
||||
total_memory_mb_usage=int(),
|
||||
total_ram_used=int(),
|
||||
total_server_groups_used=int(),
|
||||
total_vcpus_usage=int(),
|
||||
properties=dict())
|
||||
|
||||
ServerUsage
|
||||
-----------
|
||||
|
||||
Current usage for a server in Nova
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
ComputeUsage = dict(
|
||||
started_at=str(),
|
||||
ended_at=str(),
|
||||
flavor=str(),
|
||||
hours=int(),
|
||||
instance_id=str(),
|
||||
local_gb=int(),
|
||||
memory_mb=int(),
|
||||
name=str(),
|
||||
state=str(),
|
||||
uptime=int(),
|
||||
vcpus=int(),
|
||||
properties=dict())
|
||||
|
||||
Floating IP
|
||||
-----------
|
||||
|
||||
A Floating IP from Neutron or Nova
|
||||
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
FloatingIP = dict(
|
||||
location=Location(),
|
||||
id=str(),
|
||||
description=str(),
|
||||
attached=bool(),
|
||||
fixed_ip_address=str() or None,
|
||||
floating_ip_address=str() or None,
|
||||
network=str() or None,
|
||||
port=str() or None,
|
||||
router=str(),
|
||||
status=str(),
|
||||
created_at=str() or None,
|
||||
updated_at=str() or None,
|
||||
revision_number=int() or None,
|
||||
properties=dict())
|
||||
|
||||
Volume
|
||||
------
|
||||
|
||||
A volume from cinder.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
Volume = dict(
|
||||
location=Location(),
|
||||
id=str(),
|
||||
name=str(),
|
||||
description=str(),
|
||||
size=int(),
|
||||
attachments=list(),
|
||||
status=str(),
|
||||
migration_status=str() or None,
|
||||
host=str() or None,
|
||||
replication_driver=str() or None,
|
||||
replication_status=str() or None,
|
||||
replication_extended_status=str() or None,
|
||||
snapshot_id=str() or None,
|
||||
created_at=str(),
|
||||
updated_at=str() or None,
|
||||
source_volume_id=str() or None,
|
||||
consistencygroup_id=str() or None,
|
||||
volume_type=str() or None,
|
||||
metadata=dict(),
|
||||
is_bootable=bool(),
|
||||
is_encrypted=bool(),
|
||||
can_multiattach=bool(),
|
||||
properties=dict())
|
||||
|
||||
|
||||
VolumeType
|
||||
----------
|
||||
|
||||
A volume type from cinder.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
VolumeType = dict(
|
||||
location=Location(),
|
||||
id=str(),
|
||||
name=str(),
|
||||
description=str() or None,
|
||||
is_public=bool(),
|
||||
qos_specs_id=str() or None,
|
||||
extra_specs=dict(),
|
||||
properties=dict())
|
||||
|
||||
|
||||
VolumeTypeAccess
|
||||
----------------
|
||||
|
||||
A volume type access from cinder.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
VolumeTypeAccess = dict(
|
||||
location=Location(),
|
||||
volume_type_id=str(),
|
||||
project_id=str(),
|
||||
properties=dict())
|
||||
|
||||
|
||||
ClusterTemplate
|
||||
---------------
|
||||
|
||||
A Cluster Template from magnum.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
ClusterTemplate = dict(
|
||||
location=Location(),
|
||||
apiserver_port=int(),
|
||||
cluster_distro=str(),
|
||||
coe=str(),
|
||||
created_at=str(),
|
||||
dns_nameserver=str(),
|
||||
docker_volume_size=int(),
|
||||
external_network_id=str(),
|
||||
fixed_network=str() or None,
|
||||
flavor_id=str(),
|
||||
http_proxy=str() or None,
|
||||
https_proxy=str() or None,
|
||||
id=str(),
|
||||
image_id=str(),
|
||||
insecure_registry=str(),
|
||||
is_public=bool(),
|
||||
is_registry_enabled=bool(),
|
||||
is_tls_disabled=bool(),
|
||||
keypair_id=str(),
|
||||
labels=dict(),
|
||||
master_flavor_id=str() or None,
|
||||
name=str(),
|
||||
network_driver=str(),
|
||||
no_proxy=str() or None,
|
||||
server_type=str(),
|
||||
updated_at=str() or None,
|
||||
volume_driver=str(),
|
||||
properties=dict())
|
||||
|
||||
MagnumService
|
||||
-------------
|
||||
|
||||
A Magnum Service from magnum
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
MagnumService = dict(
|
||||
location=Location(),
|
||||
binary=str(),
|
||||
created_at=str(),
|
||||
disabled_reason=str() or None,
|
||||
host=str(),
|
||||
id=str(),
|
||||
report_count=int(),
|
||||
state=str(),
|
||||
properties=dict())
|
||||
|
||||
Stack
|
||||
-----
|
||||
|
||||
A Stack from Heat
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
Stack = dict(
|
||||
location=Location(),
|
||||
id=str(),
|
||||
name=str(),
|
||||
created_at=str(),
|
||||
deleted_at=str(),
|
||||
updated_at=str(),
|
||||
description=str(),
|
||||
action=str(),
|
||||
identifier=str(),
|
||||
is_rollback_enabled=bool(),
|
||||
notification_topics=list(),
|
||||
outputs=list(),
|
||||
owner=str(),
|
||||
parameters=dict(),
|
||||
parent=str(),
|
||||
stack_user_project_id=str(),
|
||||
status=str(),
|
||||
status_reason=str(),
|
||||
tags=dict(),
|
||||
tempate_description=str(),
|
||||
timeout_mins=int(),
|
||||
properties=dict())
|
||||
|
||||
Identity Resources
|
||||
==================
|
||||
|
||||
Identity Resources are slightly different.
|
||||
|
||||
They are global to a cloud, so location.availability_zone and
|
||||
location.region_name and will always be None. If a deployer happens to deploy
|
||||
OpenStack in such a way that users and projects are not shared amongst regions,
|
||||
that necessitates treating each of those regions as separate clouds from
|
||||
shade's POV.
|
||||
|
||||
The Identity Resources that are not Project do not exist within a Project,
|
||||
so all of the values in ``location.project`` will be None.
|
||||
|
||||
Project
|
||||
-------
|
||||
|
||||
A Project from Keystone (or a tenant if Keystone v2)
|
||||
|
||||
Location information for Project has some additional specific semantics.
|
||||
If the project has a parent project, that will be in ``location.project.id``,
|
||||
and if it doesn't that should be ``None``.
|
||||
|
||||
If the Project is associated with a domain that will be in
|
||||
``location.project.domain_id`` in addition to the normal ``domain_id``
|
||||
regardless of the current user's token scope.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
Project = dict(
|
||||
location=Location(),
|
||||
id=str(),
|
||||
name=str(),
|
||||
description=str(),
|
||||
is_enabled=bool(),
|
||||
is_domain=bool(),
|
||||
domain_id=str(),
|
||||
properties=dict())
|
||||
|
||||
Role
|
||||
----
|
||||
|
||||
A Role from Keystone
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
Project = dict(
|
||||
location=Location(),
|
||||
id=str(),
|
||||
name=str(),
|
||||
domain_id=str(),
|
||||
properties=dict())
|
||||
@@ -1,811 +0,0 @@
|
||||
================
|
||||
Multi-Cloud Demo
|
||||
================
|
||||
|
||||
This document contains a presentation in `presentty`_ format. If you want to
|
||||
walk through it like a presentation, install `presentty` and run:
|
||||
|
||||
.. code:: bash
|
||||
|
||||
presentty doc/source/user/multi-cloud-demo.rst
|
||||
|
||||
The content is hopefully helpful even if it's not being narrated, so it's being
|
||||
included in the `shade` docs.
|
||||
|
||||
.. _presentty: https://pypi.org/project/presentty
|
||||
|
||||
Using Multiple OpenStack Clouds Easily with Shade
|
||||
=================================================
|
||||
|
||||
Who am I?
|
||||
=========
|
||||
|
||||
Monty Taylor
|
||||
|
||||
* OpenStack Infra Core
|
||||
* irc: mordred
|
||||
* twitter: @e_monty
|
||||
|
||||
What are we going to talk about?
|
||||
================================
|
||||
|
||||
`shade`
|
||||
|
||||
* a task and end-user oriented Python library
|
||||
* abstracts deployment differences
|
||||
* designed for multi-cloud
|
||||
* simple to use
|
||||
* massive scale
|
||||
|
||||
* optional advanced features to handle 20k servers a day
|
||||
|
||||
* Initial logic/design extracted from nodepool
|
||||
* Librified to re-use in Ansible
|
||||
|
||||
shade is Free Software
|
||||
======================
|
||||
|
||||
* https://opendev.org/openstack/shade
|
||||
* openstack-discuss@lists.openstack.org
|
||||
* #openstack-shade on freenode
|
||||
|
||||
This talk is Free Software, too
|
||||
===============================
|
||||
|
||||
* Written for presentty (https://pypi.org/project/presentty)
|
||||
* doc/source/multi-cloud-demo.rst
|
||||
* examples in doc/source/examples
|
||||
* Paths subject to change- this is the first presentation in tree!
|
||||
|
||||
Complete Example
|
||||
================
|
||||
|
||||
.. code:: python
|
||||
|
||||
import shade
|
||||
|
||||
# Initialize and turn on debug logging
|
||||
shade.simple_logging(debug=True)
|
||||
|
||||
for cloud_name, region_name in [
|
||||
('my-vexxhost', 'ca-ymq-1'),
|
||||
('my-citycloud', 'Buf1'),
|
||||
('my-internap', 'ams01')]:
|
||||
# Initialize cloud
|
||||
cloud = shade.openstack_cloud(cloud=cloud_name, region_name=region_name)
|
||||
|
||||
# Upload an image to the cloud
|
||||
image = cloud.create_image(
|
||||
'devuan-jessie', filename='devuan-jessie.qcow2', wait=True)
|
||||
|
||||
# Find a flavor with at least 512M of RAM
|
||||
flavor = cloud.get_flavor_by_ram(512)
|
||||
|
||||
# Boot a server, wait for it to boot, and then do whatever is needed
|
||||
# to get a public ip for it.
|
||||
cloud.create_server(
|
||||
'my-server', image=image, flavor=flavor, wait=True, auto_ip=True)
|
||||
|
||||
Let's Take a Few Steps Back
|
||||
===========================
|
||||
|
||||
Multi-cloud is easy, but you need to know a few things.
|
||||
|
||||
* Terminology
|
||||
* Config
|
||||
* Shade API
|
||||
|
||||
Cloud Terminology
|
||||
=================
|
||||
|
||||
Let's define a few terms, so that we can use them with ease:
|
||||
|
||||
* `cloud` - logically related collection of services
|
||||
* `region` - completely independent subset of a given cloud
|
||||
* `patron` - human who has an account
|
||||
* `user` - account on a cloud
|
||||
* `project` - logical collection of cloud resources
|
||||
* `domain` - collection of users and projects
|
||||
|
||||
Cloud Terminology Relationships
|
||||
===============================
|
||||
|
||||
* A `cloud` has one or more `regions`
|
||||
* A `patron` has one or more `users`
|
||||
* A `patron` has one or more `projects`
|
||||
* A `cloud` has one or more `domains`
|
||||
* In a `cloud` with one `domain` it is named "default"
|
||||
* Each `patron` may have their own `domain`
|
||||
* Each `user` is in one `domain`
|
||||
* Each `project` is in one `domain`
|
||||
* A `user` has one or more `roles` on one or more `projects`
|
||||
|
||||
HTTP Sessions
|
||||
=============
|
||||
|
||||
* HTTP interactions are authenticated via keystone
|
||||
* Authenticating returns a `token`
|
||||
* An authenticated HTTP Session is shared across a `region`
|
||||
|
||||
Cloud Regions
|
||||
=============
|
||||
|
||||
A `cloud region` is the basic unit of REST interaction.
|
||||
|
||||
* A `cloud` has a `service catalog`
|
||||
* The `service catalog` is returned in the `token`
|
||||
* The `service catalog` lists `endpoint` for each `service` in each `region`
|
||||
* A `region` is completely autonomous
|
||||
|
||||
Users, Projects and Domains
|
||||
===========================
|
||||
|
||||
In clouds with multiple domains, project and user names are
|
||||
only unique within a region.
|
||||
|
||||
* Names require `domain` information for uniqueness. IDs do not.
|
||||
* Providing `domain` information when not needed is fine.
|
||||
* `project_name` requires `project_domain_name` or `project_domain_id`
|
||||
* `project_id` does not
|
||||
* `username` requires `user_domain_name` or `user_domain_id`
|
||||
* `user_id` does not
|
||||
|
||||
Confused Yet?
|
||||
=============
|
||||
|
||||
Don't worry - you don't have to deal with most of that.
|
||||
|
||||
Auth per cloud, select per region
|
||||
=================================
|
||||
|
||||
In general, the thing you need to know is:
|
||||
|
||||
* Configure authentication per `cloud`
|
||||
* Select config to use by `cloud` and `region`
|
||||
|
||||
clouds.yaml
|
||||
===========
|
||||
|
||||
Information about the clouds you want to connect to is stored in a file
|
||||
called `clouds.yaml`.
|
||||
|
||||
`clouds.yaml` can be in your homedir: `~/.config/openstack/clouds.yaml`
|
||||
or system-wide: `/etc/openstack/clouds.yaml`.
|
||||
|
||||
Information in your homedir, if it exists, takes precedence.
|
||||
|
||||
Full docs on `clouds.yaml` are at
|
||||
https://docs.openstack.org/os-client-config/latest/
|
||||
|
||||
What about Mac and Windows?
|
||||
===========================
|
||||
|
||||
`USER_CONFIG_DIR` is different on Linux, OSX and Windows.
|
||||
|
||||
* Linux: `~/.config/openstack`
|
||||
* OSX: `~/Library/Application Support/openstack`
|
||||
* Windows: `C:\\Users\\USERNAME\\AppData\\Local\\OpenStack\\openstack`
|
||||
|
||||
`SITE_CONFIG_DIR` is different on Linux, OSX and Windows.
|
||||
|
||||
* Linux: `/etc/openstack`
|
||||
* OSX: `/Library/Application Support/openstack`
|
||||
* Windows: `C:\\ProgramData\\OpenStack\\openstack`
|
||||
|
||||
Config Terminology
|
||||
==================
|
||||
|
||||
For multi-cloud, think of two types:
|
||||
|
||||
* `profile` - Facts about the `cloud` that are true for everyone
|
||||
* `cloud` - Information specific to a given `user`
|
||||
|
||||
Apologies for the use of `cloud` twice.
|
||||
|
||||
Environment Variables and Simple Usage
|
||||
======================================
|
||||
|
||||
* Environment variables starting with `OS_` go into a cloud called `envvars`
|
||||
* If you only have one cloud, you don't have to specify it
|
||||
* `OS_CLOUD` and `OS_REGION_NAME` are default values for
|
||||
`cloud` and `region_name`
|
||||
|
||||
TOO MUCH TALKING - NOT ENOUGH CODE
|
||||
==================================
|
||||
|
||||
basic clouds.yaml for the example code
|
||||
======================================
|
||||
|
||||
Simple example of a clouds.yaml
|
||||
|
||||
* Config for a named `cloud` "my-citycloud"
|
||||
* Reference a well-known "named" profile: `citycloud`
|
||||
* `os-client-config` has a built-in list of profiles at
|
||||
https://docs.openstack.org/os-client-config/latest/user/vendor-support.html
|
||||
* Vendor profiles contain various advanced config
|
||||
* `cloud` name can match `profile` name (using different names for clarity)
|
||||
|
||||
.. code:: yaml
|
||||
|
||||
clouds:
|
||||
my-citycloud:
|
||||
profile: citycloud
|
||||
auth:
|
||||
username: mordred
|
||||
project_id: 65222a4d09ea4c68934fa1028c77f394
|
||||
user_domain_id: d0919bd5e8d74e49adf0e145807ffc38
|
||||
project_domain_id: d0919bd5e8d74e49adf0e145807ffc38
|
||||
|
||||
Where's the password?
|
||||
|
||||
secure.yaml
|
||||
===========
|
||||
|
||||
* Optional additional file just like `clouds.yaml`
|
||||
* Values overlaid on `clouds.yaml`
|
||||
* Useful if you want to protect secrets more stringently
|
||||
|
||||
Example secure.yaml
|
||||
===================
|
||||
|
||||
* No, my password isn't XXXXXXXX
|
||||
* `cloud` name should match `clouds.yaml`
|
||||
* Optional - I actually keep mine in my `clouds.yaml`
|
||||
|
||||
.. code:: yaml
|
||||
|
||||
clouds:
|
||||
my-citycloud:
|
||||
auth:
|
||||
password: XXXXXXXX
|
||||
|
||||
more clouds.yaml
|
||||
================
|
||||
|
||||
More information can be provided.
|
||||
|
||||
* Use v3 of the `identity` API - even if others are present
|
||||
* Use `https://image-ca-ymq-1.vexxhost.net/v2` for `image` API
|
||||
instead of what's in the catalog
|
||||
|
||||
.. code:: yaml
|
||||
|
||||
my-vexxhost:
|
||||
identity_api_version: 3
|
||||
image_endpoint_override: https://image-ca-ymq-1.vexxhost.net/v2
|
||||
profile: vexxhost
|
||||
auth:
|
||||
user_domain_id: default
|
||||
project_domain_id: default
|
||||
project_name: d8af8a8f-a573-48e6-898a-af333b970a2d
|
||||
username: 0b8c435b-cc4d-4e05-8a47-a2ada0539af1
|
||||
|
||||
Much more complex clouds.yaml example
|
||||
=====================================
|
||||
|
||||
* Not using a profile - all settings included
|
||||
* In the `ams01` `region` there are two networks with undiscoverable qualities
|
||||
* Each one are labeled here so choices can be made
|
||||
* Any of the settings can be specific to a `region` if needed
|
||||
* `region` settings override `cloud` settings
|
||||
* `cloud` does not support `floating-ips`
|
||||
|
||||
.. code:: yaml
|
||||
|
||||
my-internap:
|
||||
auth:
|
||||
auth_url: https://identity.api.cloud.iweb.com
|
||||
username: api-55f9a00fb2619
|
||||
project_name: inap-17037
|
||||
identity_api_version: 3
|
||||
floating_ip_source: None
|
||||
regions:
|
||||
- name: ams01
|
||||
values:
|
||||
networks:
|
||||
- name: inap-17037-WAN1654
|
||||
routes_externally: true
|
||||
default_interface: true
|
||||
- name: inap-17037-LAN3631
|
||||
routes_externally: false
|
||||
|
||||
Complete Example Again
|
||||
======================
|
||||
|
||||
.. code:: python
|
||||
|
||||
import shade
|
||||
|
||||
# Initialize and turn on debug logging
|
||||
shade.simple_logging(debug=True)
|
||||
|
||||
for cloud_name, region_name in [
|
||||
('my-vexxhost', 'ca-ymq-1'),
|
||||
('my-citycloud', 'Buf1'),
|
||||
('my-internap', 'ams01')]:
|
||||
# Initialize cloud
|
||||
cloud = shade.openstack_cloud(cloud=cloud_name, region_name=region_name)
|
||||
|
||||
# Upload an image to the cloud
|
||||
image = cloud.create_image(
|
||||
'devuan-jessie', filename='devuan-jessie.qcow2', wait=True)
|
||||
|
||||
# Find a flavor with at least 512M of RAM
|
||||
flavor = cloud.get_flavor_by_ram(512)
|
||||
|
||||
# Boot a server, wait for it to boot, and then do whatever is needed
|
||||
# to get a public ip for it.
|
||||
cloud.create_server(
|
||||
'my-server', image=image, flavor=flavor, wait=True, auto_ip=True)
|
||||
|
||||
Step By Step
|
||||
============
|
||||
|
||||
Import the library
|
||||
==================
|
||||
|
||||
.. code:: python
|
||||
|
||||
import shade
|
||||
|
||||
Logging
|
||||
=======
|
||||
|
||||
* `shade` uses standard python logging
|
||||
* Special `shade.request_ids` logger for API request IDs
|
||||
* `simple_logging` does easy defaults
|
||||
* Squelches some meaningless warnings
|
||||
|
||||
* `debug`
|
||||
|
||||
* Logs shade loggers at debug level
|
||||
* Includes `shade.request_ids` debug logging
|
||||
|
||||
* `http_debug` Implies `debug`, turns on HTTP tracing
|
||||
|
||||
.. code:: python
|
||||
|
||||
# Initialize and turn on debug logging
|
||||
shade.simple_logging(debug=True)
|
||||
|
||||
Example with Debug Logging
|
||||
==========================
|
||||
|
||||
* doc/source/examples/debug-logging.py
|
||||
|
||||
.. code:: python
|
||||
|
||||
import shade
|
||||
shade.simple_logging(debug=True)
|
||||
|
||||
cloud = shade.openstack_cloud(
|
||||
cloud='my-vexxhost', region_name='ca-ymq-1')
|
||||
cloud.get_image('Ubuntu 16.04.1 LTS [2017-03-03]')
|
||||
|
||||
Example with HTTP Debug Logging
|
||||
===============================
|
||||
|
||||
* doc/source/examples/http-debug-logging.py
|
||||
|
||||
.. code:: python
|
||||
|
||||
import shade
|
||||
shade.simple_logging(http_debug=True)
|
||||
|
||||
cloud = shade.openstack_cloud(
|
||||
cloud='my-vexxhost', region_name='ca-ymq-1')
|
||||
cloud.get_image('Ubuntu 16.04.1 LTS [2017-03-03]')
|
||||
|
||||
Cloud Regions
|
||||
=============
|
||||
|
||||
* `cloud` constructor needs `cloud` and `region_name`
|
||||
* `shade.openstack_cloud` is a helper factory function
|
||||
|
||||
.. code:: python
|
||||
|
||||
for cloud_name, region_name in [
|
||||
('my-vexxhost', 'ca-ymq-1'),
|
||||
('my-citycloud', 'Buf1'),
|
||||
('my-internap', 'ams01')]:
|
||||
# Initialize cloud
|
||||
cloud = shade.openstack_cloud(cloud=cloud_name, region_name=region_name)
|
||||
|
||||
Upload an Image
|
||||
===============
|
||||
|
||||
* Picks the correct upload mechanism
|
||||
* **SUGGESTION** Always upload your own base images
|
||||
|
||||
.. code:: python
|
||||
|
||||
# Upload an image to the cloud
|
||||
image = cloud.create_image(
|
||||
'devuan-jessie', filename='devuan-jessie.qcow2', wait=True)
|
||||
|
||||
Always Upload an Image
|
||||
======================
|
||||
|
||||
Ok. You don't have to. But, for multi-cloud...
|
||||
|
||||
* Images with same content are named different on different clouds
|
||||
* Images with same name on different clouds can have different content
|
||||
* Upload your own to all clouds, both problems go away
|
||||
* Download from OS vendor or build with `diskimage-builder`
|
||||
|
||||
Find a flavor
|
||||
=============
|
||||
|
||||
* Flavors are all named differently on clouds
|
||||
* Flavors can be found via RAM
|
||||
* `get_flavor_by_ram` finds the smallest matching flavor
|
||||
|
||||
.. code:: python
|
||||
|
||||
# Find a flavor with at least 512M of RAM
|
||||
flavor = cloud.get_flavor_by_ram(512)
|
||||
|
||||
Create a server
|
||||
===============
|
||||
|
||||
* my-vexxhost
|
||||
|
||||
* Boot server
|
||||
* Wait for `status==ACTIVE`
|
||||
|
||||
* my-internap
|
||||
|
||||
* Boot server on network `inap-17037-WAN1654`
|
||||
* Wait for `status==ACTIVE`
|
||||
|
||||
* my-citycloud
|
||||
|
||||
* Boot server
|
||||
* Wait for `status==ACTIVE`
|
||||
* Find the `port` for the `fixed_ip` for `server`
|
||||
* Create `floating-ip` on that `port`
|
||||
* Wait for `floating-ip` to attach
|
||||
|
||||
.. code:: python
|
||||
|
||||
# Boot a server, wait for it to boot, and then do whatever is needed
|
||||
# to get a public ip for it.
|
||||
cloud.create_server(
|
||||
'my-server', image=image, flavor=flavor, wait=True, auto_ip=True)
|
||||
|
||||
Wow. We didn't even deploy Wordpress!
|
||||
=====================================
|
||||
|
||||
Image and Flavor by Name or ID
|
||||
==============================
|
||||
|
||||
* Pass string to image/flavor
|
||||
* Image/Flavor will be found by name or ID
|
||||
* Common pattern
|
||||
* doc/source/examples/create-server-name-or-id.py
|
||||
|
||||
.. code:: python
|
||||
|
||||
import shade
|
||||
|
||||
# Initialize and turn on debug logging
|
||||
shade.simple_logging(debug=True)
|
||||
|
||||
for cloud_name, region_name, image, flavor in [
|
||||
('my-vexxhost', 'ca-ymq-1',
|
||||
'Ubuntu 16.04.1 LTS [2017-03-03]', 'v1-standard-4'),
|
||||
('my-citycloud', 'Buf1',
|
||||
'Ubuntu 16.04 Xenial Xerus', '4C-4GB-100GB'),
|
||||
('my-internap', 'ams01',
|
||||
'Ubuntu 16.04 LTS (Xenial Xerus)', 'A1.4')]:
|
||||
# Initialize cloud
|
||||
cloud = shade.openstack_cloud(cloud=cloud_name, region_name=region_name)
|
||||
|
||||
# Boot a server, wait for it to boot, and then do whatever is needed
|
||||
# to get a public ip for it.
|
||||
server = cloud.create_server(
|
||||
'my-server', image=image, flavor=flavor, wait=True, auto_ip=True)
|
||||
print(server.name)
|
||||
print(server['name'])
|
||||
cloud.pprint(server)
|
||||
# Delete it - this is a demo
|
||||
cloud.delete_server(server, wait=True, delete_ips=True)
|
||||
|
||||
cloud.pprint method was just added this morning
|
||||
===============================================
|
||||
|
||||
Delete Servers
|
||||
==============
|
||||
|
||||
* `delete_ips` Delete any `floating_ips` the server may have
|
||||
|
||||
.. code:: python
|
||||
|
||||
cloud.delete_server('my-server', wait=True, delete_ips=True)
|
||||
|
||||
Image and Flavor by Dict
|
||||
========================
|
||||
|
||||
* Pass dict to image/flavor
|
||||
* If you know if the value is Name or ID
|
||||
* Common pattern
|
||||
* doc/source/examples/create-server-dict.py
|
||||
|
||||
.. code:: python
|
||||
|
||||
import shade
|
||||
|
||||
# Initialize and turn on debug logging
|
||||
shade.simple_logging(debug=True)
|
||||
|
||||
for cloud_name, region_name, image, flavor_id in [
|
||||
('my-vexxhost', 'ca-ymq-1', 'Ubuntu 16.04.1 LTS [2017-03-03]',
|
||||
'5cf64088-893b-46b5-9bb1-ee020277635d'),
|
||||
('my-citycloud', 'Buf1', 'Ubuntu 16.04 Xenial Xerus',
|
||||
'0dab10b5-42a2-438e-be7b-505741a7ffcc'),
|
||||
('my-internap', 'ams01', 'Ubuntu 16.04 LTS (Xenial Xerus)',
|
||||
'A1.4')]:
|
||||
# Initialize cloud
|
||||
cloud = shade.openstack_cloud(cloud=cloud_name, region_name=region_name)
|
||||
|
||||
# Boot a server, wait for it to boot, and then do whatever is needed
|
||||
# to get a public ip for it.
|
||||
server = cloud.create_server(
|
||||
'my-server', image=image, flavor=dict(id=flavor_id),
|
||||
wait=True, auto_ip=True)
|
||||
# Delete it - this is a demo
|
||||
cloud.delete_server(server, wait=True, delete_ips=True)
|
||||
|
||||
Munch Objects
|
||||
=============
|
||||
|
||||
* Behave like a dict and an object
|
||||
* doc/source/examples/munch-dict-object.py
|
||||
|
||||
.. code:: python
|
||||
|
||||
import shade
|
||||
shade.simple_logging(debug=True)
|
||||
|
||||
cloud = shade.openstack_cloud(cloud='zetta', region_name='no-osl1')
|
||||
image = cloud.get_image('Ubuntu 14.04 (AMD64) [Local Storage]')
|
||||
print(image.name)
|
||||
print(image['name'])
|
||||
|
||||
API Organized by Logical Resource
|
||||
=================================
|
||||
|
||||
* list_servers
|
||||
* search_servers
|
||||
* get_server
|
||||
* create_server
|
||||
* delete_server
|
||||
* update_server
|
||||
|
||||
For other things, it's still {verb}_{noun}
|
||||
|
||||
* attach_volume
|
||||
* wait_for_server
|
||||
* add_auto_ip
|
||||
|
||||
Cleanup Script
|
||||
==============
|
||||
|
||||
* Sometimes my examples had bugs
|
||||
* doc/source/examples/cleanup-servers.py
|
||||
|
||||
.. code:: python
|
||||
|
||||
import shade
|
||||
|
||||
# Initialize and turn on debug logging
|
||||
shade.simple_logging(debug=True)
|
||||
|
||||
for cloud_name, region_name in [
|
||||
('my-vexxhost', 'ca-ymq-1'),
|
||||
('my-citycloud', 'Buf1'),
|
||||
('my-internap', 'ams01')]:
|
||||
# Initialize cloud
|
||||
cloud = shade.openstack_cloud(cloud=cloud_name, region_name=region_name)
|
||||
for server in cloud.search_servers('my-server'):
|
||||
cloud.delete_server(server, wait=True, delete_ips=True)
|
||||
|
||||
Normalization
|
||||
=============
|
||||
|
||||
* https://docs.openstack.org/shade/latest/user/model.html#image
|
||||
* doc/source/examples/normalization.py
|
||||
|
||||
.. code:: python
|
||||
|
||||
import shade
|
||||
shade.simple_logging()
|
||||
|
||||
cloud = shade.openstack_cloud(cloud='fuga', region_name='cystack')
|
||||
image = cloud.get_image(
|
||||
'Ubuntu 16.04 LTS - Xenial Xerus - 64-bit - Fuga Cloud Based Image')
|
||||
cloud.pprint(image)
|
||||
|
||||
Strict Normalized Results
|
||||
=========================
|
||||
|
||||
* Return only the declared model
|
||||
* doc/source/examples/strict-mode.py
|
||||
|
||||
.. code:: python
|
||||
|
||||
import shade
|
||||
shade.simple_logging()
|
||||
|
||||
cloud = shade.openstack_cloud(
|
||||
cloud='fuga', region_name='cystack', strict=True)
|
||||
image = cloud.get_image(
|
||||
'Ubuntu 16.04 LTS - Xenial Xerus - 64-bit - Fuga Cloud Based Image')
|
||||
cloud.pprint(image)
|
||||
|
||||
How Did I Find the Image Name for the Last Example?
|
||||
===================================================
|
||||
|
||||
* I often make stupid little utility scripts
|
||||
* doc/source/examples/find-an-image.py
|
||||
|
||||
.. code:: python
|
||||
|
||||
import shade
|
||||
shade.simple_logging()
|
||||
|
||||
cloud = shade.openstack_cloud(cloud='fuga', region_name='cystack')
|
||||
cloud.pprint([
|
||||
image for image in cloud.list_images()
|
||||
if 'ubuntu' in image.name.lower()])
|
||||
|
||||
Added / Modified Information
|
||||
============================
|
||||
|
||||
* Servers need more extra help
|
||||
* Fetch addresses dict from neutron
|
||||
* Figure out which IPs are good
|
||||
* `detailed` - defaults to True, add everything
|
||||
* `bare` - no extra calls - don't even fix broken things
|
||||
* `bare` is still normalized
|
||||
* doc/source/examples/server-information.py
|
||||
|
||||
.. code:: python
|
||||
|
||||
import shade
|
||||
shade.simple_logging(debug=True)
|
||||
|
||||
cloud = shade.openstack_cloud(cloud='my-citycloud', region_name='Buf1')
|
||||
try:
|
||||
server = cloud.create_server(
|
||||
'my-server', image='Ubuntu 16.04 Xenial Xerus',
|
||||
flavor=dict(id='0dab10b5-42a2-438e-be7b-505741a7ffcc'),
|
||||
wait=True, auto_ip=True)
|
||||
|
||||
print("\n\nFull Server\n\n")
|
||||
cloud.pprint(server)
|
||||
|
||||
print("\n\nTurn Detailed Off\n\n")
|
||||
cloud.pprint(cloud.get_server('my-server', detailed=False))
|
||||
|
||||
print("\n\nBare Server\n\n")
|
||||
cloud.pprint(cloud.get_server('my-server', bare=True))
|
||||
|
||||
finally:
|
||||
# Delete it - this is a demo
|
||||
cloud.delete_server(server, wait=True, delete_ips=True)
|
||||
|
||||
Exceptions
|
||||
==========
|
||||
|
||||
* All shade exceptions are subclasses of `OpenStackCloudException`
|
||||
* Direct REST calls throw `OpenStackCloudHTTPError`
|
||||
* `OpenStackCloudHTTPError` subclasses `OpenStackCloudException`
|
||||
and `requests.exceptions.HTTPError`
|
||||
* `OpenStackCloudURINotFound` for 404
|
||||
* `OpenStackCloudBadRequest` for 400
|
||||
|
||||
User Agent Info
|
||||
===============
|
||||
|
||||
* Set `app_name` and `app_version` for User Agents
|
||||
* (sssh ... `region_name` is optional if the cloud has one region)
|
||||
* doc/source/examples/user-agent.py
|
||||
|
||||
.. code:: python
|
||||
|
||||
import shade
|
||||
shade.simple_logging(http_debug=True)
|
||||
|
||||
cloud = shade.openstack_cloud(
|
||||
cloud='datacentred', app_name='AmazingApp', app_version='1.0')
|
||||
cloud.list_networks()
|
||||
|
||||
Uploading Large Objects
|
||||
=======================
|
||||
|
||||
* swift has a maximum object size
|
||||
* Large Objects are uploaded specially
|
||||
* shade figures this out and does it
|
||||
* multi-threaded
|
||||
* doc/source/examples/upload-object.py
|
||||
|
||||
.. code:: python
|
||||
|
||||
import shade
|
||||
shade.simple_logging(debug=True)
|
||||
|
||||
cloud = shade.openstack_cloud(cloud='ovh', region_name='SBG1')
|
||||
cloud.create_object(
|
||||
container='my-container', name='my-object',
|
||||
filename='/home/mordred/briarcliff.sh3d')
|
||||
cloud.delete_object('my-container', 'my-object')
|
||||
cloud.delete_container('my-container')
|
||||
|
||||
Uploading Large Objects
|
||||
=======================
|
||||
|
||||
* Default max_file_size is 5G
|
||||
* This is a conference demo
|
||||
* Let's force a segment_size
|
||||
* One MILLION bytes
|
||||
* doc/source/examples/upload-object.py
|
||||
|
||||
.. code:: python
|
||||
|
||||
import shade
|
||||
shade.simple_logging(debug=True)
|
||||
|
||||
cloud = shade.openstack_cloud(cloud='ovh', region_name='SBG1')
|
||||
cloud.create_object(
|
||||
container='my-container', name='my-object',
|
||||
filename='/home/mordred/briarcliff.sh3d',
|
||||
segment_size=1000000)
|
||||
cloud.delete_object('my-container', 'my-object')
|
||||
cloud.delete_container('my-container')
|
||||
|
||||
Service Conditionals
|
||||
====================
|
||||
|
||||
.. code:: python
|
||||
|
||||
import shade
|
||||
shade.simple_logging(debug=True)
|
||||
|
||||
cloud = shade.openstack_cloud(cloud='kiss', region_name='region1')
|
||||
print(cloud.has_service('network'))
|
||||
print(cloud.has_service('container-orchestration'))
|
||||
|
||||
Service Conditional Overrides
|
||||
=============================
|
||||
|
||||
* Sometimes clouds are weird and figuring that out won't work
|
||||
|
||||
.. code:: python
|
||||
|
||||
import shade
|
||||
shade.simple_logging(debug=True)
|
||||
|
||||
cloud = shade.openstack_cloud(cloud='rax', region_name='DFW')
|
||||
print(cloud.has_service('network'))
|
||||
|
||||
.. code:: yaml
|
||||
|
||||
clouds:
|
||||
rax:
|
||||
profile: rackspace
|
||||
auth:
|
||||
username: mordred
|
||||
project_id: 245018
|
||||
# This is already in profile: rackspace
|
||||
has_network: false
|
||||
|
||||
Coming Soon
|
||||
===========
|
||||
|
||||
* Completion of RESTification
|
||||
* Full version discovery support
|
||||
* Multi-cloud facade layer
|
||||
* Microversion support (talk tomorrow)
|
||||
* Completion of caching tier (talk tomorrow)
|
||||
* All of you helping hacking on shade!!! (we're friendly)
|
||||
@@ -1,21 +0,0 @@
|
||||
=====
|
||||
Usage
|
||||
=====
|
||||
|
||||
To use shade in a project:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import shade
|
||||
|
||||
For a simple example, see :ref:`usage_example`.
|
||||
|
||||
.. note::
|
||||
API methods that return a description of an OpenStack resource (e.g.,
|
||||
server instance, image, volume, etc.) do so using a `munch.Munch` object
|
||||
from the `Munch library <https://github.com/Infinidat/munch>`_. `Munch`
|
||||
objects can be accessed using either dictionary or object notation
|
||||
(e.g., ``server.id``, ``image.name`` and ``server['id']``, ``image['name']``)
|
||||
|
||||
.. autoclass:: shade.OpenStackCloud
|
||||
:members:
|
||||
@@ -1,14 +0,0 @@
|
||||
neutron router-gateway-clear router1
|
||||
neutron router-interface-delete router1
|
||||
for subnet in private-subnet ipv6-private-subnet ; do
|
||||
neutron router-interface-delete router1 $subnet
|
||||
subnet_id=$(neutron subnet-show $subnet -f value -c id)
|
||||
neutron port-list | grep $subnet_id | awk '{print $2}' | xargs -n1 neutron port-delete
|
||||
neutron subnet-delete $subnet
|
||||
done
|
||||
neutron router-delete router1
|
||||
neutron net-delete private
|
||||
|
||||
# Make the public network directly consumable
|
||||
neutron subnet-update public-subnet --enable-dhcp=True
|
||||
neutron net-update public --shared=True
|
||||
@@ -1,31 +0,0 @@
|
||||
#!/bin/bash
|
||||
# Copyright (c) 2017 Red Hat, Inc.
|
||||
#
|
||||
# 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.
|
||||
|
||||
for lib in \
|
||||
python-keystoneclient \
|
||||
os-client-config \
|
||||
keystoneauth
|
||||
do
|
||||
egg=$(echo $lib | tr '-' '_' | sed 's/python-//')
|
||||
if [ -d /opt/stack/new/$lib ] ; then
|
||||
tip_location="git+file:///opt/stack/new/$lib#egg=$egg"
|
||||
echo "$(which pip) install -U -e $tip_location"
|
||||
pip uninstall -y $lib
|
||||
pip install -U -e $tip_location
|
||||
else
|
||||
echo "$lib not found in /opt/stack/new/$lib"
|
||||
fi
|
||||
done
|
||||
@@ -1,70 +0,0 @@
|
||||
#!/bin/bash
|
||||
#############################################################################
|
||||
# run-ansible-tests.sh
|
||||
#
|
||||
# Script used to setup a tox environment for running Ansible. This is meant
|
||||
# to be called by tox (via tox.ini). To run the Ansible tests, use:
|
||||
#
|
||||
# tox -e ansible [TAG ...]
|
||||
# or
|
||||
# tox -e ansible -- -c cloudX [TAG ...]
|
||||
#
|
||||
# USAGE:
|
||||
# run-ansible-tests.sh -e ENVDIR [-c CLOUD] [TAG ...]
|
||||
#
|
||||
# PARAMETERS:
|
||||
# -e ENVDIR Directory of the tox environment to use for testing.
|
||||
# -c CLOUD Name of the cloud to use for testing.
|
||||
# Defaults to "devstack-admin".
|
||||
# [TAG ...] Optional list of space-separated tags to control which
|
||||
# modules are tested.
|
||||
#
|
||||
# EXAMPLES:
|
||||
# # Run all Ansible tests
|
||||
# run-ansible-tests.sh -e ansible
|
||||
#
|
||||
# # Run auth, keypair, and network tests against cloudX
|
||||
# run-ansible-tests.sh -e ansible -c cloudX auth keypair network
|
||||
#############################################################################
|
||||
|
||||
|
||||
CLOUD="devstack-admin"
|
||||
ENVDIR=
|
||||
|
||||
while getopts "c:de:" opt
|
||||
do
|
||||
case $opt in
|
||||
c) CLOUD=${OPTARG} ;;
|
||||
e) ENVDIR=${OPTARG} ;;
|
||||
?) echo "Invalid option: -${OPTARG}"
|
||||
exit 1;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ -z ${ENVDIR} ]
|
||||
then
|
||||
echo "Option -e is required"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
shift $((OPTIND-1))
|
||||
TAGS=$( echo "$*" | tr ' ' , )
|
||||
|
||||
# Run the shade Ansible tests
|
||||
tag_opt=""
|
||||
if [ ! -z ${TAGS} ]
|
||||
then
|
||||
tag_opt="--tags ${TAGS}"
|
||||
fi
|
||||
|
||||
# Until we have a module that lets us determine the image we want from
|
||||
# within a playbook, we have to find the image here and pass it in.
|
||||
# We use the openstack client instead of nova client since it can use clouds.yaml.
|
||||
IMAGE=`openstack --os-cloud=${CLOUD} image list -f value -c Name | grep cirros | grep -v -e ramdisk -e kernel`
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
echo "Failed to find Cirros image"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ansible-playbook -vvv ./shade/tests/ansible/run.yml -e "cloud=${CLOUD} image=${IMAGE}" ${tag_opt}
|
||||
@@ -1,43 +0,0 @@
|
||||
appdirs==1.4.3
|
||||
certifi==2018.1.18
|
||||
chardet==3.0.4
|
||||
coverage==4.0
|
||||
decorator==4.2.1
|
||||
deprecation==2.0
|
||||
dogpile.cache==0.6.5
|
||||
extras==1.0.0
|
||||
fixtures==3.0.0
|
||||
future==0.16.0
|
||||
idna==2.6
|
||||
iso8601==0.1.12
|
||||
jmespath==0.9.3
|
||||
jsonpatch==1.21
|
||||
jsonpointer==2.0
|
||||
keystoneauth1==3.8.0
|
||||
linecache2==1.0.0
|
||||
mock==2.0.0
|
||||
mox3==0.20.0
|
||||
munch==2.2.0
|
||||
netifaces==0.10.6
|
||||
openstacksdk==0.15.0
|
||||
os-client-config==1.28.0
|
||||
os-service-types==1.2.0
|
||||
oslotest==3.2.0
|
||||
packaging==17.1
|
||||
pbr==2.0.0
|
||||
pyparsing==2.2.0
|
||||
python-mimeparse==1.6.0
|
||||
python-subunit==1.0.0
|
||||
PyYAML==3.12
|
||||
requests-mock==1.2.0
|
||||
requests==2.18.4
|
||||
requestsexceptions==1.4.0
|
||||
six==1.11.0
|
||||
stestr==1.0.0
|
||||
stevedore==1.28.0
|
||||
testrepository==0.0.18
|
||||
testscenarios==0.4
|
||||
testtools==2.2.0
|
||||
traceback2==1.4.0
|
||||
unittest2==1.1.0
|
||||
urllib3==1.22
|
||||
@@ -1,10 +0,0 @@
|
||||
- hosts: all
|
||||
tasks:
|
||||
|
||||
- name: Set shade libraries to master branch before functional tests
|
||||
command: git checkout master
|
||||
args:
|
||||
chdir: "src/opendev.org/openstack/{{ item }}"
|
||||
with_items:
|
||||
- keystoneauth
|
||||
- os-client-config
|
||||
@@ -1,4 +0,0 @@
|
||||
- hosts: all
|
||||
roles:
|
||||
- fetch-tox-output
|
||||
- fetch-subunit-output
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
features:
|
||||
- Added a new property, 'current_user_id' which contains
|
||||
the id of the currently authenticated user from the token.
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
features:
|
||||
- All get and search functions can now take a jmespath expression in their
|
||||
filters parameter.
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
features:
|
||||
- Add a list_flavor_access method to list all
|
||||
the projects/tenants allowed to access a given flavor.
|
||||
@@ -1,6 +0,0 @@
|
||||
---
|
||||
features:
|
||||
- Added get_server_console method to fetch the console
|
||||
log from a Server. On clouds that do not expose this
|
||||
feature, a debug line will be logged and an empty
|
||||
string will be returned.
|
||||
@@ -1,9 +0,0 @@
|
||||
---
|
||||
features:
|
||||
- Added flag "show_all" to list_images. The behavior of
|
||||
Glance v2 to only show shared images if they have been
|
||||
accepted by the user can be confusing, and the only way
|
||||
to change it is to use search_images(filters=dict(member_status='all'))
|
||||
which isn't terribly obvious. "show_all=True" will set
|
||||
that flag, as well as disabling the filtering of images
|
||||
in "deleted" state.
|
||||
@@ -1,9 +0,0 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
The networking API v2 specification, which is implemented by OpenStack
|
||||
Neutron, features an optional routes parameter - when updating a router
|
||||
(PUT requests). Static routes are crucial for routers to handle traffic
|
||||
from subnets not directly connected to a router. The routes parameter has
|
||||
now been added to the OpenStackCloud.update_router method as a list of
|
||||
dictionaries with destination and nexthop parameters.
|
||||
@@ -1,3 +0,0 @@
|
||||
---
|
||||
features:
|
||||
- Add description parameter to create_user, available on Keystone v3
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
features:
|
||||
- Add support for Designate recordsets resources, with the
|
||||
usual methods (search/list/get/create/update/delete).
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
features:
|
||||
- Add support for Designate zones resources, with the
|
||||
usual methods (search/list/get/create/update/delete).
|
||||
@@ -1,7 +0,0 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
Add tags support when creating a stack, as specified by the openstack
|
||||
orchestration api at [1]
|
||||
|
||||
[1]https://developer.openstack.org/api-ref/orchestration/v1/#create-stack
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
features:
|
||||
- Add support for host aggregates and host aggregate
|
||||
membership.
|
||||
@@ -1,7 +0,0 @@
|
||||
---
|
||||
features:
|
||||
- Add support for Magnum baymodels, with the
|
||||
usual methods (search/list/get/create/update/delete). Due to upcoming
|
||||
rename in Magnum from baymodel to cluster_template, the shade
|
||||
functionality uses the term cluster_template. However, baymodel aliases
|
||||
are provided for each api call.
|
||||
@@ -1,3 +0,0 @@
|
||||
---
|
||||
features:
|
||||
- Add support for listing Magnum services.
|
||||
@@ -1,3 +0,0 @@
|
||||
---
|
||||
features:
|
||||
- Adds support to create and delete server groups.
|
||||
@@ -1,3 +0,0 @@
|
||||
---
|
||||
features:
|
||||
- Add update_server method to update name or description of a server.
|
||||
@@ -1,6 +0,0 @@
|
||||
---
|
||||
features:
|
||||
- Add the ability to update a keystone service information. This feature is
|
||||
not available on keystone v2.0. The new function, update_service(), allows
|
||||
the user to update description, name of service, service type, and enabled
|
||||
status.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
features:
|
||||
- Added methods for making new cloud connections
|
||||
based on the current OpenStackCloud. This should enable working
|
||||
more easily across projects or user accounts.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
upgrade:
|
||||
- Cluster Templates have data model and normalization
|
||||
now. As a result, the detail parameter is now ignored
|
||||
and detailed records are always returned.
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
features:
|
||||
- Added ``group`` parameter to create_server to allow
|
||||
booting a server into a specific server group.
|
||||
@@ -1,10 +0,0 @@
|
||||
---
|
||||
prelude: >
|
||||
Fixed a bug where a project was always enabled upon update, unless
|
||||
``enabled=False`` is passed explicitly.
|
||||
fixes:
|
||||
- |
|
||||
[`bug 2001080 <https://storyboard.openstack.org/#!/story/2001080>`_]
|
||||
Project update will only update the enabled field of projects when
|
||||
``enabled=True`` or ``enabled=False`` is passed explicitly. The previous
|
||||
behavior had ``enabled=True`` as the default.
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
fixes:
|
||||
- Fixed caching the volume list when volumes are in
|
||||
use.
|
||||
@@ -1,8 +0,0 @@
|
||||
---
|
||||
upgrade:
|
||||
- |
|
||||
The ``attach_volume`` method now always returns a ``volume_attachment``
|
||||
object. Previously, ``attach_volume`` would return a ``volume`` object if
|
||||
it was called with ``wait=True`` and a ``volume_attachment`` object
|
||||
otherwise.
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
features:
|
||||
- Add support for Cinder volume backup resources, with the
|
||||
usual methods (search/list/get/create/delete).
|
||||
@@ -1,3 +0,0 @@
|
||||
---
|
||||
fixes:
|
||||
- Fixed the volume normalization function when used with cinder v2.
|
||||
@@ -1,6 +0,0 @@
|
||||
---
|
||||
features:
|
||||
- If shade has to create objects in swift to upload an
|
||||
image, it will now delete those objects upon successful
|
||||
image creation as they are no longer needed. They will
|
||||
also be deleted on fatal import errors.
|
||||
@@ -1,3 +0,0 @@
|
||||
---
|
||||
features:
|
||||
- Add new APIs, OperatorCloud.get_compute_quotas(), OperatorCloud.set_compute_quotas() and OperatorCloud.delete_compute_quotas() to manage nova quotas for projects and users
|
||||
@@ -1,9 +0,0 @@
|
||||
---
|
||||
features:
|
||||
- get_compute_usage now has a default value for the start
|
||||
parameter of 2010-07-06. That was the date the OpenStack
|
||||
project started. It's completely impossible for someone
|
||||
to have Nova usage data that goes back further in time.
|
||||
Also, both the start and end date parameters now also
|
||||
accept strings which will be parsed and timezones will
|
||||
be properly converted to UTC which is what Nova expects.
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
features:
|
||||
- Adds ability to add a config setting to clouds.yaml to
|
||||
disable fetching extra_specs from flavors.
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
fixes:
|
||||
- The create_stack() call was fixed to call the correct iterator
|
||||
method and to return the updated stack object when waiting.
|
||||
@@ -1,6 +0,0 @@
|
||||
---
|
||||
fixes:
|
||||
- The create_server() API call would not use the supplied 'network'
|
||||
parameter if the 'nics' parameter was also supplied, even though it would
|
||||
be an empty list. It now uses 'network' if 'nics' is not supplied or if
|
||||
it is an empty list.
|
||||
@@ -1,3 +0,0 @@
|
||||
---
|
||||
fixes:
|
||||
- The returned data from a create_service() call was not being normalized.
|
||||
@@ -1,8 +0,0 @@
|
||||
---
|
||||
features:
|
||||
- Explicit data model contracts are now defined for
|
||||
Flavors, Images, Security Groups, Security Group Rules,
|
||||
and Servers.
|
||||
- Resources with data model contracts are now being returned with
|
||||
'location' attribute. The location carries cloud name, region
|
||||
name and information about the project that owns the resource.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
features:
|
||||
- Added new method, delete_autocreated_image_objects
|
||||
that can be used to delete any leaked objects shade
|
||||
may have created on behalf of the user.
|
||||
@@ -1,18 +0,0 @@
|
||||
---
|
||||
fixes:
|
||||
- Delete swift objects uploaded in service of uploading images
|
||||
at the time that the corresponding image is deleted. On some clouds,
|
||||
image uploads are accomplished by uploading the image to swift and
|
||||
then running a task-import. As shade does this action on behalf of the
|
||||
user, it is not reasonable to assume that the user would then be aware
|
||||
of or manage the swift objects shade created, which led to an ongoing
|
||||
leak of swift objects.
|
||||
- Upload swift Large Objects as Static Large Objects by default. Shade
|
||||
automatically uploads objects as Large Objects when they are over a
|
||||
segment_size threshold. It had been doing this as Dynamic Large Objects,
|
||||
which sound great, but which have the downside of not deleting their
|
||||
sub-segments when the primary object is deleted. Since nothing in the
|
||||
shade interface exposes that the object was segmented, the user would not
|
||||
know they would also need to find and delete the segments. Instead, we
|
||||
now upload as Static Large Objects which behave as expected and delete
|
||||
segments when the object is deleted.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
fixes:
|
||||
- The delete_object() method was not returning True/False,
|
||||
similar to other delete methods. It is now consistent with
|
||||
the other delete APIs.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
fixes:
|
||||
- The delete_project() API now conforms to our standard of returning True
|
||||
when the delete succeeds, or False when the project was not found. It
|
||||
would previously raise an expection if the project was not found.
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
features:
|
||||
- Added name_or_id parameter to domain operations, allowing
|
||||
an admin to update/delete/get by domain name.
|
||||
@@ -1,8 +0,0 @@
|
||||
---
|
||||
features:
|
||||
- Added support for dual stack networks where the IPv4 subnet and the
|
||||
IPv6 subnet have opposite public/private qualities. It is now possible
|
||||
to add configuration to clouds.yaml that will indicate that a network
|
||||
is public for v6 and private for v4, which is otherwise very difficult
|
||||
to correctly infer while setting server attributes like private_v4,
|
||||
public_v4 and public_v6.
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
features:
|
||||
- Add new method, 'endpoint_for' which will return the
|
||||
raw endpoint for a given service from the current catalog.
|
||||
@@ -1,6 +0,0 @@
|
||||
---
|
||||
fixes:
|
||||
- delete_image used to fail with an AttributeError if an invalid image
|
||||
name or id was passed, rather than returning False which was the
|
||||
intent. This is worthy of note because it's a behavior change, but the
|
||||
previous behavior was a bug.
|
||||
@@ -1,3 +0,0 @@
|
||||
---
|
||||
features:
|
||||
- Add new APIs, OpenStackCloud.set_server_metadata() and OpenStackCloud.delete_server_metadata() to manage metadata of existing nova compute instances
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
fixes:
|
||||
- When creating a new server, the timeout was not being passed through to
|
||||
floating IP creation, which could also timeout.
|
||||
@@ -1,6 +0,0 @@
|
||||
---
|
||||
issues:
|
||||
- Fixed an issue where nodepool could cause config_drive
|
||||
to be passed explicitly as None, which was getting directly
|
||||
passed through to the JSON. Also fix the same logic for key_name
|
||||
and scheduler_hints while we're in there.
|
||||
@@ -1,6 +0,0 @@
|
||||
---
|
||||
issues:
|
||||
- Fixed the logic in delete_ips and added regression
|
||||
tests to cover it. The old logic was incorrectly looking
|
||||
for floating ips using port syntax. It was also not
|
||||
swallowing errors when it should.
|
||||
@@ -1,3 +0,0 @@
|
||||
---
|
||||
fixes:
|
||||
- Fix for list_networks() ignoring any filters.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
fixes:
|
||||
- Added missing dependency on futures library for python 2.
|
||||
The depend was missed in testing due to it having been listed
|
||||
in test-requirements already.
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
issues:
|
||||
- Images in the cloud with a string property named "properties"
|
||||
caused image normalization to bomb.
|
||||
@@ -1,7 +0,0 @@
|
||||
---
|
||||
fixes:
|
||||
- Fixed an issue where shade could report a floating IP being attached
|
||||
to a server erroneously due to only matching on fixed ip. Changed the
|
||||
lookup to match on port ids. This adds an API call in the case where
|
||||
the workaround is needed because of a bug in the cloud, but in most
|
||||
cases it should have no difference.
|
||||
@@ -1,3 +0,0 @@
|
||||
---
|
||||
fixes:
|
||||
- Fix for update_domain() where 'name' was not updatable.
|
||||
@@ -1,6 +0,0 @@
|
||||
---
|
||||
fixes:
|
||||
- Fixed magnum service_type. shade was using it as 'container'
|
||||
but the correct type is 'container-infra'. It's possible that on
|
||||
old clouds with magnum shade may now do the wrong thing. If that
|
||||
occurs, please file a bug.
|
||||
@@ -1,7 +0,0 @@
|
||||
---
|
||||
features:
|
||||
- Flavors will always contain an 'extra_specs' attribute. Client cruft,
|
||||
such as 'links', 'HUMAN_ID', etc. has been removed.
|
||||
fixes:
|
||||
- Setting and unsetting flavor extra specs now works. This had
|
||||
been broken since the 1.2.0 release.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
features:
|
||||
- name_or_id parameters to search/get methods now support
|
||||
filename-like globbing. This means search_servers('nb0*')
|
||||
will return all servers whose names start with 'nb0'.
|
||||
@@ -1,3 +0,0 @@
|
||||
---
|
||||
features:
|
||||
- Allow to retrieve the limits of a specific project
|
||||
@@ -1,3 +0,0 @@
|
||||
---
|
||||
features:
|
||||
- Allow to retrieve the usage of a specific project
|
||||
Loaded 100 of 341 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user