API-Docker

 view release on metacpan or  search on metacpan

LICENSE  view on Meta::CPAN

    you changed the files and the date of any change; and

    b) cause the whole of any work that you distribute or publish, that
    in whole or in part contains the Program or any part thereof, either
    with or without modifications, to be licensed at no charge to all
    third parties under the terms of this General Public License (except
    that you may choose to grant warranty protection to some or all
    third parties, at your option).

    c) If the modified program normally reads commands interactively when
    run, you must cause it, when started running for such interactive use
    in the simplest and most usual way, to print or display an
    announcement including an appropriate copyright notice and a notice
    that there is no warranty (or else, saying that you provide a
    warranty) and that users may redistribute the program under these
    conditions, and telling the user how to view a copy of this General
    Public License.

    d) You may charge a fee for the physical act of transferring a
    copy, and you may at your option offer warranty protection in
    exchange for a fee.

LICENSE  view on Meta::CPAN

                     END OF TERMS AND CONDITIONS

        Appendix: How to Apply These Terms to Your New Programs

  If you develop a new program, and you want it to be of the greatest
possible use to humanity, the best way to achieve this is to make it
free software which everyone can redistribute and change under these
terms.

  To do so, attach the following notices to the program.  It is safest to
attach them to the start of each source file to most effectively convey
the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.

    <one line to give the program's name and a brief idea of what it does.>
    Copyright (C) 19yy  <name of author>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 1, or (at your option)
    any later version.

LICENSE  view on Meta::CPAN

    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    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

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

    # System information
    my $info = $docker->system->info;
    my $version = $docker->system->version;

    # Container management
    my $containers = $docker->containers->list(all => 1);
    my $result = $docker->containers->create(
        Image => 'nginx:latest',
        name  => 'my-nginx',
    );
    $docker->containers->start($result->{Id});

    # Image operations
    $docker->images->pull(fromImage => 'nginx', tag => 'latest');
    my $images = $docker->images->list;

    # Network and volume management
    my $networks = $docker->networks->list;
    my $volumes = $docker->volumes->list;

=head1 DESCRIPTION

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

Path to TLS certificates. Defaults to C<$ENV{DOCKER_CERT_PATH}>.

=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>.

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



sub inspect {
  my ($self, $id) = @_;
  croak "Container ID required" unless $id;
  my $result = $self->client->get("/containers/$id/json");
  return $self->_wrap($result);
}


sub start {
  my ($self, $id) = @_;
  croak "Container ID required" unless $id;
  return $self->client->post("/containers/$id/start", undef);
}


sub stop {
  my ($self, $id, %opts) = @_;
  croak "Container ID required" unless $id;
  my %params;
  $params{t}      = $opts{timeout} if defined $opts{timeout};
  $params{signal} = $opts{signal}  if defined $opts{signal};
  return $self->client->post("/containers/$id/stop", undef, params => \%params);
}


sub restart {
  my ($self, $id, %opts) = @_;
  croak "Container ID required" unless $id;
  my %params;
  $params{t} = $opts{timeout} if defined $opts{timeout};
  return $self->client->post("/containers/$id/restart", undef, params => \%params);
}


sub kill {
  my ($self, $id, %opts) = @_;
  croak "Container ID required" unless $id;
  my %params;
  $params{signal} = $opts{signal} if defined $opts{signal};
  return $self->client->post("/containers/$id/kill", undef, params => \%params);
}

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


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

    # List containers
    my $containers = $docker->containers->list(all => 1);
    for my $container (@$containers) {
        say $container->Id;
        say $container->Status;
    }

    # Create and start a container
    my $result = $docker->containers->create(
        Image => 'nginx:latest',
        name  => 'my-nginx',
        ExposedPorts => { '80/tcp' => {} },
    );
    $docker->containers->start($result->{Id});

    # Inspect container details
    my $container = $docker->containers->inspect($result->{Id});
    say $container->Name;

    # Stop and remove
    $docker->containers->stop($result->{Id}, timeout => 10);
    $docker->containers->remove($result->{Id});

    # View logs
    my $logs = $docker->containers->logs($result->{Id}, tail => 100);

=head1 DESCRIPTION

This module provides methods for managing Docker containers including creation,
lifecycle operations (start, stop, restart), inspection, logs, and more.

All C<list> and C<inspect> methods return L<API::Docker::Container> objects
for convenient access to container properties and operations.

Accessed via C<< $docker->containers >>.

=head2 client

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

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

