Os desenvolvedores de Perl dispõem de um maravilhoso recurso, o Comprehensive Perl Archive Network (CPAN). A Amazon também dispõe de um grande recurso —o Simple Storage Service (S3). Apesar de existir uma biblioteca oficial Amazon S3 Perl (chamada "S3") no CPAN, há pelo menos cinco ou seis módulos (embora alguns não sejam totalmente independentes) para conversar com o S3. É como se houvesse uma competição de culinária e 2000 pessoas aparecessem em vez de 200.
Bom, aqui estou eu, um dia após a competição, com um esfregão e um balde, compartilhando as melhores receitas com você. Estes módulos e ferramentas estão no CPAN, disponíveis gratuitamente, e você pode começar a usá-los imediatamente. As três receitas que recomendo pertencem a esses três módulos: Net::Amazon::S3, Amazon::S3 e SOAP::Amazon::S3.
Veja as discussões sobre as vantagens e desvantagens do S3 na série de artigos do developerWorks Perl Elaborado: Perl e a nuvem Amazon Não é necessário tratar novamente do tema aqui, mesmo assim, farei um breve resumo do mesmo.
O S3 é um serviço de armazenamento fornecido e gerenciado pela Amazon. A Amazon cobra pelo acesso, assim, os usuários não têm de se preocuparem com servidores, backups, disponibilidade e distribuição geográfica de largura de banda, etc. Assim, o S3 é, com a maioria das coisas na vida, uma comodidade que tem um preço, e somente você pode decidir se este serve ou não para o seu negócio ou uso pessoal.
Os dados do S3 são organizados em depósitos (a grosso modo vinculados a um nome de domínio) e os itens de dados nestes depósitos. Além disso, é muito importante incluir o tipo MIME no upload ou você irá receber dados binários crus de volta (isso não é bom, especialmente para imagens). O tipo MIME e outros metadados não podem ser alterados depois de escritos —ou seja, você tem que deletar e recriar o item.
Antes de começar, é importante mencionar que este artigo é voltado para programadores de Perl de nível intermediário. Técnicas básicas de Perl não são explicadas em detalhes. Você também deve saber o que é o Amazon S3 e como instalar um módulo CPAN. Caso não souber, consulte a seção Recursos para fazer uma leitura em segundo plano.
Usando os três módulos (Net::Amazon::S3, Amazon::S3 e SOAP::Amazon::S3), eu explico como executar uma série de operações S3 básicas, mostrando o código fonte quando necessário:
- Listar, criar e deletar depósitos
- Listar, criar, recuperar e deletar itens em um depósito.
- Adquirir os metadados de um item
Para que seja possível comparar as tarefas entre os módulos, eu reutilizei as mesmas opções de linha de comando e a mesma estrutura geral.
O módulo Net::Amazon::S3 é bem conhecido, suportado e compreensivo. Ele tem alguns poucos pré-requisitos, mas nada tão ridículo quanto o Moose, caso você seja familiar com o mesmo.
Nós vamos armazenar as chaves S3 no ambiente como S3KEY e S3SECRET. Desse modo, nós podemos acessá-las do Perl como $ENV{S3KEY} e $ENV{S3SECRET}. Este método de classificar dados em um arquivo é uma maneira bastante segura de proteger valores secretos (lembre-se, se suas chaves S3 forem roubadas, você vai pagar pela largura de banda de outra pessoa).
Ok, então o Net::Amazon::S3 está instalado. (Você deve usar a interface sugerida, Net::Amazon::S3::Client, como a Net::Amazon::S3 é descrita como a "interface herdada", mas a Net::Amazon::S3::Client versão 0.50 tinha um erro devido ao módulo Moose, o que me impediu de usá-la ao mesmo tempo em que eu escrevia este artigo. Esse erro foi fixado na versão 0.51. A versão atual é a 0.52.) De qualquer modo, vamos ao exemplo. Como de costume, todos os scripts estão disponíveis na seção downloads.
Listagem 1. net-amazon-s3.pl preliminares
#!/usr/bin/perl use warnings; use strict; use Data::Dumper; use Getopt::Long; use Net::Amazon::S3; use MIME::Types; my $mime = MIME::Types->new(); |
Isso é um script padrão, incluindo Data::Dumper para propósitos de depuração. Um objeto MIME genérico é criado, embora vamos usá-lo somente para uploads.
Listagem 2. net-amazon-s3.pl conexão S3 inicial, auxiliares e opções
my %opts = (
key => $ENV{S3KEY},
secret => $ENV{S3SECRET},
separator => '/',
);
GetOptions(
\%opts,
"create|c=s",
"delete|d=s",
"list|l:s", # the parameter is optional
"keys|k",
"metadata|m",
"get=s",
"put=s",
"separator=s",
"help|h",
);
unless ($opts{key} && $opts{secret} )
{
die "$0 requires the S3KEY and S3SECRET environment variables to be set.";
}
# handle -h
usage() if exists $opts{help};
my $s3 = Net::Amazon::S3->new(
aws_access_key_id => $opts{key},
aws_secret_access_key => $opts{secret},
retry => 1,
);
die "Could not connect to S3" unless defined $s3;
sub read_filename
{
print "\nEnter filename: ";
my $name = <>;
chomp $name;
return $name;
}
sub usage
{
print lt;<EOHIPPUS;
$0 [OPTIONS]
Pass your S3 key and secret in the S3KEY and S3SECRET environment entries.
Options:
--help or -h : this help
--separator $opts{separator} : BUCKET and KEY separator character
(for --get and --put)
--create BUCKET (or -c BUCKET) : create BUCKET
--delete BUCKET (or -d BUCKET) : delete BUCKET
--delete BUCKET$opts{separator}KEY : delete KEY in BUCKET
--list [BUCKET] (or -l) : list a specific bucket or all buckets
--keys (or -k) : list the keys in each bucket (requires --list)
--metadata (or -m) : show the keys' metadata
(requires --keys and --list)
--get BUCKET$opts{separator}KEY : download KEY from BUCKET
--put BUCKET$opts{separator}KEY : upload a file to KEY in BUCKET
EOHIPPUS
exit 0;
}
|
Mais um script padrão. As opções estão definidas aqui. A função usage() é bem compreensiva para tornar o programa útil. Todas as opções são listadas e explicadas brevemente.
Listagem 3. net-amazon-s3.pl operações de criação e exclusão
if (exists $opts{create})
{
my $bucket = $s3->add_bucket( { bucket => $opts{create}} )
or die sprintf ("%s: %s", $s3->err, $s3->errstr);
print "Created bucket '$opts{create}' successfully.\n";
}
elsif (exists $opts{delete})
{
my ($b, $key) = split $opts{separator}, $opts{delete};
my $bucket = $s3->bucket($b);
die "Could not retrieve bucket $b" unless $bucket;
if (defined $key)
{
$bucket->delete_key($key)
or die sprintf ("%s: %s", $s3->err, $s3->errstr);
print "Deleted key '$key' in bucket '$b' successfully.\n";
}
else
{
$bucket->delete_bucket()
or die sprintf ("%s: %s", $s3->err, $s3->errstr);
print "Deleted bucket '$b' successfully.\n";
}
}
|
A opção --create é muito simples. Você simplesmente cria o depósito e retorna.
--delete lida tanto com a exclusão de depósito (não recursiva, assim o usuário tem que primeiro remover todas as chaves no depósito) ou a exclusão de chaves em um depósito. Aqui, o caractere separador entra em jogo como o ponto divisório entre o nome do depósito e o nome da chave.
Listagem 4. net-amazon-s3.pl operações get e put
...
elsif (exists $opts{get})
{
my ($b, $key) = split $opts{separator}, $opts{get};
my $bucket = $s3->bucket($b);
die "Could not get the bucket $b" unless $bucket;
my $where = read_filename();
my $response = $bucket->get_key_filename( $key, 'GET', $where )
or die sprintf ("%s: %s", $s3->err, $s3->errstr);
die "Could not create file $where" unless -f $where;
print "Successfully downloaded $key from bucket $b into $where\n";
}
elsif (exists $opts{put})
{
my ($b, $key) = split $opts{separator}, $opts{put};
my $bucket = $s3->bucket($b);
die "Could not get the bucket $b" unless $bucket;
my $where = read_filename();
die "File $where does not exist or is not readable" unless -f $where && -r $where;
my $response = $bucket->add_key_filename(
$key,
$where,
{ content_type => $mime->mimeTypeOf($where), },
)
or die sprintf ("%s: %s", $s3->err, $s3->errstr);
print "Successfully uploaded $where into $key in bucket $b\n";
}
|
Get e put são duas operações muito parecidas, ambas operando em um nome de arquivo e nome de chave. A única parte interessante aqui é o objeto $mime do MIME::Types, o qual usamos para adquirir o tipo de conteúdo. Lembre-se, não é possível fazer alterações após o upload.
Listagem 5. net-amazon-s3.pl operações de listagem
...
elsif (exists $opts{list})
{
print "Available buckets:\n";
my @todo;
if ($opts{list})
{
push @todo, map { $s3->bucket($_) } $opts{list};
}
else
{
print "(Getting all buckets)\n";
my $response = $s3->buckets;
die "Could not get the bucket list" unless $response;
@todo = @{$response->{buckets}};
}
foreach my $bucket ( @todo )
{
printf "\t%s\n", $bucket->bucket;
if (exists $opts{keys})
{
my $response = $bucket->list_all
or die sprintf ("%s: %s", $s3->err, $s3->errstr);
foreach my $key (@{$response->{keys}})
{
printf "\t\t%10s\t%s\n", $key->{size}, $key->{key};
if (exists $opts{metadata})
{
my $detail = $bucket->get_key($key->{key});
foreach my $entry (qw/content_length content_type etag/)
{
printf "\t\t\t%20s=%s\n", $entry, ($detail->{$entry}||'UNDEFINED');
}
}
}
}
}
}
|
O último e mais longo, o manipulador --list lida com um único ou múltiplos depósitos. Ele mostra a lista de chaves e seus metadados com os alternadores adequados.
Os caracteres \t são convertidos em tabulações; o que é uma maneira bruta de indentar a saída, de modo que ela apareça sem problemas em um terminal de texto.
Como você pode ver, o Net::Amazon::S3 é um modulo bastante claro. Alguns dos métodos são um pouco estranhos, mas eles funcionam bem. Há uma quebra entre adquirir um item e usá-lo com os metadados que requer uma chamada adicional get_key(). Em qualquer lugar, o código é curto e simples.
O módulo Amazon::S3 é um substituto para o Net::Amazon::S3. Eu tive que mudar a chamada new() para usar uma referência hash, porém, esta foi a única mudança (além de, obviamente, mudar todas as referências Net::Amazon::S3 para Amazon::S3).
Listagem 6. Mudanças do net-amazon-s3.pl para o amazon-s3.pl
my $s3 = Amazon::S3->new({
aws_access_key_id => $opts{key},
aws_secret_access_key => $opts{secret},
retry => 1,
});
|
O Amazon::S3 suporta muitas operações; você deve consultar a documentação para poder usá-las. Em geral, o Amazon::S3 parece ter objetivos um pouco diferentes do Net::Amazon::S3, mas do ponto de vista de um desenvolvedor, a API é a mesma. Isso é realmente um bom exemplo sobre a interoperabilidade da biblioteca.
Uma característica do Amazon::S3 que você deverá gostar é que ele não depende de tantos módulos como o Net::Amazon::S3. Seu autor enfatiza sua mobilidade, a qual é uma vantagem para aqueles que a necessitam.
O módulo SOAP::Amazon::S3 requer uma pequena explanação, a qual vou simplificar para este artigo. SOAP é uma maneira de acessar informação em HTTP (a Web) diferente dos pedidos de HTTP usuais, que usa o caminho para indicar um recurso. Esses pedidos são normalmente chamados REST-style e tendem a resultar em muitas variações de URL. Por outro lado, o SOAP trabalha com poucas URLs e entrega um lote inteiro de XML para o servidor.
Eu gostaria de continuar tratando do SOAP, mas, por tratar-se de um tópico extenso, vou deixar que você mesmo procure em livros e ferramentas de busca caso esteja curioso. Para o que servem, o SOAP e o REST não são tão diferentes. Com ambos, é possível escrever com facilidade tanto códigos ótimos quanto códigos terríveis.
Infelizmente, o SOAP::Amazon::S3 está marcado como experimental em sua documentação. Você deve testá-lo por conta própria para decidir se ele é adequado para você.
Vamos às mudanças. Primeiro de tudo, necessitamos do módulo File::Slurp, pois o SOAP::Amazon::S3 não tem os métodos para colocar e adquirir um arquivo que o Net::Amazon::S3 e o Amazon::S3 têm.
Listagem 7. net-amazon-s3.pl preliminares
# set Debug to 0 if you don't want to see all the XML
my $s3 = SOAP::Amazon::S3->new( $opts{key}, $opts{secret},
{ Debug => 1, RaiseError => 1 } );
|
Eu deixei Debug=1 porque você provavelmente vai ficar curioso para ver todo o tráfego SOAP que o SOAP::Amazon::S3 gera. Todas as verificações de erros que fiz com o Net::Amazon::S3 não foram necessárias devido a RaiseError=1, porém isso pode não ser uma boa ideia para um ambiente de produção.
Criar um depósito (my $bucket = $s3->createbucket($opts{create});) é diferente de criar o mesmo com o Net::Amazon::S3, o mesmo vale para a exclusão de um depósito ($bucket->delete()) ou um objeto ($bucket->object($key)->delete();).
Escrever para um arquivo foi um pouco mais complicado, porque, como eu disse, o SOAP::Amazon::S3 não tem as funções convenientes que vimos no Net::Amazon::S3.
Listagem 8. net-amazon-s3.pl escrever arquivo
open W, '>', $where or die "Could not write to $where: $!"; print W $bucket->object($key)->getdata(); close W; |
Ditto para fazer upload a partir de um arquivo.
Listagem 9. net-amazon-s3.pl upload de arquivo
my $type = ''.$mime->mimeTypeOf($where); # force $type to be a string
# use File::Slurp::read_file in scalar context to grab the whole file's contents
my $data = read_file($where);
$bucket->putobject($key, $data, { 'Content-Type' => $type });
|
O tipo MIME deve ser forçado em uma cadeia de caractere ou haverá reclamações dos módulos de ajuda XML. Além disso, o tipo de conteúdo é capitalizado de forma diferente do Net::Amazon::S3.
Finalmente, vamos listar estes itens. Aqui, o SOAP::Amazon::S3 não foi tão poderoso quanto o Net::Amazon::S3, pois os metadados dos objetos são estavam disponíveis. O SOAP::Amazon::S3 tem um bom método $object->url(), mas ele não converte espaços para %20, por exemplo. Assim, você deve experimentá-lo para assegurar-se que ele vai funcionar para você. Eu enviei um bug (lembre que trata-se de um módulo experimental), mas, por enquanto, eu evitaria o método $object->url() em um ambiente produtivo.
Listagem 10. soap-amazon-s3.pl listando depósitos e objetos nestes depósitos
...
elsif (exists $opts{list})
{
print "Available buckets:\n";
my @todo;
if ($opts{list})
{
push @todo, map { $s3->bucket($_) } $opts{list};
}
else
{
print "(Getting all buckets)\n";
@todo = $s3->listbuckets;
}
foreach my $bucket ( @todo )
{
printf "\t%s\n", $bucket->name;
if (exists $opts{keys})
{
foreach my $key ($bucket->list())
{
printf "\t\t%10s\t%-30s\t%s\n", $key->{Size}, $key->name, $key->url;
if (exists $opts{metadata})
{
foreach my $entry (qw/Size ETag LastModified/)
{
printf "\t\t\t%20s=%s\n", $entry, ($key->{$entry}||'UNDEFINED');
}
}
}
}
}
}
|
Como você pode ver, o SOAP::Amazon::S3 não adquire os metadados, assim, não é possível ver o tipo de conteúdo dos objetos, por exemplo. Esta pode ser uma restrição desagradável caso você use os metadados para armazenar informações importantes sobre um objeto. De qualquer forma, o SOAP::Amazon::S3 pode ser comparado com o Net::Amazon::S3 para a listagem de depósitos e seus elementos.
Eu não avaliei outros dois módulos S3 CPAN em detalhes, mas aqui vai um rápido resumo:
- O Net::Amazon::S3::Tools é bom caso você deseje ter acesso em linha de comando ao S3. É melhor do que escrever o seu próprio, assim, para um kit de ferramentas já pronto para o uso, você deve experimentar.
- O Tie::Amazon::S3 é um bom módulo para se trabalhar com um único depósito. É possível deletar ou modificar entradas hash, adicionar novas entradas, etc. Infelizmente, ele não permite operações em nível de depósito (criar depósito, excluir depósito, etc.) ou operações de metadados (especialmente configurar o tipo de conteúdo em uma nova chave). Assim, o Tie::Amazon::S3 é útil se você deseja armazenar dados puros no S3, mas, tratando-se de imagens, ele não é muito proveitoso.
No geral, o Net::Amazon::S3 e o Amazon::S3 são atualmente as melhores escolhas para se trabalhar com S3. Suas APIs intercambiáveis permitem fácil alteração, quando esta for necessária. Eles suportam todas as operações, desde operações com depósitos até a recuperação dos metadados dos itens. Suas APIs são um pouco estranhas, porém fáceis de usar depois de configuradas.
Mantenha-se de olho no SOAP::Amazon::S3, pois ele tem um bom potencial. Se você está trabalhando com dados puros em um único depósito, opte com certeza pelo Tie::Amazon::S3, pois ele vai facilitar muito a sua vida.
Boa sorte usando o S3!
| Descrição | Nome | Tamanho | Método de download |
|---|---|---|---|
| Sample scripts | amazon-s3-scripts.zip | 5KB | HTTP |
Informações sobre métodos de download
Aprender
- Saiba mais sobre o Amazon S3.
- A série Perl elaborado: Perl e a nuvem Amazon (developerWorks, março - junho de 2009) lhe ensina como criar um simples Web site de compartilhamento de fotos usando Perl e Apache para acessar o Amazon's Simple Storage Service (S3) e o SimpleDB:
- A Parte 1 mostra as vantagens e desvantagens do S3 e do SimpleDB através de uma viagem por suas arquiteturas .
- A Parte 2 mostra como fazer o upload de um arquivo no S3 a partir de uma Web page através de um formulário HTML para minimizar a carga no servidor e manter uma forte política de segurança.
- A Parte 3 mostra em detalhes como a URL cria um registro do SimpleDB do arquivo enviado e como criar, editar e excluir comentários como simples registros do SimpleDB em uma foto para um usuário em particular.
- A Parte 4 examina todo o código base
mod_perldo site, incluindo como configurar o nível superior, o que fazer com os manipuladores e como configurar dependências externas. - A Parte 5 examina completamente os modelos
mod_perldo site, incluindo um para indexação, três para uploading (geral, formulários S3 e acréscimos de URL), um para imagem e navegação de comentários e um para procurar comentários recursivamente para uma imagem (ou executar um thread).
- O Moose intrigou você? Experimente. Ditto com File::Slurp.
- Para mais sobre o SOAP e o REST, acesse a zona developerWorks SOA and Web services.
- Na zona Linux do developerWorks, você encontrará mais recursos para desenvolvedores Linux, e poderá ver nossos artigos e tutoriais mais populares.
- Consulte todos os artigos para Linux e os tutoriais de Linux do developerWorks.
- Mantenha-se atualizado com os webcasts e eventos técnicos do developerWorks.
Obter produtos e tecnologias
- No site CPAN (Comprehensive Perl Archive Network), é possível encontrar módulos —montes e montes de módulos— e a documentação do módulo. Aqui estão os módulos Net-Amazon-S3-0.current; Amazon-S3-0.current; e SOAP-Amazon-S3-0.current. Além dos dois que não foram realmente tratados: Net-Amazon-S3-Tools-0.current e Tie-Amazon-S3-0.current.
- Com o software de teste IBM, disponível para download diretamente no developerWorks, faça seu próximo projeto de desenvolvimento em Linux.
Discutir
- Envolva-se na comunidade My developerWorks. Entre em contato com outros usuários do developerWorks enquanto explora os blogs, fóruns, grupos e wikis dos desenvolvedores.

Teodor Zlatanov surgiu com um M.S. em engenharia da computação na Universidade de Boston em 1999. É programador desde 1992, usando Perl, Java, C e C++. Seus interesses estão no trabalho de software livre em análise de texto, arquitetura de banco de dados, interfaces do usuário e administração de sistemas UNIX.