Avançar para a área de conteúdo

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

Na primeira vez que você efetua sign in no developerWorks, um perfil é criado para você. Informações selecionadas do seu perfil developerWorks são exibidas ao público, mas você pode editá-las a qualquer momento. Seu primeiro nome, sobrenome (a menos que escolha ocultá-los), e seu nome de exibição acompanharão o conteúdo que postar.

Todas as informações enviadas são seguras.

  • Fechar [x]

Ao se conectar ao developerWorks pela primeira vez, é criado um perfil para você e é necessário selecionar um nome de exibição. O nome de exibição acompanhará o conteúdo que você postar no developerWorks.

Escolha um nome de exibição de 3 - 31 caracteres. Seu nome de exibição deve ser exclusivo na comunidade do developerWorks e não deve ser o seu endereço de email por motivo de privacidade.

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

Todas as informações enviadas são seguras.

  • Fechar [x]

Computação em Nuvem com PHP, Parte 2: Usando Amazon EC2 com o Zend Framework

Usando máquinas virtuais com o Zend Framework

Doug Tidwell, developerWorks staff, IBM
Doug Tidwell
Doug Tidwell é um engenheiro de software sênior no grupo Emerging Technology da IBM. Ele foi um palestrante na primeira conferência sobre XML em 1997 e trabalhou com linguagem de marcações, serviços da Web e tecnologia SOA por vários anos. Seu trabalho como um evangelista de tecnologia é explicar os padrões e tecnologias por trás da computação em nuvem e ajudar clientes a integrá-los com suas arquiteturas e estratégias gerais de negócios. Ele é autor de vários artigos aqui no developerWorks e é o autor do livro sobre XSLT da O'Reilly (ISBN 0-596-52721-7), um presente inteligente para todas as ocasiões. Ele reside em Chapel Hill, N.C., com sua esposa, filha e cão.

Resumo:  O Zend Framework contém várias classes que tornam fácil o uso de serviços de armazenamento com base em nuvem. A parte 1 desta série "Computação em Nuvem com PHP" aborda o uso de classes Zend com o serviço de armazenamento em nuvem S3 da Amazon. Este artigo aborda as classes Zend que tornam mais fácil o trabalho com máquinas virtuais no Elastic Compute Cloud (EC2) da Amazon.

Visualizar mais conteúdo nesta série

Data:  11/Nov/2009
Nível:  Intermediário
Atividade:  3414 visualizações
Comentários:  


Um dos aspectos mais excitantes da computação em nuvem é a capacidade de executar máquinas virtuais em um datacenter do provedor em nuvem. O EC2 da Amazon proporciona a arquitetos e desenvolvedores a capacidade de criar imagens de máquinas virtuais e executá-las na nuvem. É possível criar imagens customizadas que contêm o software e os dados que sua organização precisa, então será possível executar quantas cópias dessas máquinas virtuais forem necessárias. Este artigo aborda algumas das classes no Zend Framework que tornam mais fácil trabalhar com imagens EC2.

Como o EC2 é um produto sofisticado, os recursos do EC2 são divididos em dois artigos. Este artigo aborda os conceitos básicos do trabalho com imagens, início e término das instâncias dessas imagens e os pares de chaves e grupos de segurança que permitem proteger as instâncias. Tópicos como Endereços IP Elásticos, Monitoramento do Amazon CloudWatch e Armazenamento em Bloco Elástico são abordados em um outro artigo.

Introdução

Neste artigo, você verá como realizar várias tarefas importantes do EC2:

  • Localizar as Amazon Machine Images (AMIs) que pertencem a você
  • Trabalhar com pares de chaves, incluindo localizar aqueles que pertencem a você, criar novos e excluir antigos
  • Trabalhar com grupos de segurança, incluindo controle de acesso às portas TCP/IP de sua máquina virtual
  • Iniciar uma instância de uma AMI
  • Reinicializar ou terminar uma instância de uma AMI

Como com todos os artigos nesta série, você aproveitará o máximo dos exemplos se você tiver o Zend Framework instalado antes de iniciar. Se não tiver o Zend Framework instalado ainda, faça o download e instale o pacote completo a partir de zend.com/community/downloads. Esse pacote instala o Zend Framework, o PHP e o servidor da Web Apache em sua máquina. Quando a instalação for concluída, acesse http://localhost/ZendServer/ em seu navegador. Consulte a documentação de instalação do Zend Framework para obter todos os detalhes. Se você conseguir efetuar login no console do ZendServer, tudo estará configurado.

Também será necessário configurar uma conta com a Amazon (consulte Recursos).

Os exemplos usam a classe Credentials do PHP criada na Parte 1. Essa classe gerencia as credenciais para sua conta Amazon. As credenciais são armazenadas em um arquivo .ini.


Lista 1. Armazenando credenciais em um arquivo .ini do PHP
, 
; Arquivos de configuração para conter chaves secretas, 
números de contas e outras cadeias úteis para a Amazon e outras contas de nuvem.

