=encoding utf8

=head1 NAME

Eixo::Docker - Suite of Perl modules to interact with Docker  

=head1 SYNOPSIS

First we need docker api server running in a tcp socket

- For example, to run api in localhost:4243, add this line to B</etc/default/docker>

    DOCKER_OPTS="-H 127.0.0.1:4243 -d"

- And restart docker service

    $ sudo service docker restart

Now to interact with it, instantiate a docker api client with the tcp socket url of the docker API:

    use Eixo::Docker::Api;
    
    my $a = Eixo::Docker::Api->new('http://127.0.0.1:4243'); 

    # TO USE https

    my $a = Eixo::Docker::Api->new(

        host => '1.1.1.1:2376', # default to $ENV{DOCKER_HOST},
        tls_verify => 1,        # default to $ENV{DOCKER_TLS_VERIFY}
        ca_file => 'ca.pem',    # path to ca cert file, default to $ENV{DOCKER_CERT_PATH}/ca.pem,
        cert_file =>'cert.pem', # path to client cert file, default to $ENV{DOCKER_CERT_PATH}/cert.pem,
        key_file => 'key.pem',  # path to client key file, default to $ENV{DOCKER_CERT_PATH}/key.pem

    );

    # OR

    my $a = Eixo::Docker::Api->new(
        'https://1.1.1.1:2376'

        ca_file => 'ca.pem',
        cert_file =>'cert.pem',
        key_file => 'key.pem',
    );


From now on you can call all the Docker api methods throught api products (B<containers> and B<images>), passing the args indicated in L<api documentation|http://docs.docker.io/en/latest/reference/api/docker_remote_api/>:

=head2 Interacting with containers

=head3 Getting a container

    #
    # CONTAINERS
    #
    
    ## get (by id)
    my $c = $a->containers->get(id => "340f03a2c2cfxx");
    
    ## getByName
    my $c = $a->containers->getByName("testing123");


=head3 Creating a container    

    # create
    # to see all available params 
    # http://docs.docker.io/en/latest/api/docker_remote_api_v1.10/#create-a-container
    my $c = $a->container->create(
        Hostname => 'test',
        Memory   => 128,
        Cmd => ["ls","-l"],
        Image => "ubuntu",
        Name => "testing123"
    );

=head3 Creating a container (asynchronous version)

    #
    #  Closure to get the created container
    # 
    my $new_container;

    $api->containers->createAsync(
	
	%args_creation,

	onSuccess=> sub {

		$new_container = $_[0];

	}

    );

    #
    # Waiting for the job to complete
    #
    $api->waitForJobs;


=head3 Start/stop/restart/kill a container

   $container->start();

   $container->stop();

   $container->restart();

   $container->kill();


=head3 Binding a container port to a host interface

I<The container must be created with 'NetworkDisabled' = 'false' and 'ExposedPorts' defined> 

    my $c = $a->containers->create(
        Hostname => 'test',
        Cmd => ["nc", "-l", '0.0.0.0', '5555'],
        Image => "ubuntu",
        Name => "testing123",
        NetworkDisabled => "false",
        ExposedPorts => {
                 "5555/tcp" =>  {}  
         },
    );

I<When starting the container the 'PortBindings' must be defined>
    
    $c->start(
         "PortBindings" => { 
                 "5555/tcp" =>  [{"HostIp" =>  "0.0.0.0", "HostPort" =>  "11022" }] 
         },
    );

=head3 Attaching volumes to containers

I<Similar to ports, Volumes must be specified in creation as 'Binds' inside 'HostConfig' (since api v1.19)>

    my $c = $a->containers->create(
        Hostname => 'test',
        Cmd => ["nc", "-l", '0.0.0.0', '5555'],
        Image => "ubuntu",
        Name => $name,
        HostConfig => {
            Binds => {
                '/mnt:/tmp',
                '/usr:/usr:ro'
            },
        }
    );

