EC2: Waiting until a new instance is in running state - amazon-ec2

I would like to create a new instance based on my stored AMI.
I achieve this by the following code:
RunInstancesRequest rir = new RunInstancesRequest(imageId,1, 1);
// Code for configuring the settings of the new instance
...
RunInstancesResult runResult = ec2.runInstances(rir);
However, I cannot find a wait to "block"/wait until the instance is up and running apart from Thread.currentThread().sleep(xxxx) command.
On the other hand, StartInstancesResult and TerminateInstancesResult gives you a way to have access on the state of the instances and be able to monitor any changes. But, what about the state of a completely new instance?

boto3 has:
instance.wait_until_running()
From the boto3 docs:
Waits until this Instance is running. This method calls EC2.Waiter.instance_running.wait() which polls EC2.Client.describe_instances() every 15 seconds until a successful state is reached. An error is returned after 40 failed checks.

From the AWS CLI changelog for v1.6.0:
Add a wait subcommand that allows for a command to block until an AWS
resource reaches a given state (issue 992, issue 985)
I don't see this mentioned in the documentation, but the following worked for me:
aws ec2 start-instances --instance-ids "i-XXXXXXXX"
aws ec2 wait instance-running --instance-ids "i-XXXXXXXX"
The wait instance-running line did not finish until the EC2 instance was running.
I don't use Python/boto/botocore but assume it has something similar. Check out waiter.py on Github.

Waiting for the EC2 instance to get ready is a common pattern. In the Python library boto you also solve this with sleep calls:
reservation = conn.run_instances([Instance configuration here])
instance = reservation.instances[0]
while instance.state != 'running':
print '...instance is %s' % instance.state
time.sleep(10)
instance.update()
With this mechanism you will be able to poll when your new instance will come up.

Depending on what you are trying to do (and how many servers you plan on starting), instead of polling for the instance start events, you could install on the AMI a simple program/script that runs once when the instance starts and sends out a notification to that effect, i.e. to an AWS SNS Topic.
The process that needs to know about new servers starting could then subscribe to this SNS topic, and would receive a push notifications each time a server starts.
Solves the same problem from a different angle; your mileage may vary.

Go use Boto3's wait_until_running method:
http://boto3.readthedocs.io/en/latest/reference/services/ec2.html#EC2.Instance.wait_until_running

You can use boto3 waiters,
https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ec2.html#waiters
for this ex: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ec2.html#EC2.Waiter.InstanceRunning
Or in Java https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/
I am sure there are waiters implemented in all the AWS sdks.

Related

TerraForm: deploying EC2 instances without starting them

I want to deploy my infrastructure in different AWS environments (dev, prod, qa).
That deployment creates a few EC2 instances from a custom AMI. When deployed, instances are in the "running" state. I understand this seems to be related to some constraint in the EC2 API. However, I don't necessarily want my instances started, depending on context. Sometimes, I just want the instances to be created, and they will be started later on. I guess this is a quite common scenario.
Reading the few related issues/requests on Hashicorp's github, makes me think so:
Terraform aws instance state change
Stop instances
aws_instance should allow to specify the instance state
There must be some TerraForm based solution which doesn't require to rely on AWS CLI / CDK or lambda, right? Something in the TerraForm script that, for example, would stop the instance right after its creation.
My google foo didn't help me much here. Any help / suggestion for dealing with that scenario is welcome.
Provisioning a new instance automatically puts it in a 'started' state.
As Marcin suggested, you can use user data scripts, here's some psuedo user data script. For you to figure out the actual implementation ;)
#!/bin/bash
get instance id, pass it to the subsequent line
aws ec2 stop-instances --instance-ids i-1234567890abcdef0
You can read about running scripts as part of the bootstrapping here: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/user-data.html
Basically its all up to your use case. We don't do this generally. Still, if you want to provision your EC2 instances and need to put them in stopped state, as bschaatsbergen suggested, you can use the user_data in Terraform. Make sure to attach the role with relevant permission.
#!/bin/bash
INSTANCE_ID=`curl -s http://169.254.169.254/latest/meta-data/instance-id/`
REGION=`curl -s http://169.254.169.254/latest/meta-data/placement/availability-zone | sed 's/.$//'`
aws ec2 stop-instances --instance-ids $INSTANCE_ID --region $REGION
As already stated by others, you cannot just "create" instances, they will be in "started" state.
Rather I would ask what is the exact use case here :
Sometimes, I just want the instances to be created, and they will be started later on.
Why you have to create instances now and use them later? Can't they be created exactly when they are required? Any specific requirement to keep them initialized before they are used? Or the instances take time to start?

AWS SSM describe_instance_information using old data?

