Skip to content

Commit

Permalink
Implement LB Removal task in Prelude
Browse files Browse the repository at this point in the history
Implement Load balancer removal task to dispatch removal requests
 to photon load balancer task

Change-Id: I274b5fedfc3c2879e9ce2bcffec8bb53fd814d30
Reviewed-on: http://bellevue-ci.eng.vmware.com:8080/11689
Compute-Verified: jenkins <[email protected]>
Upgrade-Verified: jenkins <[email protected]>
Closures-Verified: jenkins <[email protected]>
Bellevue-Verified: jenkins <[email protected]>
CS-Verified: jenkins <[email protected]>
Reviewed-by: Peter Mitrov <[email protected]>
  • Loading branch information
Kristiyan Georgiev committed Jun 20, 2017
1 parent c2a477e commit 02487cb
Show file tree
Hide file tree
Showing 5 changed files with 433 additions and 27 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Copyright (c) 2017 VMware, Inc. All Rights Reserved.
*
* This product is licensed to you under the Apache License, Version 2.0 (the "License").
* You may not use this product except in compliance with the License.
*
* This product may include a number of subcomponents with separate copyright notices
* and license terms. Your use of these subcomponents is subject to the terms and
* conditions of the subcomponent's license, as noted in the LICENSE file.
*/

package com.vmware.admiral.adapter.common;

import java.util.HashMap;
import java.util.Map;

