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

com.vmware.xenon.common.ServiceHost Maven / Gradle / Ivy

There is a newer version: 1.6.18
Show newest version
/*
 * Copyright (c) 2014-2015 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.xenon.common;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.nio.file.StandardOpenOption;
import java.security.KeyStore;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.UUID;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.ConcurrentSkipListSet;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinWorkerThread;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.logging.ConsoleHandler;
import java.util.logging.FileHandler;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;

import io.opentracing.ActiveSpan;
import io.opentracing.ActiveSpan.Continuation;
import io.opentracing.SpanContext;
import io.opentracing.Tracer;
import io.opentracing.propagation.Format;
import io.opentracing.propagation.TextMapExtractAdapter;
import io.opentracing.propagation.TextMapInjectAdapter;
import io.opentracing.tag.Tags;

import com.vmware.xenon.common.FileUtils.ResourceEntry;
import com.vmware.xenon.common.NodeSelectorService.SelectAndForwardRequest;
import com.vmware.xenon.common.NodeSelectorService.SelectAndForwardRequest.ForwardingOption;
import com.vmware.xenon.common.NodeSelectorService.SelectOwnerResponse;
import com.vmware.xenon.common.Operation.AuthorizationContext;
import com.vmware.xenon.common.Operation.CompletionHandler;
import com.vmware.xenon.common.Operation.OperationOption;
import com.vmware.xenon.common.OperationProcessingChain.OperationProcessingContext;
import com.vmware.xenon.common.Service.Action;
import com.vmware.xenon.common.Service.ProcessingStage;
import com.vmware.xenon.common.Service.ServiceOption;
import com.vmware.xenon.common.ServiceDocumentDescription.Builder;
import com.vmware.xenon.common.ServiceHost.RequestRateInfo.Option;
import com.vmware.xenon.common.ServiceHost.ServiceHostState.MemoryLimitType;
import com.vmware.xenon.common.ServiceHost.ServiceHostState.SslClientAuthMode;
import com.vmware.xenon.common.ServiceMaintenanceRequest.MaintenanceReason;
import com.vmware.xenon.common.ServiceStats.ServiceStat;
import com.vmware.xenon.common.ServiceStats.TimeSeriesStats;
import com.vmware.xenon.common.ServiceStats.TimeSeriesStats.AggregationType;
import com.vmware.xenon.common.ServiceSubscriptionState.ServiceSubscriber;
import com.vmware.xenon.common.config.XenonConfiguration;
import com.vmware.xenon.common.http.netty.NettyHttpListener;
import com.vmware.xenon.common.http.netty.NettyHttpServiceClient;
import com.vmware.xenon.common.jwt.JWTUtils;
import com.vmware.xenon.common.jwt.Signer;
import com.vmware.xenon.common.jwt.Verifier;
import com.vmware.xenon.common.opentracing.TracerFactory;
import com.vmware.xenon.common.opentracing.TracingExecutor;
import com.vmware.xenon.common.opentracing.TracingScheduledExecutor;
import com.vmware.xenon.common.opentracing.TracingUtils;
import com.vmware.xenon.services.common.AuthCredentialsService;
import com.vmware.xenon.services.common.AuthorizationContextService;
import com.vmware.xenon.services.common.AuthorizationTokenCacheService;
import com.vmware.xenon.services.common.CheckpointFactoryService;
import com.vmware.xenon.services.common.ConsistentHashingNodeSelectorService;
import com.vmware.xenon.services.common.DirectoryContentService;
import com.vmware.xenon.services.common.GraphQueryTaskService;
import com.vmware.xenon.services.common.GuestUserService;
import com.vmware.xenon.services.common.LocalQueryTaskFactoryService;
import com.vmware.xenon.services.common.LuceneDocumentIndexBackupService;
import com.vmware.xenon.services.common.LuceneDocumentIndexService;
import com.vmware.xenon.services.common.NodeGroupFactoryService;
import com.vmware.xenon.services.common.NodeGroupService.JoinPeerRequest;
import com.vmware.xenon.services.common.NodeGroupUtils;
import com.vmware.xenon.services.common.NodeSelectorReplicationService;
import com.vmware.xenon.services.common.ODataQueryService;
import com.vmware.xenon.services.common.OperationIndexService;
import com.vmware.xenon.services.common.QueryFilter;
import com.vmware.xenon.services.common.QueryPageForwardingService;
import com.vmware.xenon.services.common.QueryTaskFactoryService;
import com.vmware.xenon.services.common.ReliableSubscriptionService;
import com.vmware.xenon.services.common.ResourceGroupService;
import com.vmware.xenon.services.common.RoleService;
import com.vmware.xenon.services.common.ServiceHostLogService;
import com.vmware.xenon.services.common.ServiceHostManagementService;
import com.vmware.xenon.services.common.ServiceUriPaths;
import com.vmware.xenon.services.common.SynchronizationManagementService;
import com.vmware.xenon.services.common.SystemUserService;
import com.vmware.xenon.services.common.TaskFactoryService;
import com.vmware.xenon.services.common.TenantService;
import com.vmware.xenon.services.common.TransactionFactoryService;
import com.vmware.xenon.services.common.TransactionService;
import com.vmware.xenon.services.common.UpdateIndexRequest;
import com.vmware.xenon.services.common.UserGroupService;
import com.vmware.xenon.services.common.UserService;
import com.vmware.xenon.services.common.authn.BasicAuthenticationService;

/**
 * Service host manages service life cycle, delivery of operations (remote and local) and performing
 * periodic maintenance on all services.
 *
 * Service host allows the process to specify at runtime key infrastructure services such as authz
 * and document storage / indexing.
 *
 * The HTTP service host listens on HTTP URIs but shares common functionality with hosts on other
 * protocols
 */