[amazon]
accessKey=0123456789ABCDEFGHIJ
secretKey=0123456789abcdefghiABCDEFGHI1234567890AB
ownerId=123456789012
            

Neste artigo, o valor ownerId é essencial. Há milhares de AMIs disponíveis na Amazon, a maioria das quais não estão disponíveis para o público em geral. Você usará o valor ownerId para filtrar as AMIs nas quais você não possui autorização para acesso. Seu ID de proprietário é o número de 12 dígitos de sua conta no Amazon Web Services. Para localizá-lo, acesse http://aws.amazon.com/, efetue login em sua conta e, em seguida, selecione o menu Your Account e o item Security Credentials .


Figura 1. Localizando suas credenciais de segurança


Role para baixo até o meio da página e verá o ID de sua conta AWS.


Figura 2. ID de sua conta no AWS


Ao colocar o ID de sua conta no arquivo cloud.ini, não use os hifens. Se este fosse seu ID, você incluiria ownerId=999999999999 no arquivo .ini.

Notas:

  • Sempre que iniciar uma instância de uma AMI, você está gastando dinheiro. Mesmo que as taxas do EC2 sejam razoáveis (algumas instâncias custam menos de 10 centavos de dólar americano por hora), você não desejará simplesmente iniciar uma AMI e deixá-la em execução por tempo indeterminado. Certifique-se de terminar suas instâncias quando não for usá-las mais.
  • Os exemplos neste artigo assumem que você criou pelo menos uma AMI. Se não criou, poderá usar o valor especial ownerId=amazon. Isso retornará uma lista de mais de 100 AMIs, mas fornecerá algumas imagens que você pode ativar.
  • Se estiver usando ownerId=amazon, esteja ciente de que algumas dessas instâncias podem ser bastante caras. A IBM® possui várias AMIs que apresentam produtos de software de classe corporativa. Se estiver usando uma dessas AMIs, estará pagando uma taxa de licenciamento enquanto a instância estiver em execução. Se tudo o que deseja fazer é experimentar trabalhar com o EC2, uma AMI resumida em recursos provavelmente possui um baixo custo.

Sobre o aplicativo de amostra

O aplicativo de amostra consiste em seis páginas de código em PHP:

  1. amis.php — Lista todas as AMIs de sua conta. É possível iniciar uma instância de qualquer AMI apenas clicando em um botão.
  2. manage_instance.php — Manipual pedidos a partir do amis.php para criar, reinicializar e terminar uma instância de uma AMI.
  3. instances.php — Lista todas as instâncias em execução controladas por sua conta. Reinicialize ou termine qualquer instância em execução apenas clicando em um botão.
  4. keypairs.php — Lista todos os pares de chaves públicas/privadas que você criou. Examine pares de chaves existentes, crie novos e exclua os existentes.
  5. securitygroups.php — Lista todos os grupos de segurança definidos para sua conta. Clique em um botão para ver os detalhes de um determinado grupo de segurança.
  6. securitygroup.php — Lista todas as permissões para um determinado grupo de segurança. Inclua novas permissões ou exclua as existentes.

Trabalhando com AMIs

Para começar, crie um objeto Zend_Service_Amazon_Ec2_Image .


Lista 2. Criando um objeto Zend_Service_Amazon_Ec2_Image
, 

; Configuration file to hold secret keys, account numbers and other useful
; strings for Amazon and other cloud accounts.

[amazon]
accessKey=0123456789ABCDEFGHIJ
secretKey=0123456789abcdefghiABCDEFGHI1234567890AB
ownerId=123456789012

            

Este objeto permite trabalhar com as AMIs armazenadas na Amazon. O método Zend_Service_Amazon_Ec2_Image->describe() retorna os metadados sobre uma AMI. Sem argumentos, ele retorna os detalhes de todas as AMIs armazenadas na Amazon. Isso gera uma grande quantidade de dados, a maioria dos quais não é útil para você. Infelizmente, a atual representação do Zend Framework não suporta a versão de describe() que permite especificar um ownerId. Isso significa que a primeira vez que desejar listar as AMIs relevantes para o usuário, precisará classificar toda a lista para localizar as AMIs que deseja. Para contornar isso, é possível armazenar em cache os IDs das AMIs que deseja exibir. A lógica de processamento é que, se existe um arquivo listando as AMIs relevantes, você simplesmente lê esse arquivo e chama describe('ami-id') para cada ID. Se o arquivo não existe, será necessário criá-lo; o arquivo PHP também fornece ao usuário a opção de atualizar a lista de AMIs se ele desejar. Isso demorará um pouco, mas garantirá que a lista esteja consistente com os dados na Amazon.

O código para criar a lista de AMIs é semelhante à Lista 3.


Lista 3. Armazenando em cache os IDs de AMIs
, 
if (!file_exists('amis.text') ||
    array_key_exists('refresh', $_POST)) {
  $imageData = $ec2_img->describe();
  $amiFile = fopen('amis.text', 'w');
  $myOwnerId = $creds->getCredential('amazon', 'ownerId');
  foreach ($imageData as $nextImage) {
    if ($nextImage['imageOwnerId'] === $myOwnerId)
      fwrite($amiFile, $nextImage['imageId']."\n");
  }
  fclose($amiFile);
}
            

