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

com.vmware.photon.controller.model.resources.util.PhotonModelUtils Maven / Gradle / Ivy

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

import static java.util.Collections.singletonMap;

import static com.vmware.photon.controller.model.constants.PhotonModelConstants.CUSTOM_PROP_ENDPOINT_LINK;

import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.function.Consumer;
import java.util.logging.Level;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;

import com.vmware.photon.controller.model.constants.PhotonModelConstants;
import com.vmware.photon.controller.model.resources.ComputeDescriptionService.ComputeDescription;
import com.vmware.photon.controller.model.resources.ComputeService.ComputeState;
import com.vmware.photon.controller.model.resources.ComputeService.ComputeStateWithDescription;
import com.vmware.photon.controller.model.resources.DiskService.DiskState;
import com.vmware.photon.controller.model.resources.EndpointService;
import com.vmware.photon.controller.model.resources.ImageService.ImageState;
import com.vmware.photon.controller.model.resources.LoadBalancerDescriptionService.LoadBalancerDescription;
import com.vmware.photon.controller.model.resources.LoadBalancerService.LoadBalancerState;
import com.vmware.photon.controller.model.resources.NetworkInterfaceDescriptionService.NetworkInterfaceDescription;
import com.vmware.photon.controller.model.resources.NetworkInterfaceService.NetworkInterfaceState;
import com.vmware.photon.controller.model.resources.NetworkInterfaceService.NetworkInterfaceStateWithDescription;
import com.vmware.photon.controller.model.resources.NetworkService.NetworkState;
import com.vmware.photon.controller.model.resources.ResourceGroupService.ResourceGroupState;
import com.vmware.photon.controller.model.resources.ResourceState;
import com.vmware.photon.controller.model.resources.RouterService.RouterState;
import com.vmware.photon.controller.model.resources.SecurityGroupService.SecurityGroupState;
import com.vmware.photon.controller.model.resources.StorageDescriptionService.StorageDescription;
import com.vmware.photon.controller.model.resources.SubnetService.SubnetState;
import com.vmware.photon.controller.model.resources.TagService;
import com.vmware.xenon.common.DeferredResult;
import com.vmware.xenon.common.Operation;
import com.vmware.xenon.common.OperationContext;
import com.vmware.xenon.common.ReflectionUtils;
import com.vmware.xenon.common.Service;
import com.vmware.xenon.common.ServiceDocument;
import com.vmware.xenon.common.ServiceDocumentDescription;
import com.vmware.xenon.common.ServiceStateCollectionUpdateRequest;
import com.vmware.xenon.common.ServiceStats;
import com.vmware.xenon.common.StatefulService;
import com.vmware.xenon.common.UriUtils;
import com.vmware.xenon.services.common.AuthCredentialsService.AuthCredentialsServiceState;
import com.vmware.xenon.services.common.QueryTask;
import com.vmware.xenon.services.common.QueryTask.Query;
import com.vmware.xenon.services.common.QueryTask.Query.Occurance;

public class PhotonModelUtils {

    /**
     * The set of ResourceStates which support {@code endpointLink} property through explicit
     * field.
     */
    public static final Set> ENDPOINT_LINK_EXPLICIT_SUPPORT;

    static {
        Set> set = new HashSet<>();
        set.add(ComputeDescription.class);
        set.add(ComputeState.class);
        set.add(ComputeStateWithDescription.class);
        set.add(DiskState.class);
        set.add(ImageState.class);
        set.add(LoadBalancerDescription.class);
        set.add(LoadBalancerState.class);
        set.add(NetworkInterfaceDescription.class);
        set.add(NetworkInterfaceState.class);
        set.add(NetworkInterfaceStateWithDescription.class);
        set.add(NetworkState.class);
        set.add(ResourceGroupState.class);
        set.add(RouterState.class);
        set.add(SecurityGroupState.class);
        set.add(StorageDescription.class);
        set.add(SubnetState.class);

        ENDPOINT_LINK_EXPLICIT_SUPPORT = Collections.unmodifiableSet(set);
    }

    /**
     * The set of ServiceDocuments which support {@code endpointLink} property through custom
     * property.
     */
    public static final Set> ENDPOINT_LINK_CUSTOM_PROP_SUPPORT;

    static {
        Set> set = new HashSet<>();
        set.add(AuthCredentialsServiceState.class);

        ENDPOINT_LINK_CUSTOM_PROP_SUPPORT = Collections.unmodifiableSet(set);
    }

    /**
     * Return {@code endpointLink} property of passed state, if presented.
     *
     * @see #ENDPOINT_LINK_EXPLICIT_SUPPORT
     */
    public static  String getEndpointLink(T state) {

        if (state == null) {
            return null;
        }

        if (ENDPOINT_LINK_EXPLICIT_SUPPORT.contains(state.getClass())) {

            ServiceDocumentDescription sdDesc = ServiceDocumentDescription.Builder.create()
                    .buildDescription(state.getClass());

            return (String) ReflectionUtils.getPropertyValue(
                    sdDesc.propertyDescriptions.get(PhotonModelConstants.FIELD_NAME_ENDPOINT_LINK),
                    state);
        }

        return null;
    }

