Este é um seguimento a esta pergunta .
Eu tenho um jogo que provisiona várias instâncias do EC2. Por necessidade, o hosts
valor é localhost
(porque quando é executado não há hosts), e o play monta uma nova lista de hosts chamada ec2hosts
, e gera um host ip to hostname map porque esta é a primeira e única vez que a informação é disponibilizada , e salva usando set_fact
. Esta lista de anfitriões é então o assunto de uma peça de acompanhamento. O problema é que eu preciso usar o hostname_map
dict criado durante o jogo de provisionamento no segundo jogo, e não consigo ver como fazer isso.
Aqui está a primeira jogada:
- hosts: localhost
connection: local
gather_facts: False
tasks:
- name: Provision a set of instances
ec2:
key_name: marcus
instance_type: t2.micro
image: "{{ ami_id }}"
wait: true
exact_count: "{{ server_count }}"
count_tag:
Tutorial: "{{ tutorial_name }}"
instance_tags:
Tutorial: "{{ tutorial_name }}"
groups: ['SSH', 'Web']
register: ec2
- name: Add all instance public IPs to host group
add_host:
hostname: "{{ item.public_ip }}"
groups: ec2hosts
loop: "{{ ec2.instances }}"
- name: Build an IP to hostname map
set_fact:
hostname_map: "{{ hostname_map | combine({item.0.public_ip: (item.1 + '.' + tutorial_domain)}) }}"
loop: "{{ ec2.instances|zip(hostnames)|list }}"
- name: Debug hostname_map
debug:
msg: "{{ hostname_map }}"
No final deste, hostname_map
contém um mapa como:
{
"18.184.109.70": "host1.example.com",
"18.196.135.59": "host2.example.com"
}
Ao ler os documentos do ansible no escopo da variável, ele diz que as variáveis ​​definidas em um jogo não estão disponÃveis fora desse jogo, a menos que estejam sendo aplicadas ao mesmo conjunto de hosts. Isso não é possÃvel neste caso, então preciso usar um var com escopo global e, pelo que li, set_fact
é a maneira apropriada de fazer isso. Então criei uma variável vazia em /group_vars/all
, para que a variável fique acessÃvel a todas as jogadas:
hostname_map: {}
A próxima jogada se conecta a cada instância recém-criada (usando a lista de hosts que criamos dinamicamente) e define seu nome de host por dentro:
- hosts: ec2hosts
gather_facts: yes
tasks:
- name: Debug hostname_map
debug:
msg: "{{ hostname_map }}"
- name: Set hostnames
hostname:
name: "{{ hostname_map[ansible_host] }}"
No entanto, isso falha porque hostname_map
está vazio
TASK [Debug hostname_map]
ok: [18.184.109.70] => {
"msg": {}
}
ok: [18.196.135.59] => {
"msg": {}
}
então recebo este erro:
fatal: [18.184.109.70]: FALHOU! => {"msg": "A tarefa inclui uma opção com uma variável indefinida. O erro foi: 'dict object' não tem atributo u'18.184.109.70'
Curiosamente, recebo a mesma saÃda e erro de depuração, mesmo quando não defino a variável globalmente .
Outros artigos que li sugerem que os valores devem ser enumerados explicitamente em vars
, mas não posso fazer isso porque os dados são dinâmicos e desconhecidos até o tempo de execução. Da mesma forma, não posso fornecê-lo usando extra_vars
uma linha de comando pelo mesmo motivo.
Como posso disponibilizar essa variável na segunda jogada? Eu gostaria de evitar soluções desajeitadas, como escrever um arquivo local e depois lê-lo novamente!
Também estou aberto a sugestões para fazer isso de uma maneira completamente diferente, onde "isto" é: crie um número arbitrário de instâncias do EC2 e atribua a elas nomes de host retirados de uma lista estática.
Um valor com o qual você definiu
set_fact
estará disponÃvel entre as diferentes jogadas. Tenha em mente que set_fact são definidos para um host especÃfico . Sua primeira jogada é executada contra localhost , então o fato faz parte das variáveis ​​localhosts. Portanto, na próxima jogada, você poderá acessá-lo com uma tarefa como esta.Você pode usar o host fictÃcio que armazenará todas as variáveis ​​que deseja compartilhar com a ajuda de add_host . Depois é só acessar suas variáveis ​​com hostvars
Depende de como você define o jogo. Se você tiver várias jogadas com uma única execução ansible, funcionará. No entanto, não funciona com várias jogadas sequenciais. O que quero dizer, não funciona quando você executa o playbook1.yml do ansible-playbook e depois o playbook2.yml do ansible-playbook