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

com.vmware.photon.controller.model.adapters.awsadapter.AWSSecurityGroupService 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;

import static com.vmware.photon.controller.model.adapters.awsadapter.util.AWSSecurityGroupClient.DEFAULT_SECURITY_GROUP_DESC;
import static com.vmware.photon.controller.model.tasks.ProvisionSecurityGroupTaskService.NETWORK_STATE_ID_PROP_NAME;
import static com.vmware.photon.controller.model.util.PhotonModelUriUtils.createInventoryUri;

import java.net.URI;
import java.util.HashMap;
import java.util.UUID;

import com.vmware.photon.controller.model.adapterapi.SecurityGroupInstanceRequest;
import com.vmware.photon.controller.model.adapters.awsadapter.util.AWSClientManager;
import com.vmware.photon.controller.model.adapters.awsadapter.util.AWSClientManagerFactory;
import com.vmware.photon.controller.model.adapters.awsadapter.util.AWSSecurityGroupClient;
import com.vmware.photon.controller.model.adapters.util.TaskManager;
import com.vmware.photon.controller.model.resources.SecurityGroupService.SecurityGroupState;
import com.vmware.xenon.common.DeferredResult;
import com.vmware.xenon.common.Operation;
import com.vmware.xenon.common.StatelessService;
import com.vmware.xenon.services.common.AuthCredentialsService.AuthCredentialsServiceState;

/**
 * Security group service for AWS. AWS Security Groups will be the
 * primary artifact created and managed.
 */
public class AWSSecurityGroupService extends StatelessService {
    public static final String SELF_LINK = AWSUriPaths.AWS_SECURITY_GROUP_ADAPTER;
    public static final String SECURITY_GROUP_ID = "awsSecurityGroupID";

    private AWSClientManager clientManager;

    /**
     * Security Group request stages.
     */
    public static class AWSSecurityGroupContext {

        public AWSSecurityGroupClient client;
        public AuthCredentialsServiceState credentials;
        public SecurityGroupInstanceRequest request;
        public SecurityGroupState securityGroup;
        public String securityGroupId;
        public Throwable error;
        TaskManager taskManager;
        public Operation operation;

        AWSSecurityGroupContext(StatelessService service, Operation operation,
                SecurityGroupInstanceRequest request) {
            this.request = request;
            if (request.taskReference != null) {
                this.taskManager = new TaskManager(service, request.taskReference,
                        request.resourceLink());
            }

            this.operation = operation;
        }

        public boolean isAsync() {
            return this.taskManager != null;
        }
    }

    /**
     * Extend default 'start' logic with loading AWS client.
     */
    @Override
    public void handleStart(Operation op) {
        this.clientManager = AWSClientManagerFactory
                .getClientManager(AWSConstants.AwsClientType.EC2);

        super.handleStart(op);
    }

    @Override
    public void handleStop(Operation op) {
        AWSClientManagerFactory.returnClientManager(this.clientManager,
                AWSConstants.AwsClientType.EC2);
        super.handleStop(op);
    }

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

        // initialize request context
        AWSSecurityGroupContext context = new AWSSecurityGroupContext(this, op, request);
        if (context.isAsync()) {
            // Immediately complete the Operation from calling task.
            op.complete();
        }

