diff options
author | gjoranv <gv@verizonmedia.com> | 2019-04-04 11:00:19 +0200 |
---|---|---|
committer | gjoranv <gv@verizonmedia.com> | 2019-05-02 16:14:08 +0200 |
commit | 680f2e880caacc040a0e766db890033f0181f6c2 (patch) | |
tree | 6d2057b3776f2aa8cd9273de1c3699bff201e2dd /config-model | |
parent | 099bde8f27218e97c5da33ce8bde5a796a1c0f5a (diff) |
Install metrics-proxy on MetricsProxyContainerClusters.
* Add metrics-proxy dep to config-model.
* Install metrics-proxy bundle for MPConatinerClusters.
* Add metrics-proxy components and generate configs.
* Put node specific components to the Container, not the cluster.
Diffstat (limited to 'config-model')
9 files changed, 405 insertions, 7 deletions
diff --git a/config-model/pom.xml b/config-model/pom.xml index 715718f8bb5..0e5769e64e5 100644 --- a/config-model/pom.xml +++ b/config-model/pom.xml @@ -96,6 +96,12 @@ </dependency> <dependency> <groupId>com.yahoo.vespa</groupId> + <artifactId>metrics-proxy</artifactId> + <version>${project.version}</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>com.yahoo.vespa</groupId> <artifactId>container-disc</artifactId> <version>${project.version}</version> <scope>provided</scope> diff --git a/config-model/src/main/java/com/yahoo/vespa/model/admin/Admin.java b/config-model/src/main/java/com/yahoo/vespa/model/admin/Admin.java index dd27dd176e0..e0956097c84 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/admin/Admin.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/admin/Admin.java @@ -207,7 +207,7 @@ public class Admin extends AbstractConfigProducer implements Serializable { var metricsProxyCluster = new MetricsProxyContainerCluster(this, "metrics", deployState); int index = 0; for (var host : hosts) { - var container = new MetricsProxyContainer(metricsProxyCluster, index++); + var container = new MetricsProxyContainer(metricsProxyCluster, index++, deployState.isHosted()); addAndInitializeService(deployState.getDeployLogger(), host, container); metricsProxyCluster.addContainer(container); } diff --git a/config-model/src/main/java/com/yahoo/vespa/model/admin/metricsproxy/ConsumersConfigGenerator.java b/config-model/src/main/java/com/yahoo/vespa/model/admin/metricsproxy/ConsumersConfigGenerator.java new file mode 100644 index 00000000000..2df4008214a --- /dev/null +++ b/config-model/src/main/java/com/yahoo/vespa/model/admin/metricsproxy/ConsumersConfigGenerator.java @@ -0,0 +1,88 @@ +/* + * Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + */ + +package com.yahoo.vespa.model.admin.metricsproxy; + +import ai.vespa.metricsproxy.core.ConsumersConfig.Consumer; +import com.yahoo.vespa.model.admin.monitoring.Metric; +import com.yahoo.vespa.model.admin.monitoring.MetricSet; +import com.yahoo.vespa.model.admin.monitoring.MetricsConsumer; + +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import static com.yahoo.vespa.model.admin.monitoring.DefaultMetricsConsumer.VESPA_CONSUMER_ID; +import static com.yahoo.vespa.model.admin.monitoring.DefaultMetricsConsumer.getDefaultMetricsConsumer; + +/** + * Helper class to generate config for metrics consumers. + * + * @author gjoranv + */ +class ConsumersConfigGenerator { + + /** + * @param userConsumers The consumers set up by the user in services.xml + * @return A list of consumer builders (a mapping from consumer to its metrics) + */ + static List<Consumer.Builder> generate(Map<String, MetricsConsumer> userConsumers) { + // Normally, the user given consumers should not contain VESPA_CONSUMER_ID, but it's allowed for some internally used applications. + var allConsumers = new LinkedHashMap<>(userConsumers); + allConsumers.put(VESPA_CONSUMER_ID, combineConsumers(getDefaultMetricsConsumer(), allConsumers.get(VESPA_CONSUMER_ID))); + + return allConsumers.values().stream() + .map(ConsumersConfigGenerator::toConsumerBuilder) + .collect(Collectors.toList()); + } + + /* + * Returns a new consumer that is a combination of the two given consumers + * (ignoring the id of the consumers' metric sets). + * If a metric with the same id exists in both consumers, output name and + * dimensions from the 'overriding' consumer is used, but dimensions from 'original' + * are added if they don't exist in 'overriding'. + */ + private static MetricsConsumer combineConsumers(MetricsConsumer original, MetricsConsumer overriding) { + if (overriding == null) return original; + return addMetrics(original, overriding.getMetrics()); + } + + private static MetricsConsumer addMetrics(MetricsConsumer original, Map<String, Metric> metrics) { + Map<String, Metric> combinedMetrics = new LinkedHashMap<>(original.getMetrics()); + metrics.forEach((name, newMetric) -> + combinedMetrics.put(name, combineMetrics(original.getMetrics().get(name), newMetric))); + + return new MetricsConsumer(original.getId(), + new MetricSet(original.getMetricSet().getId(), combinedMetrics.values())); + } + + private static Metric combineMetrics(@Nullable Metric original, Metric newMetric) { + return original != null ? newMetric.addDimensionsFrom(original) : newMetric; + } + + private static Consumer.Builder toConsumerBuilder(MetricsConsumer consumer) { + Consumer.Builder builder = new Consumer.Builder().name(consumer.getId()); + consumer.getMetrics().values().forEach(metric -> builder.metric(toConsumerMetricBuilder(metric))); + return builder; + } + + private static Consumer.Metric.Builder toConsumerMetricBuilder(Metric metric) { + Consumer.Metric.Builder builder = new Consumer.Metric.Builder().name(metric.name) + .outputname(metric.outputName) + .description(metric.description); + metric.dimensions.forEach((name, value) -> builder.dimension(toMetricDimensionBuilder(name, value))); + return builder; + } + + private static Consumer.Metric.Dimension.Builder toMetricDimensionBuilder(String name, String value) { + return new Consumer.Metric.Dimension.Builder() + .key(name) + .value(value); + } + +} diff --git a/config-model/src/main/java/com/yahoo/vespa/model/admin/metricsproxy/MetricsProxyContainer.java b/config-model/src/main/java/com/yahoo/vespa/model/admin/metricsproxy/MetricsProxyContainer.java index 742196c91d1..5aef2a2db1d 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/admin/metricsproxy/MetricsProxyContainer.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/admin/metricsproxy/MetricsProxyContainer.java @@ -1,22 +1,62 @@ +/* + * Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + */ + package com.yahoo.vespa.model.admin.metricsproxy; +import ai.vespa.metricsproxy.metric.dimensions.NodeDimensions; +import ai.vespa.metricsproxy.metric.dimensions.NodeDimensionsConfig; +import ai.vespa.metricsproxy.rpc.RpcConnector; +import ai.vespa.metricsproxy.rpc.RpcConnectorConfig; +import ai.vespa.metricsproxy.service.VespaServices; +import ai.vespa.metricsproxy.service.VespaServicesConfig; import com.yahoo.config.model.api.container.ContainerServiceType; import com.yahoo.config.model.producer.AbstractConfigProducer; +import com.yahoo.config.provision.ClusterMembership; import com.yahoo.vespa.model.container.Container; +import java.util.LinkedHashMap; +import java.util.Map; + import static com.yahoo.config.model.api.container.ContainerServiceType.METRICS_PROXY_CONTAINER; +import static com.yahoo.vespa.model.admin.metricsproxy.MetricsProxyContainer.NodeDimensionNames.CANONICAL_FLAVOR; +import static com.yahoo.vespa.model.admin.metricsproxy.MetricsProxyContainer.NodeDimensionNames.CLUSTER_ID; +import static com.yahoo.vespa.model.admin.metricsproxy.MetricsProxyContainer.NodeDimensionNames.CLUSTER_TYPE; +import static com.yahoo.vespa.model.admin.metricsproxy.MetricsProxyContainer.NodeDimensionNames.FLAVOR; +import static com.yahoo.vespa.model.admin.metricsproxy.MetricsProxyContainerCluster.METRICS_PROXY_BUNDLE_NAME; /** * Container running a metrics proxy. * * @author gjoranv */ -public class MetricsProxyContainer extends Container { +public class MetricsProxyContainer extends Container implements + NodeDimensionsConfig.Producer, + RpcConnectorConfig.Producer, + VespaServicesConfig.Producer +{ + + static final class NodeDimensionNames { + static final String FLAVOR = "flavor"; + static final String CANONICAL_FLAVOR = "canonicalFlavor"; + static final String CLUSTER_TYPE = "clustertype"; + static final String CLUSTER_ID = "clusterid"; + } + + private final boolean isHostedVespa; - public MetricsProxyContainer(AbstractConfigProducer parent, int index) { + public MetricsProxyContainer(AbstractConfigProducer parent, int index, boolean isHostedVespa) { super(parent, "" + index, index); + this.isHostedVespa = isHostedVespa; setProp("clustertype", "admin"); setProp("index", String.valueOf(index)); + addNodeSpecificComponents(); + } + + private void addNodeSpecificComponents() { + addMetricsProxyComponent(NodeDimensions.class); + addMetricsProxyComponent(RpcConnector.class); + addMetricsProxyComponent(VespaServices.class); } @Override @@ -45,4 +85,36 @@ public class MetricsProxyContainer extends Container { portsMeta.on(numHttpServerPorts).tag("rpc").tag("metrics"); } + @Override + public void getConfig(RpcConnectorConfig.Builder builder) { + builder.port(getRelativePort(0)); + } + + @Override + public void getConfig(VespaServicesConfig.Builder builder) { + builder.service.addAll(VespaServicesConfigGenerator.generate(getHostResource().getServices())); + } + + @Override + public void getConfig(NodeDimensionsConfig.Builder builder) { + Map<String, String> dimensions = new LinkedHashMap<>(); + if (isHostedVespa) { + getHostResource().getFlavor().ifPresent(flavor -> { + dimensions.put(FLAVOR, flavor.name()); + dimensions.put(CANONICAL_FLAVOR, flavor.canonicalName()); + }); + + getHostResource().primaryClusterMembership().map(ClusterMembership::cluster).ifPresent(cluster -> { + dimensions.put(CLUSTER_TYPE, cluster.type().name()); + dimensions.put(CLUSTER_ID, cluster.id().value()); + }); + + builder.dimensions(dimensions); + } + } + + private void addMetricsProxyComponent(Class<?> componentClass) { + addSimpleComponent(componentClass.getName(), null, METRICS_PROXY_BUNDLE_NAME); + } + } diff --git a/config-model/src/main/java/com/yahoo/vespa/model/admin/metricsproxy/MetricsProxyContainerCluster.java b/config-model/src/main/java/com/yahoo/vespa/model/admin/metricsproxy/MetricsProxyContainerCluster.java index 437df42d531..d9a969ab7c9 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/admin/metricsproxy/MetricsProxyContainerCluster.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/admin/metricsproxy/MetricsProxyContainerCluster.java @@ -1,23 +1,183 @@ +/* + * Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + */ + package com.yahoo.vespa.model.admin.metricsproxy; +import ai.vespa.metricsproxy.core.MetricsConsumers; +import ai.vespa.metricsproxy.core.ConsumersConfig; +import ai.vespa.metricsproxy.core.MetricsManager; +import ai.vespa.metricsproxy.metric.ExternalMetrics; +import ai.vespa.metricsproxy.core.VespaMetrics; +import ai.vespa.metricsproxy.metric.dimensions.ApplicationDimensions; +import ai.vespa.metricsproxy.metric.dimensions.ApplicationDimensionsConfig; +import ai.vespa.metricsproxy.rpc.RpcServer; +import ai.vespa.metricsproxy.core.MonitoringConfig; +import ai.vespa.metricsproxy.service.SystemPollerProvider; +import ai.vespa.metricsproxy.service.ConfigSentinelClient; import com.yahoo.config.model.deploy.DeployState; import com.yahoo.config.model.producer.AbstractConfigProducer; +import com.yahoo.config.model.producer.AbstractConfigProducerRoot; +import com.yahoo.config.provision.ApplicationId; +import com.yahoo.config.provision.Zone; +import com.yahoo.vespa.model.VespaModel; +import com.yahoo.vespa.model.admin.Admin; +import com.yahoo.vespa.model.admin.monitoring.MetricsConsumer; +import com.yahoo.vespa.model.admin.monitoring.Monitoring; +import com.yahoo.vespa.model.admin.monitoring.builder.Metrics; import com.yahoo.vespa.model.container.ContainerCluster; +import java.nio.file.Path; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Optional; +import java.util.logging.Logger; + +import static com.yahoo.vespa.model.admin.metricsproxy.MetricsProxyContainerCluster.AppDimensionNames.APPLICATION; +import static com.yahoo.vespa.model.admin.metricsproxy.MetricsProxyContainerCluster.AppDimensionNames.APPLICATION_ID; +import static com.yahoo.vespa.model.admin.metricsproxy.MetricsProxyContainerCluster.AppDimensionNames.INSTANCE; +import static com.yahoo.vespa.model.admin.metricsproxy.MetricsProxyContainerCluster.AppDimensionNames.LEGACY_APPLICATION; +import static com.yahoo.vespa.model.admin.metricsproxy.MetricsProxyContainerCluster.AppDimensionNames.TENANT; +import static com.yahoo.vespa.model.admin.metricsproxy.MetricsProxyContainerCluster.AppDimensionNames.ZONE; +import static com.yahoo.vespa.model.container.xml.BundleMapper.JarSuffix.JAR_WITH_DEPS; +import static com.yahoo.vespa.model.container.xml.BundleMapper.bundlePathFromName; + /** * Container cluster for metrics proxy containers. * * @author gjoranv */ -public class MetricsProxyContainerCluster extends ContainerCluster<MetricsProxyContainer> { +public class MetricsProxyContainerCluster extends ContainerCluster<MetricsProxyContainer> implements + ApplicationDimensionsConfig.Producer, + ConsumersConfig.Producer, + MonitoringConfig.Producer +{ + public static final Logger log = Logger.getLogger(MetricsProxyContainerCluster.class.getName()); + + private static final String METRICS_PROXY_NAME = "metrics-proxy"; + private static final Path METRICS_PROXY_BUNDLE_FILE = bundlePathFromName(METRICS_PROXY_NAME, JAR_WITH_DEPS); + static final String METRICS_PROXY_BUNDLE_NAME = "com.yahoo.vespa." + METRICS_PROXY_NAME; + + static final String DEFAULT_NAME_IN_MONITORING_SYSTEM = "vespa"; + static final int DEFAULT_MONITORING_INTERVAL = 1; + + static final class AppDimensionNames { + static final String ZONE = "zone"; + static final String APPLICATION_ID = "applicationId"; // tenant.app.instance + static final String TENANT = "tenantName"; + static final String APPLICATION = "applicationName"; + static final String INSTANCE = "instanceName"; + static final String LEGACY_APPLICATION = "app"; // app.instance + } + + private final AbstractConfigProducer<?> parent; + private final ApplicationId applicationId; public MetricsProxyContainerCluster(AbstractConfigProducer<?> parent, String name, DeployState deployState) { super(parent, name, name, deployState); + this.parent = parent; + applicationId = deployState.getProperties().applicationId(); + setRpcServerEnabled(false); addDefaultHandlersExceptStatus(); + + addPlatformBundle(METRICS_PROXY_BUNDLE_FILE); + addClusterComponents(); + } + + private void addClusterComponents() { + addMetricsProxyComponent(ApplicationDimensions.class); + addMetricsProxyComponent(ConfigSentinelClient.class); + addMetricsProxyComponent(ExternalMetrics.class); + addMetricsProxyComponent(MetricsConsumers.class); + addMetricsProxyComponent(MetricsManager.class); + addMetricsProxyComponent(RpcServer.class); + addMetricsProxyComponent(SystemPollerProvider.class); + addMetricsProxyComponent(VespaMetrics.class); } @Override protected void doPrepare(DeployState deployState) { } + @Override + public void getConfig(MonitoringConfig.Builder builder) { + builder.systemName(getSystemName()) + .intervalMinutes(getIntervalMinutes()); + } + + @Override + public void getConfig(ConsumersConfig.Builder builder) { + builder.consumer.addAll(ConsumersConfigGenerator.generate(getUserMetricsConsumers())); + } + + @Override + public void getConfig(ApplicationDimensionsConfig.Builder builder) { + if (isHostedVespa()) { + builder.dimensions(applicationDimensions()); + } + } + + // Returns the metricConsumers from services.xml + private Map<String, MetricsConsumer> getUserMetricsConsumers() { + return getAdmin() + .map(this::consumersInAdmin) + .orElse(Collections.emptyMap()); + } + + private Map<String, MetricsConsumer> consumersInAdmin(Admin admin) { + Metrics metrics = admin.getUserMetrics(); + return metrics.getConsumers(); + } + + private Optional<Admin> getAdmin() { + if (parent != null) { + AbstractConfigProducerRoot r = parent.getRoot(); + if (r instanceof VespaModel) { + VespaModel model = (VespaModel) r; + return Optional.ofNullable(model.getAdmin()); + } + } + return Optional.empty(); + } + + private String getSystemName() { + Monitoring monitoring = getMonitoringService(); + if (monitoring != null && ! monitoring.getClustername().equals("")) + return monitoring.getClustername(); + return DEFAULT_NAME_IN_MONITORING_SYSTEM; + } + + private int getIntervalMinutes() { + Monitoring monitoring = getMonitoringService(); + if (monitoring != null && monitoring.getInterval() != null) { + return monitoring.getInterval(); + } + return DEFAULT_MONITORING_INTERVAL; + } + + private void addMetricsProxyComponent(Class<?> componentClass) { + addSimpleComponent(componentClass.getName(), null, METRICS_PROXY_BUNDLE_NAME); + } + + private Map<String, String> applicationDimensions() { + Map<String, String> dimensions = new LinkedHashMap<>(); + dimensions.put(ZONE, zoneString(getZone())); + dimensions.put(APPLICATION_ID, serializeWithDots(applicationId)); + dimensions.put(TENANT, applicationId.tenant().value()); + dimensions.put(APPLICATION, applicationId.application().value()); + dimensions.put(INSTANCE, applicationId.instance().value()); + dimensions.put(LEGACY_APPLICATION, applicationId.application().value() + "." + applicationId.instance().value()); + return dimensions; + } + + // ApplicationId uses ':' as separator. + private static String serializeWithDots(ApplicationId applicationId) { + return applicationId.serializedForm().replace(':', '.'); + } + + static String zoneString(Zone zone) { + return zone.environment().value() + "." + zone.region().value(); + } + } diff --git a/config-model/src/main/java/com/yahoo/vespa/model/admin/metricsproxy/VespaServicesConfigGenerator.java b/config-model/src/main/java/com/yahoo/vespa/model/admin/metricsproxy/VespaServicesConfigGenerator.java new file mode 100644 index 00000000000..08a81fad0a3 --- /dev/null +++ b/config-model/src/main/java/com/yahoo/vespa/model/admin/metricsproxy/VespaServicesConfigGenerator.java @@ -0,0 +1,46 @@ +/* + * Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + */ + +package com.yahoo.vespa.model.admin.metricsproxy; + +import ai.vespa.metricsproxy.service.VespaServicesConfig; +import com.yahoo.vespa.model.Service; + +import java.util.List; +import java.util.stream.Collectors; + +/** + * @author gjoranv + */ +public class VespaServicesConfigGenerator { + + public static List<VespaServicesConfig.Service.Builder> generate(List<Service> services) { + return services.stream() + .filter(VespaServicesConfigGenerator::doIncludeServiceMetrics) + .map(VespaServicesConfigGenerator::toServiceBuilder) + .collect(Collectors.toList()); + } + + private static boolean doIncludeServiceMetrics(Service s) { + return s.getStartupCommand() != null || s.getServiceType().equals("configserver") || s.getServiceType().equals("config-sentinel"); + } + + private static VespaServicesConfig.Service.Builder toServiceBuilder(Service service) { + VespaServicesConfig.Service.Builder builder = new VespaServicesConfig.Service.Builder() + .configId(service.getConfigId()) + .name(service.getServiceName()) + .port(service.getHealthPort()) + .healthport(service.getHealthPort()); + + service.getDefaultMetricDimensions().forEach((name, value) -> builder.dimension(toServiceDimensionBuilder(name, value))); + return builder; + } + + private static VespaServicesConfig.Service.Dimension.Builder toServiceDimensionBuilder(String name, String value) { + return new VespaServicesConfig.Service.Dimension.Builder() + .key(name) + .value(value); + } + +} diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/Container.java b/config-model/src/main/java/com/yahoo/vespa/model/container/Container.java index f449feb5fc1..f2bd67cdd81 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/container/Container.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/container/Container.java @@ -10,6 +10,7 @@ import com.yahoo.container.QrConfig; import com.yahoo.container.core.ContainerHttpConfig; import com.yahoo.container.jdisc.ContainerMbusConfig; import com.yahoo.container.jdisc.JdiscBindingsConfig; +import com.yahoo.osgi.provider.model.ComponentModel; import com.yahoo.search.config.QrStartConfig; import com.yahoo.vespa.defaults.Defaults; import com.yahoo.vespa.model.AbstractService; @@ -36,6 +37,10 @@ import static com.yahoo.container.QrConfig.Filedistributor; import static com.yahoo.container.QrConfig.Rpc; /** + * Note about components: In general, all components should belong to the cluster and not the container. However, + * components that need node specific config must be added at the container level, along with the node-specific + * parts of the config generation (getConfig). + * * @author gjoranv * @author Einar M R Rosenvinge * @author Tony Vaagenes @@ -107,11 +112,15 @@ public abstract class Container extends AbstractService implements return components; } - public void addComponent(Component c) { + public final void addComponent(Component c) { components.addComponent(c); } - public void addHandler(Handler h) { + public final void addSimpleComponent(String idSpec, String classSpec, String bundleSpec) { + addComponent(new SimpleComponent(new ComponentModel(idSpec, classSpec, bundleSpec))); + } + + public final void addHandler(Handler h) { handlers.addComponent(h); } diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/ContainerCluster.java b/config-model/src/main/java/com/yahoo/vespa/model/container/ContainerCluster.java index ad087288799..1f0c3d6f84e 100755 --- a/config-model/src/main/java/com/yahoo/vespa/model/container/ContainerCluster.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/container/ContainerCluster.java @@ -200,7 +200,7 @@ public abstract class ContainerCluster<CONTAINER extends Container> addVipHandler(); } - public void addDefaultHandlersExceptStatus() { + public final void addDefaultHandlersExceptStatus() { addDefaultRootHandler(); addMetricStateHandler(); addApplicationStatusHandler(); diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/xml/BundleMapper.java b/config-model/src/main/java/com/yahoo/vespa/model/container/xml/BundleMapper.java index 11d467a61d5..4c5c14dad87 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/container/xml/BundleMapper.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/container/xml/BundleMapper.java @@ -15,7 +15,20 @@ import java.util.Optional; */ public class BundleMapper { + public enum JarSuffix { + JAR_WITH_DEPS("-jar-with-dependencies.jar"), + DEPLOY("-deploy.jar"); + + private final String suffix; + + JarSuffix(String suffix) { + this.suffix = suffix; + } + } + public static final Path LIBRARY_PATH = Paths.get(Defaults.getDefaults().underVespaHome("lib/jars")); + + public static final String searchAndDocprocBundle = "container-search-and-docproc"; private static final Map<String, String> bundleFromClass; @@ -34,6 +47,10 @@ public class BundleMapper { return LIBRARY_PATH.resolve(fileName); } + public static Path bundlePathFromName(String name, JarSuffix suffix) { + return Paths.get(Defaults.getDefaults().underVespaHome(LIBRARY_PATH + name + suffix.suffix)); + } + /** * TODO: This is a temporary hack to ensure that users can use our internal components without * specifying the bundle in which the components reside. Ideally, this information |