0

I read that you can only run userdata once on an EC2 AMI. If you make a custom AMI from an EC2 instance, you cannot run userdata script on that custom AMI. On Ubuntu instances, you can remove /var/lib/cloud/* , make a custom AMI and run userdata on the custom AMI. I cannot find an equivalent of /var/lib/cloud/* on FreeBSD.

Is there a way to run userdata on custom FreeBSD AMI or an alternative to create an AMI so that you can run userdata scripts again?

There is #cloud-boothook for Linux but for FreeBSD, I only found configinit which doesn't do what I need. We pass arguments into the userdata scripts from the command line while launching instances.

1

The FreeBSD AMI on AWS does not provide the same level of support for user_data scripts as other AMIs. As you pointed out, it does not support #cloud-boothook user_data and ignores any user_data passed after boot.

A simple solution is the following:

sed -i '' '/KEYWORD: *firstboot$/d' /usr/local/etc/rc.d/ec2_configinit

This is a hack -- your instance will now execute all user_data scripts, even those without the #cloud-boothook tag, but in my opinion it is much better than the default behavior of the script. Note that one can always disable the ec2_configinit script altogether by turning it off in /etc/rc.conf.

1
  • BEWARE! This sed -i command is a destructive command, it edits the file and there is no backup. I've been hacking sed for 20 years, but never used sed -i and now I edited the file and have no way to get back to the original. What was the original line that I deleted? OK, I suppose it was just '# KEYWORD: firstboot' and as such I restored mine. It is indeed a hack. Jan 13 '20 at 0:49
0

I provide my own answer, as the accepted answer is very crude.

UPDATE: I thought the accepted answer was very crude, but in the end, I am using it anyway as it works best for me. The rest down here will just give some additional background someone might find useful. The accepted answer works best for me in the end because: (1) it allows me to always execute a shell script, (2) it doesn't do anything else other than processing the user data file in the way I explain below, (3) I can still disable it in rc.conf if I want.

The thing is, even on Amazon Linux, the user-data script is only executed on first boot, except if you use the MIME multipart/mixed trick. You can look it up https://cloudinit.readthedocs.io/en/latest/topics/format.html but I am giving an example of something that pushes the limit:

Content-Type: multipart/mixed; boundary="schnipp-schnapp"
MIME-Version: 1.0

--schnipp-schnapp
Content-Type: text/cloud-config; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename="cloud-config.txt"

#cloud-config
cloud_final_modules:
- [scripts-user, always]

--schnipp-schnapp
Content-Type: text/x-shellscript; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename="user-data.sh"

#!/bin/bash
echo "Hello World." >> /etc/motd

--schnipp-schnapp
Content-Type: text/x-shellscript; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename="another.sh"

#!/bin/bash
echo "Kilroy was here." >> /etc/motd

--schnipp-schnapp
Content-Type: image/jpeg
MIME-Version: 1.0
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="imput64-8503-small.jpg"

/9j/4AAQSkZJRgABAQEAlgCWAAD/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcU
FhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSj/2wBDAQcHBwoIChMKChMoGhYaKCgoKCgo
...
JFSUkfQjjHr9yT2T9SSSdLS15R/qM64pbLRUcsExOk6axzpxhiQATFSDIB6E68K/c6WlrzEoTypl
JoceL9zq7NbXis8oopa6RRNUQovmNlCM5IIzxQLkgkD0wQCAFLYaXzKkSSVEkzOZXqJJOUjsfXkf
cknJOMk++lpa9u+AGkJwsuJACiqCeJGm5pJiZJXBr4Sx04IfzZiS3I9r3/TQakADkD260tLWjxQk
hE9/tVFgPm8K/9k=

--schnipp-schnapp--

What I found was that the two scripts are executed in alphabetical order and the image part was just ignored.

Unless the FreeBSD AMI maintainers implement this multi-part stuff and all the things it involves

  • text/cloud-boothook
  • text/cloud-config
  • text/cloud-config-archive
  • text/jinja2
  • text/part-handler
  • text/upstart-job
  • text/x-include-once-url
  • text/x-include-url
  • text/x-shellscript

why would you want all the other things that ec2-cloudinit does executed like that always? Ultimately you are on your own.

There is really no harm in just fetching the user data yourself and decide what to do with it. Here is how you fetch it:

fetch -q -o - http://169.254.169.254/latest/user-data

and so, if you want it executed you can just put it into rc.local:

fetch -q -o - http://169.254.169.254/latest/user-data |sh 

or

fetch -q -o /tmp/user-data.sh http://169.254.169.254/latest/user-data
mkdir 700 /tmp/user-data.sh
/tmp/user-data.sh

no big deal really. Not sure if it's worth it to support the complex multipart structure. FreeBSD AMI does it very different, and simpler, and arguably just fine.

  • if it starts with hash-bang #! it will be saved and executed
  • if it starts with ">/var/tmp/here" it will be written into the destination so specified
  • if it starts with ">>/var/tmp/here" it will be appended to the destination so specified
  • otherwise it is treated as an uncompressed tar archive of shell scrips, expanded and then each of the files is executed using the above rules.

Since it's not AWS standard, I would just not bother with it. Simply have a single script and force it to be executed in rc.local, or not even executed, just inspected to find some parameter that controls the behavior somehow.

1
  • Coming back here after many months and man this is some useful detail! Thanks to myself for sharing it so I could find my notes with Google. I forgot all about this! Oct 30 '20 at 21:40

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.