O código aqui verifica se ele precisa classificar todas as AMIs no catálogo da Amazon. Se o arquivo não existe ou há um pedido explícito para atualizá-lo, o código obtém a lista de detalhes de todas as AMIs na Amazon. O objetivo aqui é criar uma tabela de AMIs.


Figura 3. Uma lista de AMIs


Cada linha na tabela apresenta o ID da AMI, sua localização, seu status e sua plataforma. Além disso, há duas listas suspensas que permitem a escolha de um par de chaves e um grupo de segurança. A coluna final na tabela é um botão de pressionamento que permite iniciar a AMI com o par de chaves e o grupo de segurança atualmente selecionados. Para criar a tabela, use o método file() do PHP para ler a lista de AMIs em uma array. Para cada item na array, crie uma linha de tabela que conterá todas as informações relevantes. A seguir, o código que cria as linhas da tabela.


Lista 4. Gerando as linhas da tabela de AMIs
, 
$amiList = file('amis.text', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
foreach ($amiList as $nextAmi) {
  echo "<tr>";

  // Each table row is a form. Clicking the 'Start this image' button submits
  // the data from the current row, which tells instances.php which image to
  // start and which key pair and security group to use.
  echo "<form action='manage_instance.php' method='POST' ";
  echo " onsubmit='return confirm(\"Start image '".$nextAmi."'?\")'>";
  echo "<input type='hidden' name='imagetostart' value='".$nextAmi."'/>";

  echo "<td>".$nextAmi."</td>";

  // Get the description of this AMI
  $imageData = $ec2_img->describe(array('imageId' => $nextAmi));
  echo "<td>".$imageData[0]['imageLocation']."</td>";
  echo "<td>".$imageData[0]['imageState']."</td>";

  // If the platform is blank, assume it's some flavor of Linux
  if (strlen($imageData[0]['platform']))
    echo "<td>".$imageData[0]['platform']."</td>";
  else
    echo "<td>Linux</td>";

  // Insert the lists of key pairs and security groups
  echo "<td>".$keypairsForm."</td>";
  echo "<td>".$secGroupsForm."</td>";

  // If the state of the image is "available," insert a start button.
  if ($imageData[0]['imageState'] == 'available')
    echo "<td><input type='submit' value='Start this image'/></td>";
  else
    echo "<td>Not available</td>";

  echo "</form>";
  echo "</tr>";
}
            

Cada linha da tabela deve estar em um elemento <form> separado para que o navegador saiba qual par de chaves e grupo de segurança está selecionado quando o botão Start for clicado. Conforme você itera por meio da array de IDs de AMIs, chamar describe() com um ID específico retorna a descrição dessa AMI em particular. O restante da linha de tabela consiste no local da imagem (onde a imagem é armazenada em sua conta S3), o status da imagem, uma lista suspensa de pares de chaves, uma lista suspensa de grupos de segurança e um botão Start this image . O botão Start é exibido apenas se o status da imagem for available. Os controles de formulário para cada linha da tabela se parecem com a Figura 4.


Figura 4. Controles de formulário para cada linha da tabela


As listas de pares de chaves e grupos de segurança são criados fora do loop.


Lista 4. Gerando as listas de pares de chaves e grupos de segurança
, 
$ec2_kp = new Zend_Service_Amazon_Ec2_Keypair($aws_key, $aws_secret);
$keypairs = $ec2_kp->describe();
foreach ($keypairs as $key => $row) {
  $keyName[$key]  = $row['keyName'];
  $keyFingerprint[$key] = $row['keyFingerprint'];
}
array_multisort($keyName, $keypairs);

$keypairsList = "<select name='keypair'>";
foreach ($keypairs as $nextKeypair) {
  $keypairsList = $keypairsList."<option value='".$nextKeypair['keyName']."'>";
  $keypairsList = $keypairsList.$nextKeypair['keyName']."</option>";
}
$keypairsList = $keypairsList."</select>";

$secGroupsList = "<select name='secgroup'>";
$ec2_sg = new Zend_Service_Amazon_Ec2_Securitygroups($aws_key, $aws_secret);
$securityGroups = $ec2_sg->describe();
foreach ($securityGroups as $key => $row) {
  $groupName[$key]  = $row['groupName'];
  $groupDescription[$key] = $row['groupDescription'];
}
array_multisort($groupName, $securityGroups);

foreach ($securityGroups as $nextGroup) {
  $secGroupsList = $secGroupsList."<option value='".$nextGroup['groupName']."'>";
  $secGroupsList = $secGroupsList.$nextGroup['groupName']."</option>";
}
$secGroupsList = $secGroupsList."</select>";
            

Cada lista é uma cadeia que contém os elementos <select> e <option> do HTML para os pares de chaves e grupos de segurança. (Observe que o código usa o array_multisort do PHP para classificar os nomes dos pares de chaves e grupos de segurança.) Como o início de uma instância de uma AMI significa que encargos começam a acumular em sua conta no AWS, um diálogo de confirmação é exibido.


Figura 5. O início de uma instância deve ser confirmado


Nesta captura de tela, o par de chaves id_rsa-gsg-keypair e o grupo de segurança default estão selecionados.


Trabalhando com instâncias

Ao clicar no botão OK para ativar uma instância, as informações sobre a nova instância são enviadas para a página manage_instance.php . A primeira etapa ao trabalhar com instâncias é criar um objeto Zend_Service_Amazon_Ec2_Instance .


Lista 6. Criando um objeto Zend_Service_Amazon_Ec2_Instance
, 
$creds = new Credentials;
$aws_key = $creds->getCredential('amazon', 'accessKey');
$aws_secret = $creds->getCredential('amazon', 'secretKey');

$ec2_instance = new Zend_Service_Amazon_Ec2_Instance($aws_key, $aws_secret);
            

Com o objeto criado, agora é possível iniciar uma instância da imagem solicitada.


Lista 7. Criando uma nova instância
, 
if (strlen($imageIdToStart) && strlen($keypairToStart) && strlen($secgroupToStart)) {
  $startResults = $ec2_instance->run(array('imageId' => $imageIdToStart, 
                                           'keyName' => $keypairToStart,
                                           'securityGroup' => $secgroupToStart));

  echo "<p><b>Status of instance ".$startResults['instances'][0]['instanceId'].": ";
  echo $startResults['instances'][0]['instanceState']['name'].".</b></p><hr/>";
}
            

Observação: É possível especificar outros parâmetros ao iniciar uma instância, como o número de instâncias, o tamanho da instância (quanta memória e processamento de CPU ela possui) e a região geográfica em que a instância deverá estar hospedada. Para manter os exemplos simples, todas as solicitações de início de uma instância apenas iniciam uma instância, essa instância possui o menor tamanho (especificado como m1.small no pedido real para a Amazon) e é hospedada na região padrão para sua conta.

Este código assume o ID da AMI e os nomes do par de chaves e do grupo de segurança selecionados no formulário na página amis.php . Então, a página exibe o status da nova instância.


Figura 6. O status de uma instância recém-criada


Ao clicar em OK será enviada a você a página instances.php . Essa página exibe a lista atual de instâncias.


Figura 7. A lista de instâncias


Observação: Os valores para o ID de imagem, nome da chave e grupo de segurança são passados para a página manage_instance.php via HTTP POST. Usar uma página intermediária para criar a nova instância significa que é possível atualizar a página instances.php sem iniciar acidentalmente uma outra instância. A página manage_instance.php também manipula pedidos de reinicialização ou término de uma imagem.

Ao iniciar uma instância, seu estado inicial é pending. Isso significa que a imagem da máquina está inicializando, mas ainda não está ativada e em execução. Observe também que a Amazon designou i-373c995f como ID de instância para esta instância; esse ID é como você trabalhará com a instância posteriormente. Clicar no botão "Refresh list of instances" atualiza a exibição.


Figura 8. Atualizar lista de instâncias


Na lista atualizada, o status da instância agora é running. Observe que a Amazon designou o nome de DNS ec2-75-101-220-48.compute-1.amazonaws.com para esta instância. Isso significa que, se você habilitou esta instância para acesso pela Web e a instância está executando um servidor da Web na porta 80, será possível visitar http://ec2-75-101-220-48.compute-1.amazonaws.com para ver a página inicial da instância. (É possível ativar a porta 80 criando uma regra em um grupo de segurança; mais sobre grupos de segurança em breve.)

Para gerar as linhas da tabela de instâncias, use o método Zend_Service_Amazon_Ec2_Instance->describe() .


Lista 8. Criando a tabela de instâncias
, 
$instanceDetails = $ec2_instance->describe();
if (count($instanceDetails['instances'])) {
  echo "<table border='1' cellpadding='5'>";
  echo "<tr style='font-weight: bold;'>";
  echo "<td>Status</td><td>Instance ID</td><td>AMI ID</td><td>Public DNS name</td>";
  echo "<td>Security Group</td><td>Key Pair</td><td>&nbsp;</td><td>&nbsp;</td>";
  echo "</tr>";

  foreach ($instanceDetails['instances'] as $nextInstance) {
    echo "<tr>";
    $status = $nextInstance['instanceState']['name'];
    // Make the cell background green if the status is running.
    if (strripos('running', $status) === 0)
      echo "<td style='background-color: green; color: white; font-weight: bold;'>";

    // Make the cell background yellow if the status is shutting-down.
    else if (strripos('shutting-down', $status) === 0)
      echo "<td style='background-color: yellow; font-weight: bold;'>";

    // Make the cell background red if the status is terminated.
    else if (strripos('terminated', $status) === 0)
      echo "<td style='background-color: red; color: white; font-weight: bold;'>";

    // Make the cell background purple for any other status.
    else
      echo "<td style='background-color: purple; color: white; font-weight: bold;'>";
    echo $status."</td>";

    echo "<td>".$nextInstance['instanceId']."</td>";
    echo "<td>".$nextInstance['imageId']."</td>";
    echo "<td>".$nextInstance['dnsName']."</td>";
    echo "<td><a href='securitygroup.php?groupname=".$nextInstance['groupSet'][0];
    echo "&previous=instances'>".$nextInstance['groupSet'][0]."</a></td>";
    echo "<td>".$nextInstance['keyName']."</td>";
    . . .
            

Primeiro, o código verifica se há alguma instância. Assumindo que há pelo menos uma, cada instância é descrita em uma linha da tabela. O ID da instância e o ID da AMI são exibidos, juntamente com o nome de DNS público, grupo de segurança e par de chaves. Como com a página amis.php , cada linha da tabela é um formulário.


Figura 9. Controles de formulário para gerenciar instâncias


Esta tabela lista três instâncias. O status de dois dos itens é running, portanto, há botões Reboot e Terminate para essas instâncias. Para uma instância em um outro estado (pending, shutting-down ou terminated), os botões não aparecem.


Lista 9. Criando os controles de formulário para a tabela de instâncias
, 
if (strripos('running', $status) === false) {
      echo "<i>[Can't reboot]</i>";
    }
    else {
     echo "<form action='manage_instance.php' method='POST' ";
      echo "onsubmit='return confirm(\"Reboot instance &apos;";
      echo $nextInstance['instanceId']."&apos;?\")'>";
      echo "<input type='hidden' name='imagetoreboot' value='";
      echo $nextInstance['instanceId']."'/>";
      echo "<input type='submit' value='Reboot'/></form>";
    }
    echo "</td>";

    echo "<td style='text-align: center;'>";
    if (strripos('running', $status) === false) {
      echo "<i>[Can't terminate]</i>";
    }
    else {
     echo "<form action='manage_instance.php' method='POST' ";
      echo "onsubmit='return confirm(\"Terminate instance &apos;";
      echo $nextInstance['instanceId']."&apos;?\")'>";
      echo "<input type='hidden' name='imagetoterminate' value='";
      echo $nextInstance['instanceId']."'/>";
      echo "<input type='submit' value='Terminate'/></form>";
    }
    echo "</td>";
            

Se a instância estiver em execução, o código criará botões para reinicializar ou terminar a instância. Clicar nesses botões gera um diálogo de confirmação.


Figura 10. O término ou reinicialização de uma instância deve ser confirmado


Clicar em OK leva você novamente para a página manage_instance.php .


Figura 11. O status de uma instância recém-terminada


Ao retornar para a lista de instâncias, o status atualizado é mostrado.


Figura 12. A lista de instâncias atualizada


Em algum ponto, o status da instância será alterado para terminated.


Figura 13. Uma instância terminada


Observação: Em algum ponto após o término de uma instância, o EC2 exclui todos os dados associados a ela. Geralmente, isso ocorre dentro de uma hora. Assim que os dados sobre a instância forem excluídos, eles não serão mais mostrados nos resultados.


Trabalhando com pares de chaves

Um par de chaves é um par de chaves públicas e privadas usadas para autenticar um usuário. Ao iniciar uma instância, especifique um par de chaves que possa ser usado para acessar a instância quando ela estiver ativada e em execução. A Amazon associa a chave pública a essa instância. Dependendo de como a AMI estiver configurada, talvez não seja possível acessar a instância sem a chave privada. O arquivo keypairs.php exibe todos os pares de chaves definidos para sua conta.


Figura 14. A lista de pares de chaves


Para cada par de chaves, a tabela exibe seu nome e impressão digital.


Lista 10. Criando a tabela de pares de chaves
, 
$creds = new Credentials;
$ec2_kp = new Zend_Service_Amazon_Ec2_Keypair>
                ($creds->getCredential('amazon', 'accessKey'), 
                 $creds->getCredential('amazon', 'secretKey'));

$keypairs = $ec2_kp->describe();
if (count($keypairs)) {
  echo "<p>Here are the key pairs defined for your account:</p>";

  echo "<table border='1' cellpadding='5'>";
  echo "<tr style='font-weight: bold;'>";
  echo "<td>Key Pair Name</td>";
  echo "<td>Fingerprint</td>";
  echo "<td>&nbsp;</td>";
  echo "</tr>";

  foreach ($keypairs as $key => $row) {
    $keyName[$key] = $row['keyName'];
    $keyFingerprint[$key] = $row['keyFingerprint'];
  }
  array_multisort($keyName, $keypairs);

  foreach ($keypairs as $nextKeypair) {
    echo "<tr>";
    echo "<td>&nbsp;".$nextKeypair['keyName']."</td>";
    echo "<td>&nbsp;".$nextKeypair['keyFingerprint']."</td>";
    echo "<td>";
    echo "<form action='".$_SERVER['PHP_SELF']."' method='post'";
    echo " onsubmit='return confirm(\"Do you really want to delete the key pair ";
    echo "&apos;".$nextKeypair['keyName']."&apos;?\");'>";
    echo "<input type='hidden' name='keypairtodelete' ";
    echo "value='".$nextKeypair['keyName']."'/>";
    echo "<input type='submit' value='Delete'/>";
    echo "</form>";
    echo "</td>";
    echo "</tr>";
  }
  echo "</table>";
}
else
  echo "<p>Sorry, your account doesn't have any key pairs defined.</p>";
            

O código cria um objeto Zend_Service_Amazon_Ec2_Keypair e, em seguida, chama seu método describe() para obter os detalhes de todos os pares de chaves definidos para sua conta. Para cada par de chaves, o AWS retorna o nome do par de chaves e sua impressão digital. Cada linha da tabela também contém um formulário HTML com um botão Excluir . O formulário requer uma confirmação para qualquer pedido de exclusão.


Figura 15. A exclusão de um par de chaves deve ser confirmada

O método delete() torna direta a exclusão do par de chaves.


Lista 11. Excluindo um par de chaves
, 
if (strlen($keypairToDelete)) {
  echo "<p><b>";
  try {
    $ec2_kp->delete($keypairToDelete);
    echo "The key pair named ".$keypairToDelete." was deleted successfully.";
  }
  catch (Zend_Service_Amazon_Ec2_Exception $ec2e) {
    echo "The key pair could not be deleted. The error message from Amazon is:";
    echo "<br/><br/><i>".$ec2e->getMessage()."</i>";
  }
  echo "</b></p><hr/><br/>";
}
            

A página keypairs.php também contém um formulário para criar um novo par de chaves. O único parâmetro é um nome para o novo par de chaves.


Figura 16. Formulário para criar um novo par de chaves


Criar um par de chaves é tão simples quanto chamar o método create() .


Lista 12. Criando a tabela de regras no grupo de segurança
foreach ($list[0]['ipPermissions'] as $key => $row) {
  $ipProtocol[$key] = $row['ipProtocol'];
  $startingPort[$key] = $row['fromPort'];
  $toPort[$key] = $row['toPort'];
  $ipRanges[$key] = $row['ipRanges'];
}
array_multisort($startingPort, SORT_ASC, $list[0]['ipPermissions']);

foreach($list[0]['ipPermissions'] as $rule) {
. . .
  echo "<tr>\n";
  echo "<td>&nbsp;".strtoupper($rule['ipProtocol'])."</td>\n";
  echo "<td>&nbsp;".$rule['fromPort']."</td>\n";
  echo "<td>&nbsp;".$rule['toPort']."</td>\n";

  if ((is_array($rule['ipRanges']) && count($rule['ipRanges']) == 0) ||
      (strlen($rule['ipRanges']) == 0)) {
    echo "<td>&nbsp;---</td>\n";
    echo "<td>&nbsp;</td>\n";
  }
  else {
    echo "<td>&nbsp;".$rule['ipRanges']."</td>\n";
    echo "<td style='text-align: center;'>";
    echo "<form action='".$_SERVER['PHP_SELF']."' method='POST'";
    echo " onsubmit='return confirm(\"Do you really want to revoke access for IP ";
    echo " address range '".$rule['ipRanges']."' on this port?\");'>";
    echo "<input type='hidden' name='groupname' value='".$groupName."'/>";
    echo "<input type='hidden' name='fromport' value='".$rule['fromPort']."'/>";
    echo "<input type='hidden' name='toport' value='".$rule['toPort']."'/>";
    echo "<input type='hidden' name='iptorevoke' value='".$rule['ipRanges']."'/>";
    echo "<input type='submit' value='Revoke'/></form></td>";
  }

A resposta da Amazon contém a chave privada para o novo par de chaves. A página PHP exibe essa informação com uma mensagem para o usuário.


Figura 17. Um par de chaves recém-criado


O usuário deve copiar e colar a informação de chave privada em um arquivo. Se esta informação for perdida, ela não poderá ser recriada. (A criação de uma solução mais elegante que grava automaticamente os dados do par de chaves em um arquivo é deixada como um exercício para o leitor.)


Trabalhando com grupos de segurança

O formulário que permite criar novas instâncias requer a especificação de uma imagem de máquina, um par de chaves e um grupo de segurança. Um grupo de segurança permite definir como outras máquinas poderão acessar uma instância. Por exemplo, se deseja usar uma instância em execução como um servidor da Web, você definiria uma regra em seu grupo de segurança que os pedidos de conexão na porta 80 devem ser aceitos a partir de qualquer máquina. Para cada regra, especifique um protocolo, um intervalo de portas e um intervalo de endereços IP autorizados a acessar essas portas por meio desse protocolo. A exibição de um grupo de segurança é semelhante à Figura 18.


Figura 18. Um grupo de segurança


Aqui, a tabela lista as políticas de segurança para o grupo de segurança default. Na parte inferior da captura de tela, é possível ver que a política permite que os hosts 67.93.2.12 e 76.182.90.9 acessem a porta 80. A porta 3389, geralmente usada para sessões do Desktop Remoto com VMs Windows, também é autorizada para o endereço IP 76.182.90.9. É possível especificar um intervalo de portas; neste exemplo, as regras para as portas 21, 22 e 23 poderiam ter sido definidas com uma única regra. Cada linha da tabela contém um formulário para exclusão de uma regra individual. O código para criar a tabela é relativamente direto.


Lista 13. Criando a tabela de regras no grupo de segurança
, 
foreach ($list[0]['ipPermissions'] as $key => $row) {
  $ipProtocol[$key] = $row['ipProtocol'];
  $startingPort[$key] = $row['fromPort'];
  $toPort[$key] = $row['toPort'];
  $ipRanges[$key] = $row['ipRanges'];
}
array_multisort($startingPort, SORT_ASC, $list[0]['ipPermissions']);

foreach($list[0]['ipPermissions'] as $rule) {
. . .
  echo "<tr>\n";
  echo "<td>&nbsp;".strtoupper($rule['ipProtocol'])."</td>\n";
  echo "<td>&nbsp;".$rule['fromPort']."</td>\n";
  echo "<td>&nbsp;".$rule['toPort']."</td>\n";

  if ((is_array($rule['ipRanges']) && count($rule['ipRanges']) == 0) ||
      (strlen($rule['ipRanges']) == 0)) {
    echo "<td>&nbsp;---</td>\n";
    echo "<td>&nbsp;</td>\n";
  }
  else {
    echo "<td>&nbsp;".$rule['ipRanges']."</td>\n";
    if (strripos('0.0.0.0', $rule['ipRanges'][0]) === false) {
      echo "<td style='text-align: center;'>";
      echo "<form action='".$_SERVER['PHP_SELF']."' method='POST'";
      echo " onsubmit='return confirm(\"Do you really want to revoke access for IP ";
      echo " address range '".$rule['ipRanges']."' on this port?\");'>";
      echo "<input type='hidden' name='groupname' value='".$groupName."'/>";
      echo "<input type='hidden' name='fromport' value='".$rule['fromPort']."'/>";
      echo "<input type='hidden' name='toport' value='".$rule['toPort']."'/>";
      echo "<input type='hidden' name='iptorevoke' value='".$rule['ipRanges']."'/>";
      echo "<input type='submit' value='Revoke'/></form></td>";
    }
    else
    echo "<td>&nbsp;</td>";

Antes de construir as linhas da tabela, o código usa a função array_multisort para classificar a array de regras pelo número da porta inicial de cada regra. A exibição do nome do protocolo, da porta inicial e da porta final é direta. As duas últimas colunas na tabela estão no intervalo de endereços IP e um botão para revogar uma permissão. Em alguns casos, o intervalo de endereços IP é retornado como uma array vazia ou uma cadeia vazia. Se esse for o caso, a tabela conterá uma célula vazia em vez de um botão Revoke .

A última linha da tabela contém um formulário para criação de uma nova regra.


Figura 19. O formulário para criação de uma nova regra


A Amazon requer que o endereço IP seja especificado na nota Classless Inter-Domain Routing (CIDR). A nota CIDR é um endereço IP, seguido por uma barra e um número de 0 a 32. O número após a barra especifica quantos bits do endereço IP estão no prefixo. Por exemplo, a nota CIDR 9.67.0.0/16 corresponde a qualquer endereço que inicie com 9.67. O intervalo de IPs 0.0.0.0/0 corresponde a qualquer endereço IP, apesar do intervalo 76.182.90.9/32 corresponder apenas com o endereço IP 76.182.90.9. Se o usuário inserir um endereço IP que não está na nota CIDR, a página PHP incluirá /32 no endereço. (Consulte Recursos para aprender mais sobre CIDR.) O código para autorizar um intervalo de IPs é direto.


Lista 14. Autorizando um novo intervalo de endereços IP
, 
if (strlen($ipToAuthorize) && strripos($ipToAuthorize, '/') === false)
  $ipToAuthorize = $ipToAuthorize."/32";
  . . .
  try {
    $ec2_sg->authorizeIp($groupName, $protocol, $fromPort, $toPort, $ipToAuthorize);
    echo "IP address ".$ipToAuthorize." is now authorized.";
  }
  catch (Zend_Service_Amazon_Ec2_Exception $ec2e) {
     // We get an exception if this IP address is already authorized, that's okay. 
    if ($ec2e->getErrorCode() == 'InvalidPermission.Duplicate')
      echo "IP address range ".$ipToAuthorize." is already authorized.";

    // If the IP address range isn't formatted correctly, tell the user. 
    else if ($ec2e->getErrorCode() == 'InvalidPermission.Malformed')
      echo "The value ".$ipToAuthorize." is not a valid IP address range.";

    //  For all other exceptions, we just dump the exception to the screen.
    else {
      echo "<i>Something really bad happened:</i><br/><pre>";
      var_dump($ec2e);
      echo "</pre>";
    }
  }
      

Chamar o método authorizeIp cria uma nova regra para o grupo de segurança. Aqui, o código manipula duas exceções comuns: O Zend Framework emite uma exceção se você autorizar um intervalo de endereços IP que já está autorizado, e uma segunda exceção ocorre quando o intervalo de endereços IP estiver malformado. Para qualquer outra exceção, o código apenas realiza o dump da mensagem de erro para a tela.

Observação: Um erro corrigido recentemente no Zend Framework retorna uma array de listagens quando mais de um intervalo de endereços estiver autorizado para uma determinada porta. Se sua versão do Zend Framework não tiver essa correção, você verá apenas um endereço para cada porta. Todas as autorizações são parte do grupo de segurança armazenado na nuvem Amazon; elas apenas não são mostradas nos resultados do Zend. O código de amostra possui uma lógica para manipular isso de forma elegante.

Finalmente, clicar no botão Revoke próximo à regra solicita a confirmação do usuário.


Figura 20. A exclusão de uma regra de segurança deve ser confirmada


A exclusão de uma regra de segurança é realizada por meio do método revokeIp() .


Resumo

Este artigo apresentou um conjunto de páginas para trabalhar com imagens de máquinas virtuais, instâncias em execução dessas imagens e os pares de chaves e grupos de segurança que permitem gerenciá-los. Mais uma vez, o Zend Framework torna mais fácil a interação com a nuvem. A próxima parte desta série mostrará como usar o Zend Framework para trabalhar com recursos mais avançados do EC2, com endereços IP elásticos, armazenamento em bloco elástico e CloudWatch.



Download

DescriçãoNomeTamanhoMétodo de download
Sample codeos-php-cloud2-source.zip13KBHTTP

Informações sobre métodos de download


Recursos

Aprender

Obter produtos e tecnologias

Discutir

Sobre o autor

Doug Tidwell

Doug Tidwell é um engenheiro de software sênior no grupo Emerging Technology da IBM. Ele foi um palestrante na primeira conferência sobre XML em 1997 e trabalhou com linguagem de marcações, serviços da Web e tecnologia SOA por vários anos. Seu trabalho como um evangelista de tecnologia é explicar os padrões e tecnologias por trás da computação em nuvem e ajudar clientes a integrá-los com suas arquiteturas e estratégias gerais de negócios. Ele é autor de vários artigos aqui no developerWorks e é o autor do livro sobre XSLT da O'Reilly (ISBN 0-596-52721-7), um presente inteligente para todas as ocasiões. Ele reside em Chapel Hill, N.C., com sua esposa, filha e cão.

Ajuda para Relatar Abuso

Relatar abuso

Obrigado. Esta entrada foi sinalizada para atenção do moderador.


Ajuda para Relatar Abuso

Relatar abuso

Falha no envio do Relatório de abuso. Tente novamente mais tarde.


developerWorks: Registre-se


Precisa de um ID IBM?
Esqueceu seu ID IBM?


Esqueceu sua senha?
Alterar sua senha

Ao clicar em Enviar, você concorda com os termos de uso do developerWorks.

 


Na primeira vez que você efetua sign in no developerWorks, um perfil é criado para você. Informações selecionadas do seu perfil developerWorks são exibidas ao público, mas você pode editá-las a qualquer momento. Seu primeiro nome, sobrenome (a menos que escolha ocultá-los), e seu nome de exibição acompanharão o conteúdo que postar.

Selecione seu nome de exibição

Ao se conectar ao developerWorks pela primeira vez, é criado um perfil para você e é necessário selecionar um nome de exibição. O nome de exibição acompanhará o conteúdo que você postar no developerWorks.

Escolha um nome de exibição de 3 - 31 caracteres. Seu nome de exibição deve ser exclusivo na comunidade do developerWorks e não deve ser o seu endereço de email por motivo de privacidade.

(Deve possuir de 3 a 31 caracteres.)


Ao clicar em Enviar, você concorda com os termos de uso do developerWorks.

 


Classificar este artigo

Comentários

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=80
Zone=Software livre, Cloud computing
ArticleID=446275
ArticleTitle=Computação em Nuvem com PHP, Parte 2: Usando Amazon EC2 com o Zend Framework
publish-date=11112009

Conheça a IBM da sua cidade

Virtual Branch Office Brasil

A IBM está mais perto do que você imagina!


Tags

Help
Use o campo de pesquisa para encontrar todos os tipos de conteúdo no My developerWorks com essa tag.

Use a barra de rolagem para ver mais ou menos tags.

Tags populares mostra as principais tags para esta zona de conteúdo em particular (por exemplo, Java technology, Linux, WebSphere).

Minhas tags mostra suas tags para esta zona de conteúdo em particular (por exemplo, Java technology, Linux, WebSphere).

Use o campo de pesquisa para localizar todos os tipos de conteúdo no Meu developerWorks com essa tag. Tags populares mostra as tags principais para essa zona de conteúdo particular (por exemplo, tecnologia Java, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere). Minhas tags mostra as suas tags para essa zona de conteúdo em particular (por exemplo, tecnologia Java, Linux, WebSphere).