API-Docker

 view release on metacpan or  search on metacpan

lib/API/Docker/API/Plugins.pm  view on Meta::CPAN

ArrayRef of progress events, and L</enable>, L</disable>, L</remove> and
L</configure> C<undef>.

=head2 client

Reference to L<API::Docker> client. Weak reference to avoid circular dependencies.

=head2 list

    my $plugins = $plugins->list;
    my $enabled = $plugins->list(filters => { enabled => ['true'] });

List installed plugins. Returns an ArrayRef of L<API::Docker::Type::Plugin>
objects, each carrying the methods of L<API::Docker::Role::Entity::Plugin>.
An engine with no plugins installed answers C<[]>, never C<null>, so this is
an empty ArrayRef rather than C<undef>.

Options:

=over

=item * C<filters> - HashRef of filters, JSON-encoded by the transport. Values
are ArrayRefs of strings even for booleans -- L<API::Docker::Role::Filters>
shape-checks and normalises that, but not the names, which the daemon
validates itself

=back

The accepted filter names are C<enabled> and C<capability>. B<It is C<enabled>,
not C<enable>> -- the published Engine API reference says C<enable>, and the
daemon validates plugin filter names against its own list, so the documented
spelling is refused outright rather than silently matching nothing. C<enabled>
takes C<['true']> or C<['false']>; C<capability> takes a capability name such
as C<['volumedriver']>.

=head2 privileges

    my $privileges = $plugins->privileges('vieux/sshfs:latest');

Get the privileges a plugin demands, without installing it. Returns an
ArrayRef of HashRefs:

    [ { Name => 'network', Description => '', Value => ['host'] },
      { Name => 'mount',   Description => '', Value => ['/var/lib/docker/plugins/'] } ]

This is the first half of the install; see L</"Installing is two calls, and
the engine enforces it">. Reading it is the point -- the result is what you
hand to L</install>, and the daemon accepts the install only if the two
lists agree.

A plugin that demands nothing answers with an empty ArrayRef.

The C<remote> reference is normalised by the daemon, so C<vieux/sshfs> and
C<docker.io/vieux/sshfs:latest> name the same plugin; C<:latest> is the
default when no tag is given.

Options:

=over

=item * C<auth> - Registry credentials for a plugin in a private registry;
HashRef of C<username> / C<password> / C<serveraddress> / C<identitytoken>,
or a pre-encoded base64 string. Sent as C<X-Registry-Auth>. The Engine API
reference does not document this header on this endpoint, but the daemon
reads it here exactly as it does on the pull

=back

=head2 install

    my $privileges = $plugins->privileges('vieux/sshfs:latest');
    $plugins->install('vieux/sshfs:latest', privileges => $privileges);

    # blanket grant, in one call
    $plugins->install('vieux/sshfs:latest', accept_privileges => 1);

Pull and install a plugin (C<< POST /plugins/pull >>). The plugin is installed
disabled -- call L</enable> afterwards.

C<privileges> is required. Without it this croaks and names both ways
forward; see L</"Installing is two calls, and the engine enforces it"> for
why it is not defaulted.

Options:

=over

=item * C<privileges> - ArrayRef of privilege HashRefs from L</privileges>.
Required, unless C<accept_privileges> is set

=item * C<accept_privileges> - Fetch the privileges and grant them, in one
call. A blanket grant: use it where the call site is allowed to trust the
plugin, and know that it reads as consent to whatever the plugin demands

=item * C<name> - Local name for the installed plugin, if it should differ
from C<remote>. A digest is not allowed here

=item * C<auth> - Registry credentials, as for L</privileges>

=item * C<on_event> - CodeRef called with each progress event as it arrives,
instead of the ArrayRef being collected and returned; see below

=back

Returns an ArrayRef of progress events, one per object in the engine's
newline-delimited JSON stream, C<[]> when the engine sent no progress
at all.

=head2 Progress as it arrives

