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

com.yahoo.vespa.model.builder.xml.dom.DomAdminV2Builder Maven / Gradle / Ivy

// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.model.builder.xml.dom;

import com.yahoo.config.model.ConfigModelContext;
import com.yahoo.config.model.api.ConfigServerSpec;
import com.yahoo.config.model.deploy.DeployState;
import com.yahoo.config.model.producer.AnyConfigProducer;
import com.yahoo.config.model.producer.TreeConfigProducer;
import com.yahoo.text.XML;
import com.yahoo.vespa.model.HostResource;
import com.yahoo.vespa.model.SimpleConfigProducer;
import com.yahoo.vespa.model.admin.Admin;
import com.yahoo.vespa.model.admin.Configserver;
import com.yahoo.vespa.model.admin.Logserver;
import com.yahoo.vespa.model.admin.LogserverContainer;
import com.yahoo.vespa.model.admin.LogserverContainerCluster;
import com.yahoo.vespa.model.admin.Slobrok;
import com.yahoo.vespa.model.admin.clustercontroller.ClusterControllerCluster;
import com.yahoo.vespa.model.admin.clustercontroller.ClusterControllerContainer;
import com.yahoo.vespa.model.admin.clustercontroller.ClusterControllerContainerCluster;
import com.yahoo.vespa.model.admin.otel.OpenTelemetryCollector;
import com.yahoo.vespa.model.builder.xml.dom.VespaDomBuilder.DomConfigProducerBuilderBase;
import com.yahoo.vespa.model.container.Container;
import com.yahoo.vespa.model.container.ContainerModel;
import org.w3c.dom.Element;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.logging.Level;

/**
 * Builds the admin model from a V2 admin XML tag.
 *
 * @author vegardh
 */
public class DomAdminV2Builder extends DomAdminBuilderBase {

    private static final String ATTRIBUTE_CLUSTER_CONTROLLER_STANDALONE_ZK = "standalone-zookeeper";

    private final ConfigModelContext context;

    public DomAdminV2Builder(ConfigModelContext context,
                             boolean multitenant,
                             List configServerSpecs) {
        super(context.getApplicationType(), multitenant, configServerSpecs);
        this.context = context;
    }

    private void addOtelcol(TreeConfigProducer parent, DeployState deployState, HostResource hostResource) {
        var otelcol = new OpenTelemetryCollector(parent);
        otelcol.setHostResource(hostResource);
        otelcol.initService(deployState);
    }

    @Override
    protected void doBuildAdmin(DeployState deployState, Admin admin, Element adminE) {
        List configservers = parseConfigservers(deployState, admin, adminE);
        var logserver = parseLogserver(deployState, admin, adminE);
        admin.setLogserver(logserver);
        createContainerOnLogserverHost(deployState, admin, logserver.getHostResource());
        if (deployState.featureFlags().logserverOtelCol()) {
            // for manual testing
            addOtelcol(admin, deployState, logserver.getHostResource());
        }
        admin.addConfigservers(configservers);
        admin.addSlobroks(getSlobroks(deployState, admin, XML.getChild(adminE, "slobroks")));
        if ( ! admin.multitenant())
            admin.setClusterControllers(addConfiguredClusterControllers(deployState, admin, adminE), deployState);

        addLogForwarders(new ModelElement(adminE).child("logforwarding"), admin, deployState);
        addLoggingSpecs(new ModelElement(adminE).child("logging"), admin);
    }

    private void createContainerOnLogserverHost(DeployState deployState, Admin admin, HostResource hostResource) {
        LogserverContainerCluster logServerCluster = new LogserverContainerCluster(admin, "logs", deployState);
        ContainerModel logserverClusterModel = new ContainerModel(context.withParent(admin).withId(logServerCluster.getSubId()));
        logserverClusterModel.setCluster(logServerCluster);

        LogserverContainer container = new LogserverContainer(logServerCluster, deployState);
        container.useDynamicPorts();
        container.setHostResource(hostResource);
        container.initService(deployState);
        logServerCluster.addContainer(container);
        admin.addAndInitializeService(deployState, hostResource, container);
        admin.setLogserverContainerCluster(logServerCluster);
        context.getConfigModelRepoAdder().add(logserverClusterModel);
    }

    private List parseConfigservers(DeployState deployState, Admin admin, Element adminE) {
        List configservers;
        if (multitenant)
            configservers = getConfigServersFromSpec(deployState, admin);
        else
            configservers = getConfigServers(deployState, admin, adminE);
        if (configservers.isEmpty() && ! multitenant)
            configservers = createSingleConfigServer(deployState, admin);
        if (configservers.size() % 2 == 0)
            deployState.getDeployLogger().logApplicationPackage(Level.WARNING,
                                                                "An even number (" + configservers.size() +
                                                                ") of config servers have been configured. " +
                                                                "This is discouraged, see doc for configuration server ");
        return configservers;
    }

    private Logserver parseLogserver(DeployState deployState, Admin admin, Element adminE) {
        Element logserverE = XML.getChild(adminE, "logserver");
        if (logserverE == null) {
            var adminserverE = XML.getChild(adminE, "adminserver");
            logserverE = adminserverE != null ? adminserverE : adminE;
        }
        return new LogserverBuilder().build(deployState, admin, logserverE);
    }

