Rabadash8820
Rabadash8820

Reputation: 2524

Rebooting From CloudFormation::Init Command

I'm having trouble rebooting my EC2 instance from a cfn-init command. I have the following config key in my instance's CloudFormation::Init metadata.

dns-hostname:
  commands:
    dns-hostname:
      env: { publicDns: !Ref PublicDns }
      command: |
        old=$(hostname)
        sed "s|HOSTNAME=localhost.localdomain|HOSTNAME=$publicDns|" --in-place /etc/sysconfig/network
        echo HOSTNAME changed from \"$old\" to \"$publicDns\"
        reboot
      ignoreErrors: true

All the command is supposed to do is change the instance's hostname to the provided public DNS name. A reboot is required for this change to take effect, and since cfn-init doesn't know this, I have to include the actual call to reboot in the last line. Unfortunately, the build fails with the following log message (from /var/log/cfn-init.log):

2017-04-16 12:16:00,301 [DEBUG] Running command dns-hostname
2017-04-16 12:16:00,301 [DEBUG] Running test for command dns-hostname
2017-04-16 12:16:00,309 [DEBUG] Test command output: HOSTNAME will be changed to "bastion.example.com"
2017-04-16 12:16:00,309 [DEBUG] Test for command dns-hostname passed
2017-04-16 12:16:00,321 [ERROR] Command dns-hostname (old=$(hostname)
sed "s|HOSTNAME=localhost.localdomain|HOSTNAME=$publicDns|" --in-place /etc/sysconfig/network
echo HOSTNAME changed from \"$old\" to \"$publicDns\"
reboot
) failed
2017-04-16 12:16:00,321 [DEBUG] Command dns-hostname output: HOSTNAME changed from "ip-10-0-128-4" to "bastion.example.com"
/bin/sh: line 3: reboot: command not found
2017-04-16 12:16:00,321 [INFO] ignoreErrors set to true, continuing build

Clearly, the actual hostname change is not failing, just the call to reboot. I get the same error message if I try to use shutdown -r instead of reboot, and if I try to use an absolute path (sbin/reboot), then it just hangs and stack creation times out. How are these very basic commands not found? Am I missing something simple here? Any help is appreciated!

EDIT: According to this post, when common commands are not available, it may be due to a screwed up PATH. And indeed, the CloudFormation::Init docs say that using the env property will overwrite the current environment, potentially including PATH. However, I added a line to my template to echo $PATH inside the command, and that yielded: "usr/local/bin:/bin:/usr/bin". So my PATH still includes the path to the bash executable, and I am still confused...

Upvotes: 0

Views: 1923

Answers (1)

Rabadash8820
Rabadash8820

Reputation: 2524

Well, it looks like the env property was the issue. Even though I thought that my PATH still had the necessary paths to find the bash executable and thereby run the reboot command, it wasn't until I removed the env property from my template that everything was able to build successfully. I still had some trouble getting the reboot command to behave as expected, as the command doesn't seem to run as soon as you call it. For instance, the following code will output numbers 1-10 before rebooting.

echo 1
echo 2
echo 3
echo 4
echo 5
reboot
echo 6
echo 7
echo 8
echo 9
echo 10

So the instance would apparently try to reboot while in the middle of running other commands from later CloudFormation::Init configs, causeing cfn-init to fail. My solution to this was just to run configs with commands blocks that manually called reboot after all other configs. Long story short, here is the working template snippet:

other-config:
  ...

# This config comes after the other b/c it manually calls 'reboot'
dns-hostname:
  commands:
    dns-hostname:
      command: !Sub |
        publicDns=${PublicDns}
        old=$(hostname)
        sed "s|HOSTNAME=localhost.localdomain|HOSTNAME=$publicDns|" --in-place /etc/sysconfig/network
        echo HOSTNAME changed from \"$old\" to \"$publicDns\"
        reboot
      ignoreErrors: true
# Any other configs that call reboot can follow

Upvotes: 1

Related Questions