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

com.vmware.photon.controller.model.resources.LoadBalancerService Maven / Gradle / Ivy

/*
 * 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.resources;

import java.net.URI;
import java.util.Arrays;
import java.util.Collection;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.function.Supplier;
import java.util.stream.Collectors;

import com.esotericsoftware.kryo.serializers.VersionFieldSerializer.Since;

import com.vmware.photon.controller.model.ServiceUtils;
import com.vmware.photon.controller.model.UriPaths;
import com.vmware.photon.controller.model.constants.PhotonModelConstants;
import com.vmware.photon.controller.model.constants.ReleaseConstants;
import com.vmware.photon.controller.model.resources.ComputeService.ComputeState;
import com.vmware.photon.controller.model.resources.EndpointService.EndpointState;
import com.vmware.photon.controller.model.resources.LoadBalancerDescriptionService.LoadBalancerDescription;
import com.vmware.photon.controller.model.resources.LoadBalancerDescriptionService.LoadBalancerDescription.HealthCheckConfiguration;
import com.vmware.photon.controller.model.resources.LoadBalancerDescriptionService.LoadBalancerDescription.Protocol;
import com.vmware.photon.controller.model.resources.LoadBalancerDescriptionService.LoadBalancerDescription.RouteConfiguration;
import com.vmware.photon.controller.model.resources.SubnetService.SubnetState;
import com.vmware.photon.controller.model.resources.util.PhotonModelUtils;
import com.vmware.xenon.common.DeferredResult;
import com.vmware.xenon.common.Operation;
import com.vmware.xenon.common.ServiceDocument;
import com.vmware.xenon.common.ServiceDocumentDescription.DocumentIndexingOption;
import com.vmware.xenon.common.ServiceDocumentDescription.PropertyUsageOption;
import com.vmware.xenon.common.StatefulService;
import com.vmware.xenon.common.UriUtils;
import com.vmware.xenon.common.Utils;

/**
 * Represents the actual state of a load balancer.
 */
public class LoadBalancerService extends StatefulService {

    public static final String FACTORY_LINK = UriPaths.RESOURCES_LOAD_BALANCERS;

    public static final String FIELD_NAME_DESCRIPTION_LINKS = "descriptionLink";
    public static final String FIELD_NAME_ENDPOINT_LINK = PhotonModelConstants.FIELD_NAME_ENDPOINT_LINK;
    public static final String FIELD_NAME_COMPUTE_LINKS = "computeLinks";
    public static final String FIELD_NAME_SUBNET_LINKS = "subnetLinks";
    public static final String FIELD_NAME_SECURITY_GROUP_LINKS = "securityGroupLinks";
    public static final String FIELD_NAME_ROUTES = "routes";
    public static final String FIELD_NAME_ROUTES_PROTOCOL = "protocol";
    public static final String FIELD_NAME_ROUTES_PORT = "port";
    public static final String FIELD_NAME_ROUTES_INSTANCE_PROTOCOL = "instanceProtocol";
    public static final String FIELD_NAME_ROUTES_INSTANCE_PORT = "instancePort";
    public static final String FIELD_NAME_INTERNET_FACING = "internetFacing";
    public static final String FIELD_NAME_ADDRESS = "address";

    public static final int MIN_PORT_NUMBER = 1;
    public static final int MAX_PORT_NUMBER = 65535;

    /**
     * Represents the state of a load balancer.
     */
    public static class LoadBalancerState extends ResourceState {
        /**
         * Link to the desired state of the load balancer, if any.
         */
        @UsageOption(option = PropertyUsageOption.OPTIONAL)
        public String descriptionLink;

        /**
         * Link to the cloud account endpoint the load balancer belongs to.
         */
        @UsageOption(option = PropertyUsageOption.REQUIRED)
        public String endpointLink;

        /**
         * Links to the load balanced instances.
         */
        @UsageOption(option = PropertyUsageOption.AUTO_MERGE_IF_NOT_NULL)
        public Set computeLinks;

