API-Docker
view release on metacpan or search on metacpan
lib/API/Docker.pm view on Meta::CPAN
package API::Docker;
# ABSTRACT: Perl client for the Docker Engine API
our $VERSION = '0.004';
use Moo;
use Carp qw( croak );
use Log::Any qw( $log );
use API::Docker::API::System;
use API::Docker::API::Containers;
use API::Docker::API::Images;
use API::Docker::API::Networks;
use API::Docker::API::Volumes;
use API::Docker::API::Exec;
use API::Docker::API::Distribution;
use API::Docker::API::Secrets;
use API::Docker::API::Configs;
use API::Docker::API::Plugins;
use namespace::clean;
has host => (
is => 'ro',
default => sub { $ENV{DOCKER_HOST} // 'unix:///var/run/docker.sock' },
);
has api_version => (
is => 'rwp',
default => undef,
);
has tls => (
is => 'lazy',
);
sub _build_tls {
my ($self) = @_;
# The docker CLI's own rule, read off cli/flags/options.go:
# dockerTLSVerify = os.Getenv(client.EnvTLSVerify) != ""
# Every non-empty value turns TLS on, DOCKER_TLS_VERIFY=0 included. Perl
# truthiness would read that '0' as off and disagree with the CLI on exactly
# the value a user is most likely to type for "off", so the test is
# defined-and-not-empty rather than a boolean one.
return 0 unless defined $ENV{DOCKER_TLS_VERIFY}
&& $ENV{DOCKER_TLS_VERIFY} ne '';
# And the CLI ignores TLS on a socket host without saying so
# (cli/context/docker/load.go, "there's no need to configure TLS for a
# socket connection"). Ignoring it here is not politeness: BUILD croaks on
# tls => 1 with a non-tcp:// host, so a host-blind default would make a bare
# API::Docker->new die on every unix:// machine that exports the variable.
return $self->host =~ m{^tcp://} ? 1 : 0;
}
has cert_path => (
is => 'ro',
default => sub { $ENV{DOCKER_CERT_PATH} },
);
has tls_insecure => (
is => 'ro',
default => 0,
);
sub BUILD {
my ($self) = @_;
# Both checks are here rather than at connect time so that a request for
# encryption that cannot be honoured is refused before the caller has a
# client to hand credentials to.
croak __PACKAGE__ . '->new tls_insecure => 1 without tls => 1 does '
. 'nothing: verification is only reachable on a connection that has TLS '
. 'to verify. Set tls => 1 as well, or drop the option'
if $self->tls_insecure && !$self->tls;
return unless $self->tls;
my $host = $self->host;
croak __PACKAGE__ . '->new tls => 1 is only meaningful for a tcp:// host, '
. 'and this one is ' . $host . '. A Unix socket is a file rather than a '
. 'wire and carries nothing to encrypt, so honouring the option is not '
. 'possible and ignoring it would answer a request for an encrypted '
. 'transport with an unencrypted one'
unless $host =~ m{^tcp://};
}
has _version_negotiated => (
is => 'rw',
default => 0,
);
with 'API::Docker::Role::HTTP';
has system => (
is => 'lazy',
builder => sub { API::Docker::API::System->new(client => $_[0]) },
);
has containers => (
is => 'lazy',
builder => sub { API::Docker::API::Containers->new(client => $_[0]) },
);
lib/API/Docker.pm view on Meta::CPAN
which leaves a connection encrypted against a passive listener and against
nothing else: whoever answers it chooses the certificate, so anyone able to
redirect the connection reads and rewrites everything on it -- registry
credentials, image contents, the commands containers are started with.
It exists for a self-signed daemon certificate whose CA is not to hand. The
better answer is nearly always L</cert_path>: a self-signed certificate is its
own CA and works as F<ca.pem> directly.
Setting it without L</tls> croaks, rather than being accepted and doing
nothing.
=head2 system
Returns L<API::Docker::API::System> instance for system operations like
C<info>, C<version>, C<ping>, and C<events>.
=head2 containers
Returns L<API::Docker::API::Containers> instance for container operations like
C<list>, C<create>, C<start>, C<stop>, and C<remove>.
=head2 images
Returns L<API::Docker::API::Images> instance for image operations like
C<list>, C<pull>, C<push>, and C<remove>.
=head2 networks
Returns L<API::Docker::API::Networks> instance for network operations like
C<list>, C<create>, C<connect>, and C<disconnect>.
=head2 volumes
Returns L<API::Docker::API::Volumes> instance for volume operations like
C<list>, C<create>, and C<remove>.
=head2 exec
Returns L<API::Docker::API::Exec> instance for executing commands in containers.
=head2 distribution
Returns L<API::Docker::API::Distribution> instance for registry manifest
lookups: C<inspect> and C<exists>.
=head2 secrets
Returns L<API::Docker::API::Secrets> instance for secret operations: C<list>,
C<create>, C<inspect>, C<update> and C<remove>.
=head2 configs
Returns L<API::Docker::API::Configs> instance for config operations: C<list>,
C<create>, C<inspect>, C<update> and C<remove>.
=head2 plugins
Returns L<API::Docker::API::Plugins> instance for managed-plugin operations:
C<list>, C<privileges>, C<install>, C<inspect>, C<remove>, C<enable>,
C<disable>, C<upgrade>, C<push> and C<configure>.
=head2 negotiate_version
$docker->negotiate_version;
$docker->negotiate_version(read_timeout => 5, connect_timeout => 2);
Automatically negotiate the highest API version supported by the Docker daemon.
This is called automatically before the first API request if L</api_version>
is not set.
After negotiation, L</api_version> will contain the negotiated version
(e.g., C<1.41>).
C<GET /version> must answer with a JSON object carrying an C<ApiVersion> of
the form C<N.N> -- the value is placed directly into the path of every later
request (C</v1.44/...>). A body that is not such an object croaks, naming the
endpoint and the shape expected: a non-object body, an object with no
C<ApiVersion>, or an C<ApiVersion> that is not two dot-separated numbers. This
replaces three earlier failures on the same path -- a non-object body dying in
C<strict refs>, an object with no C<ApiVersion> silently leaving the client
sending every request unversioned, and a malformed C<ApiVersion> being copied
verbatim into the request path.
Options:
=over
=item * C<read_timeout> - Seconds of silence after which the request gives up
and croaks with an L<API::Docker::Error::Timeout>. Off by default; see
L<API::Docker::Role::HTTP/"Bounding a request that never ends">
=item * C<connect_timeout> - Seconds after which opening the connection gives
up and croaks with an L<API::Docker::Error::Timeout> whose C<< ->phase >> is
C<'connect'>. Off by default; see
L<API::Docker::Role::HTTP/"Bounding the connection itself">
=back
Called on its own, with no options, the negotiation is bounded by the
L<API::Docker::Role::HTTP/read_timeout> and
L<API::Docker::Role::HTTP/connect_timeout> attributes of the client, like any
other request. Reached the way it normally is -- automatically, from the first
request -- it inherits that request's own bounds instead; see
L</"What a timeout covers">.
=head1 TIMEOUTS
=head2 What a timeout covers
Two bounds, covering different halves of a request.
L<API::Docker::Role::HTTP/connect_timeout> bounds opening the connection;
L<API::Docker::Role::HTTP/read_timeout> bounds reading the answer. Both are
attributes of the client, and they are set in two places -- which are two
levels, not two spellings of one thing:
# the rule, for this client
my $docker = API::Docker->new(connect_timeout => 2, read_timeout => 30);
# the exception, for this run of calls
$docker->containers->using(read_timeout => 5)->list;
( run in 0.756 second using v1.01-cache-2.11-cpan-aadc1410aed )