    /**
     * Set passed end-point link to:
     * 
    *
  • explicit {@code endpointLink} property of passed state, if presented
  • *
  • {@code __endpointLink} custom property of passed state, if supported
  • *
  • explicit {@code endpointLinks} property of passed state, if presented
  • *
* * @see #ENDPOINT_LINK_EXPLICIT_SUPPORT * @see #ENDPOINT_LINK_CUSTOM_PROP_SUPPORT */ public static T setEndpointLink(T state, String endpointLink) { if (state == null) { return state; } ServiceDocumentDescription sdDesc = ServiceDocumentDescription.Builder.create() .buildDescription(state.getClass()); if (ENDPOINT_LINK_EXPLICIT_SUPPORT.contains(state.getClass())) { String epLink = (String) ReflectionUtils.getPropertyValue(sdDesc.propertyDescriptions .get(PhotonModelConstants.FIELD_NAME_ENDPOINT_LINK), state); if (StringUtils.isEmpty(epLink) && endpointLink != null && !endpointLink.isEmpty()) { ReflectionUtils.setPropertyValue( sdDesc.propertyDescriptions .get(PhotonModelConstants.FIELD_NAME_ENDPOINT_LINK), state, endpointLink); } } else if (ENDPOINT_LINK_CUSTOM_PROP_SUPPORT.contains(state.getClass())) { String epLink = (String) ReflectionUtils.getPropertyValue( sdDesc.propertyDescriptions.get( ResourceState.FIELD_NAME_CUSTOM_PROPERTIES + "." + PhotonModelConstants.CUSTOM_PROP_ENDPOINT_LINK), state); if (StringUtils.isEmpty(epLink) && endpointLink != null && !endpointLink.isEmpty()) { ReflectionUtils.setOrUpdatePropertyValue( sdDesc.propertyDescriptions.get(ResourceState.FIELD_NAME_CUSTOM_PROPERTIES), state, singletonMap(CUSTOM_PROP_ENDPOINT_LINK, endpointLink)); } } return state; } /** * Wait\Block for {@link DeferredResult} to complete. *

* Note: Use with care, for example within tests. */ public static T waitToComplete(DeferredResult dr) { return ((CompletableFuture) dr.toCompletionStage()).join(); } /** * Utility method to create an operation to remove an endpointLink from the endpointLinks set of * the resourceState and also update the endpointLink property of the specific resourceState */ public static Operation createRemoveEndpointLinksOperation( Service service, String endpointLink, ResourceState resource) { /* * endpointLink is also updated to provide backward compatibility to Tango team's Day 2 * operation. The verbose code to update endpointLink can be cleaned up once the * endpointLink is completely deprecated within photon-model. */ if (resource.endpointLinks == null || !resource.endpointLinks.contains(endpointLink)) { return null; } Map> endpointsToRemoveMap = Collections.singletonMap( EndpointService.EndpointState.FIELD_NAME_ENDPOINT_LINKS, Collections.singleton(endpointLink)); ServiceStateCollectionUpdateRequest serviceStateCollectionUpdateRequest = ServiceStateCollectionUpdateRequest .create(null, endpointsToRemoveMap); return Operation .createPatch(UriUtils.buildUri(service.getHost(), resource.documentSelfLink)) .setReferer(service.getUri()) .setBody(serviceStateCollectionUpdateRequest) .setCompletion((updateOp, exception) -> { if (exception != null) { service.getHost().log(Level.WARNING, () -> String.format("PATCH " + "to instance service %s, failed: %s", updateOp.getUri(), exception.toString())); return; } service.getHost().log(Level.FINE, () -> String.format("PATCH to " + "update endpointLink in endpointLinks " + "to instance service %s finished successfully", updateOp.getUri())); String resourceEndpointLink = getEndpointLink(resource); if (resourceEndpointLink != null) { // if the endpoint being deleted is the endpointLink of the // resourceState, then assign a new endpointLink updateEndpointLink(service, endpointLink, resource.documentSelfLink, resourceEndpointLink, resource.endpointLinks); } }); } private static void updateEndpointLink(Service service, String endpointLink, String selfLink, String resourceEndpointLink, Set resourceEndpointLinks) { if (!endpointLink.equals(resourceEndpointLink)) { return; } EndpointLinkPatchReq req = new EndpointLinkPatchReq(); req.endpointLink = getUpdatedEndpointLink(resourceEndpointLink, resourceEndpointLinks); handleResourceStateEndpointLinkUpdate(service, selfLink, req); } public static class EndpointLinkPatchReq { String endpointLink; } private static String getUpdatedEndpointLink(String resourceEndpointLink, Set endpointLinks) { String endpointLinkVal = ""; if (endpointLinks.size() == 1 && endpointLinks.contains(resourceEndpointLink)) { return ""; } SortedSet sortedEndpointLinks = new TreeSet<>(); sortedEndpointLinks.addAll(endpointLinks); for (String endpointLink : sortedEndpointLinks) { if (!endpointLink.equals(resourceEndpointLink)) { endpointLinkVal = endpointLink; break; } } return endpointLinkVal; } private static void handleResourceStateEndpointLinkUpdate(Service service, String selfLink, Object endpointLinkPatchReq) { Operation.createPatch(UriUtils.buildUri(service.getHost(), selfLink)) .setReferer(service.getUri()) .setBody(endpointLinkPatchReq) .setCompletion( (o, e) -> { if (e != null) { service.getHost().log(Level.WARNING, () -> String.format("PATCH to " + "updated endpointLink in instance" + " service %s, failed: %s", o.getUri(), e .toString())); return; } }) .sendWith(service); } public static T updateEndpointLinks(T state, String endpointLink) { if (state == null) { return state; } ServiceDocumentDescription sdDesc = ServiceDocumentDescription.Builder.create() .buildDescription(state.getClass()); // This method will assign the value of the endpointLinks if it does not exist for the given // resource OR it will merge it with the existing collection if already set. Set endpointLinks = new HashSet<>(); endpointLinks.add(endpointLink); ReflectionUtils.setOrUpdatePropertyValue( sdDesc.propertyDescriptions.get(PhotonModelConstants.FIELD_NAME_ENDPOINT_LINKS), state, endpointLinks); return state; } public static void handleIdempotentPut(StatefulService s, Operation put) { if (put.hasPragmaDirective(Operation.PRAGMA_DIRECTIVE_POST_TO_PUT)) { // converted PUT due to IDEMPOTENT_POST option s.logFine(() -> String.format("Task %s has already started. Ignoring converted PUT.", put.getUri())); put.setBody(s.getState(put)); put.addPragmaDirective(Operation.PRAGMA_DIRECTIVE_STATE_NOT_MODIFIED); put.setStatusCode(Operation.STATUS_CODE_OK); put.complete(); return; } // normal PUT is not supported put.fail(Operation.STATUS_CODE_BAD_METHOD); } public static void validateRegionId(ResourceState resourceState) { if (resourceState.regionId == null) { throw (new IllegalArgumentException("regionId is required")); } } /** * Merges two lists of strings, filtering duplicate elements from the second one (the patch). * Also keeping track if change of source list has been modified. * * @param source * The source list (can be null). * @param patch * The patch list. If null, the @source will be the result. * @return Returns a pair. The left part is the merged list and the right one is the boolean * value, indicating if the changes to @source is modified. */ public static > Pair mergeLists( C source, C patch) { if (patch == null) { return new ImmutablePair<>(source, Boolean.FALSE); } boolean hasChanged = false; C result = source; if (result == null) { result = patch; hasChanged = true; } else { for (String newValue : patch) { if (!result.contains(newValue)) { result.add(newValue); hasChanged = true; } } } return new ImmutablePair<>(result, Boolean.valueOf(hasChanged)); } /** * Executes given code in the specified executor. * * @param executor * Executor in which code is to be executed. * @param runnable * Code to be executed in the executor. * @param failure * failure consumer. */ public static void runInExecutor(ExecutorService executor, Runnable runnable, Consumer failure) { try { OperationContext operationContext = OperationContext.getOperationContext(); executor.submit(() -> { OperationContext.restoreOperationContext(operationContext); try { runnable.run(); } catch (Throwable runnableExc) { failure.accept(runnableExc); } }); } catch (Throwable executorExc) { failure.accept(executorExc); } } /** * Sets a metric with unit and value in the ServiceStat associated with the service */ public static void setStat(Service service, String name, String unit, double value) { service.getHost().log(Level.INFO, "Setting stat [service=%s] [name=%s] [unit=%s] [value=%f]", service.getClass(), name, unit, value); ServiceStats.ServiceStat stat = new ServiceStats.ServiceStat(); stat.name = name; stat.unit = unit; service.setStat(stat, value); } /** * @param external * @param origin * @return Returns a query with the needed terms for external and origin field */ public static Query createOriginTagQuery(Boolean external, Map origin) { QueryTask.Query externalQuery = new Query() .setTermPropertyName(TagService.TagState.FIELD_NAME_EXTERNAL) .setTermMatchValue(external.toString()); externalQuery.occurance = Occurance.SHOULD_OCCUR; QueryTask.Query.Builder originClauseBuilder = QueryTask.Query.Builder.create(); for (Map.Entry entry : origin.entrySet()) { Occurance occurance = entry.getValue() == null ? Occurance.MUST_OCCUR : entry.getValue(); if (entry.getKey() != null) { originClauseBuilder.addCollectionItemClause(TagService.TagState.FIELD_NAME_ORIGIN, entry.getKey(), occurance); } } Query originQuery = originClauseBuilder.build() .setOccurance(Occurance.SHOULD_OCCUR); Query originOrExternalQuery = new Query().addBooleanClause(externalQuery) .addBooleanClause(originQuery) .setOccurance(Occurance.MUST_OCCUR); return originOrExternalQuery; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy