API-Docker
view release on metacpan or search on metacpan
## API conventions
- **Resource accessors live under the client:** `$docker->images`,
`$docker->containers`, etc. Each returns a `*::API::*` instance.
- **List/inspect endpoints return entity objects** (e.g.
`$docker->images->list` returns `[API::Docker::Image, ...]`); raw
endpoints (e.g. `tag`, `push`) return the raw daemon response.
- **`$docker->_request($method, $path, %opts)`** is the single transport
entry point. Opts: `body` (auto-JSON-encoded), `raw_body` +
`content_type` (e.g. tarballs), `params` (query string),
`headers` (extra HTTP headers â used by push for `X-Registry-Auth`).
- **`/build`, `/images/create`, `/images/.../push`** are streaming
endpoints. `_request` parses newline-delimited JSON and returns an
arrayref of events; callers iterate and look for `errorDetail`,
`progress`, `aux`, etc.
- **`X-Registry-Auth` is required on every push** by the Docker Engine â
even anonymous attempts. `images->push` always sends the header; pass
`auth => { username, password, serveraddress, identitytoken }` to
authenticate, omit it for the empty-`{}` form.
You should have received a copy of the GNU General Public License
along with this program; if not, see <https://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) 19xx name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the
appropriate parts of the General Public License. Of course, the
commands you use may be called something other than `show w' and `show
c'; they could even be mouse-clicks or menu items--whatever suits your
program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here a sample; alter the names:
}
}
},
"release_status" : "stable",
"resources" : {
"bugtracker" : {
"web" : "https://github.com/Getty/p5-api-docker/issues"
},
"homepage" : "https://github.com/Getty/p5-api-docker",
"repository" : {
"type" : "git",
"url" : "https://github.com/Getty/p5-api-docker.git",
"web" : "https://github.com/Getty/p5-api-docker"
}
},
"version" : "0.002",
"x_Dist_Zilla" : {
"perl" : {
"version" : "5.036000"
},
"plugins" : [
}
},
"name" : "@Author::GETTY/PodWeaver",
"version" : "4.010"
},
{
"class" : "Dist::Zilla::Plugin::Prereqs",
"config" : {
"Dist::Zilla::Plugin::Prereqs" : {
"phase" : "develop",
"type" : "recommends"
}
},
"name" : "@Author::GETTY/@Git::VersionManager/pluginbundle version",
"version" : "6.037"
},
{
"class" : "Dist::Zilla::Plugin::RewriteVersion::Transitional",
"config" : {
"Dist::Zilla::Plugin::RewriteVersion" : {
"add_tarball_name" : 0,
class: Pod::Weaver::Plugin::Transformer
name: '@GETTY/GETTY'
version: '4.020'
name: '@Author::GETTY/PodWeaver'
version: '4.010'
-
class: Dist::Zilla::Plugin::Prereqs
config:
Dist::Zilla::Plugin::Prereqs:
phase: develop
type: recommends
name: '@Author::GETTY/@Git::VersionManager/pluginbundle version'
version: '6.037'
-
class: Dist::Zilla::Plugin::RewriteVersion::Transitional
config:
Dist::Zilla::Plugin::RewriteVersion:
add_tarball_name: 0
finders:
- ':ExecFiles'
- ':InstallModules'
lib/API/Docker/API/Images.pm view on Meta::CPAN
}
if ($opts{labels}) {
require JSON::MaybeXS;
$params{labels} = JSON::MaybeXS::encode_json($opts{labels});
}
my $raw = ref $context eq 'SCALAR' ? $$context : $context;
return $self->client->_request('POST', '/build',
raw_body => $raw,
content_type => 'application/x-tar',
params => \%params,
);
}
sub pull {
my ($self, %opts) = @_;
croak "fromImage required" unless $opts{fromImage};
my %params;
$params{fromImage} = $opts{fromImage};
lib/API/Docker/API/System.pm view on Meta::CPAN
my $pong = $system->ping;
Health check endpoint. Returns C<OK> string if daemon is responsive.
=head2 events
my $events = $system->events(
since => 1234567890,
until => 1234567900,
filters => { type => ['container'] },
);
Get real-time events from the Docker daemon.
Options:
=over
=item * C<since> - Show events created since this timestamp
=item * C<until> - Show events created before this timestamp
=item * C<filters> - Hashref of filters (e.g., C<< { type => ['container', 'image'] } >>)
=back
=head2 df
my $usage = $system->df;
Get data usage information (disk usage by images, containers, and volumes).
Returns hashref with C<LayersSize>, C<Images>, C<Containers>, and C<Volumes> arrays.
lib/API/Docker/Role/HTTP.pm view on Meta::CPAN
return $self->_socket;
}
sub _request {
my ($self, $method, $path, %opts) = @_;
my $version = $self->api_version;
my $url_path = defined $version ? "/v$version$path" : $path;
my $body_content = '';
my $content_type = 'application/json';
if ($opts{raw_body}) {
$body_content = $opts{raw_body};
$content_type = $opts{content_type} // 'application/x-tar';
}
elsif ($opts{body}) {
$body_content = encode_json($opts{body});
}
if ($opts{params}) {
my @pairs;
for my $k (sort keys %{$opts{params}}) {
my $v = $opts{params}{$k};
next unless defined $v;
lib/API/Docker/Role/HTTP.pm view on Meta::CPAN
}
$log->debugf("%s %s", $method, $url_path);
my $request = "$method $url_path HTTP/1.1\r\n";
$request .= "Host: localhost\r\n";
$request .= "Connection: close\r\n";
$request .= "User-Agent: API-Docker\r\n";
if ($body_content) {
$request .= "Content-Type: $content_type\r\n";
$request .= "Content-Length: " . length($body_content) . "\r\n";
}
if ($opts{headers}) {
for my $h (sort keys %{$opts{headers}}) {
my $v = $opts{headers}{$h};
next unless defined $v;
$v =~ s/[\r\n]//g;
$request .= "$h: $v\r\n";
}
# Test custom host
my $docker_tcp = API::Docker->new(
host => 'tcp://remote:2375',
api_version => '1.47',
);
is($docker_tcp->host, 'tcp://remote:2375', 'custom host');
# Test API accessors exist
can_ok($docker, qw(system containers images networks volumes exec));
# Test API accessor types
isa_ok($docker->system, 'API::Docker::API::System');
isa_ok($docker->containers, 'API::Docker::API::Containers');
isa_ok($docker->images, 'API::Docker::API::Images');
isa_ok($docker->networks, 'API::Docker::API::Networks');
isa_ok($docker->volumes, 'API::Docker::API::Volumes');
isa_ok($docker->exec, 'API::Docker::API::Exec');
done_testing;
t/fixtures/system_info.json view on Meta::CPAN
{
"ID": "7TRN:IPZB:QYBB:VPBQ:UMPP:KARE:6ZNR:XE6T:7EWV:PKF4:ZOJD:TPYS",
"Containers": 14,
"ContainersRunning": 3,
"ContainersPaused": 1,
"ContainersStopped": 10,
"Images": 25,
"Driver": "overlay2",
"DriverStatus": [
["Backing Filesystem", "extfs"],
["Supports d_type", "true"],
["Using metacopy", "false"],
["Native Overlay Diff", "true"]
],
"DockerRootDir": "/var/lib/docker",
"SystemTime": "2025-01-15T10:30:00.000000000Z",
"Name": "test-host",
"ServerVersion": "27.4.1",
"OperatingSystem": "Debian GNU/Linux 12 (bookworm)",
"OSType": "linux",
"Architecture": "x86_64",
# --- Write Tests (mock always, live only with WRITE) ---
subtest 'image build and pull lifecycle' => sub {
skip_unless_write();
my $docker = test_docker(
'POST /build' => sub {
my ($method, $path, %opts) = @_;
ok(defined $opts{raw_body}, 'raw_body present in request');
is($opts{content_type}, 'application/x-tar', 'content type is tar');
return { stream => 'Successfully built abc123def456' };
},
'POST /images/create' => sub {
my ($method, $path, %opts) = @_;
return '';
},
'POST /images/nginx:latest/tag' => undef,
'DELETE /images/nginx:latest' => [
{ Untagged => 'nginx:latest' },
{ Deleted => 'sha256:abc123' },
time => 1705300000,
},
],
);
my $events = $docker->system->events(since => 1705290000, until => 1705310000);
is(ref $events, 'ARRAY', 'events is array');
unless (is_live()) {
is($events->[0]{Type}, 'container', 'event type');
is($events->[0]{Action}, 'start', 'event action');
}
};
done_testing;
( run in 1.389 second using v1.01-cache-2.11-cpan-df04353d9ac )