https://pulumi.com logo
Title
p

proud-art-41399

12/07/2022, 5:11 PM
Hi, I'm using
ec2.Instance
to spin up a new EC2 instance which employes user data to provision the needed software upon start. Now I want to use
ec2.AmiFromInstance
to create an AMI from the newly created EC2 instance. However, it seems that the later resource doesn't wait until the instance is fully up. Creating an AMI involves stopping the instance, creating a snapshot of EBS volume and starting it up again. However, I can see in the cloud init logs that the EC2 instance user data script is interrupted before it can finish the provisioning. Is there any way to wait for the user data script to finish? I could put some artificial sleep/delay before the creating the AMI resource, but there might be a better and more elegant way.
m

many-telephone-49025

12/07/2022, 6:34 PM
Hi, What I recently did was to create a command resource and wait cloud-init to be finished:
installDocker, err := remote.NewCommand(ctx, "install-docker", &remote.CommandArgs{
			Connection: &remote.ConnectionArgs{
				Host:       instance.Ipv4Address,
				PrivateKey: readFileOrPanic("~/.ssh/id_rsa"),
				User:       pulumi.String("root"),
			},
			Create: pulumi.String("cloud-init status --wait && sleep 30s"),
		})
		if err != nil {
			return err
		}
And then I have a
pulumi.DependsOn([]pulumi.Resource{installDocker})
in the next resource.
p

proud-art-41399

12/07/2022, 6:52 PM
That sounds really interesting, will give it a try. Thanks!
f

fierce-ability-58936

12/07/2022, 7:41 PM
I'd tackle this problem using https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-signal.html Not really a fan of Cloudformation 🙂 But you could create a mini-Cloudformation template that waits until the script on ec2 signals to proceed. Pros: no ssh key, works with instances that don't have public IPs.
m

many-telephone-49025

12/07/2022, 7:45 PM
@fierce-ability-58936, thats nice! My snippet is not from AWS (actually DO) and I had to come up with an "vanilla" solution.
p

proud-art-41399

12/08/2022, 7:14 AM
@fierce-ability-58936 hmm the thing with public IP is something I didn't consider. I plan to spin up the instance in a private subnet... Good tip 👍
In the end, I achieved it a bit differently. I used a local command calling the AWS CLI to wait for the status checks:
wait_for_instance_command = command.local.Command(
        "wait-for-instance-command",
        create=pulumi.Output.format(
            "aws ec2 wait instance-status-ok --instance-ids {instance_id}",
            instance_id=run_instance_command.stdout,
        ),
        triggers=[run_instance_command.stdout],
        opts=pulumi.ResourceOptions(depends_on=[run_instance_command]),
    )
For a bit more context. I realized that I don't even want the EC2 instance managed by Pulumi because the only resource I care about is the created AMI. So I start the EC2 instance also with local command (the
run_instance_command
) and get the instance ID from the command output. Then I wait to the instance to come up and report successful status check. The
ec2.AmiFromInstance
specifies the wait command as an explicit dependency. The final local command in the chain is the
terminate_instance_command
which terminates the ephemeral instance.