public class ServiceHost implements ServiceRequestSender {


    public static class ServiceAlreadyStartedException extends IllegalStateException {
        private static final long serialVersionUID = -1444810129515584386L;

        public ServiceAlreadyStartedException(String servicePath) {
            super("Service already started: " + servicePath);
        }

        public ServiceAlreadyStartedException(String servicePath, ProcessingStage stage) {
            super("Service already started: " + servicePath + " stage: " + stage);
        }

        public ServiceAlreadyStartedException(String servicePath, String customErrorMessage) {
            super("Service already started: " + servicePath + ". " + customErrorMessage);
        }
    }

    public static class ServiceNotFoundException extends IllegalStateException {
        private static final long serialVersionUID = 663670123267539178L;

        public ServiceNotFoundException() {
            super();
        }

        public ServiceNotFoundException(String servicePath) {
            super("Service not found: " + servicePath);
        }

        public ServiceNotFoundException(String servicePath, String customErrorMessage) {
            super("Service not found: " + servicePath + ". " + customErrorMessage);
        }
    }

    public static class Arguments {
        /**
         * HTTP port
         */
        public int port = DEFAULT_PORT;

        /**
         * HTTPS port
         */
        public int securePort = PORT_VALUE_LISTENER_DISABLED;

        /**
         * SSL client authorization mode
         */
        public SslClientAuthMode sslClientAuthMode = SslClientAuthMode.NONE;

        /**
         * File path to key file(PKCS#8 private key file in PEM format)
         */
        public Path keyFile;

        /**
         * Key passphrase
         */
        public String keyPassphrase;

        /**
         * File path to certificate file
         */
        public Path certificateFile;

        /**
         * File directory path used to store service state
         */
        public Path sandbox = DEFAULT_SANDBOX;

        /**
         * Network interface address to bind to
         */
        public String bindAddress = DEFAULT_BIND_ADDRESS;

        /**
         * Optional public URI the host uses to advertise itself to peers. If its
         * not set, the bind address and port will be used to form the host URI
         */
        public String publicUri;

        /**
         * Comma separated list of one or more peer nodes to join through Nodes
         * must be defined in URI form, e.g --peerNodes=http://192.168.1.59:8000,http://192.168.1.82
         */
        public String[] peerNodes;