I<When starting the container the volumes will be seen as 'Mounts' (since docker api v1.20)>

  "Mounts": [
        {
            "Source": "/mnt",
            "Destination": "/tmp",
            "Mode": "",
            "RW": true
        },
        {
            "Source": "/usr",
            "Destination": "/usr",
            "Mode": "",
            "RW": false
        }

    ],
    


=head3 Deleting a container

    ## delete
    $container->delete();

=head3 Deleting a container (asynchronous version)

    my $job_id = $container->deleteAsync(

	onSuccess=>sub {

		# 
		# Container has been deleted
		#
	}

    );

    # Others things to do...
    #

    #
    # We wait for the specific job to finish
    #	
    $api->waitForJob($job_id);

=head2 Interacting with images

=head3 Getting an image 

    ## get
    my $image = $a->images->get(id => "busybox");


=head3 Getting an image history

    ## history 
    print Dumper($image->history);


=head3 Create an image pulling it from registry

    ## create
    my $image = $a->images->create(
    
        fromImage=>'busybox',
    
        onSuccess=>sub {
            
            print "FINISHED\n";     
    
        },
    
        onProgress=>sub{
    
            print $_[0] . "\n";
        }
    );
    

=head3 Building images (from a Dockerfile)

    ## build
    my $image = $a->images->build(
        t => "my_image",
        Dockerfile => join("\n", <DATA>),
    );
    
    ## build_from_dir
    my $image = $a->images->build_from_dir(
        t => "my_image",
        DIR => "/tmp/directory_with_a_Dockerfile"
    );


=head3 Deleting an image

    ## delete
    $image->delete();


=head1 DESCRIPTION

The purpose of this library is to provide a set of modules to interact in a
simple, but powerful way, with the L<Docker remote api |http://docs.docker.io/en/latest/reference/api/docker_remote_api/>

B<Containers> supported methods:

=over

=item *

get


=item *

getByName


=item *

getAll


=item *

create 


=item *

delete


=item *

status


=item *

start


=item *

stop


=item *

restart


=item *

kill


=item *

copy


=item *

attach


=item *

top



=back

B<Images> supported methods:


=over

=item *

get


=item *

getAll


=item *

history


=item *

create


=item *

build


=item *

build_from_dir


=item *

delete


=back


=head1 DEPENDENCIES

Currently this module has the following dependencies:


=over

=item *

Eixo::Base >= 1.200,

=item *

Eixo::Rest >=  1.020,

=item *

JSON >= 2.50,

=item *

Net::HTTP >= 6.06,


=item *

HTTP::Server::Simple::CGI (for testing purpose)


=back


=head1 CAVEATS

- No unix socket support, currently only supports tcp connections to Docker API.


=head1 DEVELOPMENT

To setup development environment:

Ubuntu 12.04 64bits:

Install kernel 3.8 

    # install the backported kernel
    sudo apt-get update
    sudo apt-get install linux-image-generic-lts-raring linux-headers-generic-lts-raring
    
    # reboot
    sudo reboot

Install docker:

    curl -s https://get.docker.io/ubuntu/ | sudo sh

Setup docker daemon listening in localhost:4243 tcp port:

=over

=item *

Add this line to B</etc/default/docker>

    DOCKER_OPTS="-H 127.0.0.1:4243 -d"



=item *

restart docker service:

    $ sudo service docker restart



=item *

export B<DOCKER_TEST_HOST> var to run integration tests

    export DOCKER_TEST_HOST=http://127.0.0.1:4243



=back

More info at L<http://docs.docker.io>


=head1 AUTHOR

Francisco Maseda, <frmadem@gmail.com>

Javier Gomez, <alambike@gmail.com>


=head1 COPYRIGHT AND LICENSE

Copyright (C) 2014, Francisco Maseda

Copyright (C) 2014, Javier Gómez

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

L<http://www.apache.org/licenses/LICENSE-2.0>

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

=cut