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

com.tangosol.internal.management.resources.ClusterResource Maven / Gradle / Ivy

There is a newer version: 24.09
Show newest version
/*
 * Copyright (c) 2000, 2022, Oracle and/or its affiliates.
 *
 * Licensed under the Universal Permissive License v 1.0 as shown at
 * https://oss.oracle.com/licenses/upl.
 */
package com.tangosol.internal.management.resources;

import com.oracle.coherence.common.base.Logger;

import com.tangosol.internal.http.HttpRequest;
import com.tangosol.internal.http.RequestRouter;
import com.tangosol.internal.http.Response;

import com.tangosol.internal.management.EntityMBeanResponse;

import com.tangosol.net.CacheFactory;
import com.tangosol.net.management.MBeanAccessor.QueryBuilder;

import com.tangosol.util.Base;
import com.tangosol.util.Resources;

import java.io.IOException;

import java.net.URI;
import java.net.URL;

import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;

import static com.tangosol.internal.management.resources.ClusterMemberResource.DIAGNOSTIC_CMD;

/**
 * Handles management API requests for a Coherence cluster level MBeans.
 *
 * @author sr 2017.08.21
 * @author Jonathan Knight  2022.01.25
 * @since 12.2.1.4.0
 */
public class ClusterResource
        extends AbstractManagementResource
    {
    // ----- Routes methods -------------------------------------------------

    @Override
    public void addRoutes(RequestRouter router, String sPathRoot)
        {
        router.addGet(sPathRoot, this::get);
        router.addGet(sPathRoot + "/" + MANAGEMENT, this::getManagement);
        router.addGet(sPathRoot + "/" + JOURNAL, this::getJournalResponse);
        router.addGet(sPathRoot + "/" + PLATFORM + "/{" + PLATFORM_MBEAN + "}", this::getPlatformResponse);
        router.addGet(sPathRoot + "/" + METADATA_CATALOG, this::getMetadataCatalog)
                .produces(MEDIA_TYPE_JSON, MEDIA_TYPE_SWAGGER_JSON);

        router.addPost(sPathRoot, this::updateNodes);
        router.addPost(sPathRoot + "/" + SHUTDOWN, this::shutdownCluster);
        router.addPost(sPathRoot + "/" + CLUSTER_STATE, this::logClusterState);
        router.addPost(sPathRoot + "/" + DUMP_CLUSTER_HEAP, this::dumpClusterHeap);
        router.addPost(sPathRoot + "/" + CONFIGURE_TRACING, this::configureTracing);
        router.addPost(sPathRoot + "/" + MANAGEMENT, this::updateJMXManagement);
        router.addPost(sPathRoot + "/" + SEARCH, this::search);
        router.addPost(sPathRoot + "/" + DIAGNOSTIC_CMD + "/{" + JFR_CMD + "}", this::diagnosticCmd);
        router.addPost(sPathRoot + "/{" + OPERATION_NAME + "}", this::executeOperation);
        router.addPost(sPathRoot + "/" + NETWORK_STATS + "/trackWeakest", this::trackWeakestMember);

        // child resources
        router.addRoutes(sPathRoot + "/" + CACHES, new CachesResource());
        router.addRoutes(sPathRoot + "/" + EXECUTORS, new ExecutorsResource());
        router.addRoutes(sPathRoot + "/" + HEALTH, new HealthsResource());
        router.addRoutes(sPathRoot + "/" + JOURNAL + "/{" + JOURNAL_TYPE + "}", new JournalResource());
        router.addRoutes(sPathRoot + "/" + MEMBERS, new ClusterMembersResource());
        router.addRoutes(sPathRoot + "/" + REPORTERS, new ReportersResource());
        router.addRoutes(sPathRoot + "/" + SERVICES, new ServicesResource());
        }

    // ----- GET API --------------------------------------------------------

    /**
     * Return the swagger document for the Management Resource.
     *
     * @return the response object
     */
    public Response getMetadataCatalog()
        {
        URL url = Resources.findFileOrResource(SWAGGER_RESOURCE, this.getClass().getClassLoader());
        try
            {
            return url == null
                       ? Response.notFound().build()
                       : Response.ok(url.openStream()).build();
            }
        catch (IOException e)
            {
            Logger.warn("Exception occurred while returning Swagger resource " + SWAGGER_RESOURCE, e);
            return Response.serverError().build();
            }
        }

    /**
     * Return the attributes of a ClusterMBean.
     *
     * @param request  the {@link HttpRequest}
     *
     * @return the response object
     */
    public Response get(HttpRequest request)
        {
        return response(getResponseEntityForMbean(request, getQuery(request), CHILD_LINKS));
        }

    /**
     * Return the attributes of a ManagementMBean.
     *
     * @param request  the {@link HttpRequest}
     *
     * @return the response object
     */
    public Response getManagement(HttpRequest request)
        {
        return response(getResponseEntityForMbean(request, getManagementQuery(request)));
        }

    /**
     * Return the response to a "journal" link for a cluster.
     *
     * @param request  the {@link HttpRequest}
     *
     * @return the response object
     */
    public Response getJournalResponse(HttpRequest request)
        {
        return response(getLinksOnlyResponseBody(request, getParentUri(request), getCurrentUri(request), "ram", "flash").toJson());
        }


    /**
     * Return aggregated metrics of a platform(JVM) MBean across cluster members.
     *
     * @param request  the {@link HttpRequest}
     *
     * @return the response object
     */
    public Response getPlatformResponse(HttpRequest request)
        {
        String sPlatformMBeanType = request.getFirstPathParameter(PLATFORM_MBEAN);
        String sRoleName          = request.getFirstPathParameter(ROLE_NAME);
        String sCollector         = request.getFirstPathParameter(COLLECTOR);

        String sBaseQuery = MAP_PLATFORM_URL_TO_MBEAN_QUERY.get(sPlatformMBeanType);

        if (sBaseQuery == null)
            {
            sBaseQuery = MAP_PLATFORM_PS_URL_TO_MBEAN_QUERY.get(sPlatformMBeanType);
            if (sBaseQuery == null)
                {
                sBaseQuery = MAP_PLATFORM_G1_URL_TO_MBEAN_QUERY.get(sPlatformMBeanType);
                if (sBaseQuery == null)
                    {
                    return Response.status(Response.Status.NOT_FOUND).build();
                    }
                }
            }

        QueryBuilder        queryBuilder = createQueryBuilder(request).withBaseQuery(sBaseQuery);
        EntityMBeanResponse response  = getLinksOnlyResponseBody(request, getParentUri(request), getCurrentUri(request));

        Map responseMap = response.toJson();

        addAggregatedMetricsToResponseMap(request, sRoleName, sCollector, queryBuilder, responseMap);

        return response(responseMap);
        }

    // ----- POST API (Operations) ------------------------------------------

    /**
     * Call "shutdown" operation on ClusterMBean.
     *
     * @param request  the {@link HttpRequest}
     *
     * @return the response object
     */
    public Response shutdownCluster(HttpRequest request)
        {
        return executeMBeanOperation(request, getQuery(request), "shutdown", null, null);
        }

    /**
     * Call "logClusterState" operation on ClusterMBean.
     *
     * @param request  the {@link HttpRequest}
     *
     * @return the response object
     */
    public Response logClusterState(HttpRequest request)
        {
        Map mapBody   = getJsonBody(request);
        String              sRoleName = (String) mapBody.get(ROLE_NAME);
        return executeMBeanOperation(request, getQuery(request), CLUSTER_STATE,
                new Object[]{sRoleName}, new String[] {String.class.getName()});
        }

    /**
     * Call "dumpClusterHeap" operation on ClusterMBean.
     *
     * @param request  the {@link HttpRequest}
     *
     * @return the response object
     */
    public Response dumpClusterHeap(HttpRequest request)
        {
        Map mapBody       = getJsonBody(request);
        String              sRoleName     = (String) mapBody.get(ROLE_NAME);
        return executeMBeanOperation(request, getQuery(request), DUMP_CLUSTER_HEAP,
                                     new Object[]{sRoleName}, new String[] {String.class.getName()});
        }

    /**
     * Call the {@value CONFIGURE_TRACING} operation on ClusterMBean.
     * 

* This call expects two parameters, {@value ROLE} and {@value TRACING_RATIO}. {@value ROLE} allows enabling * tracing on members matching the specified role. If {@value ROLE} is null or a zero-length string, * {@value TRACING_RATIO} will be applied to all members of the cluster. {@value TRACING_RATIO} specifies * the ratio of tracing spans that will be captured. A value of {@code -1} disables tracing. A value of * {@code 0} means Coherence will not initiate spans unless an active span is already present. * A value between {@code 0} (exclusively) and {@code 1.0} (inclusively) represents the percentage of tracing * spans that will be captured. * * @param request the {@link HttpRequest} * * @return the response object * * @since 14.1.1.0 */ public Response configureTracing(HttpRequest request) { Map mapParameters = getJsonBody(request); Object oRole = mapParameters == null ? null : mapParameters.get(ROLE); float oRatio = mapParameters == null ? -1.0f : Float.parseFloat(mapParameters.get(TRACING_RATIO).toString()); return executeMBeanOperation(request, getQuery(request), CONFIGURE_TRACING, new Object[]{oRole, oRatio}, new String[] {String.class.getName(), Float.class.getName()}); } /** * Call "shutdown/resetStatistics" operation on NodeMBean for all the members. * * @param request the {@link HttpRequest} * * @return the response object */ public Response executeOperation(HttpRequest request) { String sOperationName = request.getFirstPathParameter(OPERATION_NAME); if (sOperationName.equalsIgnoreCase("logMemberState")) { sOperationName = "logNodeState"; } if ("shutdown".equals(sOperationName) || "resetStatistics".equals(sOperationName) || "logNodeState".equals(sOperationName)) { return executeMBeanOperation(request, getMembersQuery(request), sOperationName, null, null); } return Response.notFound().build(); } /** * Call "trackWeakest" operation on PointToPointMBean for all the members. * * @param request the {@link HttpRequest} * * @return the response object */ public Response trackWeakestMember(HttpRequest request) { return executeMBeanOperation(request, getPointToPointMBeanQuery(request), "trackWeakest", null, null); } // ----- POST API(Update) ----------------------------------------------- /** * Update a ManagementMBean with the parameters present in the input entity map. * * @param request the {@link HttpRequest} * * @return the response object */ public Response updateJMXManagement(HttpRequest request) { Map mapParameters = getJsonBody(request); return update(request, mapParameters, getManagementQuery(request)); } /** * Update a ClusterNodeMBean with the parameters present in the input * entity map for all the members. * * @param request the {@link HttpRequest} * * @return the response object */ public Response updateNodes(HttpRequest request) { Map entity = getJsonBody(request); QueryBuilder queryBuilder = getMembersQuery(request); return update(request, entity, queryBuilder); } // ----- POST API(Search) ----------------------------------------------- public Response search(HttpRequest request) { Map mapQuery = getJsonBody(request); URI uriParent = getParentUri(request); URI uriCurrent = getCurrentUri(request); String sCluster = getClusterName(request); return response(getSearchResults(request, sCluster, mapQuery, uriParent, uriCurrent, uriCurrent)); } // ----- Child Resources ------------------------------------------------ /** * Call "diagnostic-cmd/jfrCmd" to perform JFR operation on ClusterMBean. * * Valid commands are jfrStart, jfrStop, jfrDump, and jfrCheck. See jcmd JFR * command for valid options. E.g. * jfrStart?options=name=myJfr,duration=3s,filename=/tmp/myRecording.jfr * * @param request the {@link HttpRequest} * * @return the response object */ public Response diagnosticCmd(HttpRequest request) { String sCmd = request.getFirstPathParameter(JFR_CMD); String sOptions = request.getFirstQueryParameter(OPTIONS); String sRole = request.getFirstQueryParameter(ROLE_NAME); // execute the role based cluster wide JFR operation and return // the result message from the operation return response(getResponseFromMBeanOperation(request, getQuery(request), "status", "flightRecording", new Object[]{sRole, sCmd, sOptions}, new String[]{String.class.getName(), String.class.getName(), String.class.getName()})); } // ----- ClusterResource methods ---------------------------------------- /** * The response for a Coherence ClusterMBean. * * @param request the {@link HttpRequest} * @param uriParent the parent URI * @param sClusterName the cluster name * * @return response for a Coherence ClusterMBean */ public Map getClusterResponseMap(HttpRequest request, URI uriParent, String sClusterName) { EntityMBeanResponse response = getResponseEntityForMbean(request, getQuery(request), uriParent, getSubUri(uriParent, sClusterName), null, CHILD_LINKS); return response != null ? response.toJson() : new LinkedHashMap<>(); } /** * Return the search results for a Coherence Cluster. * * * @param request the {@link HttpRequest} * @param mapQuery the Query map * @param uriParent the parent URI of the current resource * @param uriCurrent the current URI of the resource * @param uriChild the children current URI of the resource * * @return the cluster search results */ @SuppressWarnings({"CollectionAddAllCanBeReplacedWithConstructor", "unchecked", "rawtypes"}) public Map getSearchResults(HttpRequest request, String sCluster, Map mapQuery, URI uriParent, URI uriCurrent, URI uriChild) { Map mapResponse = new LinkedHashMap<>(); EntityMBeanResponse response = getResponseEntityForMbean(request, getQuery(sCluster), uriParent, uriCurrent, mapQuery); mapResponse.putAll(response.toJson()); Object oChildren = getChildrenQuery(mapQuery); if (oChildren instanceof Map) { Map mapChildrenQuery = (Map) oChildren; addChildMbeanQueryResult(request, uriParent, uriChild, MANAGEMENT, getManagementQuery(request), mapResponse, mapChildrenQuery); addChildResourceQueryResult(request, new ServicesResource(), SERVICES, mapResponse, mapChildrenQuery, null); addChildResourceQueryResult(request, new ClusterMembersResource(), MEMBERS, mapResponse, mapChildrenQuery, null); addChildResourceQueryResult(request, new ReportersResource(), REPORTERS, mapResponse, mapChildrenQuery, null); addChildResourceQueryResult(request, new ExecutorsResource(), EXECUTORS, mapResponse, mapChildrenQuery, null); Object oJournal = mapChildrenQuery.get(JOURNAL); if (oJournal instanceof Map) { Map mapJournal = new LinkedHashMap<>(); Object oJournalChildren = getChildrenQuery((Map) oJournal); if (oJournalChildren instanceof Map) { Map mapJournalQuery = (Map) oJournalChildren; addChildResourceQueryResult(request, new JournalResource(), RAM_JOURNAL_TYPE, mapJournal, mapJournalQuery, Collections.singletonMap(JOURNAL_TYPE, RAM_JOURNAL_TYPE)); addChildResourceQueryResult(request, new JournalResource(), FLASH_JOURNAL_TYPE, mapJournal, mapJournalQuery, Collections.singletonMap(JOURNAL_TYPE, FLASH_JOURNAL_TYPE)); mapResponse.put(JOURNAL, mapJournal); } } } return mapResponse; } /** * The MBean query for ClusterMBean. * * @param request the {@link HttpRequest} * * @return the MBean query */ protected QueryBuilder getQuery(HttpRequest request) { return getQuery(getClusterName(request)); } /** * The MBean query for ClusterMBean. * * @param sCluster the Coherence cluster name * * @return the MBean query */ protected QueryBuilder getQuery(String sCluster) { return createQueryBuilder(sCluster).withBaseQuery(CLUSTER_QUERY); } /** * The MBean query for ManagementMBean. * * @param request the {@link HttpRequest} * * @return the MBean query */ protected QueryBuilder getManagementQuery(HttpRequest request) { return createQueryBuilder(request) .withBaseQuery(MANAGEMENT_QUERY); } /** * The MBean query for NodeMBean. * * @param request the {@link HttpRequest} * * @return the MBean query */ protected QueryBuilder getMembersQuery(HttpRequest request) { return createQueryBuilder(request) .withBaseQuery(CLUSTER_MEMBERS_QUERY); } /** * Return the PointToPoint MBean query for all the members. * * @param request the {@link HttpRequest} * * @return the MBean query */ protected QueryBuilder getPointToPointMBeanQuery(HttpRequest request) { return createQueryBuilder(request) .withBaseQuery(POINT_TO_POINT_QUERY) .withMember("*"); } // ----- POST API (Operations) constants -------------------------------- public static final String DUMP_CLUSTER_HEAP = "dumpClusterHeap"; /** * The REST resource name and path element to configure OpenTracing. * * @since 14.1.1.0 */ public static final String CONFIGURE_TRACING = "configureTracing"; // ----- constants ------------------------------------------------------ public static final String ROLE = "role"; /** * Constant for {@code POST} parameter {@code tracing-ratio}. * * @since 14.1.1.0 */ public static final String TRACING_RATIO = "tracingRatio"; public static final String[] CHILD_LINKS = {SERVICES, CACHES, MEMBERS, MANAGEMENT, JOURNAL, HOTCACHE, REPORTERS, WEB_APPS, EXECUTORS}; }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy