Skip to content

Commit 10dcb8e

Browse files
authored
Add systemd native access (#106151)
This commit moves systemd access to the NativeAccess lib. relates #104876
1 parent d8da8fa commit 10dcb8e

File tree

17 files changed

+281
-123
lines changed

17 files changed

+281
-123
lines changed

libs/native/jna/src/main/java/org/elasticsearch/nativeaccess/jna/JnaNativeLibraryProvider.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,12 @@
1010

1111
import org.elasticsearch.nativeaccess.lib.NativeLibraryProvider;
1212
import org.elasticsearch.nativeaccess.lib.PosixCLibrary;
13+
import org.elasticsearch.nativeaccess.lib.SystemdLibrary;
1314

1415
import java.util.Map;
1516

1617
public class JnaNativeLibraryProvider extends NativeLibraryProvider {
1718
public JnaNativeLibraryProvider() {
18-
super("jna", Map.of(PosixCLibrary.class, JnaPosixCLibrary::new));
19+
super("jna", Map.of(PosixCLibrary.class, JnaPosixCLibrary::new, SystemdLibrary.class, JnaSystemdLibrary::new));
1920
}
2021
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License
4+
* 2.0 and the Server Side Public License, v 1; you may not use this file except
5+
* in compliance with, at your election, the Elastic License 2.0 or the Server
6+
* Side Public License, v 1.
7+
*/
8+
9+
package org.elasticsearch.nativeaccess.jna;
10+
11+
import com.sun.jna.Library;
12+
import com.sun.jna.Native;
13+
14+
import org.elasticsearch.nativeaccess.lib.SystemdLibrary;
15+
16+
class JnaSystemdLibrary implements SystemdLibrary {
17+
private interface NativeFunctions extends Library {
18+
int sd_notify(int unset_environment, String state);
19+
}
20+
21+
private final NativeFunctions functions;
22+
23+
JnaSystemdLibrary() {
24+
this.functions = Native.load("libsystemd.so.0", NativeFunctions.class);
25+
}
26+
27+
@Override
28+
public int sd_notify(int unset_environment, String state) {
29+
return functions.sd_notify(unset_environment, state);
30+
}
31+
}

libs/native/src/main/java/module-info.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
requires org.elasticsearch.base;
1515
requires org.elasticsearch.logging;
1616

17-
exports org.elasticsearch.nativeaccess to org.elasticsearch.server;
17+
exports org.elasticsearch.nativeaccess to org.elasticsearch.server, org.elasticsearch.systemd;
1818
// allows jna to implement a library provider, and ProviderLocator to load it
1919
exports org.elasticsearch.nativeaccess.lib to org.elasticsearch.nativeaccess.jna, org.elasticsearch.base;
2020

libs/native/src/main/java/org/elasticsearch/nativeaccess/AbstractNativeAccess.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,9 @@ protected AbstractNativeAccess(String name) {
2424
String getName() {
2525
return name;
2626
}
27+
28+
@Override
29+
public Systemd systemd() {
30+
return null;
31+
}
2732
}

libs/native/src/main/java/org/elasticsearch/nativeaccess/LinuxNativeAccess.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,19 @@
99
package org.elasticsearch.nativeaccess;
1010

1111
import org.elasticsearch.nativeaccess.lib.NativeLibraryProvider;
12+
import org.elasticsearch.nativeaccess.lib.SystemdLibrary;
1213

1314
class LinuxNativeAccess extends PosixNativeAccess {
15+
16+
Systemd systemd;
17+
1418
LinuxNativeAccess(NativeLibraryProvider libraryProvider) {
1519
super("Linux", libraryProvider);
20+
this.systemd = new Systemd(libraryProvider.getLibrary(SystemdLibrary.class));
21+
}
22+
23+
@Override
24+
public Systemd systemd() {
25+
return systemd;
1626
}
1727
}

libs/native/src/main/java/org/elasticsearch/nativeaccess/NativeAccess.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,6 @@ static NativeAccess instance() {
2626
* @return true if running as root, or false if unsure
2727
*/
2828
boolean definitelyRunningAsRoot();
29+
30+
Systemd systemd();
2931
}

libs/native/src/main/java/org/elasticsearch/nativeaccess/NoopNativeAccess.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,10 @@ public boolean definitelyRunningAsRoot() {
1919
logger.warn("Cannot check if running as root because native access is not available");
2020
return false;
2121
}
22+
23+
@Override
24+
public Systemd systemd() {
25+
logger.warn("Cannot get systemd access because native access is not available");
26+
return null;
27+
}
2228
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License
4+
* 2.0 and the Server Side Public License, v 1; you may not use this file except
5+
* in compliance with, at your election, the Elastic License 2.0 or the Server
6+
* Side Public License, v 1.
7+
*/
8+
9+
package org.elasticsearch.nativeaccess;
10+
11+
import org.elasticsearch.logging.LogManager;
12+
import org.elasticsearch.logging.Logger;
13+
import org.elasticsearch.nativeaccess.lib.SystemdLibrary;
14+
15+
import java.util.Locale;
16+
17+
public class Systemd {
18+
private static final Logger logger = LogManager.getLogger(Systemd.class);
19+
20+
private final SystemdLibrary lib;
21+
22+
Systemd(SystemdLibrary lib) {
23+
this.lib = lib;
24+
}
25+
26+
/**
27+
* Notify systemd that the process is ready.
28+
*
29+
* @throws RuntimeException on failure to notify systemd
30+
*/
31+
public void notify_ready() {
32+
notify("READY=1", false);
33+
}
34+
35+
public void notify_extend_timeout(long seconds) {
36+
notify("EXTEND_TIMEOUT_USEC=" + (seconds * 1000000), true);
37+
}
38+
39+
public void notify_stopping() {
40+
notify("STOPPING=1", true);
41+
}
42+
43+
private void notify(String state, boolean warnOnError) {
44+
int rc = lib.sd_notify(0, state);
45+
logger.trace("sd_notify({}, {}) returned [{}]", 0, state, rc);
46+
if (rc < 0) {
47+
String message = String.format(Locale.ROOT, "sd_notify(%d, %s) returned error [%d]", 0, state, rc);
48+
if (warnOnError) {
49+
logger.warn(message);
50+
} else {
51+
throw new RuntimeException(message);
52+
}
53+
}
54+
}
55+
}

libs/native/src/main/java/org/elasticsearch/nativeaccess/lib/NativeLibrary.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,4 @@
99
package org.elasticsearch.nativeaccess.lib;
1010

1111
/** A marker interface for libraries that can be loaded by {@link org.elasticsearch.nativeaccess.lib.NativeLibraryProvider} */
12-
public sealed interface NativeLibrary permits PosixCLibrary {}
12+
public sealed interface NativeLibrary permits PosixCLibrary, SystemdLibrary {}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License
4+
* 2.0 and the Server Side Public License, v 1; you may not use this file except
5+
* in compliance with, at your election, the Elastic License 2.0 or the Server
6+
* Side Public License, v 1.
7+
*/
8+
9+
package org.elasticsearch.nativeaccess.lib;
10+
11+
public non-sealed interface SystemdLibrary extends NativeLibrary {
12+
int sd_notify(int unset_environment, String state);
13+
}

libs/native/src/main21/java/org/elasticsearch/nativeaccess/jdk/JdkNativeLibraryProvider.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,13 @@
1010

1111
import org.elasticsearch.nativeaccess.lib.NativeLibraryProvider;
1212
import org.elasticsearch.nativeaccess.lib.PosixCLibrary;
13+
import org.elasticsearch.nativeaccess.lib.SystemdLibrary;
1314

1415
import java.util.Map;
1516

1617
public class JdkNativeLibraryProvider extends NativeLibraryProvider {
1718

1819
public JdkNativeLibraryProvider() {
19-
super("jdk", Map.of(PosixCLibrary.class, JdkPosixCLibrary::new));
20+
super("jdk", Map.of(PosixCLibrary.class, JdkPosixCLibrary::new, SystemdLibrary.class, JdkSystemdLibrary::new));
2021
}
2122
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License
4+
* 2.0 and the Server Side Public License, v 1; you may not use this file except
5+
* in compliance with, at your election, the Elastic License 2.0 or the Server
6+
* Side Public License, v 1.
7+
*/
8+
9+
package org.elasticsearch.nativeaccess.jdk;
10+
11+
import org.elasticsearch.nativeaccess.lib.SystemdLibrary;
12+
13+
import java.io.IOException;
14+
import java.io.UncheckedIOException;
15+
import java.lang.foreign.Arena;
16+
import java.lang.foreign.FunctionDescriptor;
17+
import java.lang.foreign.MemorySegment;
18+
import java.lang.invoke.MethodHandle;
19+
import java.nio.file.Files;
20+
import java.nio.file.Paths;
21+
22+
import static java.lang.foreign.ValueLayout.ADDRESS;
23+
import static java.lang.foreign.ValueLayout.JAVA_INT;
24+
import static org.elasticsearch.nativeaccess.jdk.LinkerHelper.downcallHandle;
25+
26+
class JdkSystemdLibrary implements SystemdLibrary {
27+
static {
28+
System.load(findLibSystemd());
29+
}
30+
31+
// On some systems libsystemd does not have a non-versioned symlink. System.loadLibrary only knows how to find
32+
// non-versioned library files. So we must manually check the library path to find what we need.
33+
static String findLibSystemd() {
34+
final String libsystemd = "libsystemd.so.0";
35+
String libpath = System.getProperty("java.library.path");
36+
for (String basepathStr : libpath.split(":")) {
37+
var basepath = Paths.get(basepathStr);
38+
if (Files.exists(basepath) == false) {
39+
continue;
40+
}
41+
try (var stream = Files.walk(basepath)) {
42+
var foundpath = stream.filter(Files::isDirectory).map(p -> p.resolve(libsystemd)).filter(Files::exists).findAny();
43+
if (foundpath.isPresent()) {
44+
return foundpath.get().toAbsolutePath().toString();
45+
}
46+
} catch (IOException e) {
47+
throw new UncheckedIOException(e);
48+
}
49+
50+
}
51+
throw new UnsatisfiedLinkError("Could not find " + libsystemd + " in java.library.path: " + libpath);
52+
}
53+
54+
private static final MethodHandle sd_notify$mh = downcallHandle("sd_notify", FunctionDescriptor.of(JAVA_INT, JAVA_INT, ADDRESS));
55+
56+
@Override
57+
public int sd_notify(int unset_environment, String state) {
58+
try (Arena arena = Arena.ofConfined()) {
59+
MemorySegment nativeState = arena.allocateUtf8String(state);
60+
return (int) sd_notify$mh.invokeExact(unset_environment, nativeState);
61+
} catch (Throwable t) {
62+
throw new AssertionError(t);
63+
}
64+
}
65+
}

modules/systemd/build.gradle

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,7 @@ esplugin {
1111
classname 'org.elasticsearch.systemd.SystemdPlugin'
1212
}
1313

14+
dependencies {
15+
implementation project(':libs:elasticsearch-native')
16+
}
17+

modules/systemd/src/main/java/module-info.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,5 @@
1212
requires org.elasticsearch.xcontent;
1313
requires org.apache.logging.log4j;
1414
requires org.apache.lucene.core;
15-
requires com.sun.jna;
15+
requires org.elasticsearch.nativeaccess;
1616
}

modules/systemd/src/main/java/org/elasticsearch/systemd/Libsystemd.java

Lines changed: 0 additions & 38 deletions
This file was deleted.

0 commit comments

Comments
 (0)