All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.vmware.photon.controller.model.adapters.awsadapter.enumeration.AWSEnumerationAdapterService Maven / Gradle / Ivy

The newest version!
/*
 * 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.enumeration;

import static com.vmware.photon.controller.model.adapters.awsadapter.enumeration.AWSEnumerationAdapterService.AWSEnumerationStages.GET_REGIONS;
import static com.vmware.photon.controller.model.adapters.awsadapter.enumeration.AWSEnumerationAdapterService.AWSEnumerationStages.KICKOFF_ENUMERATION;
import static com.vmware.photon.controller.model.adapters.awsadapter.enumeration.AWSEnumerationAdapterService.AWSEnumerationStages.PATCH_COMPLETION;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

import com.amazonaws.regions.Regions;

import com.vmware.photon.controller.model.adapterapi.ComputeEnumerateResourceRequest;
import com.vmware.photon.controller.model.adapters.awsadapter.AWSUriPaths;
import com.vmware.photon.controller.model.adapters.awsadapter.AWSUtils;
import com.vmware.photon.controller.model.adapters.util.AdapterUtils;
import com.vmware.photon.controller.model.adapters.util.BaseAdapterContext;
import com.vmware.photon.controller.model.adapters.util.BaseAdapterContext.BaseAdapterStage;
import com.vmware.photon.controller.model.adapters.util.ComputeEnumerateAdapterRequest;
import com.vmware.xenon.common.Operation;
import com.vmware.xenon.common.OperationJoin;
import com.vmware.xenon.common.OperationSequence;
import com.vmware.xenon.common.StatelessService;
import com.vmware.xenon.common.Utils;

/**
 * Enumeration Adapter for the Amazon Web Services. Performs a list call to the AWS API and
 * reconciles the local state with the state on the remote system. It lists the instances on the
 * remote system. Compares those with the local system and creates the instances that are missing in
 * the local system.
 */
public class AWSEnumerationAdapterService extends StatelessService {

    public static final String SELF_LINK = AWSUriPaths.AWS_ENUMERATION_ADAPTER;

    public static final String[] LINKS = new String[] {
            AWSEnumerationAndCreationAdapterService.SELF_LINK,
            AWSEnumerationAndDeletionAdapterService.SELF_LINK,
            AWSEBSStorageEnumerationAdapterService.SELF_LINK,
            AWSS3StorageEnumerationAdapterService.SELF_LINK,
            AWSVolumeTypeDiscoveryService.SELF_LINK
    };

    public AWSEnumerationAdapterService() {
        super.toggleOption(ServiceOption.INSTRUMENTATION, true);
    }

    public enum AWSEnumerationStages {
        GET_REGIONS,
        KICKOFF_ENUMERATION,
        PATCH_COMPLETION,
        ERROR
    }

    /**
     * The enumeration service context needed to spawn off control to the creation and deletion
     * adapters for AWS.
     */
    public static class EnumerationContext extends BaseAdapterContext {

        public ComputeEnumerateResourceRequest request;
        public AWSEnumerationStages stage;

        public List regions;

        public EnumerationContext(StatelessService service, ComputeEnumerateResourceRequest request,
                Operation op) {
            super(service, request);
            this.request = request;
            this.stage = GET_REGIONS;
            this.regions = new ArrayList<>();
            this.operation = op;
        }
    }

    @Override
    public void handleStart(Operation startPost) {
        startHelperServices(startPost);
    }

    @Override
    public void handlePatch(Operation op) {
        setOperationHandlerInvokeTimeStat(op);
        if (!op.hasBody()) {
            op.fail(new IllegalArgumentException("body is required"));
            return;
        }
        op.complete();
        ComputeEnumerateResourceRequest request = op.getBody(ComputeEnumerateResourceRequest.class);

        AdapterUtils.validateEnumRequest(request);
        EnumerationContext context = new EnumerationContext(this, request, op);
        if (request.isMockRequest) {
            // patch status to parent task
            context.taskManager.finishTask();
            return;
        }

        context.populateBaseContext(BaseAdapterStage.PARENTDESC)
                .whenComplete((ignoreCtx, t) -> {
                    // NOTE: In case of error 'ignoreCtx' is null so use passed context!
                    if (t != null) {
                        context.error = t;
                        context.stage = AWSEnumerationStages.ERROR;
                    }
                    handleEnumerationRequest(context);
                });
    }

    /**
     * Starts the related services for the Enumeration Service
     */
    public void startHelperServices(Operation startPost) {
        Operation patchAWSEnumerationCreationService = Operation
                .createPatch(getHost(), AWSEnumerationAndCreationAdapterService.SELF_LINK)
                .setReferer(getUri());

        Operation patchAWSEnumerationDeletionService = Operation
                .createPatch(getHost(), AWSEnumerationAndDeletionAdapterService.SELF_LINK)
                .setReferer(getUri());

        Operation patchAWSEBSStorageEnumerationService = Operation
                .createPatch(getHost(), AWSEBSStorageEnumerationAdapterService.SELF_LINK)
                .setReferer(getUri());

        Operation patchAWSS3StorageEnumerationService = Operation
                .createPatch(getHost(), AWSS3StorageEnumerationAdapterService.SELF_LINK)
                .setReferer(getUri());

        getHost().startService(patchAWSEnumerationCreationService,
                new AWSEnumerationAndCreationAdapterService());
        getHost().startService(patchAWSEnumerationDeletionService,
                new AWSEnumerationAndDeletionAdapterService());
        getHost().startService(patchAWSEBSStorageEnumerationService,
                new AWSEBSStorageEnumerationAdapterService());
        getHost().startService(patchAWSS3StorageEnumerationService,
                new AWSS3StorageEnumerationAdapterService());

        getHost().startService(new AWSVolumeTypeDiscoveryService());

        AdapterUtils.registerForServiceAvailability(getHost(),
                operation -> startPost.complete(),
                startPost::fail,
                LINKS);
    }

