Net-Async-WebService-lxd

 view release on metacpan or  search on metacpan

README.md  view on Meta::CPAN

# NAME

Net::Async::WebService::lxd - REST client (asynchronous) for lxd Linux containers

# SYNOPSIS

    use IO::Async::Loop;
    my $loop = IO::Async::Loop->new;

    use Net::Async::WebService::lxd;
    my $lxd = Net::Async::WebService::lxd->new( loop            => $loop,
                                                endpoint        => 'https://192.168.0.50:8443',
                                                SSL_cert_file   => "t/client.crt",
                                                SSL_key_file    => "t/client.key",
                                                SSL_fingerprint => 'sha1$92:DD:63:F8:99:C4:5F:82:59:52:82:A9:09:C8:57:F0:67:56:B0:1B',
                                                );
    $lxd->create_instance(
             body => {
                 architecture => 'x86_64',
                 profiles     => [ 'default'  ],
                 name         => 'test1',
                 source       => { type        => 'image',
                                   fingerprint => '6dc6aa7c8c00' },  # image already exists in image store
                 config       => {},
             } )->get;                                               # wait for it
    # container is still stopped
    $lxd->instance_state( name => 'test1',
             body => {
                 action   => "start",
                 force    => JSON::false,
                 stateful => JSON::false,
                 timeout  => 30,
             } )->get;                                               # wait for it

# INTERFACE

## Constructor

The constructor returns a handle to one LXD server. It's address is specified via an **endpoint**
parameter, be it of an HTTPS or of a UNIX socket kind.

If you are working with a non-default LXD project in mind, then you should also provide that
project's name with the **project** parameter. Background operation polling will make use of
that. Note, that when invoking any of the methods here, you will still have to specify that project,
unless it is the `default` one, of course.

