com.vmware.photon.controller.model.adapters.awsadapter.AWSTaskStatusChecker.java Source code

Java tutorial

Introduction

Here is the source code for com.vmware.photon.controller.model.adapters.awsadapter.AWSTaskStatusChecker.java

Source

/*
 * Copyright (c) 2015-2016 VMware, Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License.  You may obtain a copy of
 * the License at http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed
 * under the License is distributed on an "AS IS" BASIS, without warranties or
 * conditions of any kind, EITHER EXPRESS OR IMPLIED.  See the License for the
 * specific language governing permissions and limitations under the License.
 */

package com.vmware.photon.controller.model.adapters.awsadapter;

import static com.vmware.photon.controller.model.adapters.awsadapter.AWSConstants.AWS_INVALID_INSTANCE_ID_ERROR_CODE;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;

import com.amazonaws.AmazonServiceException;
import com.amazonaws.handlers.AsyncHandler;
import com.amazonaws.services.ec2.AmazonEC2AsyncClient;
import com.amazonaws.services.ec2.model.DescribeInstancesRequest;
import com.amazonaws.services.ec2.model.DescribeInstancesResult;
import com.amazonaws.services.ec2.model.Instance;

import com.vmware.photon.controller.model.adapterapi.ComputeInstanceRequest;
import com.vmware.photon.controller.model.adapters.util.AdapterUtils;

import com.vmware.xenon.common.StatelessService;
import com.vmware.xenon.common.Utils;

/**
 * Class to check if an instance is in the desired state if the vm is in the
 * desired state invoke the consumer, else reschedule to check in 5 seconds.
 *
 */
public class AWSTaskStatusChecker {

    private String instanceId;
    private AmazonEC2AsyncClient amazonEC2Client;
    private String desiredState;
    private Consumer<Instance> consumer;
    private ComputeInstanceRequest computeRequest;
    private StatelessService service;
    private long expirationTimeMicros;

    private AWSTaskStatusChecker(AmazonEC2AsyncClient amazonEC2Client, String instanceId, String desiredState,
            Consumer<Instance> consumer, ComputeInstanceRequest computeRequest, StatelessService service,
            long expirationTimeMicros) {
        this.instanceId = instanceId;
        this.amazonEC2Client = amazonEC2Client;
        this.consumer = consumer;
        this.desiredState = desiredState;
        this.computeRequest = computeRequest;
        this.service = service;
        this.expirationTimeMicros = expirationTimeMicros;
    }

    public static AWSTaskStatusChecker create(AmazonEC2AsyncClient amazonEC2Client, String instanceId,
            String desiredState, Consumer<Instance> consumer, ComputeInstanceRequest computeRequest,
            StatelessService service, long expirationTimeMicros) {
        return new AWSTaskStatusChecker(amazonEC2Client, instanceId, desiredState, consumer, computeRequest,
                service, expirationTimeMicros);
    }

    public void start() {
        if (this.expirationTimeMicros > 0 && Utils.getNowMicrosUtc() > this.expirationTimeMicros) {
            String msg = String.format(
                    "Compute with instance id %s did not reach desired %s state in the required time interval.",
                    this.instanceId, this.desiredState);
            this.service.logSevere(msg);
            Throwable t = new RuntimeException(msg);
            AdapterUtils.sendFailurePatchToProvisioningTask(this.service, this.computeRequest.taskReference, t);
            return;
        }
        DescribeInstancesRequest descRequest = new DescribeInstancesRequest();
        List<String> instanceIdList = new ArrayList<String>();
        instanceIdList.add(this.instanceId);
        descRequest.setInstanceIds(instanceIdList);
        AsyncHandler<DescribeInstancesRequest, DescribeInstancesResult> describeHandler = new AsyncHandler<DescribeInstancesRequest, DescribeInstancesResult>() {

            @Override
            public void onError(Exception exception) {
                // Sometimes AWS takes time to acknowledge the presence of newly provisioned
                // instances. Not failing the request immediately in case AWS cannot find the
                // particular instanceId.
                if (exception instanceof AmazonServiceException && ((AmazonServiceException) exception)
                        .getErrorCode().equalsIgnoreCase(AWS_INVALID_INSTANCE_ID_ERROR_CODE)) {
                    AWSTaskStatusChecker.this.service.logWarning(
                            "Could not retrieve status for instance %s. Retrying... Exception on AWS is %s",
                            AWSTaskStatusChecker.this.instanceId, exception);
                    AWSTaskStatusChecker.create(AWSTaskStatusChecker.this.amazonEC2Client,
                            AWSTaskStatusChecker.this.instanceId, AWSTaskStatusChecker.this.desiredState,
                            AWSTaskStatusChecker.this.consumer, AWSTaskStatusChecker.this.computeRequest,
                            AWSTaskStatusChecker.this.service, AWSTaskStatusChecker.this.expirationTimeMicros)
                            .start();
                    return;
                }
                AdapterUtils.sendFailurePatchToProvisioningTask(AWSTaskStatusChecker.this.service,
                        AWSTaskStatusChecker.this.computeRequest.taskReference, exception);
                return;
            }

            @Override
            public void onSuccess(DescribeInstancesRequest request, DescribeInstancesResult result) {
                Instance instance = result.getReservations().get(0).getInstances().get(0);
                if (!instance.getState().getName().equals(AWSTaskStatusChecker.this.desiredState)) {
                    // if the task is not in the running state, schedule thread
                    // to run again in 5 seconds
                    AWSTaskStatusChecker.this.service.getHost().schedule(() -> {
                        AWSTaskStatusChecker.create(AWSTaskStatusChecker.this.amazonEC2Client,
                                AWSTaskStatusChecker.this.instanceId, AWSTaskStatusChecker.this.desiredState,
                                AWSTaskStatusChecker.this.consumer, AWSTaskStatusChecker.this.computeRequest,
                                AWSTaskStatusChecker.this.service, AWSTaskStatusChecker.this.expirationTimeMicros)
                                .start();
                    }, 5, TimeUnit.SECONDS);
                    return;
                }
                AWSTaskStatusChecker.this.consumer.accept(instance);
                return;
            }
        };
        this.amazonEC2Client.describeInstancesAsync(descRequest, describeHandler);
    }
}