Skip to content

Commit

Permalink
Add remaining app server service name detectors (#583)
Browse files Browse the repository at this point in the history
This builds on #579 (and will be rebased when that merges). It adds the
remaining service name detectors for various app servers.
  • Loading branch information
breedx-splk authored Nov 16, 2022
1 parent 9a32c5d commit 8d928c4
Show file tree
Hide file tree
Showing 10 changed files with 619 additions and 4 deletions.
7 changes: 6 additions & 1 deletion resource-providers/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,13 @@ from `WEB-INF/web.xml`. For `.ear` files the `<application>` element of `META-IN

It is capable of detecting common scenarios among the popular application servers listed below:

* Apache Tomcat
* Apache TomEE
* Eclipse Jetty
* GlassFish
* _remaining are tbd_
* IBM Websphere
* IBM Websphere Liberty
* Wildfly

## Component owners

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
package io.opentelemetry.resourceproviders;

import java.net.URL;
import java.util.Collections;
import java.util.Arrays;
import java.util.List;
import javax.annotation.Nullable;

Expand All @@ -24,8 +24,14 @@ private CommonAppServersServiceNameDetector() {}

private static List<ServiceNameDetector> detectors() {
ResourceLocator locator = new ResourceLocatorImpl();
// Additional implementations will be added to this list.
return Collections.singletonList(detectorFor(new GlassfishAppServer(locator)));
return Arrays.asList(
detectorFor(new TomeeAppServer(locator)),
detectorFor(new TomcatAppServer(locator)),
detectorFor(new JettyAppServer(locator)),
detectorFor(new LibertyAppService(locator)),
detectorFor(new WildflyAppServer(locator)),
detectorFor(new GlassfishAppServer(locator)),
new WebSphereServiceNameDetector(new WebSphereAppServer(locator)));
}

private static AppServerServiceNameDetector detectorFor(AppServer appServer) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.resourceproviders;

import static java.util.logging.Level.FINE;

import com.google.common.annotations.VisibleForTesting;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.logging.Logger;
import javax.annotation.Nullable;

class JettyAppServer implements AppServer {

private static final Logger logger = Logger.getLogger(JettyAppServer.class.getName());
private static final String SERVER_CLASS_NAME = "org.eclipse.jetty.start.Main";
private final ResourceLocator locator;

JettyAppServer(ResourceLocator locator) {
this.locator = locator;
}

@Override
public boolean isValidAppName(Path path) {
// jetty deployer ignores directories ending with ".d"
if (Files.isDirectory(path)) {
return !path.getFileName().toString().endsWith(".d");
}
return true;
}

@Override
public Path getDeploymentDir() {
// Jetty expects the webapps directory to be in the directory where jetty was started from.
// Alternatively the location of webapps directory can be specified by providing jetty base
// directory as an argument to jetty e.g. java -jar start.jar jetty.base=/dir where webapps
// would be located in /dir/webapps.

String programArguments = System.getProperty("sun.java.command");
logger.log(FINE, "Started with arguments '{0}'.", programArguments);
if (programArguments != null) {
Path jettyBase = parseJettyBase(programArguments);
if (jettyBase != null) {
logger.log(FINE, "Using jetty.base '{0}'.", jettyBase);
return jettyBase.resolve("webapps");
}
}

return Paths.get("webapps").toAbsolutePath();
}

@Nullable
@Override
public Class<?> getServerClass() {
return locator.findClass(SERVER_CLASS_NAME);
}

@Nullable
@VisibleForTesting
static Path parseJettyBase(String programArguments) {
if (programArguments == null) {
return null;
}
int start = programArguments.indexOf("jetty.base=");
if (start == -1) {
return null;
}
start += "jetty.base=".length();
if (start == programArguments.length()) {
return null;
}
// Take the path until the first space. If the path doesn't exist extend it up to the next
// space. Repeat until a path that exists is found or input runs out.
int next = start;
while (true) {
int nextSpace = programArguments.indexOf(' ', next);
if (nextSpace == -1) {
Path candidate = Paths.get(programArguments.substring(start));
return Files.exists(candidate) ? candidate : null;
}
Path candidate = Paths.get(programArguments.substring(start, nextSpace));
next = nextSpace + 1;
if (Files.exists(candidate)) {
return candidate;
}
}
}

@Override
public boolean supportsEar() {
return false;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.resourceproviders;

import static java.util.logging.Level.FINE;

import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.logging.Logger;
import javax.annotation.Nullable;

class LibertyAppService implements AppServer {

private static final String SERVICE_CLASS_NAME = "com.ibm.ws.kernel.boot.cmdline.EnvCheck";

private static final Logger logger = Logger.getLogger(LibertyAppService.class.getName());
private final ResourceLocator locator;

LibertyAppService(ResourceLocator locator) {
this.locator = locator;
}

@Override
public Path getDeploymentDir() {
// default installation has
// WLP_OUTPUT_DIR - libertyDir/usr/servers
// WLP_USER_DIR - libertyDir/usr
// docker image has
// WLP_USER_DIR - /opt/ol/wlp/usr
// WLP_OUTPUT_DIR - /opt/ol/wlp/output

// liberty server sets current directory to $WLP_OUTPUT_DIR/serverName we need
// $WLP_USER_DIR/servers/serverName
// in default installation we already have the right directory and don't need to do anything
Path serverDir = Paths.get("").toAbsolutePath();
String wlpUserDir = System.getenv("WLP_USER_DIR");
String wlpOutputDir = System.getenv("WLP_OUTPUT_DIR");
if (logger.isLoggable(FINE)) {
logger.log(
FINE,
"Using WLP_USER_DIR '{0}', WLP_OUTPUT_DIR '{1}'.",
new Object[] {wlpUserDir, wlpOutputDir});
}
if (wlpUserDir != null
&& wlpOutputDir != null
&& !Paths.get(wlpOutputDir).equals(Paths.get(wlpUserDir, "servers"))) {
Path serverName = serverDir.getFileName();
serverDir = Paths.get(wlpUserDir, "servers").resolve(serverName);
}

// besides dropins applications can also be deployed via server.xml using <webApplication>,
// <enterpriseApplication> and <application> tags, see
// https://openliberty.io/docs/latest/reference/config/server-configuration-overview.html
return serverDir.resolve("dropins");
}

@Nullable
@Override
public Class<?> getServerClass() {
return locator.findClass(SERVICE_CLASS_NAME);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.resourceproviders;

import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import javax.annotation.Nullable;

class TomcatAppServer implements AppServer {

private static final String SERVER_CLASS_NAME = "org.apache.catalina.startup.Bootstrap";
private final ResourceLocator locator;

TomcatAppServer(ResourceLocator locator) {
this.locator = locator;
}

@Override
public boolean isValidAppName(Path path) {
if (Files.isDirectory(path)) {
String name = path.getFileName().toString();
return !"docs".equals(name)
&& !"examples".equals(name)
&& !"host-manager".equals(name)
&& !"manager".equals(name);
}
return true;
}

@Override
public boolean isValidResult(Path path, @Nullable String result) {
String name = path.getFileName().toString();
return !"ROOT".equals(name) || !"Welcome to Tomcat".equals(result);
}

@Nullable
@Override
public Path getDeploymentDir() throws URISyntaxException {
String catalinaBase = System.getProperty("catalina.base");
if (catalinaBase != null) {
return Paths.get(catalinaBase, "webapps");
}

String catalinaHome = System.getProperty("catalina.home");
if (catalinaHome != null) {
return Paths.get(catalinaHome, "webapps");
}

// if neither catalina.base nor catalina.home is set try to deduce the location of webapps based
// on the loaded server class.
Class<?> serverClass = getServerClass();
if (serverClass == null) {
return null;
}
URL jarUrl = locator.getClassLocation(serverClass);
Path jarPath = Paths.get(jarUrl.toURI());
// jar is in bin/. First call to getParent strips jar name and the second bin/. We'll end up
// with a path to server root to which we append the autodeploy directory.
return getWebappsDir(jarPath);
}

@Nullable
private static Path getWebappsDir(Path jarPath) {
Path parent = jarPath.getParent();
if (parent == null) {
return null;
}
Path grandparent = parent.getParent();
return grandparent == null ? null : grandparent.resolve("webapps");
}

@Nullable
@Override
public Class<?> getServerClass() {
return locator.findClass(SERVER_CLASS_NAME);
}

@Override
public boolean supportsEar() {
return false;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.resourceproviders;

import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import javax.annotation.Nullable;

class TomeeAppServer implements AppServer {

private static final String SERVER_CLASS_NAME = "org.apache.catalina.startup.Bootstrap";
private final ResourceLocator locator;

TomeeAppServer(ResourceLocator locator) {
this.locator = locator;
}

@Nullable
@Override
public Path getDeploymentDir() throws URISyntaxException {
Path rootDir = getRootDir();
if (rootDir == null) {
return null;
}

// check for presence of tomee configuration file, if it doesn't exist then we have tomcat not
// tomee
if (!Files.isRegularFile(rootDir.resolve("conf/tomee.xml"))) {
return null;
}

// tomee deployment directory is configurable, we'll only look at the default 'apps' directory
// to get the actual deployment directory (or see whether it is enabled at all) we would need to
// parse conf/tomee.xml
// tomee also deploys applications from webapps directory, detecting them is handled by
// TomcatServiceNameDetector
return rootDir.resolve("apps");
}

@Nullable
@Override
public Class<?> getServerClass() {
return locator.findClass(SERVER_CLASS_NAME);
}

@Nullable
private Path getRootDir() throws URISyntaxException {
String catalinaBase = System.getProperty("catalina.base");
if (catalinaBase != null) {
return Paths.get(catalinaBase);
}

String catalinaHome = System.getProperty("catalina.home");
if (catalinaHome != null) {
return Paths.get(catalinaHome);
}

// if neither catalina.base nor catalina.home is set try to deduce the location of based on the
// loaded server class.
Class<?> serverClass = getServerClass();
if (serverClass == null) {
return null;
}
URL jarUrl = locator.getClassLocation(serverClass);
Path jarPath = Paths.get(jarUrl.toURI());
// jar is in bin/. First call to getParent strips jar name and the second bin/. We'll end up
// with a path to server root.
Path parent = jarPath.getParent();
if (parent == null) {
return null;
}
return parent.getParent();
}
}
Loading

0 comments on commit 8d928c4

Please sign in to comment.