The main question: How to I reference dependent resource attributes in a cloud formation template to build out a user data script.
What I have tried:
- Approach listed here.
- Examples from sub function
I am building a CloudFormation template for a three node Kafka cluster.
The approach I am taking here is configuring Zookeeper and Kafka on each node of the cluster using a UserData script on the EC2 instance.
I am using the Sub and Base64 functions to populate my user data script with the PrimaryPrivateIpAddress
of my NetworkInterface but they are coming across as empty strings instead of the actual values. I know that the values are being populated correctly because they are part of my output in the template.
I have included the resource block of my template below as a reference. I omitted some uninteresting parts for the sake of succinctness. I also am illustrating a couple different approaches that I have tried to the EC2 resource blocks are not consistent.
EC2I8MWW:
Type: 'AWS::EC2::Instance'
DependsOn:
- EC2NI2E8ES
- EC2NI2PFST
- EC2NI54B66
Properties:
KeyName: !Ref DesiredKeyName
InstanceType: !Ref InstanceType
NetworkInterfaces:
- NetworkInterfaceId: !Ref EC2NI54B66
DeviceIndex: "0"
UserData:
Fn::Base64:
Fn::Sub:
- |
#!/bin/bash
CONF="/etc/zookeeper/conf.dist/zoo.cfg"
PRIVATE_1=${Private1}
PRIVATE_2=${Private2}
PRIVATE_3=${Private3}
echo "# Zookeeper configuration for Talentreef" > "$CONF"
cat <<EOT >> "$CONF"
maxClientCnxns=50
tickTime=2000
initLimit=10
syncLimit=5
EOT
echo "server.1=$PRIVATE_1:2888:3888" >> $CONF
echo "server.2=$PRIVATE_2:2888:3888" >> $CONF
echo "server.3=$PRIVATE_3:2888:3888" >> $CONF
service zookeeper-server init --myid=$NODE_ID
chkconfig zookeeper-server on
- {
Private1: !GetAtt EC2NI2E8ES.PrimaryPrivateIpAddress,
Private2: !GetAtt EC2NI2PFST.PrimaryPrivateIpAddress,
Private3: !GetAtt EC2NI54B66.PrimaryPrivateIpAddress
}
EC2I2JVJI:
Type: 'AWS::EC2::Instance'
DependsOn: EC2NI54B66
Properties:
KeyName: !Ref DesiredKeyName
InstanceType: !Ref InstanceType
BlockDeviceMappings:
- DeviceName: /dev/xvdb
Ebs:
VolumeType: st1
DeleteOnTermination: 'true'
VolumeSize: '500'
- DeviceName: /dev/xvda
Ebs:
VolumeType: gp2
DeleteOnTermination: 'true'
VolumeSize: '8'
ImageId: !FindInMap
- AWSRegionArch2AMI
- !Ref 'AWS::Region'
- !FindInMap
- AWSInstanceType2Arch
- !Ref InstanceType
- Arch
NetworkInterfaces:
- NetworkInterfaceId: !Ref EC2NI2PFST
DeviceIndex: "0"
UserData:
Fn::Base64: !Sub |
#!/bin/bash
CONF="/etc/zookeeper/conf.dist/zoo.cfg"
cp $CONF /etc/zookeeper/conf.dist/zoo.cfg.bak-$(date +%s)
echo "# Zookeeper configuration for Talentreef" > "$CONF"
cat <<EOT >> "$CONF"
maxClientCnxns=50
tickTime=2000
initLimit=10
syncLimit=5
server.1=${EC2NI2E8ES.PrimaryPrivateIpAddress}:2888:3888
server.2=${EC2NI2PFST.PrimaryPrivateIpAddress}:2888:3888
server.3=${EC2NI54B66.PrimaryPrivateIpAddress}:2888:3888
EOT
service zookeeper-server init --myid=$NODE_ID
chkconfig zookeeper-server on
service zookeeper-server start
EC2I56LVQ:
Type: 'AWS::EC2::Instance'
DependsOn: EC2NI54B66
Properties:
KeyName: !Ref DesiredKeyName
InstanceType: !Ref InstanceType
BlockDeviceMappings:
- DeviceName: /dev/xvdb
Ebs:
VolumeType: st1
DeleteOnTermination: 'true'
VolumeSize: '500'
- DeviceName: /dev/xvda
Ebs:
VolumeType: gp2
DeleteOnTermination: 'true'
VolumeSize: '8'
ImageId: !FindInMap
- AWSRegionArch2AMI
- !Ref 'AWS::Region'
- !FindInMap
- AWSInstanceType2Arch
- !Ref InstanceType
- Arch
NetworkInterfaces:
- NetworkInterfaceId: !Ref EC2NI2E8ES
DeviceIndex: "0"
UserData:
Fn::Base64:
Fn::Sub:
- |
CONF="/etc/zookeeper/conf.dist/zoo.cfg"
cp $CONF /etc/zookeeper/conf.dist/zoo.cfg.bak-$(date +%s)
echo "# Zookeeper configuration for Talentreef" > "$CONF"
cat <<EOT >> "$CONF"
maxClientCnxns=50
tickTime=2000
initLimit=10
syncLimit=5
EOT
echo "server.1=${Private1}:2888:3888" >> $CONF
echo "server.2=${Private2}:2888:3888" >> $CONF
echo "server.3=${Private3}:2888:3888" >> $CONF
service zookeeper-server init --myid=$NODE_ID
chkconfig zookeeper-server on
- {
Private1: !GetAtt EC2NI2E8ES.PrimaryPrivateIpAddress,
Private2: !GetAtt EC2NI2PFST.PrimaryPrivateIpAddress,
Private3: !GetAtt EC2NI54B66.PrimaryPrivateIpAddress
}
EC2NI54B66:
Type: 'AWS::EC2::NetworkInterface'
DependsOn: EC2NI2PFST
Properties: {}
EC2NI2PFST:
Type: 'AWS::EC2::NetworkInterface'
DependsOn: EC2NI2E8ES
Properties {}
EC2NI2E8ES:
Type: 'AWS::EC2::NetworkInterface'
Properties: {}
When this script runs I get the following output in the zoo.cfg
file:
maxClientCnxns=50
tickTime=2000
initLimit=10
syncLimit=5
server.1=:2888:3888
server.2=:2888:3888
server.3=:2888:3888
Please let me know if I'm doing something wrong here or if I have to change my approach. Thank you for the help.