API-Docker

 view release on metacpan or  search on metacpan

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

use Carp qw( croak );
use MIME::Base64 qw( encode_base64 );
use namespace::clean;


has client => (
  is       => 'ro',
  required => 1,
  weak_ref => 1,
);


# The class is the caller's argument, as it is on the resource classes whose
# list and inspect really are two definitions -- here both are the swagger's
# one `Secret`, and passing it keeps the seam in the same place.
#
# from_data, not new: this is a daemon response, and the two entry points of
# API::Docker::Role::Type read it differently. from_data takes the swagger's
# wire names and nothing else, so a key it has not heard of keeps its own
# spelling instead of being read as the Perl name of one it has, and a value
# that disagrees with the swagger costs its own field rather than the whole
# response. `client` is ours rather than the engine's, so it goes beside the
# data instead of into it.
sub _wrap {
  my ($self, $class, $data) = @_;
  return $class->from_data($data, client => $self->client);
}

sub _wrap_list {
  my ($self, $class, $list) = @_;
  return [ map { $self->_wrap($class, $_) } @$list ];
}

# The wire field is base64; the public contract is raw bytes. Guarding the
# character range here keeps the failure a croak naming this class instead of
# MIME::Base64's "Wide character in subroutine entry" from two frames down.
sub _encode_data {
  my ($self, $method, $data) = @_;
  croak __PACKAGE__ . "->$method Data must be a byte string, not decoded "
    . 'characters -- encode it first (Encode::encode_utf8)'
    if $data =~ /[^\x00-\xff]/;
  return encode_base64($data, '');
}

sub list {
  my ($self, %opts) = @_;
  my %params;
  $params{filters} = $self->_normalise_filters($opts{filters})
    if defined $opts{filters};
  return $self->_wrap_list('API::Docker::Type::Secret',
    $self->client->get('/secrets',
      params => \%params,
      %{ $self->_request_options },
    ) // []);
}


sub create {
  my ($self, %spec) = @_;
  croak __PACKAGE__ . '->create Name required'
    unless defined $spec{Name} && length $spec{Name};
  croak __PACKAGE__ . '->create Data required'
    unless defined $spec{Data} && length $spec{Data};
  $spec{Data} = $self->_encode_data('create', $spec{Data});
  return $self->client->post('/secrets/create', \%spec);
}


sub inspect {
  my ($self, $id) = @_;
  croak __PACKAGE__ . '->inspect secret ID or name required'
    unless defined $id && length $id;
  return $self->_wrap('API::Docker::Type::Secret',
    $self->client->get("/secrets/$id",
      %{ $self->_request_options },
    ));
}


sub update {
  my ($self, $id, $version, %spec) = @_;
  croak __PACKAGE__ . '->update secret ID or name required'
    unless defined $id && length $id;
  croak __PACKAGE__ . '->update requires the current version as its second '
    . 'argument: the Version.Index from inspect($id), which the daemon uses '
    . 'as an optimistic-concurrency token and will not accept the update '
    . 'without'
    unless defined $version;
  croak __PACKAGE__ . '->update version must be the numeric Version.Index '
    . "from inspect(\$id), got '$version'"
    unless $version =~ /\A[0-9]+\z/;
  $spec{Data} = $self->_encode_data('update', $spec{Data})
    if defined $spec{Data};
  return $self->client->post("/secrets/$id/update", \%spec,
    params => { version => $version });
}


sub remove {
  my ($self, $id) = @_;
  croak __PACKAGE__ . '->remove secret ID or name required'
    unless defined $id && length $id;
  return $self->client->delete_request("/secrets/$id",
    %{ $self->_request_options },
  );
}



1;

__END__

=pod

=encoding UTF-8

=head1 NAME

API::Docker::API::Secrets - Docker Engine Secrets API

=head1 VERSION

version 0.004

=head1 SYNOPSIS

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

    # List secrets
    my $secrets = $docker->secrets->list;

    # Create a secret -- Data is RAW BYTES, this class base64-encodes it
    my $created = $docker->secrets->create(
        Name   => 'my-secret',
        Data   => "hunter2\n",
        Labels => { env => 'prod' },
    );

    # Inspect a secret -- an API::Docker::Type::Secret
    my $secret = $docker->secrets->inspect($created->{ID});
    say $secret->spec->name;

    # Update: the version comes from the inspect above, and is mandatory
    my %spec = %{ $secret->spec->TO_JSON };
    $spec{Labels} = { env => 'staging' };
    $secret->update(%spec);

    # Remove
    $docker->secrets->remove($created->{ID});

=head1 DESCRIPTION

This module provides methods for managing Docker secrets (C</secrets>):
listing, creation, inspection, update and removal.

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

L</list> and L</inspect> return L<API::Docker::Type::Secret> objects carrying
the convenience methods of L<API::Docker::Role::Entity::Secret>. It is B<one>



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