    /**
     * Creates operations for the creation and deletion adapter services and spawns them off in
     * parallel
     */
    public void handleEnumerationRequest(EnumerationContext aws) {
        switch (aws.stage) {
        case GET_REGIONS:
            getRegions(aws, KICKOFF_ENUMERATION);
            break;
        case KICKOFF_ENUMERATION:
            kickOffEnumerationWorkFlows(aws, PATCH_COMPLETION);
            break;
        case PATCH_COMPLETION:
            setOperationDurationStat(aws.operation);
            aws.taskManager.finishTask();
            break;
        case ERROR:
            aws.taskManager.patchTaskToFailure(aws.error);
            break;
        default:
            logSevere(() -> String.format("Unknown AWS enumeration stage %s ",
                    aws.stage.toString()));
            aws.error = new Exception("Unknown AWS enumeration stage");
            aws.taskManager.patchTaskToFailure(aws.error);
            break;

        }
    }

    /**
     * get the list of regions to enumerate on.
     */
    public void getRegions(EnumerationContext context,
            AWSEnumerationStages next) {
        if (context.parent.description.regionId != null) {
            context.regions.add(context.parent.description.regionId);
        } else {
            context.regions.addAll(Arrays.stream(Regions.values())
                    .map(Regions::getName)
                    .collect(Collectors.toList()));
        }
        context.stage = next;
        handleEnumerationRequest(context);
    }

    /**
     * Kicks off the enumeration flows for creation and deletion.
     */
    public void kickOffEnumerationWorkFlows(EnumerationContext context, AWSEnumerationStages next) {
        List> enumOperations = new ArrayList<>();

        if (!AWSUtils.isAwsClientMock()) {
            ComputeEnumerateAdapterRequest awsS3EnumerationRequest = new
                    ComputeEnumerateAdapterRequest(context.request, context.endpointAuth,
                    context.parent, Regions.DEFAULT_REGION.getName());

            Operation patchAWSS3StorageAdapterService = Operation
                    .createPatch(this,AWSS3StorageEnumerationAdapterService.SELF_LINK)
                    .setBody(awsS3EnumerationRequest)
                    .setReferer(getHost().getUri());

            enumOperations.add(Collections.singletonList(patchAWSS3StorageAdapterService));
        }

        for (String regionId : context.regions) {
            List enumOperationsForRegion = new ArrayList<>();
            ComputeEnumerateAdapterRequest awsEnumerationRequest =
                    new ComputeEnumerateAdapterRequest(
                        context.request, context.endpointAuth,
                        context.parent, regionId);

            Operation patchAWSCreationAdapterService = Operation
                    .createPatch(this, AWSEnumerationAndCreationAdapterService.SELF_LINK)
                    .setBody(awsEnumerationRequest)
                    .setReferer(this.getHost().getUri());

            Operation patchAWSDeletionAdapterService = Operation
                    .createPatch(this,
                            AWSEnumerationAndDeletionAdapterService.SELF_LINK)
                    .setBody(awsEnumerationRequest)
                    .setReferer(getHost().getUri());

            Operation patchAWSEBSStorageAdapterService = Operation
                    .createPatch(this,
                            AWSEBSStorageEnumerationAdapterService.SELF_LINK)
                    .setBody(awsEnumerationRequest)
                    .setReferer(getHost().getUri());

            enumOperationsForRegion.add(patchAWSCreationAdapterService);
            enumOperationsForRegion.add(patchAWSDeletionAdapterService);
            enumOperationsForRegion.add(patchAWSEBSStorageAdapterService);
            enumOperations.add(enumOperationsForRegion);
        }

        if (enumOperations.size() == 0) {
            logFine(() -> "No enumeration tasks to run");
            context.stage = next;
            handleEnumerationRequest(context);
            return;
        }
        OperationJoin.JoinedCompletionHandler joinCompletion = (ox,
                exc) -> {
            if (exc != null) {
                logSevere(() -> String.format("Error starting the enumeration workflows for AWS: %s",
                        Utils.toString(exc)));
                context.taskManager.patchTaskToFailure(exc.values().iterator().next());
                return;
            }
            logInfo(() -> "Completed creation and deletion enumeration for compute and storage"
                    + " states");
            context.stage = next;
            handleEnumerationRequest(context);
        };
        OperationSequence enumOp = OperationSequence.create(OperationJoin.create(enumOperations.get(0)));
        for (int i = 1; i < enumOperations.size(); i++) {
            enumOp = enumOp.next(OperationJoin.create(enumOperations.get(i)));
        }
        enumOp.setCompletion(joinCompletion);
        enumOp.sendWith(getHost());
        logFine(() -> "Started creation and deletion enumeration for AWS computes and storage");
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy