1
votes

I am using Packer with Ansible to create an AWS EC2 image (AMI). Ansible is used to install Java 8, install the database (Cassandra), install Ansible and upload an Ansible playbook (I know that I should push the playbook to git and pull it but I will do it when this is working). I am installing Ansible and uploading the playbook, because I have to change some of the Cassandra properties when an instance is launched from the AMI (add the current instance IP in the Cassandra options for example). In order to accomplish this I wrote a simple bash script, that is added as the user-data-file property. This is the script:

#cloud-boothook
#!/bin/bash 

#cloud-config
output: {all: '| tee -a /var/log/cloud-init-output.log'}


ansible-playbook -i "localhost," -c local /usr/local/etc/replace_cassandra.yaml

As you can see I am executing the ansible-playbook in a localhost mode.

The problem is that when I start the instance, I am finding an error inside the /var/log/cloud-init.log file. The error states, that ansible-playbook could not be found. So I added an ls line inside the user-data script to check the content of the /usr/bin/ folder (the folder where Ansible is installed) and there were no Ansible in it, but when I access the instance with ssh I can see that Ansible is present inside the /usr/bin/ folder and there is no problem executing the ansible-playbook.

Has anyone encountered a similar problem? I think that this should be a quite popular use case for Ansible with EC2.


EDIT

After some logging I found out that not only there is no Ansible, during the execution of the user data, but the database is missing as well.

Is it possible, that some of the code (or all of it) in the Ansible provisioner in Packer, is executed when the instance is launched?


EDIT2

I have found out what is happening here. When I add the user data via packer trough the user_data_file property, the user data is executed when packer lunches an instance to build the AMI. The script is launched before the Ansible provisioner is executed, and that is why Ansible is missing.

What I want to do is to automatically add a user data to the AMI, so that when an instance is launched from the AMI, the user data will be executed then, and not when packer builds the said AMI.

Any ideas on how to do this?

2
Your #cloud-config format seems wrong. Try put the ansible-playbook command into bootcmd: like this docDavid Lee
I don't think that this is the problem. As I said in my question there is no ansible-playbook in the /usr/bin folder and that is the reason why the code does not work.Ivan Stoyanov
Similar issue here, just without packer: pip install ansible; ansible-playbook ... Fails with command not foud for ansible-playbookJukka Dahlbom
It is good to know that I am not the only one with the same problem.Ivan Stoyanov
@JukkaDahlbom you can check if pip install ansible actually installs ansible. I am using apt and it required for the ansible repo to be added, before it can be installed.Ivan Stoyanov

2 Answers

0
votes

Just run multiple provisioners and don't try to run ansible via cloud-init.

I'm making an assumption here that your playbook and roles are stored locally where you are starting the packer run from. Instead of shoehorning the ansible stuff into user data, run a shell provisioner to install ansbile, run the ansible-local provisioner to run the playbook/role you want.

Below is a simplified example of what I'm talking about. It won't run without some more values in the builder config but I left those out for the sake of brevity.

In the example json, the install-prereqs.sh just adds the ansible ppa apt repo and runs apt-get update -y, then installs ansible.

#!/bin/bash

sudo apt-get install software-properties-common
sudo apt-add-repository -y ppa:ansible/ansible
sudo apt-get update
sudo apt-get install -y ansible

The second provisioner will then copy the playbook and roles you specify to the target host and run them.

{
"builders": [
  {
    "type": "amazon-ebs",
    "ssh_username": "ubuntu",
    "image_name": "some-name",
    "source_image": "some-ami-id",
    "ssh_pty": true
  }
],
"provisioners": [
  {
    "type": "shell",
    "script": "scripts/install-prereqs.sh"
  },
  {
    "type": "ansible-local",
    "playbook_file": "path/to/playbook.yml",
    "role_paths": ["path/to/roles"]
  },
 ]
}
0
votes

This is possible! Please make sure of the following.

  • An Ansible server (install ansible via cloud formation userdata if not built into AMI) and your target have SSH access in the security groups you create in cloudformation.
  • After you install ansible on the ansible server, your ansible.cfg file points to a private key on the ansible server
  • The matching public key for the ansible private key is copied to the authorized_keys file on the servers in the root user .ssh directory you wish to run playbooks on -You have enabled root ssh access between the ansible server and target server(s), this can be done by editing the the /etc/ssh/sshd_config file and making sure there is nothing preventing the SSH access from the root user in the root authorized_keys file on the target server(s)