parameters are Docker container configuration (see Docker API documentation).

Common config keys: C<Image>, C<Cmd>, C<Env>, C<ExposedPorts>, C<HostConfig>.

=head2 inspect

    my $container = $containers->inspect($id);

Get detailed information about a container. Returns L<API::Docker::Container> object.

=head2 start

    $containers->start($id);

Start a container.

=head2 stop

    $containers->stop($id, timeout => 10);

Stop a container.

Options:

=over

=item * C<timeout> - Seconds to wait before killing (default 10)

=item * C<signal> - Signal to send (default SIGTERM)

=back

=head2 restart

    $containers->restart($id, timeout => 10);

Restart a container. Optionally specify C<timeout> in seconds.

=head2 kill

    $containers->kill($id, signal => 'SIGKILL');

Send a signal to a container. Default signal is C<SIGKILL>.

=head2 remove

    $containers->remove($id, force => 1, volumes => 1);

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



sub create {
  my ($self, $container_id, %config) = @_;
  croak "Container ID required" unless $container_id;
  croak "Cmd required" unless $config{Cmd};
  return $self->client->post("/containers/$container_id/exec", \%config);
}


sub start {
  my ($self, $exec_id, %opts) = @_;
  croak "Exec ID required" unless $exec_id;
  my $body = {
    Detach => $opts{Detach} ? \1 : \0,
    Tty    => $opts{Tty}    ? \1 : \0,
  };
  return $self->client->post("/exec/$exec_id/start", $body);
}


sub resize {
  my ($self, $exec_id, %opts) = @_;
  croak "Exec ID required" unless $exec_id;
  my %params;
  $params{h} = $opts{h} if defined $opts{h};
  $params{w} = $opts{w} if defined $opts{w};
  return $self->client->post("/exec/$exec_id/resize", undef, params => \%params);

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

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

    # Create an exec instance
    my $exec = $docker->exec->create($container_id,
        Cmd         => ['/bin/sh', '-c', 'echo hello'],
        AttachStdout => 1,
        AttachStderr => 1,
    );

    # Start the exec
    $docker->exec->start($exec->{Id});

    # Inspect exec instance
    my $info = $docker->exec->inspect($exec->{Id});

=head1 DESCRIPTION

This module provides methods for executing commands inside running containers
using the Docker Exec API.

Accessed via C<< $docker->exec >>.

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

        Tty          => 0,
    );

Create an exec instance. Returns hashref with C<Id>.

Required config: C<Cmd> (ArrayRef of command and arguments).

Common config keys: C<AttachStdin>, C<AttachStdout>, C<AttachStderr>, C<Tty>,
C<Env>, C<User>, C<WorkingDir>.

=head2 start

    $exec->start($exec_id, Detach => 0);

Start an exec instance. Options: C<Detach>, C<Tty>.

=head2 resize

    $exec->resize($exec_id, h => 40, w => 120);

Resize the TTY for an exec instance. Options: C<h> (height), C<w> (width).

=head2 inspect

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

has Labels        => (is => 'ro');
has SizeRw        => (is => 'ro');
has SizeRootFs    => (is => 'ro');
has HostConfig    => (is => 'ro');
has NetworkSettings => (is => 'ro');
has Mounts        => (is => 'ro');

has Name          => (is => 'ro');


has RestartCount  => (is => 'ro');
has Driver        => (is => 'ro');
has Platform      => (is => 'ro');
has Path          => (is => 'ro');
has Args          => (is => 'ro');
has Config        => (is => 'ro');

sub start {
  my ($self) = @_;
  return $self->client->containers->start($self->Id);
}


sub stop {
  my ($self, %opts) = @_;
  return $self->client->containers->stop($self->Id, %opts);
}


sub restart {
  my ($self, %opts) = @_;
  return $self->client->containers->restart($self->Id, %opts);
}


sub kill {
  my ($self, %opts) = @_;
  return $self->client->containers->kill($self->Id, %opts);
}