As we are operating under an [IO::Async](https://metacpan.org/pod/IO::Async) regime here, the handle also needs a **loop** parameter to
the central event loop. The handle will also regularily poll autonomously the server which
operations are still running or have completed. The optional parameter **polling\_time** controls how
often that will occur; it will default to 1 sec, if not provided.

As LXC can be accessed remotely only via HTTPS, TLS (SSL) parameters must be provided. These will be
forwarded directly to
[IO::Socket::SSL](https://metacpan.org/pod/IO::Socket::SSL#Description-Of-Methods). But, specifically,
one should consider to provide:

- **client certificate**, via a proper subset of `SSL_cert_file`, `SSL_key_file`, `SSL_cert` and `SSL_key`.
(Look at the ["HINTS"](#hints) section to generate such a certificate for LXD.)
- **server fingerprint**, via `SSL_fingerprint`
(Look at the ["HINTS"](#hints) section how to figure this out.)

## Methods

All methods below are automatically generated from the [LXD REST API Spec](https://raw.githubusercontent.com/lxc/lxd/master/doc/rest-api.yaml).
They should work with API version 1.0.

Let's dissect method invocations with this example:

    my $f = $lxd->instance_state( name => 'test1' );
    my $r = $f->get;

- All invocations return a [Future](https://metacpan.org/pod/Future). Thus they can be combined, sequenced, run in "parallel", etc. If
you need to wait for a definite result, then you will block the flow with `->get`.

    Polling is done behind the scenes and will watch for all operations which either succeeded or
    failed. Those will mark the associated future as `done` or `failed`. Normally, you will never need
    to use the methods for 'Operations' yourself; they are still offered as fallback.

- The result of each fully completed invocation is either
    - the string `success`, or
    - a Perl HASH ref which reflects the JSON data sent from the LXD server. Note, that Booleans have to
    be treated special, by using `JSON::false` and `JSON::true`. Otherwise, they follow **exactly** the
    structure in the specification.
    - or a HASH ref with keys `stdin` and `stdout` if this is a result of the `execute_in_instance`
    method.
- If an operation failed, then the associated future will be failed, together with the reason of the
failure from the server. If you do not cater with that, then this will - as usual with `IO::Async`
- raise an exception, with the failure as string.
- Methods named like the type of server object (e.g. `cluster`, `certificate`, `image`) are
normally "getter/setter" methods. The getter obviously returns the state of the object. The method
becomes a setter, if the additional `body` field together with a Perl HASH ref is passed:

        my $f = $lxd->instance_state( name => 'test1',
                                      body => {
                                        action   => "start",
                                        force    => JSON::false,
                                        stateful => JSON::false,
                                        timeout  => 30,
                                      } );

    How a specific object is addressed, is detailed in each method below; usually you provide a `name`,
    `id`, `fingerprint`, or similar. You may also have to provide a `project`, if not being the
    _default project_.

    That HASH ref also follows the structure outlined in the specification for that particular endpoint.

- Methods named like a type of server object (e.g. `certificates`) normally return a list of
identifiers for such objects.
- Many methods request changes in the LXD server. The names are taken from the specification, but are
adapted to better reflect what is intended:
    - Methods which change the state of the remote object usually are called `modify`\__something_.
    - Methods which add a new object to a collection are usually called `add`\__something_, or
    `create`\__something_, depending on how it sounds better.
    - Methods which remove an object from a collection are usually called `delete`\__something_.

README.md  view on Meta::CPAN


From then on, the following methods can operate on it:

- `restart`
- `start`
- `freeze`
- `unfreeze`
- `stop`
- `state`

Well, I'm not a big fan of objects.

# EXAMPLES

I encourage you to look at the `02_instances.t` test suite. It will show a complete life cycle for
containers.

# SEE ALSO

- [Linux::LXC](https://metacpan.org/pod/Linux::LXC)

    uses actually the existing lxc client to get the information

- [https://github.com/jipipayo/Linux-REST-LXD](https://github.com/jipipayo/Linux-REST-LXD)

    pretty old, never persued

# HINTS

- How to generate an SSL client certificate for LXD

    First, I found one client certificate (plus the key) in my installation at:

        /root/snap/lxd/common/config/

    Alternatively, [you can run your own small CA, generate a .crt and .key for a client, and then
    add it to lxd to trust it](https://serverfault.com/questions/882880/authenticate-to-lxd-rest-api-over-network-certificate-auth-keeps-failing).

    More on this topic is [here](https://linuxcontainers.org/lxd/docs/master/authentication/)

- How to find the SSL fingerprint for an LXD server

    With recent versions of LXD this is fairly easy:

        $ lxc info|grep fingerprint

    It is a SHA265 hash, so you will have to prefix it with `sha256$` (no blanks) when you pass it to `SSL_fingerprint`.

    Alternatively, you can try to find the server certificate and use `openssl` to derive a fingerprint of your choice.

# ISSUES

Open issues are probably best put onto [Github](https://github.com/drrrho/net-async-webservice-lxd)

# AUTHOR

Robert Barta, `<rho at devc.at>`

# CREDITS

[IO::Async](https://metacpan.org/pod/IO::Async), [Net::Async::HTTP](https://metacpan.org/pod/Net::Async::HTTP), [IO::Socket::SSL](https://metacpan.org/pod/IO::Socket::SSL) and friends are amazing.

# LICENSE AND COPYRIGHT

Copyright 2022 Robert Barta.

This program is free software; you can redistribute it and/or modify it
under the terms of the the Artistic License (2.0). You may obtain a
copy of the full license at:

[http://www.perlfoundation.org/artistic\_license\_2\_0](http://www.perlfoundation.org/artistic_license_2_0)

Any use, modification, and distribution of the Standard or Modified
Versions is governed by this Artistic License. By using, modifying or
distributing the Package, you accept this license. Do not use, modify,
or distribute the Package, if you do not accept this license.

If your Modified Version has been derived from a Modified Version made
by someone other than you, you are nevertheless required to ensure that
your Modified Version complies with the requirements of this license.

This license does not grant you the right to use any trademark, service
mark, tradename, or logo of the Copyright Holder.

This license includes the non-exclusive, worldwide, free-of-charge
patent license to make, have made, use, offer to sell, sell, import and
otherwise transfer the Package with respect to any patent claims
licensable by the Copyright Holder that are necessarily infringed by the
Package. If you institute patent litigation (including a cross-claim or
counterclaim) against any party alleging that the Package constitutes
direct or contributory patent infringement, then this Artistic License
to you shall terminate on the date that such litigation is filed.

Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER
AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES.
THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY
YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR
CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR
CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.



( run in 0.926 second using v1.01-cache-2.11-cpan-39bf76dae61 )