API-Docker

 view release on metacpan or  search on metacpan

lib/API/Docker/Role/Entity/Config.pm  view on Meta::CPAN

  my $version
    = exists $opts{version} ? delete $opts{version} : $self->version_index;
  return $self->client->configs->update($self->id, $version, %opts);
}


sub remove {
  my ($self) = @_;
  return $self->client->configs->remove($self->id);
}


# --- composition -----------------------------------------------------------
#
# Here rather than in API::Docker::API::Configs, for the reason spelled out in
# API::Docker::Role::Entity::Container: loading this role is what puts the
# methods on the class.
#
# The clash check is not decoration. Moo composes a role into a class the
# class-wins way, so a generated accessor of the same name as a method here
# would silently keep its place and the method would be missing -- and the
# generated classes are written from a specification that grows fields
# without asking. None of the five names collides today; a future one says so
# on the first `use`. `version_index` is the one to watch: the class already
# declares `version`.
{
  my @provided = Package::Stash->new(__PACKAGE__)->list_all_symbols('CODE');
  for my $class ('API::Docker::Type::Config') {
    my $fields = $class->docker_attributes;
    my @clash = sort grep { $fields->{$_} } @provided;
    croak __PACKAGE__ . ': ' . $class . ' declares ' . join(', ', @clash)
      . ' as a daemon field; the generated accessor would win over the '
      . 'method of that name and it would be missing without a word'
      if @clash;
    Moo::Role->apply_roles_to_package($class, __PACKAGE__);
  }
}


1;

__END__

=pod

=encoding UTF-8

=head1 NAME

API::Docker::Role::Entity::Config - Config operations, on the generated config type

=head1 VERSION

version 0.004

=head1 SYNOPSIS

    my $docker = API::Docker->new;
    my ($config) = @{ $docker->configs->list };

    say $config->id;
    say $config->spec->name;
    say $config->spec->data;        # still base64, as the daemon sent it
    say $config->decoded_data;      # the bytes

    my %spec = %{ $config->spec->TO_JSON };
    delete $spec{Data};             # already base64 -- see update
    $spec{Labels} = { app => 'web' };
    $config->update(%spec);

    $config->remove;

=head1 DESCRIPTION

The convenience methods of a Docker config. This role is composed, at load
time, into L<API::Docker::Type::Config>, the generated class the daemon
answers config requests with -- the same definition for C<GET /configs> and
C<GET /configs/{id}>, so L<API::Docker::API::Configs/list> and
L<API::Docker::API::Configs/inspect> hand back one class and there is no
list-versus-inspect shape to keep apart.

A config is a secret whose value can be read back: the daemon returns it in
C<< spec->data >> as base64, where a secret returns no payload at all --
L<API::Docker::Role::Entity::Secret/"There is no accessor for the value">.
L</decoded_data> is the accessor for it.

=head2 Decoding is offered here, not in the API class

L<API::Docker::API::Configs> hands back the daemon's response with nothing
rewritten, which is the rule the whole distribution follows -- so
C<< $config->spec->data >> is the base64 string the engine sent, unchanged,
and stays that way. L</decoded_data> does not touch it either: it decodes on
demand and returns the bytes, leaving the spec verbatim for anyone who wants
to compare it against the wire or hand it back.

That is the whole reason the accessor belongs on the entity rather than on
the API class: an entity may offer a derived view of a response, an API
method may not silently replace one.

=head2 The spec goes back as a whole

C<< $config->spec >> is an L<API::Docker::Type::ConfigSpec> object rather
than the raw HashRef the hand-written entity kept, so the idiom for an update
is C<< %{ $config->spec->TO_JSON } >>: C<TO_JSON> renders the spec back into
the daemon's own spelling, which is what L</update> puts in the request body.
Mind the C<Data> it brings with it -- see L</update>.

Why the methods are a role applied to a generated class rather than a class
of their own: L<API::Docker::Role::Entity/DESCRIPTION>.

=head2 decoded_data

    my $text = $config->decoded_data;

The config's content: C<< $config->spec->data >> run through
L<MIME::Base64/decode_base64>. Returns nothing when the object carries no
C<Spec> or no C<Data> in it.

The result is B<raw bytes>, symmetric with what
L<API::Docker::API::Configs/create> takes -- decode the character set yourself
if the config holds text above C<U+007F>, for instance with
C<Encode::decode_utf8>.

The spec is left alone; see



( run in 1.232 second using v1.01-cache-2.11-cpan-a49fcb8fa48 )