sub remove {

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

    # Get container from list or inspect
    my $containers = $docker->containers->list;
    my $container = $containers->[0];

    # Access container properties
    say $container->Id;
    say $container->Status;
    say $container->Image;

    # Perform operations
    $container->start;
    $container->stop(timeout => 10);
    my $logs = $container->logs(tail => 100);
    $container->remove(force => 1);

    # Check state
    if ($container->is_running) {
        say "Container is running";
    }

=head1 DESCRIPTION

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

C<inspect>: hashref with C<Running>, C<Paused>, C<ExitCode>, etc.

=head2 Status

Human-readable status string (e.g., "Up 2 hours").

=head2 Name

Container name (from C<inspect>, includes leading C</>).

=head2 start

    $container->start;

Start the container. Delegates to L<API::Docker::API::Containers/start>.

=head2 stop

    $container->stop(timeout => 10);

Stop the container. Delegates to L<API::Docker::API::Containers/stop>.

=head2 restart

    $container->restart;

Restart the container.

=head2 kill

    $container->kill(signal => 'SIGTERM');

Send a signal to the container.

=head2 remove

    $container->remove(force => 1);

t/containers.t  view on Meta::CPAN

  }
};

# --- Write Tests (mock always, live only with WRITE) ---

subtest 'container lifecycle' => sub {
  skip_unless_write();

  my $docker = test_docker(
    'POST /containers/create'         => { Id => 'mock123', Warnings => [] },
    'POST /containers/mock123/start'  => undef,
    'GET /containers/mock123/json'    => load_fixture('container_inspect'),
    'GET /containers/mock123/top'     => {
      Titles    => ['UID', 'PID', 'PPID', 'C', 'STIME', 'TTY', 'TIME', 'CMD'],
      Processes => [
        ['root', '12345', '1', '0', '08:00', '?', '00:00:00', 'sleep'],
      ],
    },
    'GET /containers/mock123/stats'   => {
      cpu_stats    => { cpu_usage => { total_usage => 1000 } },
      memory_stats => { usage => 50000000 },

t/containers.t  view on Meta::CPAN

  my $created = $docker->containers->create(
    name  => $name,
    Image => 'alpine:latest',
    Cmd   => ['sleep', '10'],
  );
  ok($created->{Id}, 'created container has Id');
  my $id = is_live() ? $created->{Id} : 'mock123';

  register_cleanup(sub { $docker->containers->remove($id, force => 1) }) if is_live();

  $docker->containers->start($id);
  pass('container started');

  my $container = $docker->containers->inspect($id);
  isa_ok($container, 'API::Docker::Container');
  ok($container->is_running, 'container is running');

  my $top = $docker->containers->top($id);
  is(ref $top->{Processes}, 'ARRAY', 'top has processes');

  my $stats = $docker->containers->stats($id);
  ok($stats->{cpu_stats}, 'has cpu_stats');

t/containers.t  view on Meta::CPAN

};

# --- Validation Tests (always run, no Docker needed) ---

subtest 'container ID required' => sub {
  my $docker = test_docker();

  eval { $docker->containers->inspect(undef) };
  like($@, qr/Container ID required/, 'croak on missing ID for inspect');

  eval { $docker->containers->start(undef) };
  like($@, qr/Container ID required/, 'croak on missing ID for start');

  eval { $docker->containers->stop(undef) };
  like($@, qr/Container ID required/, 'croak on missing ID for stop');
};

done_testing;

t/fixtures/container_inspect.json  view on Meta::CPAN

{
  "Id": "abc123def456789abc123def456789abc123def456789abc123def456789abcd",
  "Created": "2025-01-15T08:00:00.000000000Z",
  "Path": "nginx",
  "Args": ["-g", "daemon off;"],
  "State": {
    "Status": "running",
    "Running": true,
    "Paused": false,
    "Restarting": false,
    "OOMKilled": false,
    "Dead": false,
    "Pid": 12345,
    "ExitCode": 0,
    "Error": "",
    "StartedAt": "2025-01-15T08:00:01.000000000Z",
    "FinishedAt": "0001-01-01T00:00:00Z"
  },
  "Image": "sha256:abc123def456",
  "Name": "/my-container",
  "RestartCount": 0,
  "Driver": "overlay2",
  "Platform": "linux",
  "HostConfig": {
    "NetworkMode": "default",
    "RestartPolicy": {
      "Name": "no",
      "MaximumRetryCount": 0
    }
  },
  "Config": {
    "Hostname": "abc123def456",
    "Env": [
      "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
      "NGINX_VERSION=1.25.3"
    ],

t/system.t  view on Meta::CPAN

    is(scalar @{$df->{Containers}}, 1, 'one container');
    is(scalar @{$df->{Volumes}}, 1, 'one volume');
  }
};

subtest 'events' => sub {
  my $docker = test_docker(
    'GET /events' => [
      {
        Type   => 'container',
        Action => 'start',
        Actor  => { ID => '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.003 second using v1.01-cache-2.11-cpan-cdf2f3d4e48 )