I have a lambda function that is running:
ssm = boto3.client('ssm')
print(ssm.describe_instance_information())
It returns 6 instances. 5 are old instances that have been terminated and no longer show up in my console anymore. One instance is correct. I created an AMI image of that instance and tried launching several instances under the same security group and subnet. None of those instances are returned from describe_instance_information. Is it reporting old data?9
My end goal is to have the lambda function launch an instance using the AMI and send a command to it. Everything works if I use the existing instance. I am trying to get it to work with one created from the AMI.
EDIT:
After a while, the instances did show up, I guess it takes a while. I dont understand why terminated instances still show up. I can poll describe_instance_information until the instance_id I want shows up but is there a cleaner built-in function, like wait_for_xxxxx()?
You can use filter parameter with PingStatus which determine Connection status of SSM Agent.
response = client.describe_instance_information(
Filters=[
{
'Key': 'PingStatus',
'Values': [
'Online'
]
},
]
)

Check if EC2 instance finished initializing. Using the AWS Java SDK v2

I am programatically spinning up an EC2 instance from the AWS Java SDK v2. I then associate an elastic IP address to this instance. This takes a couple minutes. AWS then initializes the instance. In the AWS console it looks like this...
I cannot ssh into this instance until the initialization completes. Is there a way to programatically check that the instance has completed initialization? I have seen the method describeInstances(), but to the best of my knowledge, the most relevant information this method's response contains is the instance's state. The state is "running" and is not therefore probably not the variable that indicates initializing status. Maybe there is a different variable or a different method that is helpful for monitoring this initialization process? Cheers.
Not really.
Amazon EC2 is responsible for creating the virtual machine, attaching a disk with the operating system and then booting the instance. Everything after that is up to the operating system and startup scripts. The Amazon EC2 service can't 'see' what is happening on the instance.
If you particularly need to know this information, you could use a script on the instance to 'publish' this fact somewhere. For example, it could add a Tag to the instance saying State: Ready. Or, if you need to programmatically respond somehow, the script could trigger an AWS Lambda function or put a message into an Amazon SQS queue.
I check EC2 instance status after starting an instance with this Java code and the AWS SDK. An EC2 cd5.large instance takes about 90 seconds to stop and start back to the "running" state and then takes about another 3.5 minutes to complete initializing. This code is after the part which you probably have that spins the instance up to "running"...
boolean isInstanceInitialized = false;
while (!isInstanceInitialized) {
final DescribeInstanceStatusResult result = ec2
.describeInstanceStatus(
new DescribeInstanceStatusRequest()
.withInstanceIds(instanceId));
final List<InstanceStatus> instanceStatuses = result.getInstanceStatuses();
boolean isInstanceStatusOK;
boolean isSystemStatusOK;
for (final InstanceStatus instanceStatus : instanceStatuses) {
LOGGER.info(" InstanceStatus.instanceStatus: " + instanceStatus.getInstanceStatus().getStatus());
LOGGER.info(" SystemStatus: " + instanceStatus.getSystemStatus().getStatus());
isInstanceStatusOK = ("ok".equals(instanceStatus.getInstanceStatus().getStatus()));
isSystemStatusOK = ("ok".equals(instanceStatus.getSystemStatus().getStatus()));
isInstanceInitialized = isInstanceStatusOK && isSystemStatusOK;
}
if (isInstanceInitialized) {
break;
} else {
try {
// sleep 10 seconds between polling the instance state
Thread.sleep(10_000);
} catch (InterruptedException ex) {
// ignore
}
}
}
You can potentially use the waiter feature in AWS SDK for Java. EC2 supports waiters for a number of operations, one of which is waitUntilInstanceExists.

leave AWS EC2 instance properly

I am new to AWS EC2 instance. I use ssh to connect to the instance and just want to know how to leave the instance properly. Sometimes I just close the terminal but I couldn't connect to it next time. Then I use
shutdown -h now
It works, but this way I need to restart the instance next time. Is any proper way to leave the instance?
Type
exit
if you just want to leave it and keep it running
The EC2 instance runs independently of you connecting to it. Each time you SSH in to the instance you start a new interactive shell. exit or Control-D will close the shell that you have logged in to, and leave the instance running.
If your instance is on-demand, you can shut it down to save costs, but that is an entirely separate operation from logging in and out.

Run a script during shutdown/termination of an aws instance

I need to execute a script during shutdown/termination of an AWS instance(debian).
I added my script to the /etc/init.d/myscript and a symlink to /etc/rc0.d/K01myscript however I noticed that when I terminate the instance I don't see that my script is executed.
Any idea?
I would not expect Amazon to terminate an instance gracefully. During an normal O/S shutdown, sure you can run a kill script. But not a terminate. If you're interested in being notified that it was terminated then take look at attaching EC2 CloudWatch events to the instance. According to the docs you can get:
This example of an EC2 Instance State-change Notification event shows
the instance in the pending state. The other possible values for state
include running, shutting-down, stopped, stopping, and terminated.
with a JSON package like:
{
"id":"7bf73129-1428-4cd3-a780-95db273d1602",
"detail-type":"EC2 Instance State-change Notification",
"source":"aws.ec2",
"account":"123456789012",
"time":"2015-11-11T21:29:54Z",
"region":"us-east-1",
"resources":[
"arn:aws:ec2:us-east-1:123456789012:instance/i-abcd1111"
],
"detail":{
"instance-id":"i-abcd1111",
"state":"pending"
}
}
If you really need to handle this then you'll have to shutdown the O/S first which will run your script and then terminate the stopped instance.

Resources