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 - 2025 Weber Informatics LLC | Privacy Policy