        /**
         * Optional stable identity associated with this host. If not specified and a host configuration
         * file is not present in the current sandbox, a random unique identifier will be assigned to this
         * host and persisted in the serviceHostConfig.json file so its used on restart
         */
        public String id;

        /**
         * An upper bound, in seconds, for service synchronization to complete. The runtime synchronizes
         * one replicated factory at a time. This limit applies to upper bound the runtime will wait for
         * a given factory, before moving on to the next. The factory that did not finish in time will stay
         * unavailable (/available will return error). The runtime will continue synchronization with the next
         * factory and the node will be marked as available even if one factory fails to complete in time.
         * If a factory does not finish in time, its availability can be explicitly reset with a PATCH to
         * the STAT_NAME_IS_AVALABLE, to the factory /stats utility service.
         *
         * A factory will accept POST requests, even during synchronization, and even if it fails to
         * complete synchronization in time. The availability indicator on /available is a hint, it does
         * not prevent the factory from functioning.
         *
         * The default value of 1 hour would roughly allows for 1.8M services to synchronize.
         *
         * Synchronization starts automatically if {@link Arguments#isPeerSynchronizationEnabled} is true,
         * and the node group has observed a node joining or leaving (becoming unavailable)
         */
        public int perFactoryPeerSynchronizationLimitSeconds = (int) TimeUnit.HOURS.toSeconds(1);

        /**
         * Value indicating whether node group changes will automatically
         * trigger replicated service state synchronization. If set to false, client can issue
         * synchronization requests through core management service
         */
        public boolean isPeerSynchronizationEnabled = true;

        /**
         * Mandate an auth context for all requests
         * This option will be set to true and authn/authz enabled by default after a transition period
         */
        public boolean isAuthorizationEnabled = false;

        /**
         * Optional base URI of the xenon node that acts as the auth source for this service host
         */
        public String authProviderHostUri;

        /**
         * Optional file directory path to resource files. If specified, resources will be loaded from here instead of
         * the JAR file of the host
         */
        public Path resourceSandbox;

        /**
         * Optional tag specifying the logical or geographic location of this host
         */
        public String location;

        /**
         * Optional local directory path to store auto backup files.
         * If not specified, default directory is "[sandbox]/[port]/auto-backup".
         */
        public Path autoBackupDirectory;

        /**
         * When enabled, perform incremental backup whenever document-index service performed commits.
         */
        public boolean isAutoBackupEnabled = false;

    }

    protected static final LogFormatter LOG_FORMATTER = new LogFormatter();
    protected static final LogFormatter COLOR_LOG_FORMATTER = new ColorLogFormatter();

    public static final String SERVICE_HOST_STATE_FILE = "serviceHostState.json";

    public static final Double DEFAULT_PCT_MEMORY_LIMIT = 0.49;
    public static final Double DEFAULT_PCT_MEMORY_LIMIT_DOCUMENT_INDEX = 0.45;
    public static final Double DEFAULT_PCT_MEMORY_LIMIT_SERVICE_CONTEXT_INDEX = 0.01;

    public static final String LOOPBACK_ADDRESS = "127.0.0.1";
    public static final String LOCAL_HOST = LOOPBACK_ADDRESS;
    public static final String DEFAULT_BIND_ADDRESS = ServiceHost.LOCAL_HOST;

    public static final int PORT_VALUE_HTTP_DEFAULT = 8000;

    /**
     * Indicates that the listener associated with this port field should not be started
     */
    public static final int PORT_VALUE_LISTENER_DISABLED = -1;

    public static final int DEFAULT_PORT = PORT_VALUE_HTTP_DEFAULT;

    public static final String ALL_INTERFACES = "0.0.0.0";

    public static final String ROOT_PATH = "";

    public static final String SERVICE_URI_SUFFIX_STATS = "/stats";
    public static final String SERVICE_URI_SUFFIX_SUBSCRIPTIONS = "/subscriptions";

    public static final String SERVICE_URI_SUFFIX_SYNCHRONIZATION = "/synchronization";
    public static final String SERVICE_URI_SUFFIX_AVAILABLE = "/available";
    public static final String SERVICE_URI_SUFFIX_CONFIG = "/config";
    public static final String SERVICE_URI_SUFFIX_TEMPLATE = "/template";
    public static final String SERVICE_URI_SUFFIX_UI = "/ui";

