[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