API-Docker

 view release on metacpan or  search on metacpan

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

    %{ $self->_request_options },
  );
}



1;

__END__

=pod

=encoding UTF-8

=head1 NAME

API::Docker::API::Plugins - Docker Engine Plugins API

=head1 VERSION

version 0.004

=head1 SYNOPSIS

    my $docker = API::Docker->new;

    # List installed plugins
    my $plugins = $docker->plugins->list;

    # Install: look at what the plugin demands, then grant exactly that
    my $privileges = $docker->plugins->privileges('vieux/sshfs:latest');
    $docker->plugins->install('vieux/sshfs:latest',
        privileges => $privileges,
    );
    $docker->plugins->enable('vieux/sshfs:latest');

    # Inspect
    my $plugin = $docker->plugins->inspect('vieux/sshfs:latest');
    say $plugin->name, $plugin->enabled ? ' (enabled)' : ' (disabled)';

    # Configure, upgrade, disable, remove
    $docker->plugins->configure('vieux/sshfs:latest', ['DEBUG=1']);
    $docker->plugins->upgrade('vieux/sshfs:latest', privileges => $privileges);
    $docker->plugins->disable('vieux/sshfs:latest');
    $docker->plugins->remove('vieux/sshfs:latest');

=head1 DESCRIPTION

This module provides access to the Docker managed-plugin endpoints
(C</plugins>).

Accessed via C<< $docker->plugins >>, or through
L<API::Docker::Role::Using/using> for a run of calls that needs its own
transport bound: C<< $docker->plugins->using(read_timeout => 5) >>.

=head2 Installing is two calls, and the engine enforces it

C<< POST /plugins/pull >> takes the list of privileges the plugin demands
B<in its request body>, and the daemon compares that list against the one it
computes from the plugin's own config. They must match exactly -- same
length, same names, same values -- or the install fails with
C<incorrect privileges>. A plugin runs with the host access it asked for, so
the round trip exists to make somebody look at that access before granting
it.

L</privileges> is the first call, L</install> the second:

    my $privileges = $docker->plugins->privileges('vieux/sshfs:latest');
    # inspect $privileges here -- it is an ArrayRef of
    #   { Name => 'network', Description => '...', Value => ['host'] }
    $docker->plugins->install('vieux/sshfs:latest', privileges => $privileges);

C<install> B<requires> C<privileges> and croaks without it, which is stricter
than the engine: the daemon's own body parser treats a missing body as an
empty privilege list rather than an error, so a blind install of a plugin
that happens to demand nothing would quietly succeed and one that demands
C<network: host> would fail with an error naming neither. Passing
C<< accept_privileges => 1 >> makes C<install> perform the first call itself
and hand the answer straight back -- a blanket grant, spelled out at the call
site so it is greppable.

The same applies to L</upgrade>, which takes the same body.

=head2 Not available on Podman

Measured against the rootless Podman socket (5.4.2, API 1.41): B<none> of the
C</plugins> endpoints exist there. C<< GET /v1.41/plugins >> answers
C<404 Not Found> with
C<< {"cause":"","message":"Path /v1.41/plugins is not supported","response":0} >>
(the C<1.41> there is this client's negotiated API version, echoed back from
the request path -- it moves with negotiation, not a fixed string in the
daemon's error text),
and every other path in this family -- C</plugins/privileges>,
C</plugins/pull>, C</plugins/{name}/json>, C</plugins/{name}/enable> and the
rest -- answers a bare C<404 Not Found> as C<text/plain>, meaning the compat
layer has no route registered for them at all. Managed plugins are a Docker
feature; Podman's own plugin model is not served here. Everything in this
class therefore needs a real Docker daemon.

=head2 What this class returns

L</list> and L</inspect> return L<API::Docker::Type::Plugin> objects carrying
the convenience methods of L<API::Docker::Role::Entity::Plugin>, following
the C<list>/C<inspect> convention every other resource class here follows.
It is B<one> class for both, where containers and images have two: the
swagger answers C<GET /plugins> with an array of the C<Plugin> definition and
C<GET /plugins/{name}/json> with that same definition.

Field names are the swagger's own spelling in snake_case, and the nested
ones are generated classes rather than the raw HashRefs the old entity kept:
C<< $plugin->settings >> is an L<API::Docker::Type::Plugin::Settings> whose
C<< ->env >> is a list of C<KEY=value> strings, and C<< $plugin->config >> an
L<API::Docker::Type::Plugin::Config> whose C<< ->env >> is a list of
L<API::Docker::Type::PluginEnv> objects describing those same variables. The
entity's methods thread the plugin's name back through this class.

Everything else returns the decoded engine response as it came: L</privileges>
an ArrayRef of privilege HashRefs, L</install>, L</upgrade> and L</push> an
ArrayRef of progress events, and L</enable>, L</disable>, L</remove> and
L</configure> C<undef>.



( run in 2.749 seconds using v1.01-cache-2.11-cpan-54e63673c56 )