Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add remaining app server service name detectors #583

Merged
merged 3 commits into from
Nov 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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