API-Docker

 view release on metacpan or  search on metacpan

CLAUDE.md  view on Meta::CPAN


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

LICENSE  view on Meta::CPAN

    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:

META.json  view on Meta::CPAN

         }
      }
   },
   "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" : [

META.json  view on Meta::CPAN

               }
            },
            "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,

META.yml  view on Meta::CPAN

              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";
    }

t/basic.t  view on Meta::CPAN

# 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",

t/images.t  view on Meta::CPAN


# --- 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' },

t/system.t  view on Meta::CPAN

        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.005 second using v1.01-cache-2.11-cpan-df04353d9ac )