Skip to content

Commit 9e6b2a6

Browse files
authored
Move classes from build scripts to buildSrc (elastic#57197)
* Move classes from build scripts to buildSrc - move Run task - move duplicate SanEvaluator * Remove :run workaround * Some little cleanup on build scripts on the way
1 parent 1cda36e commit 9e6b2a6

File tree

7 files changed

+313
-476
lines changed

7 files changed

+313
-476
lines changed

build.gradle

+1-37
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ apply from: 'gradle/forbidden-dependencies.gradle'
4747
apply from: 'gradle/formatting.gradle'
4848
apply from: 'gradle/local-distribution.gradle'
4949
apply from: 'gradle/fips.gradle'
50+
apply from: 'gradle/run.gradle'
5051

5152
// common maven publishing configuration
5253
allprojects {
@@ -375,43 +376,6 @@ allprojects {
375376
tasks.named('eclipse') { dependsOn 'cleanEclipse', 'copyEclipseSettings' }
376377
}
377378

378-
// we need to add the same --debug-jvm option as
379-
// the real RunTask has, so we can pass it through
380-
class Run extends DefaultTask {
381-
boolean debug = false
382-
383-
@Option(
384-
option = "debug-jvm",
385-
description = "Enable debugging configuration, to allow attaching a debugger to elasticsearch."
386-
)
387-
public void setDebug(boolean enabled) {
388-
project.project(':distribution').run.debug = enabled
389-
}
390-
391-
@Option(
392-
option = "data-dir",
393-
description = "Override the base data directory used by the testcluster"
394-
)
395-
public void setDataDir(String dataDirStr) {
396-
project.project(':distribution').run.dataDir = dataDirStr
397-
}
398-
399-
@Option(
400-
option = "keystore-password",
401-
description = "Set the elasticsearch keystore password"
402-
)
403-
public void setKeystorePassword(String password) {
404-
project.project(':distribution').run.keystorePassword = password
405-
}
406-
}
407-
408-
tasks.register("run", Run) {
409-
dependsOn ':distribution:run'
410-
description = 'Runs elasticsearch in the foreground'
411-
group = 'Verification'
412-
impliesSubProjects = true
413-
}
414-
415379
wrapper {
416380
distributionType = 'ALL'
417381
doLast {

buildSrc/build.gradle

+2-4
Original file line numberDiff line numberDiff line change
@@ -181,10 +181,8 @@ if (project != rootProject) {
181181
testingConventions.enabled = false
182182
}
183183

184-
configurations {
185-
distribution
186-
reaper
187-
}
184+
configurations.register("distribution")
185+
configurations.register("reaper")
188186

189187
dependencies {
190188
reaper project('reaper')
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
package org.elasticsearch.gradle.network;
2+
3+
import java.io.IOException;
4+
import java.net.Inet6Address;
5+
import java.net.InetAddress;
6+
import java.net.NetworkInterface;
7+
import java.net.SocketException;
8+
import java.util.ArrayList;
9+
import java.util.Arrays;
10+
import java.util.Collections;
11+
import java.util.Comparator;
12+
import java.util.List;
13+
14+
/**
15+
* A lazy evaluator to find the san to use for certificate generation.
16+
*/
17+
public class SanEvaluator {
18+
19+
private static String san = null;
20+
21+
public String toString() {
22+
synchronized (SanEvaluator.class) {
23+
if (san == null) {
24+
san = getSubjectAlternativeNameString();
25+
}
26+
}
27+
return san;
28+
}
29+
30+
// Code stolen from NetworkUtils/InetAddresses/NetworkAddress to support SAN
31+
32+
/**
33+
* Return all interfaces (and subinterfaces) on the system
34+
*/
35+
private static List<NetworkInterface> getInterfaces() throws SocketException {
36+
List<NetworkInterface> all = new ArrayList<>();
37+
addAllInterfaces(all, Collections.list(NetworkInterface.getNetworkInterfaces()));
38+
Collections.sort(all, new Comparator<NetworkInterface>() {
39+
@Override
40+
public int compare(NetworkInterface left, NetworkInterface right) {
41+
return Integer.compare(left.getIndex(), right.getIndex());
42+
}
43+
});
44+
return all;
45+
}
46+
47+
/**
48+
* Helper for getInterfaces, recursively adds subinterfaces to {@code target}
49+
*/
50+
private static void addAllInterfaces(List<NetworkInterface> target, List<NetworkInterface> level) {
51+
if (!level.isEmpty()) {
52+
target.addAll(level);
53+
for (NetworkInterface intf : level) {
54+
addAllInterfaces(target, Collections.list(intf.getSubInterfaces()));
55+
}
56+
}
57+
}
58+
59+
private static String getSubjectAlternativeNameString() {
60+
List<InetAddress> list = new ArrayList<>();
61+
try {
62+
63+
for (NetworkInterface intf : getInterfaces()) {
64+
for (final InetAddress address : Collections.list(intf.getInetAddresses())) {
65+
/*
66+
* Some OS (e.g., BSD) assign a link-local address to the loopback interface.
67+
* While technically not a loopback interface, some of these OS treat them as one (e.g., localhost on macOS),
68+
* so we must too. Otherwise, things just won't work out of the box. So we include all addresses from
69+
* loopback interfaces.
70+
*
71+
* By checking if the interface is a loopback interface or the address is a loopback address first,
72+
* we avoid having to check if the interface is up unless necessary.
73+
* This means we can avoid checking if the interface is up for virtual ethernet devices which have
74+
* a tendency to disappear outside of our control (e.g., due to Docker).
75+
*/
76+
if ((intf.isLoopback() || address.isLoopbackAddress()) && isUp(intf, address)) {
77+
list.add(address);
78+
}
79+
}
80+
}
81+
if (list.isEmpty()) {
82+
throw new IllegalArgumentException("no up-and-running loopback addresses found, got " + getInterfaces());
83+
}
84+
85+
StringBuilder builder = new StringBuilder("san=");
86+
for (int i = 0; i < list.size(); i++) {
87+
InetAddress address = list.get(i);
88+
String hostAddress;
89+
if (address instanceof Inet6Address) {
90+
hostAddress = compressedIPV6Address((Inet6Address) address);
91+
} else {
92+
hostAddress = address.getHostAddress();
93+
}
94+
builder.append("ip:").append(hostAddress);
95+
String hostname = address.getHostName();
96+
if (hostname.equals(address.getHostAddress()) == false) {
97+
builder.append(",dns:").append(hostname);
98+
}
99+
100+
if (i != (list.size() - 1)) {
101+
builder.append(",");
102+
}
103+
}
104+
105+
return builder.toString();
106+
} catch (IOException e) {
107+
throw new IllegalStateException("Cannot resolve alternative name string", e);
108+
}
109+
}
110+
111+
private static boolean isUp(final NetworkInterface intf, final InetAddress address) throws IOException {
112+
try {
113+
return intf.isUp();
114+
} catch (final SocketException e) {
115+
/*
116+
* In Elasticsearch production code (NetworkUtils) we suppress this if the device is a virtual ethernet device.
117+
* That should not happen here since the interface must be a loopback device or the address a loopback address
118+
* to get here to begin with.
119+
*/
120+
assert intf.isLoopback() || address.isLoopbackAddress();
121+
throw new IOException("failed to check if interface [" + intf.getName() + "] is up", e);
122+
}
123+
}
124+
125+
private static String compressedIPV6Address(Inet6Address inet6Address) {
126+
byte[] bytes = inet6Address.getAddress();
127+
int[] hextets = new int[8];
128+
for (int i = 0; i < hextets.length; i++) {
129+
hextets[i] = (bytes[2 * i] & 255) << 8 | bytes[2 * i + 1] & 255;
130+
}
131+
compressLongestRunOfZeroes(hextets);
132+
return hextetsToIPv6String(hextets);
133+
}
134+
135+
/**
136+
* Identify and mark the longest run of zeroes in an IPv6 address.
137+
*
138+
* <p>Only runs of two or more hextets are considered. In case of a tie, the
139+
* leftmost run wins. If a qualifying run is found, its hextets are replaced
140+
* by the sentinel value -1.
141+
*
142+
* @param hextets {@code int[]} mutable array of eight 16-bit hextets
143+
*/
144+
private static void compressLongestRunOfZeroes(int[] hextets) {
145+
int bestRunStart = -1;
146+
int bestRunLength = -1;
147+
int runStart = -1;
148+
for (int i = 0; i < hextets.length + 1; i++) {
149+
if (i < hextets.length && hextets[i] == 0) {
150+
if (runStart < 0) {
151+
runStart = i;
152+
}
153+
} else if (runStart >= 0) {
154+
int runLength = i - runStart;
155+
if (runLength > bestRunLength) {
156+
bestRunStart = runStart;
157+
bestRunLength = runLength;
158+
}
159+
runStart = -1;
160+
}
161+
}
162+
if (bestRunLength >= 2) {
163+
Arrays.fill(hextets, bestRunStart, bestRunStart + bestRunLength, -1);
164+
}
165+
}
166+
167+
/**
168+
* Convert a list of hextets into a human-readable IPv6 address.
169+
*
170+
* <p>In order for "::" compression to work, the input should contain negative
171+
* sentinel values in place of the elided zeroes.
172+
*
173+
* @param hextets {@code int[]} array of eight 16-bit hextets, or -1s
174+
*/
175+
private static String hextetsToIPv6String(int[] hextets) {
176+
/*
177+
* While scanning the array, handle these state transitions:
178+
* start->num => "num" start->gap => "::"
179+
* num->num => ":num" num->gap => "::"
180+
* gap->num => "num" gap->gap => ""
181+
*/
182+
StringBuilder buf = new StringBuilder(39);
183+
boolean lastWasNumber = false;
184+
for (int i = 0; i < hextets.length; i++) {
185+
boolean thisIsNumber = hextets[i] >= 0;
186+
if (thisIsNumber) {
187+
if (lastWasNumber) {
188+
buf.append(':');
189+
}
190+
buf.append(Integer.toHexString(hextets[i]));
191+
} else {
192+
if (i == 0 || lastWasNumber) {
193+
buf.append("::");
194+
}
195+
}
196+
lastWasNumber = thisIsNumber;
197+
}
198+
return buf.toString();
199+
}
200+
}

0 commit comments

Comments
 (0)