Marionetes escrevem hosts usando a chamada api

3

Estou tentando escrever uma função de fantoches que chama meu ambiente de hospedagem (rackspace cloud atm) para listar servidores e atualizar meu arquivo de hosts.

Minha função get_hosts atualmente é esta:

require 'rubygems'
require 'cloudservers'

module Puppet::Parser::Functions
  newfunction(:get_hosts, :type => :rvalue) do |args|
    unless args.length == 1
      raise Puppet::ParseError, "Must provide the datacenter"
    end

    DC       = args[0] 
    USERNAME = DC == "us" ? "..." : "..."
    API_KEY  = DC == "us" ? "..." : "..."
    AUTH_URL = DC == "us" ? CloudServers::AUTH_USA : CloudServers::AUTH_UK
    DOMAIN   = "..."

    cs = CloudServers::Connection.new(:username => USERNAME, :api_key => API_KEY, :auth_url => AUTH_URL)

    cs.list_servers_detail.map {|server|
      server.map {|s| { s[:name] + "." + DC + DOMAIN => {
                          :ip      => s[:addresses][:private][0],
                          :aliases => s[:name]
      }}}
    }
  end
end

E eu tenho um hosts.pp que chama isso e 'deve' gravá-lo em / etc / hosts.

class hosts::us {
    $hosts = get_hosts("us")

    hostentry { $hosts: }
}

define hostentry() {
  host{ $name: ip => $name[ip], host_aliases => $name[aliases] }
}

Como você pode imaginar, isso não está funcionando atualmente e estou recebendo um erro 'Símbolo como índice de matriz em /etc/puppet/manifests/hosts.pp:2'. Eu imagino, uma vez que eu percebi o que estou fazendo de errado, haverá mais erros por vir.

É uma boa ideia? Alguém pode me ajudar a descobrir como fazer isso?

Atualizar

Finalmente consegui fazer isso funcionar (com ajuda dos comentários)! Aqui está o meu get_hosts.rb:

require 'rubygems'
require 'cloudservers'

module Puppet::Parser::Functions
  newfunction(:get_hosts, :type => :rvalue) do |args|
    unless args.length == 1
      raise Puppet::ParseError, "Must provide the datacenter"
    end

    dc       = args[0] 
    username = dc == "us" ? "..." : "..."
    api_key  = dc == "us" ? "..." : "..."
    auth_url = dc == "us" ? CloudServers::AUTH_USA : CloudServers::AUTH_UK
    domain   = "...."

    cs = CloudServers::Connection.new(:username => username, :api_key => api_key, :auth_url => auth_url)

    cs.list_servers_detail.map {|server|
      server[:name] + "." + dc + domain + "," + 
          server[:addresses][:private][0] + "," + 
          server[:name]
    }
  end
end

e o hosts.pp

class hosts::us {
    $hosts = get_hosts("us")

    hostentry { $hosts: }
}

define hostentry() {
  $parts   = split($name, ',')
  $address = $parts[0]
  $ip      = $parts[1]
  $aliases = $parts[2]
  host{ $address: ip => $ip, host_aliases => $aliases }
}

É muito desagradável organizar o namevar assim, mas era a única maneira que eu conseguia fazer funcionar. Quaisquer melhorias bem-vindas.

    
por Ben Smith 04.04.2012 / 22:07

2 respostas

1

Eu não diria que é uma má ideia, mas você realmente precisa parar de usar constantes em todo o seu código (qualquer coisa que comece com uma letra maiúscula no Ruby é uma constante).

Para depurar seu problema, você provavelmente desejará usar a opção --trace para sua invocação do puppetmaster, para que ele imprima um backtrace em vez de comer a exceção real e fornecer uma mensagem de erro inútil. Você tem uma pilha de desreferenciamento ocorrendo em map calls; meu palpite seria que você entendeu mal parte da estrutura de dados que sai da API e seu código está tropeçando nesse mal-entendido. Acione um depurador (ou espalhe generosamente puts pelo seu código) e você verá o que está errado em um curto espaço de tempo.

    
por 04.04.2012 / 23:34
0

Eu separaria essa funcionalidade de maneira diferente.

Use sua função para construir os dados puros em um hash de hashes representando a lista de recursos do host.

Em seguida, use a função create_resources para criar recursos de host reais a partir desses dados:

link

O exemplo deve dar o suficiente para você começar:

    # A hash of user resources:
    $myusers = {
      'nick' => { uid    => '1330',
                  group  => allstaff,
                  groups => ['developers', 'operations', 'release'], }
      'dan'  => { uid    => '1308',
                  group  => allstaff,
                  groups => ['developers', 'prosvc', 'release'], }
    }

    create_resources(user, $myusers)

Isso faz sentido?

Depois, você pode evitar o tipo definido, e você pode fazer todos os dados em sua chamada de função para obter o hash de hashes, e você tem uma boa separação entre a função que coleta dados e a função que instancia recursos .

Isso deve resolver qualquer necessidade de iteração clássica se eu entender seu problema corretamente.

    
por 05.04.2012 / 18:17