        /**
         * List of subnets the load balancer is attached to. Typically these must be in different
         * availability zones, and have nothing to do with the subnets the cluster instances are
         * attached to.
         */
        @UsageOption(option = PropertyUsageOption.AUTO_MERGE_IF_NOT_NULL)
        public Set subnetLinks;

        /**
         * Security groups applied on the load balancer. If not specified, a default one can be
         * created by the adapter.
         */
        @Since(ReleaseConstants.RELEASE_VERSION_0_6_23)
        @UsageOption(option = PropertyUsageOption.AUTO_MERGE_IF_NOT_NULL)
        public List securityGroupLinks;

        /**
         * Internet-facing load balancer or an internal load balancer
         */
        @Since(ReleaseConstants.RELEASE_VERSION_0_6_19)
        @UsageOption(option = PropertyUsageOption.AUTO_MERGE_IF_NOT_NULL)
        public Boolean internetFacing;

        /**
         * Routing configuration between the load balancer and the back-end instances.
         *
         * 

{@code PATCH} merging strategy: if not {@code NULL} in the patch body, the current * value is replaced by the one given in the patch request (no advanced per-item merging). */ @Since(ReleaseConstants.RELEASE_VERSION_0_6_19) @UsageOption(option = PropertyUsageOption.REQUIRED) public List routes; /** * The address of this load balancer instance. */ @Since(ReleaseConstants.RELEASE_VERSION_0_6_19) @UsageOption(option = PropertyUsageOption.AUTO_MERGE_IF_NOT_NULL) public String address; /** * The adapter to use to create the load balancer instance. */ @UsageOption(option = PropertyUsageOption.AUTO_MERGE_IF_NOT_NULL) public URI instanceAdapterReference; @Override public void copyTo(ResourceState target) { super.copyTo(target); if (target instanceof LoadBalancerState) { LoadBalancerState targetState = (LoadBalancerState) target; targetState.descriptionLink = this.descriptionLink; targetState.endpointLink = this.endpointLink; targetState.regionId = this.regionId; targetState.computeLinks = this.computeLinks; targetState.subnetLinks = this.subnetLinks; targetState.routes = this.routes; targetState.instanceAdapterReference = this.instanceAdapterReference; targetState.internetFacing = this.internetFacing; targetState.address = this.address; targetState.securityGroupLinks = this.securityGroupLinks; } } } /** * Load balancer state with all links expanded. */ public static class LoadBalancerStateExpanded extends LoadBalancerState { public LoadBalancerDescription description; public EndpointState endpointState; public Set computes; public Set subnets; public static URI buildUri(URI loadBalancerStateUri) { return UriUtils.buildExpandLinksQueryUri(loadBalancerStateUri); } } public LoadBalancerService() { super(LoadBalancerState.class); super.toggleOption(ServiceOption.PERSISTENCE, true); super.toggleOption(ServiceOption.REPLICATION, true); super.toggleOption(ServiceOption.OWNER_SELECTION, true); super.toggleOption(ServiceOption.IDEMPOTENT_POST, true); } @Override public void handleGet(Operation get) { LoadBalancerState currentState = getState(get); boolean doExpand = get.getUri().getQuery() != null && UriUtils.hasODataExpandParamValue(get.getUri()); if (!doExpand) { get.setBody(currentState).complete(); return; } LoadBalancerStateExpanded expanded = new LoadBalancerStateExpanded(); currentState.copyTo(expanded); DeferredResult .allOf( getDr(currentState.descriptionLink, LoadBalancerDescription.class) .thenAccept(description -> expanded.description = description), getDr(currentState.endpointLink, EndpointState.class) .thenAccept(endpointState -> expanded.endpointState = endpointState), getDr(currentState.computeLinks, ComputeState.class, HashSet::new) .exceptionally(e -> { logWarning("Error retrieving compute states: %s", e.toString()); return new HashSet<>(); }).thenAccept(computes -> expanded.computes = computes), getDr(currentState.subnetLinks, SubnetState.class, HashSet::new) .thenAccept(subnets -> expanded.subnets = subnets)) .whenComplete((ignore, e) -> { if (e != null) { get.fail(e); } else { get.setBody(expanded).complete(); } }); } @Override public void handleStart(Operation start) { try { processInput(start); start.complete(); } catch (Throwable t) { start.fail(t); } } @Override public void handlePut(Operation put) { try { LoadBalancerState returnState = processInput(put); setState(put, returnState); put.complete(); } catch (Throwable t) { put.fail(t); } } @Override public void handleDelete(Operation delete) { ResourceUtils.handleDelete(delete, this); } @Override public void handlePost(Operation post) { try { LoadBalancerState returnState = processInput(post); setState(post, returnState); post.complete(); } catch (Throwable t) { post.fail(t); } } private LoadBalancerState processInput(Operation op) { if (!op.hasBody()) { throw (new IllegalArgumentException("body is required")); } LoadBalancerState state = op.getBody(LoadBalancerState.class); validateState(state); return state; } @Override public void handlePatch(Operation patch) { LoadBalancerState currentState = getState(patch); ResourceUtils.handlePatch(patch, currentState, getStateDescription(), LoadBalancerState.class, op -> { LoadBalancerState patchBody = op.getBody(LoadBalancerState.class); boolean hasChanged = false; // if routes are passed, they override the current ones if (patchBody.routes != null) { hasChanged = true; currentState.routes = patchBody.routes; } if (patchBody.securityGroupLinks != null) { if (currentState.securityGroupLinks == null) { currentState.securityGroupLinks = patchBody.securityGroupLinks; hasChanged = true; } else { for (String link : patchBody.securityGroupLinks) { if (!currentState.securityGroupLinks.contains(link)) { currentState.securityGroupLinks.add(link); hasChanged = true; } } } } return Boolean.valueOf(hasChanged); }); } private void validateState(LoadBalancerState state) { Utils.validateState(getStateDescription(), state); PhotonModelUtils.validateRegionId(state); LoadBalancerDescriptionService.validateRoutes(state.routes); } @Override public ServiceDocument getDocumentTemplate() { ServiceDocument td = super.getDocumentTemplate(); // enable metadata indexing td.documentDescription.documentIndexingOptions = EnumSet.of(DocumentIndexingOption.INDEX_METADATA); ServiceUtils.setRetentionLimit(td); LoadBalancerState template = (LoadBalancerState) td; template.id = UUID.randomUUID().toString(); template.descriptionLink = "lb-description-link"; template.name = "load-balancer"; template.endpointLink = UriUtils.buildUriPath(EndpointService.FACTORY_LINK, "my-endpoint"); template.internetFacing = Boolean.TRUE; template.address = "my-address"; RouteConfiguration routeConfiguration = new RouteConfiguration(); routeConfiguration.protocol = Protocol.HTTP.name(); routeConfiguration.port = "80"; routeConfiguration.instanceProtocol = Protocol.HTTP.name(); routeConfiguration.instancePort = "80"; routeConfiguration.healthCheckConfiguration = new HealthCheckConfiguration(); routeConfiguration.healthCheckConfiguration.protocol = Protocol.HTTP.name(); routeConfiguration.healthCheckConfiguration.port = "80"; template.routes = Arrays.asList(routeConfiguration); return template; } private DeferredResult getDr(String link, Class type) { if (link == null) { return DeferredResult.completed(null); } return sendWithDeferredResult(Operation.createGet(this, link), type); } private > DeferredResult getDr(Collection links, Class type, Supplier collectionFactory) { if (links == null) { return DeferredResult.completed(null); } return DeferredResult .allOf(links.stream().map(link -> getDr(link, type)).collect(Collectors.toList())) .thenApply(items -> items.stream() .collect(Collectors.toCollection(collectionFactory))); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy