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
    Jun 9 '18 at 23:37
  • Yes. I logged in and verified after the instance came up.
    – theillien
    Jun 10 '18 at 13:52
5

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
    Jun 11 '18 at 15:05
  • I think I might have something: I've been using !Sub. You used Fn::Join in your example (!Join).
    – theillien
    Jun 11 '18 at 16:17
  • That didn't change anything. Commands still aren't being executed.
    – theillien
    Jun 11 '18 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
    Jun 11 '18 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
    Jun 11 '18 at 18:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.