5

I'm trying to get ansible installed on an instance. I figured I could use AWS::CloudFormation::Init to execute sudo pip install ansible. That doesn't seem to be working, though. This is my instance resource:

ansibleInstance:
  Type: 'AWS::EC2::Instance'
  Metadata:
    'AWS::CloudFormation::Init':
      commands:
        ansible:
          command: "sudo pip install ansible"
          test: "pip --version"
          ignoreErrors: 'false'
  Properties:
    ImageId: ami-467ca739
    KeyName: Candidate-EyMm7zuOcn
    InstanceType: t2.micro
    SubnetId: !Ref subnetTest
    SecurityGroupIds:
    - !Ref allowSSH
    Tags:
      - Key: Name
        Value: Test

Is there a way to see what is happening when this is attempted so I can figure out where/why it is failing? Is there anything others might suggest looking at to figure this out?

EDIT1: I removed the sudo just in case that might have been getting in the way for whatever reason (I didn't think it would, but I wanted to eliminate it all the same). That had no impact. I also verified that the aws-cli tools are installed which was expected since it is the AWS Linux AMI

EDIT2: This is a version of the ansibleInstance resource in which I tried to execute commands via UserData:

ansibleInstance:
  Type: 'AWS::EC2::Instance'
  Properties:
    ImageId: ami-467ca739
    KeyName: Candidate-EyMm7zuOcn
    InstanceType: t2.micro
    SubnetId: !Ref subnetTest
    SecurityGroupIds:
    - !Ref allowSSH
    Tags:
      - Key: Name
        Value: Test
  UserData:
    Fn::Base64:
      !Sub |
        #!/bin/bash -xe
        pip install ansible

I suspect there is something wrong with the formatting, but I can't make out what it is.

EDIT3: I ran cfn-init per the suggestion jordanm. This does appear to provide the metadata to the instance and, if I then log in and manually execute cfn-init the commands are processed:

[ec2-user@ip-192-168-1-121 ~]$ sudo /opt/aws/bin/cfn-init -v -s cfTest --resource ansibleInstance
[ec2-user@ip-192-168-1-121 ~]$ ansible --version
ansible 2.5.4
  config file = None
  configured module search path = [u'/home/ec2-user/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/local/lib/python2.7/site-packages/ansible
  executable location = /usr/local/bin/ansible
  python version = 2.7.13 (default, Jan 31 2018, 00:17:36) [GCC 4.8.5 20150623 (Red Hat 4.8.5-11)]

So now my question is: why won't cfn-init execute per the UserData?

SOLUTION: Thanks to @jordanm I was able to get though this. My working snippet:

  ansibleInstance:
    Type: 'AWS::EC2::Instance'
    Metadata:
      'AWS::CloudFormation::Init':
        config:
          commands:
            ansible:
              command: "sudo pip install ansible"
              test: "pip --version"
              ignoreErrors: 'false'
    Properties:
      ImageId: ami-467ca739
      KeyName: Candidate-EyMm7zuOcn
      InstanceType: t2.micro
      SubnetId: !Ref subnetTest
      SecurityGroupIds:
      - !Ref allowSSH
      Tags:
        - Key: Name
          Value: Test
      UserData: 
        Fn::Base64: 
          !Sub |
            #!/bin/bash -xe
            # Install Ansible from the metadata
            /opt/aws/bin/cfn-init -v -s ${AWS::StackName} --resource ansibleInstance
2
  • Is pip / python installed as part of Amazon Linux?
    – Tim
    Commented Jun 9, 2018 at 23:37
  • Yes. I logged in and verified after the instance came up.
    – theillien
    Commented Jun 10, 2018 at 13:52

1 Answer 1

6

You have to execute cfn-init in order for AWS::CloudFormation::Init to do anything. This is most commonly done via cloud-init user data. Here is the example from the cfn-init documentation:

UserData: !Base64 
  'Fn::Join':
    - ''
    - - |
        #!/bin/bash -xe
      - |
        # Install the files and packages from the metadata
      - '/opt/aws/bin/cfn-init -v '
      - '         --stack '
      - !Ref 'AWS::StackName'
      - '         --resource WebServerInstance '
      - '         --configsets InstallAndRun '
      - '         --region '
      - !Ref 'AWS::Region'
      - |+
7
  • I'm guessing that it should be possible to execute commands directly via UserData as you are doing with your example. However, I tried this and got the same result. I've edited my post to include that version.
    – theillien
    Commented Jun 11, 2018 at 15:05
  • I think I might have something: I've been using !Sub. You used Fn::Join in your example (!Join).
    – theillien
    Commented Jun 11, 2018 at 16:17
  • That didn't change anything. Commands still aren't being executed.
    – theillien
    Commented Jun 11, 2018 at 16:26
  • 2
    @theillien I would test via running cfn-init manually on the instance. Once you figure out exactly what the command should be and verified it's working properly, you will likely find it easier to add the user-data to run automatically on instance startup. The main benefit to using cfn-init over just putting the command in user-data is that you can use cfn-hup to apply changes to make to Init.
    – jordanm
    Commented Jun 11, 2018 at 16:27
  • 1
    I switched from the Fn::Join function to the Fn::Sub function. Once I got all of the necessary code in place it worked properly. Thank you for helping me out with this. I've added my working snippet to my question.
    – theillien
    Commented Jun 11, 2018 at 18:57

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .