docs: Replace/remove shade-specific docs
Lots of minor tweaks, none of them worthy of their own change. Change-Id: Iba8649b8e12f367760849fd185cf76b94b703706 Signed-off-by: Stephen Finucane <stephenfin@redhat.com>
This commit is contained in:
@@ -1,24 +1,25 @@
|
||||
========================================
|
||||
OpenStack SDK 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 openstacksdk API at least *attempted* to display some form of consistency.
|
||||
the *openstacksdk* API at least *attempted* to display some form of
|
||||
consistency.
|
||||
|
||||
Thus, these coding standards/guidelines were developed. Note that not
|
||||
all of openstacksdk adheres to these standards just yet. Some older code has
|
||||
all of *openstacksdk* 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 openstacksdk developers to follow.
|
||||
Below are the patterns that we expect *openstacksdk* developers to follow.
|
||||
|
||||
|
||||
Release Notes
|
||||
=============
|
||||
-------------
|
||||
|
||||
openstacksdk uses `reno <https://docs.openstack.org/reno/latest/>`_ for
|
||||
*openstacksdk* 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
|
||||
@@ -29,56 +30,47 @@ 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.
|
||||
|
||||
|
||||
Exceptions
|
||||
==========
|
||||
----------
|
||||
|
||||
Exceptions should NEVER be wrapped and re-raised inside of a new exception.
|
||||
This removes important debug information from the user. All of the exceptions
|
||||
should be raised correctly the first time.
|
||||
|
||||
openstack.cloud API Methods
|
||||
===========================
|
||||
|
||||
The `openstack.cloud` layer has some specific rules:
|
||||
openstack.cloud API Methods
|
||||
---------------------------
|
||||
|
||||
The ``openstack.cloud`` layer has some specific rules:
|
||||
|
||||
- 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()`.
|
||||
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).
|
||||
- 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.
|
||||
parameters, use the ``_utils.valid_kwargs`` decorator. This includes all
|
||||
Neutron ``update_*`` functions.
|
||||
|
||||
- Deleting a resource should return True if the delete succeeded, or False
|
||||
if the resource was not found.
|
||||
|
||||
Returned Resources
|
||||
------------------
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Complex objects returned to the caller must be a `openstack.resource.Resource`
|
||||
type.
|
||||
|
||||
All objects should be normalized. It is openstacksdk's purpose in life to make
|
||||
OpenStack consistent for end users, and this means not trusting the clouds
|
||||
to return consistent objects. The `Resource` object should do this for us.
|
||||
|
||||
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 `openstack.cloud`. For instance, nothing in `openstack.cloud`
|
||||
exposes the legacy OpenStack concept of "tenant" to a user, but instead uses
|
||||
"project" even if the cloud in question uses tenant.
|
||||
The ``openstack.cloud`` layer should rely on the proxy layer for the given
|
||||
service. This will ensure complex objects returned to the caller are of
|
||||
``openstack.resource.Resource`` type.
|
||||
|
||||
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
|
||||
@@ -86,16 +78,17 @@ Nova vs. Neutron
|
||||
|
||||
- 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.
|
||||
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 openstacksdk itself should be considered legacy and to be
|
||||
- New unit tests should only mock at the REST layer using ``requests_mock``.
|
||||
Any mocking of *openstacksdk* itself should be considered legacy and to be
|
||||
avoided. Exceptions to this rule can be made when attempting to test the
|
||||
internals of a logical shim where the inputs and output of the method aren't
|
||||
actually impacted by remote content.
|
||||
|
@@ -1,45 +1,46 @@
|
||||
A Brief History
|
||||
===============
|
||||
|
||||
openstacksdk started its life as three different libraries: shade,
|
||||
os-client-config and python-openstacksdk.
|
||||
*openstacksdk* started its life as three different libraries: *shade*,
|
||||
*os-client-config* and *python-openstacksdk*.
|
||||
|
||||
``shade`` started its life as some code inside of OpenStack Infra's `nodepool`_
|
||||
project, and as some code inside of the `Ansible OpenStack Modules`_.
|
||||
Ansible had 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 the 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.
|
||||
*shade*
|
||||
*shade* started its life as some code inside of OpenStack Infra's `nodepool`_
|
||||
project, and as some code inside of the `Ansible OpenStack Modules`_.
|
||||
Ansible had 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 the 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.
|
||||
|
||||
Because of its background from nodepool, shade contained abstractions to
|
||||
work around deployment differences and is resource oriented rather than service
|
||||
oriented. This allows a user to think about Security Groups without having to
|
||||
know whether Security Groups are provided by Nova or Neutron on a given cloud.
|
||||
On the other hand, as an interface that provides an abstraction, it deviates
|
||||
from the published OpenStack REST API and adds its own opinions, which may not
|
||||
get in the way of more advanced users with specific needs.
|
||||
Because of its background from nodepool, *shade* contained abstractions to
|
||||
work around deployment differences and is resource oriented rather than
|
||||
service oriented. This allows a user to think about Security Groups without
|
||||
having to know whether Security Groups are provided by Nova or Neutron on a
|
||||
given cloud. On the other hand, as an interface that provides an abstraction,
|
||||
it deviates from the published OpenStack REST API and adds its own opinions,
|
||||
which may not get in the way of more advanced users with specific needs.
|
||||
|
||||
``os-client-config`` was a library for collecting client configuration for
|
||||
using an OpenStack cloud in a consistent and comprehensive manner, which
|
||||
introduced the ``clouds.yaml`` file for expressing named cloud configurations.
|
||||
*os-client-config*
|
||||
*os-client-config* was a library for collecting client configuration for
|
||||
using an OpenStack cloud in a consistent and comprehensive manner, which
|
||||
introduced the ``clouds.yaml`` file for expressing named cloud
|
||||
configurations.
|
||||
|
||||
``python-openstacksdk`` was a library that exposed the OpenStack APIs to
|
||||
developers in a consistent and predictable manner.
|
||||
*python-openstacksdk*
|
||||
*python-openstacksdk* was a library that exposed the OpenStack APIs to
|
||||
developers in a consistent and predictable manner.
|
||||
|
||||
After a while it became clear that there was value in both the high-level
|
||||
layer that contains additional business logic and the lower-level SDK that
|
||||
exposes services and their resources faithfully and consistently as Python
|
||||
objects.
|
||||
objects. Even with both of those layers, it is still beneficial at times to be
|
||||
able to make direct REST calls and to do so with the same properly configured
|
||||
`Session`_ from `python-requests`_. This led to the merge of the three
|
||||
projects.
|
||||
|
||||
Even with both of those layers, it is still beneficial at times to be able to
|
||||
make direct REST calls and to do so with the same properly configured
|
||||
`Session`_ from `python-requests`_.
|
||||
|
||||
This led to the merge of the three projects.
|
||||
|
||||
The original contents of the shade library have been moved into
|
||||
``openstack.cloud`` and os-client-config has been moved in to
|
||||
The original contents of the *shade* library have been moved into
|
||||
``openstack.cloud`` and *os-client-config* has been moved in to
|
||||
``openstack.config``.
|
||||
|
||||
.. _nodepool: https://docs.openstack.org/infra/nodepool/
|
||||
|
@@ -1,4 +1,3 @@
|
||||
=================================
|
||||
Contributing to the OpenStack SDK
|
||||
=================================
|
||||
|
||||
|
@@ -80,9 +80,12 @@ method. For the time being, it simply passes on the ``Adapter`` maintained
|
||||
by the ``Proxy``, and returns what the underlying ``Resource.list`` method
|
||||
does.
|
||||
|
||||
The implementations and method signatures of ``Proxy`` methods are currently
|
||||
under construction, as we figure out the best way to implement them in a
|
||||
way which will apply nicely across all of the services.
|
||||
Cloud
|
||||
-----
|
||||
|
||||
.. todo
|
||||
|
||||
TODO.
|
||||
|
||||
Connection
|
||||
----------
|
||||
@@ -93,7 +96,7 @@ higher level interface constructed of ``Proxy`` objects from each of the
|
||||
services.
|
||||
|
||||
The ``Connection`` class' primary purpose is to act as a high-level interface
|
||||
to this SDK, managing the lower level connecton bits and exposing the
|
||||
to this SDK, managing the lower level connection bits and exposing the
|
||||
``Resource`` objects through their corresponding `Proxy`_ object.
|
||||
|
||||
If you've built proper ``Resource`` objects and implemented methods on the
|
||||
|
@@ -5,20 +5,18 @@ Required Tools
|
||||
--------------
|
||||
|
||||
Python
|
||||
******
|
||||
~~~~~~
|
||||
|
||||
As the OpenStack SDK is developed in Python, you will need at least one
|
||||
version of Python installed. It is strongly preferred that you have at least
|
||||
one of version 2 and one of version 3 so that your tests are run against both.
|
||||
Our continuous integration system runs against several versions, so ultimately
|
||||
we will have the proper test coverage, but having multiple versions locally
|
||||
results in less time spent in code review when changes unexpectedly break
|
||||
other versions.
|
||||
version of Python installed. Our continuous integration system runs against
|
||||
several versions, so ultimately we will have the proper test coverage, but
|
||||
having multiple versions locally results in less time spent in code review when
|
||||
changes unexpectedly break other versions.
|
||||
|
||||
Python can be downloaded from https://www.python.org/downloads.
|
||||
|
||||
virtualenv
|
||||
**********
|
||||
~~~~~~~~~~
|
||||
|
||||
In order to isolate our development environment from the system-based Python
|
||||
installation, we use `virtualenv <https://virtualenv.pypa.io/en/latest/>`_.
|
||||
@@ -28,9 +26,9 @@ Virtualenv must be installed on your system in order to use it, and it can be
|
||||
had from PyPI, via pip, as follows. Note that you may need to run this
|
||||
as an administrator in some situations.::
|
||||
|
||||
$ apt-get install python-virtualenv # Debian based platforms
|
||||
$ yum install python-virtualenv # Red Hat based platforms
|
||||
$ pip install virtualenv # Mac OS X and other platforms
|
||||
$ apt-get install python3-virtualenv # Debian based platforms
|
||||
$ dnf install python3-virtualenv # Red Hat based platforms
|
||||
$ pip install virtualenv # Mac OS X and other platforms
|
||||
|
||||
You can create a virtualenv in any location. A common usage is to store all
|
||||
of your virtualenvs in the same place, such as under your home directory.
|
||||
@@ -40,7 +38,7 @@ To create a virtualenv for the default Python, run the following::
|
||||
|
||||
To create an environment for a different version, run the following::
|
||||
|
||||
$ virtualenv -p python3.8 $HOME/envs/sdk3
|
||||
$ virtualenv -p python3 $HOME/envs/sdk3
|
||||
|
||||
When you want to enable your environment so that you can develop inside of it,
|
||||
you *activate* it. To activate an environment, run the /bin/activate
|
||||
@@ -54,7 +52,7 @@ command prompt. In order to exit that environment, run the ``deactivate``
|
||||
command.
|
||||
|
||||
tox
|
||||
***
|
||||
~~~
|
||||
|
||||
We use `tox <https://tox.readthedocs.org/en/latest/>`_ as our test runner,
|
||||
which allows us to run the same test commands against multiple versions
|
||||
@@ -64,7 +62,7 @@ run the following to install ``tox`` into it.::
|
||||
(sdk3)$ pip install tox
|
||||
|
||||
Git
|
||||
***
|
||||
~~~
|
||||
|
||||
The source of the OpenStack SDK is stored in Git. In order to work with our
|
||||
source repository, you must have Git installed on your system. If your
|
||||
|
@@ -1,4 +1,3 @@
|
||||
============
|
||||
openstacksdk
|
||||
============
|
||||
|
||||
|
@@ -1,4 +1,3 @@
|
||||
==================
|
||||
Installation guide
|
||||
==================
|
||||
|
||||
|
@@ -1,4 +1,3 @@
|
||||
=============
|
||||
Release Notes
|
||||
=============
|
||||
|
||||
|
@@ -1,4 +1,3 @@
|
||||
=======================
|
||||
Using the OpenStack SDK
|
||||
=======================
|
||||
|
||||
|
@@ -1,4 +1,3 @@
|
||||
=============
|
||||
Microversions
|
||||
=============
|
||||
|
||||
|
@@ -1,46 +1,47 @@
|
||||
==========
|
||||
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.
|
||||
*openstacksdk* has a very strict policy on not breaking backwards compatibility
|
||||
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 an openstacksdk 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.
|
||||
To combat that, openstacksdk 'normalizes' the return structure from OpenStack
|
||||
in many places, and the results of that normalization are listed below. Where
|
||||
openstacksdk 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
|
||||
openstacksdk'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.
|
||||
Some OpenStack objects allow for arbitrary attributes at the root of the
|
||||
object. openstacksdk will pass those through so as not to break anyone who may
|
||||
be counting on them, but as they are arbitrary openstacksdk can make no
|
||||
guarantees as to their existence. As part of normalization, openstacksdk 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.
|
||||
If a user passes ``strict=True`` to the openstacksdk constructor, openstacksdk
|
||||
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 openstacksdk data model
|
||||
contract will not wind up with an entry in properties - only keys that are
|
||||
unknown.
|
||||
|
||||
Location
|
||||
--------
|
||||
The ``location`` field
|
||||
----------------------
|
||||
|
||||
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,
|
||||
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
|
||||
@@ -50,491 +51,16 @@ 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_name=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,
|
||||
block_device_mapping=dict() or None,
|
||||
instance_name=str() or None,
|
||||
hypervisor_name=str() or None,
|
||||
tags=list(),
|
||||
personality=str() or None,
|
||||
scheduler_hints=str() or None,
|
||||
user_data=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())
|
||||
Location = dict(
|
||||
cloud=str(),
|
||||
region_name=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,
|
||||
)
|
||||
)
|
||||
|
@@ -1,4 +1,3 @@
|
||||
================
|
||||
Multi-Cloud Demo
|
||||
================
|
||||
|
||||
@@ -10,15 +9,12 @@ walk through it like a presentation, install `presentty` and run:
|
||||
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.
|
||||
included in the openstacksdk docs.
|
||||
|
||||
.. _presentty: https://pypi.org/project/presentty
|
||||
|
||||
Using Multiple OpenStack Clouds Easily with Shade
|
||||
=================================================
|
||||
|
||||
Who am I?
|
||||
=========
|
||||
---------
|
||||
|
||||
Monty Taylor
|
||||
|
||||
@@ -27,7 +23,7 @@ Monty Taylor
|
||||
* twitter: @e_monty
|
||||
|
||||
What are we going to talk about?
|
||||
================================
|
||||
--------------------------------
|
||||
|
||||
`OpenStackSDK`
|
||||
|
||||
@@ -43,22 +39,22 @@ What are we going to talk about?
|
||||
* Librified to re-use in Ansible
|
||||
|
||||
OpenStackSDK is Free Software
|
||||
=============================
|
||||
-----------------------------
|
||||
|
||||
* https://opendev.org/openstack/openstacksdk
|
||||
* openstack-discuss@lists.openstack.org
|
||||
* #openstack-sdks on oftc
|
||||
|
||||
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!
|
||||
* doc/source/user/multi-cloud-demo.rst
|
||||
* examples in examples/cloud
|
||||
* Paths subject to change - this is the first presentation in tree!
|
||||
|
||||
Complete Example
|
||||
================
|
||||
----------------
|
||||
|
||||
.. code:: python
|
||||
|
||||
@@ -68,15 +64,19 @@ Complete Example
|
||||
openstack.enable_logging(debug=True)
|
||||
|
||||
for cloud_name, region_name in [
|
||||
('my-vexxhost', 'ca-ymq-1'),
|
||||
('my-citycloud', 'Buf1'),
|
||||
('my-internap', 'ams01')]:
|
||||
('my-vexxhost', 'ca-ymq-1'),
|
||||
('my-citycloud', 'Buf1'),
|
||||
('my-internap', 'ams01'),
|
||||
]:
|
||||
# Initialize cloud
|
||||
cloud = openstack.connect(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)
|
||||
'devuan-jessie',
|
||||
filename='devuan-jessie.qcow2',
|
||||
wait=True,
|
||||
)
|
||||
|
||||
# Find a flavor with at least 512M of RAM
|
||||
flavor = cloud.get_flavor_by_ram(512)
|
||||
@@ -84,19 +84,24 @@ Complete Example
|
||||
# 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)
|
||||
'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
|
||||
* OpenStackSDK API
|
||||
|
||||
Cloud Terminology
|
||||
=================
|
||||
-----------------
|
||||
|
||||
Let's define a few terms, so that we can use them with ease:
|
||||
|
||||
@@ -108,7 +113,7 @@ Let's define a few terms, so that we can use them with ease:
|
||||
* `domain` - collection of users and projects
|
||||
|
||||
Cloud Terminology Relationships
|
||||
===============================
|
||||
-------------------------------
|
||||
|
||||
* A `cloud` has one or more `regions`
|
||||
* A `patron` has one or more `users`
|
||||
@@ -121,14 +126,14 @@ Cloud Terminology Relationships
|
||||
* 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.
|
||||
|
||||
@@ -138,7 +143,7 @@ A `cloud region` is the basic unit of REST interaction.
|
||||
* A `region` is completely autonomous
|
||||
|
||||
Users, Projects and Domains
|
||||
===========================
|
||||
---------------------------
|
||||
|
||||
In clouds with multiple domains, project and user names are
|
||||
only unique within a region.
|
||||
@@ -151,12 +156,12 @@ only unique within a region.
|
||||
* `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:
|
||||
|
||||
@@ -164,7 +169,7 @@ In general, the thing you need to know is:
|
||||
* 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`.
|
||||
@@ -178,7 +183,7 @@ 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.
|
||||
|
||||
@@ -193,7 +198,7 @@ What about Mac and Windows?
|
||||
* Windows: `C:\\ProgramData\\OpenStack\\openstack`
|
||||
|
||||
Config Terminology
|
||||
==================
|
||||
------------------
|
||||
|
||||
For multi-cloud, think of two types:
|
||||
|
||||
@@ -203,7 +208,7 @@ For multi-cloud, think of two types:
|
||||
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
|
||||
@@ -211,10 +216,10 @@ Environment Variables and Simple Usage
|
||||
`cloud` and `region_name`
|
||||
|
||||
TOO MUCH TALKING - NOT ENOUGH CODE
|
||||
==================================
|
||||
----------------------------------
|
||||
|
||||
basic clouds.yaml for the example code
|
||||
======================================
|
||||
--------------------------------------
|
||||
|
||||
Simple example of a clouds.yaml
|
||||
|
||||
@@ -239,14 +244,14 @@ Simple example of a clouds.yaml
|
||||
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`
|
||||
@@ -260,7 +265,7 @@ Example secure.yaml
|
||||
password: XXXXXXXX
|
||||
|
||||
more clouds.yaml
|
||||
================
|
||||
----------------
|
||||
|
||||
More information can be provided.
|
||||
|
||||
@@ -281,7 +286,7 @@ More information can be provided.
|
||||
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
|
||||
@@ -310,7 +315,7 @@ Much more complex clouds.yaml example
|
||||
routes_externally: false
|
||||
|
||||
Complete Example Again
|
||||
======================
|
||||
----------------------
|
||||
|
||||
.. code:: python
|
||||
|
||||
@@ -339,17 +344,17 @@ Complete Example Again
|
||||
'my-server', image=image, flavor=flavor, wait=True, auto_ip=True)
|
||||
|
||||
Step By Step
|
||||
============
|
||||
------------
|
||||
|
||||
Import the library
|
||||
==================
|
||||
------------------
|
||||
|
||||
.. code:: python
|
||||
|
||||
from openstack import cloud as openstack
|
||||
|
||||
Logging
|
||||
=======
|
||||
-------
|
||||
|
||||
* `openstacksdk` uses standard python logging
|
||||
* ``openstack.enable_logging`` does easy defaults
|
||||
@@ -357,7 +362,7 @@ Logging
|
||||
|
||||
* `debug`
|
||||
|
||||
* Logs shade loggers at debug level
|
||||
* Logs openstacksdk loggers at debug level
|
||||
|
||||
* `http_debug` Implies `debug`, turns on HTTP tracing
|
||||
|
||||
@@ -367,23 +372,22 @@ Logging
|
||||
openstack.enable_logging(debug=True)
|
||||
|
||||
Example with Debug Logging
|
||||
==========================
|
||||
--------------------------
|
||||
|
||||
* doc/source/examples/debug-logging.py
|
||||
* examples/cloud/debug-logging.py
|
||||
|
||||
.. code:: python
|
||||
|
||||
from openstack import cloud as openstack
|
||||
openstack.enable_logging(debug=True)
|
||||
|
||||
cloud = openstack.connect(
|
||||
cloud='my-vexxhost', region_name='ca-ymq-1')
|
||||
cloud = openstack.connect(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
|
||||
* examples/cloud/http-debug-logging.py
|
||||
|
||||
.. code:: python
|
||||
|
||||
@@ -395,7 +399,7 @@ Example with HTTP Debug Logging
|
||||
cloud.get_image('Ubuntu 16.04.1 LTS [2017-03-03]')
|
||||
|
||||
Cloud Regions
|
||||
=============
|
||||
-------------
|
||||
|
||||
* `cloud` constructor needs `cloud` and `region_name`
|
||||
* `openstack.connect` is a helper factory function
|
||||
@@ -403,14 +407,15 @@ Cloud Regions
|
||||
.. code:: python
|
||||
|
||||
for cloud_name, region_name in [
|
||||
('my-vexxhost', 'ca-ymq-1'),
|
||||
('my-citycloud', 'Buf1'),
|
||||
('my-internap', 'ams01')]:
|
||||
('my-vexxhost', 'ca-ymq-1'),
|
||||
('my-citycloud', 'Buf1'),
|
||||
('my-internap', 'ams01')
|
||||
]:
|
||||
# Initialize cloud
|
||||
cloud = openstack.connect(cloud=cloud_name, region_name=region_name)
|
||||
|
||||
Upload an Image
|
||||
===============
|
||||
---------------
|
||||
|
||||
* Picks the correct upload mechanism
|
||||
* **SUGGESTION** Always upload your own base images
|
||||
@@ -419,10 +424,13 @@ Upload an Image
|
||||
|
||||
# Upload an image to the cloud
|
||||
image = cloud.create_image(
|
||||
'devuan-jessie', filename='devuan-jessie.qcow2', wait=True)
|
||||
'devuan-jessie',
|
||||
filename='devuan-jessie.qcow2',
|
||||
wait=True,
|
||||
)
|
||||
|
||||
Always Upload an Image
|
||||
======================
|
||||
----------------------
|
||||
|
||||
Ok. You don't have to. But, for multi-cloud...
|
||||
|
||||
@@ -432,7 +440,7 @@ Ok. You don't have to. But, for multi-cloud...
|
||||
* 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
|
||||
@@ -444,7 +452,7 @@ Find a flavor
|
||||
flavor = cloud.get_flavor_by_ram(512)
|
||||
|
||||
Create a server
|
||||
===============
|
||||
---------------
|
||||
|
||||
* my-vexxhost
|
||||
|
||||
@@ -472,15 +480,15 @@ Create a 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
|
||||
* examples/cloud/create-server-name-or-id.py
|
||||
|
||||
.. code:: python
|
||||
|
||||
@@ -509,11 +517,8 @@ Image and Flavor by Name or ID
|
||||
# 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
|
||||
|
||||
@@ -522,12 +527,12 @@ Delete Servers
|
||||
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
|
||||
* examples/cloud/create-server-dict.py
|
||||
|
||||
.. code:: python
|
||||
|
||||
@@ -555,10 +560,10 @@ Image and Flavor by Dict
|
||||
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
|
||||
* examples/cloud/munch-dict-object.py
|
||||
|
||||
.. code:: python
|
||||
|
||||
@@ -571,7 +576,7 @@ Munch Objects
|
||||
print(image['name'])
|
||||
|
||||
API Organized by Logical Resource
|
||||
=================================
|
||||
---------------------------------
|
||||
|
||||
* list_servers
|
||||
* search_servers
|
||||
@@ -587,10 +592,10 @@ For other things, it's still {verb}_{noun}
|
||||
* add_auto_ip
|
||||
|
||||
Cleanup Script
|
||||
==============
|
||||
--------------
|
||||
|
||||
* Sometimes my examples had bugs
|
||||
* doc/source/examples/cleanup-servers.py
|
||||
* examples/cloud/cleanup-servers.py
|
||||
|
||||
.. code:: python
|
||||
|
||||
@@ -609,10 +614,9 @@ Cleanup Script
|
||||
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
|
||||
* examples/cloud/normalization.py
|
||||
|
||||
.. code:: python
|
||||
|
||||
@@ -625,10 +629,10 @@ Normalization
|
||||
cloud.pprint(image)
|
||||
|
||||
Strict Normalized Results
|
||||
=========================
|
||||
-------------------------
|
||||
|
||||
* Return only the declared model
|
||||
* doc/source/examples/strict-mode.py
|
||||
* examples/cloud/strict-mode.py
|
||||
|
||||
.. code:: python
|
||||
|
||||
@@ -642,10 +646,10 @@ Strict Normalized Results
|
||||
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
|
||||
* examples/cloud/find-an-image.py
|
||||
|
||||
.. code:: python
|
||||
|
||||
@@ -658,7 +662,7 @@ How Did I Find the Image Name for the Last Example?
|
||||
if 'ubuntu' in image.name.lower()])
|
||||
|
||||
Added / Modified Information
|
||||
============================
|
||||
----------------------------
|
||||
|
||||
* Servers need more extra help
|
||||
* Fetch addresses dict from neutron
|
||||
@@ -666,7 +670,7 @@ Added / Modified Information
|
||||
* `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
|
||||
* examples/cloud/server-information.py
|
||||
|
||||
.. code:: python
|
||||
|
||||
@@ -694,9 +698,9 @@ Added / Modified Information
|
||||
cloud.delete_server(server, wait=True, delete_ips=True)
|
||||
|
||||
Exceptions
|
||||
==========
|
||||
----------
|
||||
|
||||
* All shade exceptions are subclasses of `OpenStackCloudException`
|
||||
* All openstacksdk exceptions are subclasses of `OpenStackCloudException`
|
||||
* Direct REST calls throw `OpenStackCloudHTTPError`
|
||||
* `OpenStackCloudHTTPError` subclasses `OpenStackCloudException`
|
||||
and `requests.exceptions.HTTPError`
|
||||
@@ -704,11 +708,11 @@ Exceptions
|
||||
* `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
|
||||
* (ssh ... `region_name` is optional if the cloud has one region)
|
||||
* examples/cloud/user-agent.py
|
||||
|
||||
.. code:: python
|
||||
|
||||
@@ -716,17 +720,20 @@ User Agent Info
|
||||
openstack.enable_logging(http_debug=True)
|
||||
|
||||
cloud = openstack.connect(
|
||||
cloud='datacentred', app_name='AmazingApp', app_version='1.0')
|
||||
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
|
||||
* openstacksdk figures this out and does it
|
||||
* multi-threaded
|
||||
* doc/source/examples/upload-object.py
|
||||
* examples/cloud/upload-object.py
|
||||
|
||||
.. code:: python
|
||||
|
||||
@@ -735,19 +742,21 @@ Uploading Large Objects
|
||||
|
||||
cloud = openstack.connect(cloud='ovh', region_name='SBG1')
|
||||
cloud.create_object(
|
||||
container='my-container', name='my-object',
|
||||
filename='/home/mordred/briarcliff.sh3d')
|
||||
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
|
||||
* examples/cloud/upload-object.py
|
||||
|
||||
.. code:: python
|
||||
|
||||
@@ -756,14 +765,16 @@ Uploading Large Objects
|
||||
|
||||
cloud = openstack.connect(cloud='ovh', region_name='SBG1')
|
||||
cloud.create_object(
|
||||
container='my-container', name='my-object',
|
||||
container='my-container',
|
||||
name='my-object',
|
||||
filename='/home/mordred/briarcliff.sh3d',
|
||||
segment_size=1000000)
|
||||
segment_size=1000000,
|
||||
)
|
||||
cloud.delete_object('my-container', 'my-object')
|
||||
cloud.delete_container('my-container')
|
||||
|
||||
Service Conditionals
|
||||
====================
|
||||
--------------------
|
||||
|
||||
.. code:: python
|
||||
|
||||
@@ -775,7 +786,7 @@ Service Conditionals
|
||||
print(cloud.has_service('container-orchestration'))
|
||||
|
||||
Service Conditional Overrides
|
||||
=============================
|
||||
-----------------------------
|
||||
|
||||
* Sometimes clouds are weird and figuring that out won't work
|
||||
|
||||
@@ -798,12 +809,5 @@ Service Conditional Overrides
|
||||
# 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)
|
||||
FIN
|
||||
---
|
||||
|
@@ -1,7 +1,3 @@
|
||||
**Note: This class is in the process of being applied as the new base class
|
||||
for resources around the OpenStack SDK. Once that has been completed,
|
||||
this module will be drop the 2 suffix and be the only resource module.**
|
||||
|
||||
Resource
|
||||
========
|
||||
.. automodule:: openstack.resource
|
||||
|
Reference in New Issue
Block a user