        DeferredResult.completed(context)
                .thenCompose(this::populateContext)
                .thenCompose(this::handleSecurityGroupInstanceRequest)
                .whenComplete((o, e) -> {
                    // Once done patch the calling task with correct stage.
                    if (e == null) {
                        if (context.isAsync()) {
                            context.taskManager.finishTask();
                        } else {
                            context.operation.setBody(context.securityGroup);
                            context.operation.complete();
                        }
                    } else {
                        if (context.isAsync()) {
                            context.taskManager.patchTaskToFailure(e);
                        } else {
                            context.operation.fail(e);
                        }
                    }
                });

    }

    private DeferredResult populateContext(
            AWSSecurityGroupContext context) {
        return DeferredResult.completed(context)
                .thenCompose(this::getSecurityGroup)
                .thenCompose(this::getCredentials)
                .thenCompose(this::getAWSClient);
    }

    public DeferredResult getSecurityGroup(
            AWSSecurityGroupContext context) {
        return this.sendWithDeferredResult(
                Operation.createGet(context.request.resourceReference),
                SecurityGroupState.class)
                .thenApply(securityGroup -> {
                    context.securityGroup = securityGroup;
                    context.securityGroupId = securityGroup.id;
                    return context;
                });
    }

    private DeferredResult getCredentials(
            AWSSecurityGroupContext context) {
        URI uri = createInventoryUri(this.getHost(), context.securityGroup.authCredentialsLink);
        return this.sendWithDeferredResult(
                Operation.createGet(uri),
                AuthCredentialsServiceState.class)
                .thenApply(authCredentialsServiceState -> {
                    context.credentials = authCredentialsServiceState;
                    return context;
                });
    }

    private DeferredResult getAWSClient(AWSSecurityGroupContext context) {
        if (context.request.isMockRequest) {
            return DeferredResult.completed(context);
        }

        DeferredResult r = new DeferredResult<>();
        this.clientManager.getOrCreateEC2ClientAsync(context.credentials,
                context.securityGroup.regionId, this)
                .whenComplete((client, t) -> {
                    if (t != null) {
                        r.fail(t);
                        return;
                    }

                    context.client = new AWSSecurityGroupClient(this, client);
                    r.complete(context);
                });
        return r;
    }

    private DeferredResult handleSecurityGroupInstanceRequest(
            AWSSecurityGroupContext context) {

        DeferredResult execution = DeferredResult.completed(context);

        switch (context.request.requestType) {
        case CREATE:
            if (context.request.isMockRequest) {
                // no need to go the end-point; just generate AWS Security Group Id.
                context.securityGroupId = UUID.randomUUID().toString();
            } else {
                execution = execution
                        .thenCompose(this::createSecurityGroup)
                        .thenCompose(this::updateRules);
            }

            return execution;

        case DELETE:
            if (context.request.isMockRequest) {
                // no need to go to the end-point
                this.logFine("Mock request to delete an AWS security group ["
                        + context.securityGroup.name + "] processed.");
            } else {
                execution = execution.thenCompose(this::deleteSecurityGroup);
            }

            return execution.thenCompose(this::deleteSecurityGroupState);
        default:
            IllegalStateException ex = new IllegalStateException("unsupported request type");
            return DeferredResult.failed(ex);
        }
    }

    public DeferredResult createSecurityGroup(
            AWSSecurityGroupContext context) {
        String vpcId = getCustomProperty(context, AWSConstants.AWS_VPC_ID);
        vpcId = (vpcId == null &&
                context.request.customProperties != null) ?
                context.request.customProperties.get(NETWORK_STATE_ID_PROP_NAME) :
                vpcId;

        return context.client.createSecurityGroupAsync(context.securityGroup.name,
                context.securityGroup.desc != null ?
                        context.securityGroup.desc : DEFAULT_SECURITY_GROUP_DESC,
                vpcId)
                .thenApply(sgId -> {
                    context.securityGroup.id = context.securityGroupId = sgId;
                    return context;
                })
                .thenCompose(ctx -> updateSecurityGroupProperties(context.securityGroup,
                        SECURITY_GROUP_ID, context.securityGroupId)
                        .thenApply(sg -> context));
    }

    public DeferredResult updateRules(
            AWSSecurityGroupContext context) {
        return context.client.updateIngressRules(context.securityGroup.ingress,
                context.securityGroupId)
                .thenCompose(v -> context.client.updateEgressRules(context.securityGroup.egress,
                        context.securityGroupId))
                .thenCompose(v -> addInnerRules(context))
                .thenApply(v -> context);
    }

    private String getCustomProperty(AWSSecurityGroupContext requestState,
            String key) {
        if (requestState.securityGroup.customProperties != null) {
            return requestState.securityGroup.customProperties.get(key);
        }
        return null;
    }

    private DeferredResult updateSecurityGroupProperties(
            SecurityGroupState securityGroup, String key, String value) {
        if (securityGroup.customProperties == null) {
            securityGroup.customProperties = new HashMap<>();
        }

        securityGroup.customProperties.put(key, value);

        return this.sendWithDeferredResult(Operation.createPatch(this,
                securityGroup.documentSelfLink).setBody(securityGroup))
                .thenApply(o -> o.getBody(SecurityGroupState.class));
    }

    public DeferredResult deleteSecurityGroup(
            AWSSecurityGroupContext context) {

        return context.client.deleteSecurityGroupAsync(context.securityGroupId)
                .thenApply(v -> context);
    }

    public DeferredResult deleteSecurityGroupState(
            AWSSecurityGroupContext context) {
        return this.sendWithDeferredResult(
                Operation.createDelete(this, context.securityGroup.documentSelfLink))
                .thenApply(operation -> context);
    }

    /**
     * Adds the rules for internal communication among group members
     */
    public DeferredResult addInnerRules(AWSSecurityGroupContext context) {
        return context.client.addInnerIngressRule(context.securityGroupId)
                .thenCompose(v -> context.client.addInnerEgressRule(context.securityGroupId));
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy