API-Docker
view release on metacpan or search on metacpan
lib/API/Docker/Role/Entity/Container.pm view on Meta::CPAN
my ($self, $tar, %opts) = @_;
return $self->client->containers->put_archive($self->id, $tar, %opts);
}
sub stat_archive {
my ($self, %opts) = @_;
return $self->client->containers->stat_archive($self->id, %opts);
}
sub is_running {
my ($self) = @_;
my $state = $self->state;
return 0 unless defined $state;
# The one place the two shapes have to be told apart: `state` is the status
# string on a ContainerSummary and an API::Docker::Type::ContainerState on
# a ContainerInspectResponse.
return $state->running ? 1 : 0 if blessed $state;
return lc($state) eq 'running' ? 1 : 0;
}
# --- composition -----------------------------------------------------------
#
# Here rather than in API::Docker::API::Containers, which is the other
# candidate: loading this role is then what puts the methods on the classes,
# and there is no program in which an API::Docker::Type::ContainerSummary has
# ->start and another in which it does not, depending on which module was
# loaded first.
#
# 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 19 names collides today; a future one says so
# on the first `use`.
{
my @provided = Package::Stash->new(__PACKAGE__)->list_all_symbols('CODE');
for my $class (
'API::Docker::Type::ContainerSummary',
'API::Docker::Type::ContainerInspectResponse',
) {
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::Container - Container operations, on the generated container types
=head1 VERSION
version 0.004
=head1 SYNOPSIS
my $docker = API::Docker->new;
# from list: an API::Docker::Type::ContainerSummary
my ($container) = @{ $docker->containers->list };
say $container->id;
say $container->status; # "Up 2 hours"
say $container->state; # "running"
$container->start;
$container->stop(timeout => 10);
my $logs = $container->logs(tail => 100);
$container->remove(force => 1);
# from inspect: an API::Docker::Type::ContainerInspectResponse, where
# the same methods work and `state` is an object
my $full = $docker->containers->inspect($container->id);
say $full->state->status;
say $full->state->exit_code;
if ($full->is_running) { ... }
=head1 DESCRIPTION
The convenience methods of a container. This role is composed, at load time,
into the two generated classes the daemon answers container requests with:
=over
=item * L<API::Docker::Type::ContainerSummary> -- one entry of
C<GET /containers/json>, what L<API::Docker::API::Containers/list> returns
=item * L<API::Docker::Type::ContainerInspectResponse> -- the body of
C<GET /containers/{id}/json>, what L<API::Docker::API::Containers/inspect>
returns
=back
Every method here forwards to L<API::Docker::API::Containers> with the
container's own C<id> and returns whatever that method returns; the options
are that method's options, undocumented here on purpose so there is one
place to correct when the engine's are found to be something else.
The fields differ between the two classes -- see
L<API::Docker::API::Containers/"The two container shapes"> for the
differences that have bitten. L</is_running> is the one method that reads
both shapes.
Why the methods are a role applied to generated classes rather than a class
( run in 1.739 second using v1.01-cache-2.11-cpan-02e1dfdd527 )