/**
* Load balancer operation types
*/
public enum LoadBalancerOperationType {

CREATE("LoadBalancer.Create"),
DELETE("LoadBalancer.Delete");

public final String id;

LoadBalancerOperationType(String id) {
this.id = id;
}

private static final Map<String, LoadBalancerOperationType> operationsById = new HashMap<>();

static {
for (LoadBalancerOperationType opr : values()) {
operationsById.put(opr.id, opr);
}
}

public static LoadBalancerOperationType instanceById(String id) {
if (id == null) {
return null;
}
return operationsById.get(id);
}

public static String extractDisplayName(String id) {
return id.substring(id.lastIndexOf(".") + 1);
}

@Override
public String toString() {
return id;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import com.vmware.admiral.adapter.common.ApplicationOperationType;
import com.vmware.admiral.adapter.common.ClosureOperationType;
import com.vmware.admiral.adapter.common.ContainerOperationType;
import com.vmware.admiral.adapter.common.LoadBalancerOperationType;
import com.vmware.admiral.adapter.common.NetworkOperationType;
import com.vmware.admiral.adapter.common.VolumeOperationType;
import com.vmware.admiral.closures.services.closure.ClosureFactoryService;
Expand Down Expand Up @@ -1190,6 +1191,7 @@ private void createLoadBalancerProvisioningTask(RequestBrokerState state) {

provisionTask.tenantLinks = state.tenantLinks;
provisionTask.requestTrackerLink = state.requestTrackerLink;
provisionTask.resourceLinks = state.resourceLinks;

sendRequest(Operation
.createPost(this, LoadBalancerProvisionTaskService.FACTORY_LINK)
Expand All @@ -1203,7 +1205,6 @@ private void createLoadBalancerProvisioningTask(RequestBrokerState state) {
}

private void createLoadBalancerRemovalTask(RequestBrokerState state) {
// TODO: just a placeholder, needs to be implemented
boolean errorState = state.taskSubStage == SubStage.REQUEST_FAILED
|| state.taskSubStage == SubStage.RESERVATION_CLEANED_UP;

Expand All @@ -1212,6 +1213,7 @@ private void createLoadBalancerRemovalTask(RequestBrokerState state) {
return;
}
LoadBalancerRemovalTaskState removalState = new LoadBalancerRemovalTaskState();
removalState.resourceLinks = state.resourceLinks;
removalState.documentSelfLink = getSelfId();
removalState.serviceTaskCallback = ServiceTaskCallback.create(
getSelfLink(),
Expand Down Expand Up @@ -1659,12 +1661,13 @@ private boolean isAllocationOperation(RequestBrokerState state) {
private boolean isPostAllocationOperation(RequestBrokerState state) {
return (isContainerType(state) || isContainerNetworkType(state) || isComputeType(state)
|| isContainerVolumeType(state) || isComputeNetworkType(state) || isClosureType(
state))
state) || isLoadBalancerType(state))
&& (ContainerOperationType.CREATE.id.equals(state.operation)
|| NetworkOperationType.CREATE.id.equals(state.operation)
|| ComputeOperationType.CREATE.id.equals(state.operation)
|| VolumeOperationType.CREATE.id.equals(state.operation)
|| ClosureOperationType.CREATE.id.equals(state.operation));
|| ClosureOperationType.CREATE.id.equals(state.operation))
|| LoadBalancerOperationType.CREATE.id.equals(state.operation);
}

private String getPostAllocationOperation(RequestBrokerState state) {
Expand All @@ -1688,6 +1691,8 @@ private String getPostAllocationOperation(RequestBrokerState state) {
return ComputeOperationType.CREATE.id;
} else if (isContainerVolumeType(state)) {
return VolumeOperationType.CREATE.id;
} else if (isLoadBalancerType(state)) {
return LoadBalancerOperationType.CREATE.id;
} else {
// No ContainerType here since its "unified" ContainerAllocationTaskService handles it!
return null;
Expand Down Expand Up @@ -1910,6 +1915,13 @@ private boolean createRequestTrackerIfNoneProvided(RequestBrokerState state, Ope
trackedTasks.addAll(SUPPORTED_EXEC_TASKS_BY_RESOURCE_TYPE
.get(ResourceType.COMPUTE_NETWORK_TYPE));
}
} else if (isLoadBalancerType(state)) {
trackedTasks.addAll(SUPPORTED_ALLOCATION_TASKS_BY_RESOURCE_TYPE
.get(ResourceType.LOAD_BALANCER_TYPE));
if (!allocationOnly) {
trackedTasks.addAll(SUPPORTED_EXEC_TASKS_BY_RESOURCE_TYPE
.get(ResourceType.LOAD_BALANCER_TYPE));
}
} else {
for (List<String> vals : SUPPORTED_ALLOCATION_TASKS_BY_RESOURCE_TYPE.values()) {
trackedTasks.addAll(vals);
Expand All @@ -1931,6 +1943,8 @@ private boolean createRequestTrackerIfNoneProvided(RequestBrokerState state, Ope
requestStatus.addTrackedTasks(ContainerNetworkProvisionTaskService.DISPLAY_NAME);
} else if (isComputeNetworkType(state)) {
requestStatus.addTrackedTasks(ComputeNetworkProvisionTaskService.DISPLAY_NAME);
} else if (isLoadBalancerType(state)) {
requestStatus.addTrackedTasks(LoadBalancerProvisionTaskService.DISPLAY_NAME);
} else if (isContainerVolumeType(state)) {
requestStatus.addTrackedTasks(ContainerVolumeProvisionTaskService.DISPLAY_NAME);
}
Expand All @@ -1954,6 +1968,8 @@ private boolean createRequestTrackerIfNoneProvided(RequestBrokerState state, Ope
requestStatus.addTrackedTasks(ComputeRemovalTaskService.DISPLAY_NAME);
} else if (isComputeNetworkType(state)) {
requestStatus.addTrackedTasks(ComputeNetworkRemovalTaskService.DISPLAY_NAME);
} else if (isLoadBalancerType(state)) {
requestStatus.addTrackedTasks(LoadBalancerRemovalTaskService.DISPLAY_NAME);
} else {
requestStatus.addTrackedTasks(ContainerRemovalTaskService.DISPLAY_NAME);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,38 +11,80 @@

package com.vmware.admiral.request.compute;

import static com.vmware.xenon.common.ServiceDocumentDescription.PropertyIndexingOption.STORE_ONLY;
import static com.vmware.xenon.common.ServiceDocumentDescription.PropertyUsageOption.REQUIRED;

import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Consumer;
import java.util.stream.Collectors;

import com.vmware.admiral.common.DeploymentProfileConfig;
import com.vmware.admiral.common.ManagementUriParts;
import com.vmware.admiral.common.util.ServiceUtils;
import com.vmware.admiral.request.compute.LoadBalancerRemovalTaskService.LoadBalancerRemovalTaskState.SubStage;
import com.vmware.admiral.service.common.AbstractTaskStatefulService;
import com.vmware.admiral.service.common.DefaultSubStage;
import com.vmware.photon.controller.model.adapterapi.LoadBalancerInstanceRequest.InstanceRequestType;
import com.vmware.photon.controller.model.adapterapi.ResourceOperationResponse;
import com.vmware.photon.controller.model.tasks.ProvisionLoadBalancerTaskService;
import com.vmware.photon.controller.model.tasks.ProvisionLoadBalancerTaskService.ProvisionLoadBalancerTaskState;
import com.vmware.photon.controller.model.tasks.ServiceTaskCallback;
import com.vmware.photon.controller.model.tasks.SubTaskService;
import com.vmware.xenon.common.DeferredResult;
import com.vmware.xenon.common.Operation;
import com.vmware.xenon.common.TaskState.TaskStage;
import com.vmware.xenon.common.UriUtils;
import com.vmware.xenon.common.Utils;

/**
* Task implementing the removal of a load balancer.
*/
public class LoadBalancerRemovalTaskService extends
AbstractTaskStatefulService<LoadBalancerRemovalTaskService.LoadBalancerRemovalTaskState, DefaultSubStage> {
AbstractTaskStatefulService<LoadBalancerRemovalTaskService.LoadBalancerRemovalTaskState, SubStage> {

public static final String FACTORY_LINK = ManagementUriParts.REQUEST_LOAD_BALANCER_REMOVAL_TASKS;

public static final String DISPLAY_NAME = "Load Balancer Removal";

public static class LoadBalancerRemovalTaskState extends
com.vmware.admiral.service.common.TaskServiceDocument<DefaultSubStage> {
// TODO
com.vmware.admiral.service.common.TaskServiceDocument<LoadBalancerRemovalTaskState
.SubStage> {

/**
* (Required) The resources on which the given operation will be applied
*/
@PropertyOptions(usage = { REQUIRED }, indexing = STORE_ONLY)
public Set<String> resourceLinks;

public enum SubStage {
CREATED,
REMOVING_LOADBALANCERS,
COMPLETED,
ERROR;

static final Set<SubStage> TRANSIENT_SUB_STAGES = new HashSet<>(
Collections.singletonList(REMOVING_LOADBALANCERS));
}
}

public LoadBalancerRemovalTaskService() {
super(LoadBalancerRemovalTaskState.class, DefaultSubStage.class, DISPLAY_NAME);
super(LoadBalancerRemovalTaskState.class, SubStage.class, DISPLAY_NAME);
super.toggleOption(ServiceOption.PERSISTENCE, true);
super.toggleOption(ServiceOption.REPLICATION, true);
super.toggleOption(ServiceOption.OWNER_SELECTION, true);
super.toggleOption(ServiceOption.INSTRUMENTATION, true);
super.transientSubStages = SubStage.TRANSIENT_SUB_STAGES;
}

@Override
protected void handleStartedStagePatch(LoadBalancerRemovalTaskState state) {
switch (state.taskSubStage) {
case CREATED:
proceedTo(DefaultSubStage.COMPLETED);
removeLoadBalancers(state, null);
break;
case REMOVING_LOADBALANCERS:
break;
case COMPLETED:
complete();
Expand All @@ -54,4 +96,95 @@ protected void handleStartedStagePatch(LoadBalancerRemovalTaskState state) {
break;
}
}

private void removeLoadBalancers(LoadBalancerRemovalTaskState state, String subTaskLink) {
try {
if (subTaskLink == null) {
createSubTaskForRemoveLoadbalancerCallbacks(state,
link -> removeLoadBalancers(state, link));
return;
}

boolean isMockRequest = DeploymentProfileConfig.getInstance().isTest();
ServiceTaskCallback<TaskStage> callback =
ServiceTaskCallback.create(UriUtils.buildUri(getHost(), subTaskLink));
callback.onSuccessFinishTask();
callback.onErrorFailTask();

List<DeferredResult<Operation>> ops = state.resourceLinks.stream().map(lbLink -> {

ProvisionLoadBalancerTaskState task = new ProvisionLoadBalancerTaskState();
task.isMockRequest = isMockRequest;
task.requestType = InstanceRequestType.DELETE;
task.serviceTaskCallback = callback;
task.tenantLinks = state.tenantLinks;
task.documentExpirationTimeMicros = ServiceUtils
.getDefaultTaskExpirationTimeInMicros();
task.loadBalancerLink = lbLink;

return sendWithDeferredResult(
Operation.createPost(this, ProvisionLoadBalancerTaskService
.FACTORY_LINK)
.setBody(task))
.exceptionally(e -> {
ResourceOperationResponse r = ResourceOperationResponse
.fail(lbLink, e);
completeSubTask(subTaskLink, r);
return null;
});

}).collect(Collectors.toList());

DeferredResult.allOf(ops).whenComplete((all, e) -> {
logInfo("Requested removal of %s load balancers.", state.resourceLinks.size());
proceedTo(SubStage.REMOVING_LOADBALANCERS);
});

} catch (Throwable e) {
failTask("System failure removing load balancers", e);
}

}

private void createSubTaskForRemoveLoadbalancerCallbacks(LoadBalancerRemovalTaskState
state, Consumer<String> callbackFunction) {

ServiceTaskCallback<SubStage> callback = ServiceTaskCallback.create(getUri());
callback.onSuccessTo(SubStage.COMPLETED);
SubTaskService.SubTaskState<SubStage> subTaskInitState = new SubTaskService.SubTaskState<>();
// tell the sub task with what to patch us, on completion
subTaskInitState.serviceTaskCallback = callback;
subTaskInitState.completionsRemaining = state.resourceLinks.size();
subTaskInitState.tenantLinks = state.tenantLinks;
Operation startPost = Operation
.createPost(this, SubTaskService.FACTORY_LINK)
.setBody(subTaskInitState)
.setCompletion(
(o, e) -> {
if (e != null) {
logWarning("Failure creating sub task: %s",
Utils.toString(e));
failTask("Failure creating sub task", e);
return;
}
SubTaskService.SubTaskState<?> body = o
.getBody(SubTaskService.SubTaskState.class);
// continue, passing the sub task link
callbackFunction.accept(body.documentSelfLink);
});
sendRequest(startPost);
}

private void completeSubTask(String subTaskLink, Object body) {
Operation.createPatch(this, subTaskLink)
.setBody(body)
.setCompletion(
(o, ex) -> {
if (ex != null) {
logWarning("Unable to complete subtask: %s, reason: %s",
subTaskLink, Utils.toString(ex));
}
})
.sendWith(this);
}
}
Loading

0 comments on commit 02487cb

Please sign in to comment.