[lxc-devel] [pylxd/master] Add new docs
rockstar on Github
lxc-bot at linuxcontainers.org
Wed Jun 29 19:19:43 UTC 2016
A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 302 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20160629/e2a726b5/attachment.bin>
-------------- next part --------------
From 0aaf0e27d3df3b33907669e3636755f50b7452e3 Mon Sep 17 00:00:00 2001
From: Paul Hummer <paul.hummer at canonical.com>
Date: Wed, 29 Jun 2016 13:04:02 -0600
Subject: [PATCH] Add new docs
---
doc/source/api.rst | 12 +++
doc/source/authentication.rst | 6 +-
doc/source/certificates.rst | 29 ++++++
doc/source/containers.rst | 151 +++++++++++++++++++++++++++++
doc/source/events.rst | 19 ++++
doc/source/images.rst | 85 ++++++++++++++++
doc/source/index.rst | 10 +-
doc/source/networks.rst | 23 +++++
doc/source/profiles.rst | 58 +++++++++++
doc/source/usage.rst | 220 ++++++++++--------------------------------
10 files changed, 439 insertions(+), 174 deletions(-)
create mode 100644 doc/source/certificates.rst
create mode 100644 doc/source/containers.rst
create mode 100644 doc/source/events.rst
create mode 100644 doc/source/images.rst
create mode 100644 doc/source/networks.rst
create mode 100644 doc/source/profiles.rst
diff --git a/doc/source/api.rst b/doc/source/api.rst
index c7b91af..8a14682 100644
--- a/doc/source/api.rst
+++ b/doc/source/api.rst
@@ -8,6 +8,12 @@ Client
.. autoclass:: pylxd.client.Client
:members:
+Certificate
+-----------
+
+.. autoclass:: pylxd.certificate.Certificate
+ :members:
+
Container
---------
@@ -23,6 +29,12 @@ Image
.. autoclass:: pylxd.image.Image
:members:
+Network
+-------
+
+.. autoclass:: pylxd.network.Network
+ :members:
+
Operation
---------
diff --git a/doc/source/authentication.rst b/doc/source/authentication.rst
index cd12e7c..52dfe4a 100644
--- a/doc/source/authentication.rst
+++ b/doc/source/authentication.rst
@@ -1,6 +1,6 @@
-==============
-Authentication
-==============
+=====================
+Client Authentication
+=====================
When using LXD over https, LXD uses an asymmetric keypair for authentication.
The keypairs are added to the authentication database after entering the LXD
diff --git a/doc/source/certificates.rst b/doc/source/certificates.rst
new file mode 100644
index 0000000..0927617
--- /dev/null
+++ b/doc/source/certificates.rst
@@ -0,0 +1,29 @@
+Certificates
+============
+
+Certificates are used to manage authentications in LXD. Certificates are
+not editable. They may only be created or deleted. None of the certificate
+operations in LXD are asynchronous.
+
+Manager methods
+---------------
+
+Certificates can be queried through the following client manager
+methods:
+
+ - `all()` - Retrieve all certificates.
+ - `get()` - Get a specifit certificate, by its fingerprint.
+ - `create()` - Create a new certificate. This method requires
+ a first argument that is the LXD trust password, and the cert
+ data, in binary format.
+
+
+Certificate attributes
+----------------------
+
+Certificates have the following attributes:
+
+ - `fingerprint` - The fingerprint of the certificate. Certificates
+ are keyed off this attribute.
+ - `certificate` - The certificate itself, in PEM format.
+ - `type` - The certificate type (currently only "client")
diff --git a/doc/source/containers.rst b/doc/source/containers.rst
new file mode 100644
index 0000000..12aa035
--- /dev/null
+++ b/doc/source/containers.rst
@@ -0,0 +1,151 @@
+Containers
+==========
+
+`Container` objects are the core of LXD. Containers can be created,
+updated, and deleted. Most of the methods for operating on the
+container itself are asynchronous, but many of the methods for getting
+information about the container are synchronous.
+
+
+Manager methods
+---------------
+
+Containers can be queried through the following client manager
+methods:
+
+ - `all()` - Retrieve all containers.
+ - `get()` - Get a specific container, by its name.
+ - `create(wait=False)` - Create a new container. This method requires
+ a first argument that is the container name, followed by a config.
+ The config itself is beyond the scope of this documentation. Please
+ refer to the LXD documentation for more information. This method
+ will also return immediately, unless `wait` is `True`.
+
+
+Container attributes
+--------------------
+
+For more information about the specifics of these attributes, please see
+the LXD documentation.
+
+ - `architecture` - The container architecture.
+ - `config` - The container config
+ - `created_at` - The time the container was created
+ - `devices` - The devices for the container
+ - `ephemeral` - Whether the container is ephemeral
+ - `expanded_config` - An expanded version of the config
+ - `expanded_devices` - An expanded version of devices
+ - `name` - The name of the container. This attribute serves as the
+ primary identifier of a container.
+ - `profiles` - A list of profiles applied to the container
+ - `status` - A string representing the status of the container
+ - `status_code` - A LXD status code of the container
+ - `stateful` - Whether the container is stateful
+
+
+Container methods
+-----------------
+
+ - `rename` - Rename a container. Because `name` is the key, it cannot be
+ renamed by simply changing the name of the container as an attribute
+ and calling `save`. The new name is the first argument and, as the method
+ is asynchronous, you may pass `wait=True` as well.
+ - `state` - Get the expanded state of the container.
+ - `start` - Start the container
+ - `stop` - Stop the container
+ - `restart` - Restart the container
+ - `freeze` - Suspend the container
+ - `unfreeze` - Resume the container
+ - `execute` - Execute a command on the container. The first argument is
+ a list, in the form of `subprocess.Popen` with each item of the command
+ as a separate item in the list. Returns a two part tuple of
+ `(stdout, stderr)`. This method will block while the command is executed.
+ - `migrate` - Migrate the container. The first argument is a client
+ connection to the destination server. This call is asynchronous, so
+ `wait=True` is optional. The container on the new client is returned.
+
+
+
+Examples
+--------
+
+If you'd only like to fetch a single container by its name...
+
+.. code-block:: python
+
+ >>> client.containers.get('my-container')
+ <container.Container at 0x7f95d8af72b0>
+
+
+If you're looking to operate on all containers of a LXD instance, you can
+get a list of all LXD containers with `all`.
+
+.. code-block:: python
+
+ >>> client.containers.all()
+ [<container.Container at 0x7f95d8af72b0>,]
+
+
+In order to create a new :class:`~container.Container`, a container
+config dictionary is needed, containing a name and the source. A create
+operation is asynchronous, so the operation will take some time. If you'd
+like to wait for the container to be created before the command returns,
+you'll pass `wait=True` as well.
+
+.. code-block:: python
+
+ >>> config = {'name': 'my-container', 'source': {'type': 'none'}}
+ >>> container = client.containers.create(config, wait=False)
+ >>> container
+ <container.Container at 0x7f95d8af72b0>
+
+
+If you were to use an actual image source, you would be able to operate
+on the container, starting, stopping, snapshotting, and deleting the
+container.
+
+ >>> container.start()
+ >>> container.freeze()
+ >>> container.delete()
+
+
+Container Snapshots
+-------------------
+
+Each container carries its own manager for managing :class:`~container.Snapshot`
+functionality. It has `get`, `all`, and `create` functionality.
+
+Snapshots are keyed by their name (and only their name, in pylxd; LXD
+keys them by <container-name>/<snapshot-name>, but the manager allows
+us to use our own namespacing).
+
+.. code-block:: python
+ >>> snapshot = container.snapshots.get('an-snapshot')
+ >>> snapshot.created_at
+ '1983-06-16T2:38:00'
+ >>> snapshot.rename('backup-snapshot', wait=True)
+ >>> snapshot.delete(wait=True)
+
+
+To create a new snapshot, use `create` with a `name` argument. If you want
+to capture the contents of RAM in the snapshot, you can use `stateful=True`.
+**Note: Your LXD requires a relatively recent version of CRIU for this.**
+
+.. code-block:: python
+ >>> snapshot = container.snapshots.create(
+ ... 'my-backup', stateful=True, wait=True)
+ >>> snapshot.name
+ 'my-backup'
+
+
+Container files
+---------------
+
+Containers also have a `files` manager for getting and putting files on the
+container.
+
+.. code-block:: python
+ >>> filedata = open('my-script').read()
+ >>> container.files.put('/tmp/my-script', filedata)
+ >>> newfiledata = container.files.get('/tmp/my-script2')
+ >>> open('my-script2', 'wb').write(newfiledata)
diff --git a/doc/source/events.rst b/doc/source/events.rst
new file mode 100644
index 0000000..3b66095
--- /dev/null
+++ b/doc/source/events.rst
@@ -0,0 +1,19 @@
+Events
+======
+
+LXD provides an `/events` endpoint that is upgraded to a streaming websocket
+for getting LXD events in real-time. The :class:`~pylxd.Client`'s `events`
+method will return a websocket client that can interact with the
+web socket messages.
+
+.. code-block:: python
+
+ >>> ws_client = client.events()
+ >>> ws_client.connect()
+ >>> ws_client.run()
+
+A default client class is provided, which will block indefinitely, and
+collect all json messages in a `messages` attribute. An optional
+`websocket_client` parameter can be provided when more functionality is
+needed. The `ws4py` library is used to establish the connection; please
+see the `ws4py` documentation for more information.
diff --git a/doc/source/images.rst b/doc/source/images.rst
new file mode 100644
index 0000000..8f92934
--- /dev/null
+++ b/doc/source/images.rst
@@ -0,0 +1,85 @@
+Images
+======
+
+`Image` objects are the base for which containers are built. Many of
+the methods of images are asynchronous, as they required reading and
+writing large files.
+
+
+Manager methods
+---------------
+
+Images can be queried through the following client manager
+methods:
+
+ - `all()` - Retrieve all images.
+ - `get()` - Get a specific image, by its fingerprint.
+ - `create(data, public=False, wait=False)` - Create a new image. The first
+ argument is the binary data of the image itself. If the image is public,
+ set `public` to `True`.
+
+
+Image attributes
+----------------
+
+For more information about the specifics of these attributes, please see
+the LXD documentation.
+
+ - `aliases` - A list of aliases for this image
+ - `auto_update` - Whether the image should auto-update
+ - `architecture` - The target architecture for the image
+ - `cached` - Whether the image is cached
+ - `created_at` - The date and time the image was created
+ - `expires_at` - The date and time the image expires
+ - `filename` - The name of the image file
+ - `fingerprint` - The image fingerprint, a sha2 hash of the image data
+ itself. This unique key identifies the image.
+ - `last_used_at` - The last time the image was used
+ - `properties` - The configuration of image itself
+ - `public` - Whether the image is public or not
+ - `size` - The size of the image
+ - `uploaded_at` - The date and time the image was uploaded
+
+
+Image methods
+-------------
+
+ - `export` - Export the image. Returns binary data that is the
+ image itself.
+
+
+Examples
+--------
+
+:class:`~image.Image` operations follow the same protocol from the client`s
+`images` manager (i.e. `get`, `all`, and `create`). Images are keyed on
+a sha-1 fingerprint of the image itself. To get an image...
+
+.. code-block:: python
+
+ >>> image = client.images.get(
+ ... 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855')
+ >>> image
+ <image.Image at 0x7f95d8af72b0>
+
+
+Once you have an image, you can operate on it as before:
+
+.. code-block:: python
+
+ >>> image.public
+ False
+ >>> image.public = True
+ >>> image.update()
+
+
+To create a new Image, you'll open an image file, and pass that to `create`.
+If the image is to be public, `public=True`. As this is an asynchonous operation,
+you may also want to `wait=True`.
+
+.. code-block:: python
+
+ >>> image_data = open('an_image.tar.gz').read()
+ >>> image = client.images.create(image_data, public=True, wait=True)
+ >>> image.fingerprint
+ 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'
diff --git a/doc/source/index.rst b/doc/source/index.rst
index ea1dfcb..9e158c6 100644
--- a/doc/source/index.rst
+++ b/doc/source/index.rst
@@ -11,10 +11,18 @@ Contents:
.. toctree::
:maxdepth: 2
- readme
installation
usage
authentication
+
+ events
+ certificates
+ containers
+ images
+ networks
+ profiles
+
+
contributing
api
diff --git a/doc/source/networks.rst b/doc/source/networks.rst
new file mode 100644
index 0000000..42879d1
--- /dev/null
+++ b/doc/source/networks.rst
@@ -0,0 +1,23 @@
+Networks
+========
+
+`Network` objects show the current networks available to lxd. They are
+read-only via the REST API.
+
+
+Manager methods
+---------------
+
+Networks can be queried through the following client manager
+methods:
+
+ - `all()` - Retrieve all networks
+ - `get()` - Get a specific network, by its name.
+
+
+Network attributes
+----------------
+
+ - `name` - The name of the network
+ - `type` - The type of the network
+ - `used_by` - A list of containers using this network
diff --git a/doc/source/profiles.rst b/doc/source/profiles.rst
new file mode 100644
index 0000000..d1fde77
--- /dev/null
+++ b/doc/source/profiles.rst
@@ -0,0 +1,58 @@
+Profiles
+========
+
+`Profile` describe configuration options for containers in a re-usable way.
+
+
+Manager methods
+---------------
+
+Profiles can be queried through the following client manager
+methods:
+
+ - `all()` - Retrieve all networks
+ - `get()` - Get a specific network, by its name.
+ - `create(name, config, devices)` - Create a new profile. The name of the
+ profile is required. `config` and `devices` dictionaries are optional,
+ and the scope of their contents is documented in the LXD documentation.
+
+
+Profile attributes
+------------------
+
+ - `name` - The name of the network
+ - `type` - The type of the network
+ - `used_by` - A list of containers using this network
+
+
+Profile methods
+---------------
+
+ - `rename` - Rename the profile.
+
+
+Examples
+--------
+
+:class:`~profile.Profile` operations follow the same manager-style as
+Containers and Images. Profiles are keyed on a unique name.
+
+.. code-block:: python
+
+ >>> profile = client.profiles.get('my-profile')
+ >>> profile
+ <profile.Profile at 0x7f95d8af72b0>
+
+
+The profile can then be modified and saved.
+
+ >>> profile.config = profile.config.update({'security.nesting': 'true'})
+ >>> profile.update()
+
+
+To create a new profile, use `create` with a name, and optional `config`
+and `devices` config dictionaries.
+
+ >>> profile = client.profiles.create(
+ ... 'an-profile', config={'security.nesting': 'true'},
+ ... devices={'root': {'path': '/', 'size': '10GB', 'type': 'disk'}})
diff --git a/doc/source/usage.rst b/doc/source/usage.rst
index 8fa80e6..2ec1797 100644
--- a/doc/source/usage.rst
+++ b/doc/source/usage.rst
@@ -1,6 +1,6 @@
-=====
-Usage
-=====
+===============
+Getting started
+===============
.. currentmodule:: pylxd
@@ -29,192 +29,72 @@ of (cert, key) as the `cert` argument.
Note: in the case where the certificate is self signed (LXD default),
you may need to pass `verify=False`.
-Client Managers
----------------
+Querying LXD
+------------
-:class:`~client.Client` exposes an object manager protocol for
-:class:`~container.Container`, :class:`~image.Image`, and
-:class:`~profile.Profile`. These managers are `containers`, `images`,
-and `profiles` attributes on the Client itself, and contain three
-special methods.
-
-- `create` creates new object. The arguments required differ based
- on the object that is being created.
-- `get` will get a single object by its key. Each object is keyed by its
- own property.
-- `all` returns a list of all the objects. The caveat here is that
- the object is "incomplete", i.e. it doesn't have all its properties
- populated yet. Each object will require a call to `fetch` before
- it can be modified/saved.
-
-
-Containers
-==========
-
-If you'd only like to fetch a single container by its name...
-
-.. code-block:: python
-
- >>> client.containers.get('my-container')
- <container.Container at 0x7f95d8af72b0>
-
-
-If you're looking to operate on all containers of a LXD instance, you can
-get a list of all LXD containers with `all`.
+LXD exposes a number of objects via its REST API that are used to orchestrate
+containers. Those objects are all accessed via manager attributes on the client
+itself. This includes `certificates`, `containers`, `images`, `networks`,
+`operations`, and `profiles`. Each manager has methods for querying the
+LXD instance. For example, to get all containers in a LXD instance
.. code-block:: python
-
>>> client.containers.all()
[<container.Container at 0x7f95d8af72b0>,]
-See the above caveat about `all`. For example:
-The caveat with `all` is that you won't have fully fetched objects. You'll
-have an impartial object, so you must call `fetch` on the Container before
-operating on it.
-
- >>> container = client.containers.all()[0]
- >>> container.architecture
- AttributeError: ...
- >>> container.fetch()
- >>> container.architecture
- 'x86_64'
-
-
-In order to create a new :class:`~container.Container`, a container
-config dictionary is needed, containing a name and the source. A create
-operation is asynchronous, so the operation will take some time. If you'd
-like to wait for the container to be created before the command returns,
-you'll pass `wait=True` as well.
+For specific manager methods, please see the documentation for each object.
-.. code-block:: python
-
- >>> config = {'name': 'my-container', 'source': {'type': 'none'}}
- >>> container = client.containers.create(config, wait=False)
- >>> container
- <container.Container at 0x7f95d8af72b0>
-
-
-If you were to use an actual image source, you would be able to operate
-on the container, starting, stopping, snapshotting, and deleting the
-container.
-
- >>> container.start()
- >>> container.freeze()
- >>> container.delete()
-
-
-Container Snapshots
--------------------
-Each container carries its own manager for managing :class:`~container.Snapshot`
-functionality. It has `get`, `all`, and `create` functionality.
+pylxd Objects
+-------------
-Snapshots are keyed by their name (and only their name, in pylxd; LXD
-keys them by <container-name>/<snapshot-name>, but the manager allows
-us to use our own namespacing).
+Each LXD object has an analagous pylxd object. Returning to the previous
+`client.containers.all` example, a `Container` object is manipulated as
+such:
.. code-block:: python
+ >>> container = client.containers.all()[0]
+ >>> container.name
+ 'lxd-container'
- >>> snapshot = container.snapshots.get('an-snapshot')
- >>> snapshot.created_at
- '1983-06-16T2:38:00'
- >>> snapshot.rename('backup-snapshot', wait=True)
- >>> snapshot.delete(wait=True)
-
-
-To create a new snapshot, use `create` with a `name` argument. If you want
-to capture the contents of RAM in the snapshot, you can use `stateful=True`.
-**Note: Your LXD requires a relatively recent version of CRIU for this.**
-
-.. code-block:: python
-
- >>> snapshot = container.snapshots.create(
- ... 'my-backup', stateful=True, wait=True)
- >>> snapshot.name
- 'my-backup'
-
-
-Images
-======
-
-:class:`~image.Image` operations follow the same protocol from the client`s
-`images` manager (i.e. `get`, `all`, and `create`). Images are keyed on
-a sha-1 fingerprint of the image itself. To get an image...
+Each pylxd object has a lifecycle which includes support for
+transactional changes. This lifecycle includes the following
+methods and attributes:
-.. code-block:: python
+ - `sync()` - Synchronize the object with the server. This method is
+ called implicitly when accessing attributes that have not yet been
+ populated, but may also be called explicitly. Why would attributes
+ not yet be populated? When retrieving objects via `all`, LXD's
+ API does not return a full representation.
+ - `dirty` - After setting attributes on the object, the object is
+ considered "dirty".
+ - `rollback()` - Discard all local changes to the object, opting
+ for a representation taken from the server.
+ - `save()` - Save the object, writing changes to the server.
- >>> image = client.images.get(
- ... 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855')
- >>> image
- <image.Image at 0x7f95d8af72b0>
-
-Once you have an image, you can operate on it as before:
+Returning again to the `Container` example
.. code-block:: python
-
- >>> image.public
+ >>> container.config
+ { 'security.privileged': True }
+ >>> container.config.update({'security.nesting': True})
+ >>> container.dirty
+ True
+ >>> container.rollback()
+ >>> container.dirty
False
- >>> image.public = True
- >>> image.update()
-
-
-To create a new Image, you'll open an image file, and pass that to `create`.
-If the image is to be public, `public=True`. As this is an asynchonous operation,
-you may also want to `wait=True`.
-
-.. code-block:: python
-
- >>> image_data = open('an_image.tar.gz').read()
- >>> image = client.images.create(image_data, public=True, wait=True)
- >>> image.fingerprint
- 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'
-
-
-Profiles
-========
-
-:class:`~profile.Profile` operations follow the same manager-style as
-Containers and Images. Profiles are keyed on a unique name.
+ >>> container.config
+ { 'security.privileged': True }
+ >>> container.config = {'security.privileged': False}
+ >>> container.save(wait=True) # The object is now saved back to LXD
-.. code-block:: python
-
- >>> profile = client.profiles.get('my-profile')
- >>> profile
- <profile.Profile at 0x7f95d8af72b0>
-
-
-The profile can then be modified and saved.
-
- >>> profile.config = profile.config.update({'security.nesting': 'true'})
- >>> profile.update()
-
-
-To create a new profile, use `create` with a name, and optional `config`
-and `devices` config dictionaries.
-
- >>> profile = client.profiles.create(
- ... 'an-profile', config={'security.nesting': 'true'},
- ... devices={'root': {'path': '/', 'size': '10GB', 'type': 'disk'}})
-
-
-Events
-======
-
-LXD provides an `/events` endpoint that is upgraded to a streaming websocket
-for getting LXD events in real-time. The :class:`~pylxd.Client`'s `events`
-method will return a websocket client that can interact with the
-web socket messages.
-
-.. code-block:: python
- >>> ws_client = client.events()
- >>> ws_client.connect()
- >>> ws_client.run()
+A note about asynchronous operations
+------------------------------------
-A default client class is provided, which will block indefinitely, and
-collect all json messages in a `messages` attribute. An optional
-`websocket_client` parameter can be provided when more functionality is
-needed. The `ws4py` library is used to establish the connection; please
-see the `ws4py` documentation for more information.
+Some changes to LXD will return immediately, but actually occur in the
+background after the http response returns. All operations that happen
+this way will also take an optional `wait` parameter that, when `True`,
+will not return until the operation is completed.
More information about the lxc-devel
mailing list