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:
Stephen Finucane
2023-03-27 11:28:00 +01:00
parent ca770c5bcd
commit c1c6a0e916
13 changed files with 233 additions and 718 deletions

View File

@@ -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.

View File

@@ -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/

View File

@@ -1,4 +1,3 @@
=================================
Contributing to the OpenStack SDK
=================================

View File

@@ -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

View File

@@ -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

View File

@@ -1,4 +1,3 @@
============
openstacksdk
============

View File

@@ -1,4 +1,3 @@
==================
Installation guide
==================

View File

@@ -1,4 +1,3 @@
=============
Release Notes
=============

View File

@@ -1,4 +1,3 @@
=======================
Using the OpenStack SDK
=======================

View File

@@ -1,4 +1,3 @@
=============
Microversions
=============

View File

@@ -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,
)
)

View File

@@ -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
---

View File

@@ -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