Package com.netflix.exhibitor.core.rest

Source Code of com.netflix.exhibitor.core.rest.ConfigResource

/*
* Copyright 2012 Netflix, Inc.
*
*    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.netflix.exhibitor.core.rest;

import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.hash.Hashing;
import com.netflix.exhibitor.core.backup.BackupConfigSpec;
import com.netflix.exhibitor.core.config.ConfigManager;
import com.netflix.exhibitor.core.config.EncodedConfigParser;
import com.netflix.exhibitor.core.config.InstanceConfig;
import com.netflix.exhibitor.core.config.IntConfigs;
import com.netflix.exhibitor.core.config.PseudoLock;
import com.netflix.exhibitor.core.config.StringConfigs;
import com.netflix.exhibitor.core.entities.Result;
import com.netflix.exhibitor.core.state.FourLetterWord;
import com.netflix.exhibitor.core.state.ServerList;
import com.netflix.exhibitor.core.state.ServerSpec;
import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.node.JsonNodeFactory;
import org.codehaus.jackson.node.ObjectNode;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.EntityTag;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Request;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ContextResolver;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Path("exhibitor/v1/config")
public class ConfigResource
{
    private final UIContext context;

    private static final String CANT_UPDATE_CONFIG_MESSAGE = "It appears that another process has updated the config. Your change was not committed.";

    public ConfigResource(@Context ContextResolver<UIContext> resolver)
    {
        context = resolver.getContext(UIContext.class);
    }

    @Path("get-state")
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Response getSystemState(@Context Request request) throws Exception
    {
        InstanceConfig              config = context.getExhibitor().getConfigManager().getConfig();

        String                      response = new FourLetterWord(FourLetterWord.Word.RUOK, config, context.getExhibitor().getConnectionTimeOutMs()).getResponse();
        ServerList                  serverList = new ServerList(config.getString(StringConfigs.SERVERS_SPEC));
        ServerSpec                  us = Iterables.find(serverList.getSpecs(), ServerList.isUs(context.getExhibitor().getThisJVMHostname()), null);

        ObjectNode                  mainNode = JsonNodeFactory.instance.objectNode();
        ObjectNode                  configNode = JsonNodeFactory.instance.objectNode();
        ObjectNode                  controlPanelNode = JsonNodeFactory.instance.objectNode();

        mainNode.put("version", context.getExhibitor().getVersion());
        mainNode.put("running", "imok".equals(response));
        mainNode.put("backupActive", context.getExhibitor().getBackupManager().isActive());
        mainNode.put("standaloneMode", context.getExhibitor().getConfigManager().isStandaloneMode());
        mainNode.put("extraHeadingText", context.getExhibitor().getExtraHeadingText());
        mainNode.put("nodeMutationsAllowed", context.getExhibitor().nodeMutationsAllowed());

        configNode.put("rollInProgress", context.getExhibitor().getConfigManager().isRolling());
        configNode.put("rollStatus", context.getExhibitor().getConfigManager().getRollingConfigState().getRollingStatus());
        configNode.put("rollPercentDone", context.getExhibitor().getConfigManager().getRollingConfigState().getRollingPercentDone());

        configNode.put("hostname", context.getExhibitor().getThisJVMHostname());
        configNode.put("serverId", (us != null) ? us.getServerId() : -1);
        for ( StringConfigs c : StringConfigs.values() )
        {
            configNode.put(fixName(c), config.getString(c));
        }
        for ( IntConfigs c : IntConfigs.values() )
        {
            String fixedName = fixName(c);
            int value = config.getInt(c);

            configNode.put(fixedName, value);
        }

        EncodedConfigParser     zooCfgParser = new EncodedConfigParser(config.getString(StringConfigs.ZOO_CFG_EXTRA));
        ObjectNode              zooCfgNode = JsonNodeFactory.instance.objectNode();
        for ( EncodedConfigParser.FieldValue fv : zooCfgParser.getFieldValues() )
        {
            zooCfgNode.put(fv.getField(), fv.getValue());
        }
        configNode.put("zooCfgExtra", zooCfgNode);

        if ( context.getExhibitor().getBackupManager().isActive() )
        {
            ObjectNode          backupExtraNode = JsonNodeFactory.instance.objectNode();
            EncodedConfigParser parser = context.getExhibitor().getBackupManager().getBackupConfigParser();
            List<BackupConfigSpec> configs = context.getExhibitor().getBackupManager().getConfigSpecs();
            for ( BackupConfigSpec c : configs )
            {
                String value = parser.getValue(c.getKey());
                backupExtraNode.put(c.getKey(), (value != null) ? value : "");
            }
            configNode.put("backupExtra", backupExtraNode);
        }

        configNode.put("controlPanel", controlPanelNode);
        mainNode.put("config", configNode);

        String      json = JsonUtil.writeValueAsString(mainNode);
        EntityTag   tag = new EntityTag(Hashing.sha1().hashString(json).toString());

        Response.ResponseBuilder    builder = request.evaluatePreconditions(tag);
        if ( builder == null )
        {
            builder = Response.ok(json).tag(tag);
        }

        return builder.build();
    }

    @Path("rollback-rolling")
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Response rollbackRolling() throws Exception
    {
        context.getExhibitor().getConfigManager().cancelRollingConfig(ConfigManager.CancelMode.ROLLBACK);
        return Response.ok(new Result("OK", true)).build();
    }

    @Path("force-commit-rolling")
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Response forceCommitRolling() throws Exception
    {
        context.getExhibitor().getConfigManager().cancelRollingConfig(ConfigManager.CancelMode.FORCE_COMMIT);
        return Response.ok(new Result("OK", true)).build();
    }

    @Path("set-rolling")
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public Response setConfigRolling(String newConfigJson) throws Exception
    {
        InstanceConfig  wrapped = parseToConfig(newConfigJson);

        Result  result = null;
        try
        {
            PseudoLock  lock = context.getExhibitor().getConfigManager().newConfigBasedLock();
            try
            {
                if ( lock.lock(context.getExhibitor().getLog(), 10, TimeUnit.SECONDS) )  // TODO consider making configurable in the future
                {
                    if ( context.getExhibitor().getConfigManager().startRollingConfig(wrapped, null) )
                    {
                        result = new Result("OK", true);
                    }
                }
            }
            finally
            {
                lock.unlock();
            }

            if ( result == null )
            {
                result = new Result("Another process has updated the config.", false);
            }
            context.getExhibitor().resetLocalConnection();
        }
        catch ( Exception e )
        {
            result = new Result(e);
        }

        return Response.ok(result).build();
    }

    @Path("set")
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public Response setConfig(String newConfigJson) throws Exception
    {
        InstanceConfig wrapped = parseToConfig(newConfigJson);

        Result  result = null;
        try
        {
            PseudoLock  lock = context.getExhibitor().getConfigManager().newConfigBasedLock();
            try
            {
                if ( lock.lock(context.getExhibitor().getLog(), 10, TimeUnit.SECONDS) )  // TODO consider making configurable in the future
                {
                    if ( context.getExhibitor().getConfigManager().updateConfig(wrapped) )
                    {
                        result = new Result("OK", true);
                    }
                }
            }
            finally
            {
                lock.unlock();
            }

            if ( result == null )
            {
                result = new Result(CANT_UPDATE_CONFIG_MESSAGE, false);
            }
            context.getExhibitor().resetLocalConnection();
        }
        catch ( Exception e )
        {
            result = new Result(e);
        }

        return Response.ok(result).build();
    }

    private InstanceConfig parseToConfig(String newConfigJson) throws IOException
    {
        ObjectMapper mapper = new ObjectMapper();
        final JsonNode tree = mapper.readTree(mapper.getJsonFactory().createJsonParser(newConfigJson));

        String                backupExtraValue = "";
        if ( tree.get("backupExtra") != null )
        {
            List<EncodedConfigParser.FieldValue>    values = Lists.newArrayList();
            JsonNode                backupExtra = tree.get("backupExtra");
            Iterator<String> fieldNames = backupExtra.getFieldNames();
            while ( fieldNames.hasNext() )
            {
                String      name = fieldNames.next();
                String      value = backupExtra.get(name).getTextValue();
                values.add(new EncodedConfigParser.FieldValue(name, value));
            }
            backupExtraValue = new EncodedConfigParser(values).toEncoded();
        }

        List<EncodedConfigParser.FieldValue>    zooCfgValues = Lists.newArrayList();
        JsonNode                zooCfgExtra = tree.get("zooCfgExtra");
        Iterator<String>        fieldNames = zooCfgExtra.getFieldNames();
        while ( fieldNames.hasNext() )
        {
            String      name = fieldNames.next();
            String      value = zooCfgExtra.get(name).getTextValue();
            zooCfgValues.add(new EncodedConfigParser.FieldValue(name, value));
        }
        final String          zooCfgExtraValue = new EncodedConfigParser(zooCfgValues).toEncoded();

        final String          finalBackupExtraValue = backupExtraValue;
        return new InstanceConfig()
        {
            @Override
            public String getString(StringConfigs config)
            {
                switch ( config )
                {
                    case BACKUP_EXTRA:
                    {
                        return finalBackupExtraValue;
                    }

                    case ZOO_CFG_EXTRA:
                    {
                        return zooCfgExtraValue;
                    }

                    default:
                    {
                        // NOP
                        break;
                    }
                }

                JsonNode node = tree.get(fixName(config));
                if ( node == null )
                {
                    return "";
                }
                return node.getTextValue();
            }

            @Override
            public int getInt(IntConfigs config)
            {
                JsonNode node = tree.get(fixName(config));
                if ( node == null )
                {
                    return 0;
                }
                try
                {
                    return Integer.parseInt(node.getTextValue());
                }
                catch ( NumberFormatException e )
                {
                    // ignore
                }
                return 0;
            }
        };
    }

    static String fixName(Enum c)
    {
        StringBuilder   str = new StringBuilder();
        String[]        parts = c.name().toLowerCase().split("_");
        for ( String p : parts )
        {
            if ( p.length() > 0 )
            {
                if ( str.length() > 0 )
                {
                    str.append(p.substring(0, 1).toUpperCase());
                    if ( p.length() > 1 )
                    {
                        str.append(p.substring(1));
                    }
                }
                else
                {
                    str.append(p);
                }
            }
        }
        return str.toString();
    }
}
TOP

Related Classes of com.netflix.exhibitor.core.rest.ConfigResource

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.