    public static final String SERVICE_URI_SUFFIX_REPLICATION = "/replication";

    public static final String DCP_ENVIRONMENT_VAR_PREFIX = "XENON_";
    public static final String GIT_COMMIT_PROPERTIES_RESOURCE_NAME = "xenon.git.properties";
    public static final String GIT_COMMIT_SOURCE_PROPERTY_PREFIX = "git.commit";
    public static final String GIT_COMMIT_SOURCE_PROPERTY_COMMIT_ID = GIT_COMMIT_SOURCE_PROPERTY_PREFIX
            + ".id";
    public static final String GIT_COMMIT_SOURCE_PROPERTY_COMMIT_TIME = GIT_COMMIT_SOURCE_PROPERTY_PREFIX
            + ".time";

    public static final String[] RESERVED_SERVICE_URI_PATHS = {
            SERVICE_URI_SUFFIX_AVAILABLE,
            SERVICE_URI_SUFFIX_SYNCHRONIZATION,
            SERVICE_URI_SUFFIX_REPLICATION,
            SERVICE_URI_SUFFIX_STATS,
            SERVICE_URI_SUFFIX_SUBSCRIPTIONS,
            SERVICE_URI_SUFFIX_UI,
            SERVICE_URI_SUFFIX_CONFIG,
            SERVICE_URI_SUFFIX_TEMPLATE };

    static final Path DEFAULT_TMPDIR = Paths.get(System.getProperty("java.io.tmpdir"));
    static final Path DEFAULT_SANDBOX = DEFAULT_TMPDIR.resolve("xenon");
    static final Path DEFAULT_RESOURCE_SANDBOX_DIR = Paths.get("resources");
    private static final String DEFAULT_AUTO_BACKUP_DIR = "auto-backup";

    /**
     * Estimate for average service state memory cost, in bytes. This can be computed per
     * state cached, estimated per kind, or made tunable in the future. Its used solely for estimating
     * host memory consumption during maintenance
     */
    public static final int DEFAULT_SERVICE_STATE_COST_BYTES = 4096;

    /**
     * Estimate for service class runtime context cost, in bytes. It takes into account:
     *
     * 1) The cost of the self link of each service instance
     * 2) The cost of the map nodes used to store the self link
     * 3) The cost of the runtime context structure, per {@code StatefulService} instance
     * 4) Estimated cost of default statistics, if service is instrumented
     * 5) Estimated cost of a small number of subscriptions
     */
    public static final int DEFAULT_SERVICE_INSTANCE_COST_BYTES = 4096;

    private static final String PROPERTY_NAME_APPEND_PORT_TO_SANDBOX = Utils.PROPERTY_NAME_PREFIX
            + "ServiceHost.APPEND_PORT_TO_SANDBOX";

    /**
     * Control creating a directory using port number under sandbox directory.
     *
     * VM argument: "-Dxenon.ServiceHost.APPEND_PORT_TO_SANDBOX=[true|false]"
     * Default is set to true.
     */
    public static final boolean APPEND_PORT_TO_SANDBOX = System
            .getProperty(PROPERTY_NAME_APPEND_PORT_TO_SANDBOX) == null
            || Boolean.getBoolean(PROPERTY_NAME_APPEND_PORT_TO_SANDBOX);

    /**
     * Request rate limiting configuration and real time statistics
     */
    public static class RequestRateInfo {
        public enum Option {
            /**
             * Fail request when limit is reached
             */
            FAIL,

            /**
             * Pause reads from I/O channel
             */
            PAUSE_PROCESSING
        }

        /**
         * Request limit (upper bound). The value represents the maximum number of requests
         * for a given time window, specified through the {@link #timeSeries} parameters
         */
        public double limit;

        /**
         * Options affecting rate limit behavior
         */
        public EnumSet




© 2015 - 2024 Weber Informatics LLC | Privacy Policy