Without a callback the whole stream is read before anything is parsed, so
pulling a plugin is silence until it is done. Pass C<on_event> and the events
are handed over as the daemon sends them:

    my $summary = $plugins->install('vieux/sshfs:latest',
        privileges => $privileges,
        on_event   => sub {
            my ($event, $stop) = @_;
            print $event->{status}, "\n" if defined $event->{status};
        },
    );

    $summary;   # { delivered => 18, stopped => 0 }

With a callback the return value is that summary HashRef, not the events:
C<delivered> is how many went to the callback, C<stopped> is 1 when the
callback ended the stream and 0 when the daemon did. Nothing is accumulated.
See L<API::Docker::Role::HTTP/"Streaming a response as it arrives">.

The C<errorDetail> check runs on this path too, per event rather than over the
finished list, so a failure inside the 200 stream still croaks with an
L<API::Docker::Error::Stream> -- at the event that reports it, and carrying
that one event alone rather than the whole stream. It is the difference
L<API::Docker::API::Images/"A failed build still croaks, one event earlier">
describes, and it applies here identically. A caller that wants the progress
that preceded a failure must collect it in the callback.

L</upgrade> and L</push> take C<on_event> on the same terms.

A failed install croaks by one of two routes, exactly as
L<API::Docker::API::Images/pull> does, because the daemon commits to HTTP 200
the moment it flushes the first progress object. A failure before that point
arrives as a real error status -- C<incorrect privileges> is reported this
way, since it is decided before anything is pulled -- and one after it
arrives as an C<errorDetail> object inside the 200 stream, which croaks with
an L<API::Docker::Error::Stream>. C<eval> and inspect C<$@> as a string
rather than testing for the exception class.

=head2 inspect

    my $plugin = $plugins->inspect('vieux/sshfs:latest');
    say $plugin->enabled;
    say join ', ', @{ $plugin->settings->env };

Get detailed information about an installed plugin. Returns an
L<API::Docker::Type::Plugin> -- the same class L</list> returns; see
L</"What this class returns">.

lib/API/Docker/API/Plugins.pm  view on Meta::CPAN

=over

=item * C<timeout> - Seconds to wait for the plugin to come up, C<0> for no
timeout (the default)

=back

C<timeout> is B<always> sent, whether or not the caller passes it. The Engine
API reference gives it a default of C<0>, but the daemon has none: it reads
the raw query value and parses it with Go's C<strconv.Atoi>, so an absent
parameter is parsed as the empty string and the request fails with
C<strconv.Atoi: parsing "": invalid syntax> as an invalid-parameter error.
This is the one endpoint in the family where omitting an optional parameter
is fatal.

=head2 disable

    $plugins->disable('vieux/sshfs:latest');
    $plugins->disable('vieux/sshfs:latest', force => 1);

Disable an enabled plugin. Returns C<undef>.

Options:

=over

=item * C<force> - Disable even while the plugin is in use. Mounts held by
the plugin stay behind, which is what makes a later L</remove> fail

=back

=head2 upgrade

    my $privileges = $plugins->privileges('vieux/sshfs:latest');
    $plugins->upgrade('vieux/sshfs:latest', privileges => $privileges);

    # upgrade a locally renamed plugin from its upstream reference
    $plugins->upgrade('sshfs', remote => 'vieux/sshfs:v2',
        accept_privileges => 1);

Upgrade an installed plugin in place. The plugin must be disabled first.

Like L</install> this carries the privilege list in its body and the daemon
checks it against what the new version demands, so C<privileges> is required
here too -- an upgrade is where a plugin's demands can B<change>, which is
the case worth looking at.

Options:

=over

=item * C<privileges> - ArrayRef of privilege HashRefs. Required, unless
C<accept_privileges> is set

=item * C<accept_privileges> - Fetch the privileges for C<remote> and grant
them, in one call

=item * C<remote> - Remote reference to upgrade to. Defaults to C<$name>,
which is what you want unless the plugin was installed under a local name

=item * C<auth> - Registry credentials, as for L</privileges>