    private ClusterControllerContainerCluster addConfiguredClusterControllers(DeployState deployState,
                                                                              TreeConfigProducer parent,
                                                                              Element admin) {
        Element controllersElements = XML.getChild(admin, "cluster-controllers");
        if (controllersElements == null) return null;

        List controllers = XML.getChildren(controllersElements, "cluster-controller");
        if (controllers.isEmpty()) return null;

        boolean standaloneZooKeeper = "true".equals(controllersElements.getAttribute(ATTRIBUTE_CLUSTER_CONTROLLER_STANDALONE_ZK)) || multitenant;
        if (standaloneZooKeeper) {
            parent = new ClusterControllerCluster(parent, "standalone", deployState);
        }
        var cluster = new ClusterControllerContainerCluster(parent,
                                                            "cluster-controllers",
                                                            "cluster-controllers",
                                                            deployState);

        List containers = new ArrayList<>();

        for (Element controller : controllers) {
            ClusterControllerContainer clusterController = new ClusterControllerBuilder(containers.size(), standaloneZooKeeper).build(deployState, cluster, controller);
            containers.add(clusterController);
        }

        cluster.addContainers(containers);
        return cluster;
    }

    private List getConfigServers(DeployState deployState, TreeConfigProducer parent, Element adminE) {
        Element configserversE = XML.getChild(adminE, "configservers");
        if (configserversE == null) {
            Element adminserver = XML.getChild(adminE, "adminserver");
            if (adminserver == null) {
                return createSingleConfigServer(deployState, parent);
            } else {
                SimpleConfigProducer configServers = new SimpleConfigProducer<>(parent, "configservers");
                return List.of(new ConfigserverBuilder(0, configServerSpecs).build(deployState, configServers, adminserver));
            }
        }
        else {
            SimpleConfigProducer configServers = new SimpleConfigProducer<>(parent, "configservers");
            List configservers = new ArrayList<>();
            int i = 0;
            for (Element configserverE : XML.getChildren(configserversE, "configserver"))
                configservers.add(new ConfigserverBuilder(i++, configServerSpecs).build(deployState, configServers, configserverE));
            return configservers;
        }
    }

    /** Fallback when no config server is specified */
    private List createSingleConfigServer(DeployState deployState, TreeConfigProducer parent) {
        SimpleConfigProducer configServers = new SimpleConfigProducer<>(parent, "configservers");
        Configserver configServer = new Configserver(configServers, "configserver", Configserver.defaultRpcPort);
        configServer.setHostResource(parent.hostSystem().getHost(Container.SINGLENODE_CONTAINER_SERVICESPEC));
        configServer.initService(deployState);
        return List.of(configServer);
    }

    private List getSlobroks(DeployState deployState, TreeConfigProducer parent, Element slobroksE) {
        List slobroks = new ArrayList<>();
        if (slobroksE != null)
            slobroks = getExplicitSlobrokSetup(deployState, parent, slobroksE);
        return slobroks;
    }

    private List getExplicitSlobrokSetup(DeployState deployState, TreeConfigProducer parent, Element slobroksE) {
        List slobroks = new ArrayList<>();
        int i = 0;
        for (Element e : XML.getChildren(slobroksE, "slobrok"))
            slobroks.add(new SlobrokBuilder(i++).build(deployState, parent, e));
        return slobroks;
    }

    private static class LogserverBuilder extends DomConfigProducerBuilderBase {
        public LogserverBuilder() {
        }

        @Override
        protected Logserver doBuild(DeployState deployState, TreeConfigProducer parent, Element producerSpec) {
            return new Logserver(parent);
        }
    }

    private static class ConfigserverBuilder extends DomConfigProducerBuilderBase {
        private final int i;
        private final int rpcPort;

        public ConfigserverBuilder(int i, List configServerSpec) {
            this.i = i;
            Objects.requireNonNull(configServerSpec);
            if (configServerSpec.size() > 0)
                this.rpcPort = configServerSpec.get(0).getConfigServerPort();
            else
                this.rpcPort = Configserver.defaultRpcPort;
        }

        @Override
        protected Configserver doBuild(DeployState deployState, TreeConfigProducer parent, Element spec) {
            var configServer = new Configserver(parent, "configserver." + i, rpcPort);
            configServer.setProp("index", i);
            return configServer;
        }
    }

    private static class SlobrokBuilder extends DomConfigProducerBuilderBase {

        int i;

        public SlobrokBuilder(int i) {
            this.i = i;
        }

        @Override
        protected Slobrok doBuild(DeployState deployState, TreeConfigProducer parent, Element spec) {
            return new Slobrok(parent, i, deployState.featureFlags());
        }

    }

    private static class ClusterControllerBuilder extends DomConfigProducerBuilderBase {
        int i;
        boolean runStandaloneZooKeeper;

        public ClusterControllerBuilder(int i, boolean runStandaloneZooKeeper) {
            this.i = i;
            this.runStandaloneZooKeeper = runStandaloneZooKeeper;
        }

        @Override
        protected ClusterControllerContainer doBuild(DeployState deployState, TreeConfigProducer parent, Element spec) {
            return new ClusterControllerContainer(parent, i, runStandaloneZooKeeper, deployState, false);
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy