
com.vmware.photon.controller.model.adapters.awsadapter.enumeration.AWSLoadBalancerEnumerationAdapterService Maven / Gradle / Ivy
The newest version!
/*
* Copyright (c) 2015-2017 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.AWSConstants.getQueryPageSize;
import static com.vmware.photon.controller.model.adapters.awsadapter.AWSUriPaths.AWS_LOAD_BALANCER_ADAPTER;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import com.amazonaws.services.elasticloadbalancing.AmazonElasticLoadBalancingAsyncClient;
import com.amazonaws.services.elasticloadbalancing.model.DescribeLoadBalancersRequest;
import com.amazonaws.services.elasticloadbalancing.model.DescribeLoadBalancersResult;
import com.amazonaws.services.elasticloadbalancing.model.HealthCheck;
import com.amazonaws.services.elasticloadbalancing.model.Instance;
import com.amazonaws.services.elasticloadbalancing.model.ListenerDescription;
import com.amazonaws.services.elasticloadbalancing.model.LoadBalancerDescription;
import com.vmware.photon.controller.model.adapterapi.EnumerationAction;
import com.vmware.photon.controller.model.adapters.awsadapter.AWSConstants;
import com.vmware.photon.controller.model.adapters.awsadapter.AWSConstants.AwsClientType;
import com.vmware.photon.controller.model.adapters.awsadapter.AWSUriPaths;
import com.vmware.photon.controller.model.adapters.awsadapter.enumeration.AWSNetworkStateEnumerationAdapterService.AWSNetworkEnumerationResponse;
import com.vmware.photon.controller.model.adapters.awsadapter.enumeration.AWSSecurityGroupEnumerationAdapterService.AWSSecurityGroupEnumerationResponse;
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.AWSDeferredResultAsyncHandler;
import com.vmware.photon.controller.model.adapters.util.AdapterUriUtil;
import com.vmware.photon.controller.model.adapters.util.ComputeEnumerateAdapterRequest;
import com.vmware.photon.controller.model.adapters.util.Pair;
import com.vmware.photon.controller.model.adapters.util.enums.BaseComputeEnumerationAdapterContext;
import com.vmware.photon.controller.model.adapters.util.enums.EnumerationStages;
import com.vmware.photon.controller.model.query.QueryUtils.QueryByPages;
import com.vmware.photon.controller.model.resources.ComputeService.ComputeState;
import com.vmware.photon.controller.model.resources.LoadBalancerDescriptionService.LoadBalancerDescription.HealthCheckConfiguration;
import com.vmware.photon.controller.model.resources.LoadBalancerDescriptionService.LoadBalancerDescription.RouteConfiguration;
import com.vmware.photon.controller.model.resources.LoadBalancerService;
import com.vmware.photon.controller.model.resources.LoadBalancerService.LoadBalancerState;
import com.vmware.photon.controller.model.resources.ResourceState;
import com.vmware.photon.controller.model.util.ClusterUtil.ServiceTypeCluster;
import com.vmware.xenon.common.DeferredResult;
import com.vmware.xenon.common.Operation;
import com.vmware.xenon.common.ServiceStateCollectionUpdateRequest;
import com.vmware.xenon.common.StatelessService;
import com.vmware.xenon.common.Utils;
import com.vmware.xenon.services.common.QueryTask.Query;
import com.vmware.xenon.services.common.QueryTask.Query.Builder;
public class AWSLoadBalancerEnumerationAdapterService extends StatelessService {
public static final String SELF_LINK = AWSUriPaths.AWS_LOAD_BALANCER_ENUMERATION_ADAPTER;
private AWSClientManager clientManager;
public static final String ENABLE_LOAD_BALANCER_PROPERTY = "photon-model.adapter.aws"
+ ".enable.loadbalancer.enumeration";
// By default load balancer enumeration is disabled
private static final Boolean ENABLE_LOAD_BALANCER_ENUMERATION = Boolean
.getBoolean(ENABLE_LOAD_BALANCER_PROPERTY);
public AWSLoadBalancerEnumerationAdapterService() {
super.toggleOption(ServiceOption.INSTRUMENTATION, true);
}
/**
* Request accepted by this service to trigger enumeration of Network entities in Amazon.
*
* @see AWSNetworkEnumerationResponse
*/
public static class AWSLoadBalancerEnumerationRequest {
public ComputeEnumerateAdapterRequest computeRequest;
public AWSNetworkEnumerationResponse enumeratedNetworks;
public AWSSecurityGroupEnumerationResponse enumeratedSecurityGroups;
}
private static class LoadBalancerEnumContext extends
BaseComputeEnumerationAdapterContext {
private static final String TARGET_PATTERN = "([a-zA-Z]*):([\\d]*)(/.*)?";
private String regionId;
public AmazonElasticLoadBalancingAsyncClient amazonLoadBalancerClient;
private Map localComputeStates = new HashMap<>();
private Map localSubNetworkStates = new HashMap<>();
private Map localSecurityGroupStates = new HashMap<>();
public LoadBalancerEnumContext(StatelessService service,
AWSLoadBalancerEnumerationRequest request, Operation op) {
super(service, request.computeRequest, op, LoadBalancerState.class,
LoadBalancerService.FACTORY_LINK);
this.regionId = request.computeRequest.regionId;
if (request.enumeratedNetworks != null && request.enumeratedNetworks.subnets != null) {
this.localSubNetworkStates = request.enumeratedNetworks.subnets;
}
if (request.enumeratedSecurityGroups != null
&& request.enumeratedSecurityGroups.securityGroupStates != null) {
this.localSecurityGroupStates = request.enumeratedSecurityGroups.securityGroupStates;
}
}
@Override
protected DeferredResult queryLocalStates(
LoadBalancerEnumContext context) {
return super.queryLocalStates(context)
.thenCompose(this::getComputeStates);
}
private DeferredResult getComputeStates(
LoadBalancerEnumContext context) {
if (context.remoteResources.values().isEmpty()) {
return DeferredResult.completed(context);
}
List instanceIds = context.remoteResources.values().stream()
.flatMap(lb -> lb.getInstances().stream())
.map(Instance::getInstanceId)
.collect(Collectors.toList());
if (instanceIds.isEmpty()) {
return DeferredResult.completed(context);
}
Query.Builder qBuilder = Builder.create()
.addKindFieldClause(ComputeState.class)
.addInClause(ResourceState.FIELD_NAME_ID, instanceIds);
QueryByPages queryByPages = new QueryByPages<>(
this.service.getHost(),
qBuilder.build(),
ComputeState.class,
context.request.parentCompute.tenantLinks,
context.request.original.endpointLink);
queryByPages.setClusterType(ServiceTypeCluster.INVENTORY_SERVICE);
return queryByPages.queryDocuments(
computeState -> this.localComputeStates
.put(computeState.id, computeState.documentSelfLink))
.thenApply(ignore -> context);
}
@Override
protected DeferredResult getExternalResources(String nextPageLink) {
DescribeLoadBalancersRequest describeRequest = new DescribeLoadBalancersRequest()
.withPageSize(getQueryPageSize());
if (nextPageLink != null) {
describeRequest.setMarker(nextPageLink);
}
String msg =
"Getting AWS Load Balancers [" + this.request.original.resourceReference + "]";
AWSDeferredResultAsyncHandler asyncHandler =
new AWSDeferredResultAsyncHandler<>(this.service, msg);
this.amazonLoadBalancerClient.describeLoadBalancersAsync(describeRequest, asyncHandler);
return asyncHandler.toDeferredResult().thenApply(describeLoadBalancersResult -> {
RemoteResourcesPage page = new RemoteResourcesPage();
page.nextPageLink = describeLoadBalancersResult.getNextMarker();
describeLoadBalancersResult.getLoadBalancerDescriptions().forEach(
lbDescription -> page.resourcesPage
.put(lbDescription.getLoadBalancerName(), lbDescription));
return page;
});
}
@Override
protected DeferredResult buildLocalResourceState(
LoadBalancerDescription remoteResource,
LoadBalancerState existingLocalResourceState) {
LocalStateHolder stateHolder = new LocalStateHolder();
stateHolder.localState = new LoadBalancerState();
stateHolder.localState.name = remoteResource.getLoadBalancerName();
stateHolder.localState.address = remoteResource.getDNSName();
stateHolder.localState.endpointLink = this.request.original.endpointLink;
if (stateHolder.localState.endpointLinks == null) {
stateHolder.localState.endpointLinks = new HashSet();
}
stateHolder.localState.endpointLinks.add(this.request.original.endpointLink);
stateHolder.localState.internetFacing = !"internal".equals(remoteResource.getScheme());
stateHolder.localState.computeHostLink = this.request.parentCompute.documentSelfLink;
stateHolder.localState.routes = getRouteConfigurations(remoteResource);
if (existingLocalResourceState == null) {
stateHolder.localState.regionId = this.regionId;
stateHolder.localState.instanceAdapterReference = AdapterUriUtil
.buildAdapterUri(this.service.getHost(), AWS_LOAD_BALANCER_ADAPTER);
stateHolder.localState.subnetLinks = remoteResource.getSubnets().stream()
.map(subnetId -> this.localSubNetworkStates.get(subnetId))
.filter(Objects::nonNull).collect(Collectors.toSet());
stateHolder.localState.securityGroupLinks = remoteResource.getSecurityGroups()
.stream()
.map(sgId -> this.localSecurityGroupStates.get(sgId))
.filter(Objects::nonNull)
.collect(Collectors.toList());
stateHolder.localState.computeLinks = remoteResource.getInstances().stream()
.map(instance -> this.localComputeStates.get(instance.getInstanceId()))
.filter(Objects::nonNull)
.collect(Collectors.toSet());
// Skip load balancers that do not have any instances attached
if (stateHolder.localState.computeLinks.isEmpty()) {
stateHolder.localState = SKIP;
return DeferredResult.completed(stateHolder);
}
} else {
ServiceStateCollectionUpdateRequest updateRequest = calculateDeltaForUpdateCollectionRequest(
remoteResource, existingLocalResourceState);
return this.service
.sendWithDeferredResult(Operation
.createPatch(this.service,
existingLocalResourceState.documentSelfLink)
.setBody(updateRequest)
)
.thenApply(ignore -> stateHolder);
}
return DeferredResult.completed(stateHolder);
}
/**
* Calculates the links that need to be added and the links to be removed from the
* Compute links, SecurityGroup links and Subnet links
*/
private ServiceStateCollectionUpdateRequest calculateDeltaForUpdateCollectionRequest(
LoadBalancerDescription remoteResource,
LoadBalancerState existingLocalResourceState) {
Map> linksToAdd = new HashMap<>();
Map> linksToRemove = new HashMap<>();
// Only update compute links if the load balancer is not manager by the adapter
if (existingLocalResourceState.descriptionLink == null) {
Set remoteComputeLinks = remoteResource.getInstances().stream()
.map(instance -> this.localComputeStates.get(instance.getInstanceId()))
.filter(Objects::nonNull)
.collect(Collectors.toSet());
Pair, Collection
© 2015 - 2025 Weber Informatics LLC | Privacy Policy