=item * C<on_event> - CodeRef called with each progress event as it arrives.
The return value is then the summary HashRef; see
L</"Progress as it arrives">

=back

Returns an ArrayRef of progress events, C<[]> when the engine sent no
progress. Failure is reported by the same two routes as L</install>.

=head2 push

    $plugins->push('myrepo/sshfs:v1', auth => {
        username      => 'me',
        password      => 'secret',
        serveraddress => 'https://index.docker.io/v1/',
    });

Push an installed plugin to a registry. B<This writes to a real registry>
under the credentials given.

Options:

=over

=item * C<auth> - Registry credentials; HashRef of C<username> / C<password> /
C<serveraddress> / C<identitytoken>, or a pre-encoded base64 string. Sent as
C<X-Registry-Auth>

=item * C<on_event> - CodeRef called with each progress event as it arrives --
layer by layer, rather than the whole upload in one silence. The return value
is then the summary HashRef; see L</"Progress as it arrives">

=back

Unlike L<API::Docker::API::Images/push>, which sends C<X-Registry-Auth> on
every call because the engine rejects an image push without it, this sends
the header only when C<auth> is given: the plugin router decodes the header
and discards a decoding failure, so an anonymous push needs no header. The
Engine API reference documents no header on this endpoint at all; the daemon
reads it.

Returns an ArrayRef of progress events, C<[]> when the engine sent no
progress. Failure is reported by the same two routes as L</install>.

C<push> shadows the Perl builtin inside this package, which is why
L<namespace::clean> is loaded. Always call it as a method.

=head2 configure

    $plugins->configure('vieux/sshfs:latest', ['DEBUG=1']);
    $plugins->configure('vieux/sshfs:latest', 'DEBUG=1', 'sshkey.source=/tmp');

Set a plugin's user-configurable settings (C<< POST /plugins/{name}/set >>).
The plugin must be disabled. Returns C<undef>.

Settings are C<KEY=value> strings, given either as one ArrayRef or as a plain
list. They name the mutable fields of the plugin's config -- the environment
variables, mount sources, devices and args that C<< $plugin->settings >>
reports; L</inspect> is how you find out which ones a given plugin has.

The engine replaces nothing it is not told about, and rejects a key the
plugin's config does not declare as mutable.

    $plugins->configure('vieux/sshfs:latest', ['DEBUG=1']);
    $plugins->configure('vieux/sshfs:latest', 'DEBUG=1');

Both forms mean the same call, and this method takes no options in either:
anything after the ArrayRef croaks rather than being read as a setting or
quietly dropped. To bound the request, clone the resource class --
C<< $docker->plugins->using(read_timeout => 5)->configure(...) >>, see
L<API::Docker::Role::Using>.

=head1 SEE ALSO

=over

=item * L<API::Docker::Role::Entity::Plugin> - the convenience methods the
returned objects carry

=item * L<API::Docker::Type::Plugin> - the fields L</list> and L</inspect>
return

=item * L<API::Docker> - Main Docker client

=item * L<API::Docker::Role::RegistryAuth> - the C<X-Registry-Auth>
encoding used here, shared with the other registry-facing endpoints

=item * L<API::Docker::API::Images> - Image endpoints, whose C<push>
sends that header on every call rather than only when credentials were
given

=item * L<API::Docker::Error::Stream> - Raised for a failure reported inside
a 200 event stream by L</install>, L</upgrade> and L</push>

=back

=head1 SUPPORT

=head2 Issues

Please report bugs and feature requests on GitHub at
L<https://github.com/Getty/p5-api-docker/issues>.

=head1 CONTRIBUTING

Contributions are welcome! Please fork the repository and submit a pull request.

=head1 AUTHOR

Torsten Raudssus <getty@cpan.org>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2026 by Torsten Raudssus <torsten@raudssus.de> L<https://raudssus.de/>.

This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.

=cut



( run in 0.900 second using v1.01-cache-2.11-cpan-85d3896f969 )