Run GitHub Action in a container
This commit is contained in:
		
							parent
							
								
									44a5d86641
								
							
						
					
					
						commit
						b711288faa
					
				| 
						 | 
					@ -5,14 +5,19 @@ on: [push]
 | 
				
			||||||
jobs:
 | 
					jobs:
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
    runs-on: ubuntu-latest
 | 
					    runs-on: ubuntu-latest
 | 
				
			||||||
 | 
					    container: ubuntu:22.04
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - uses: actions/checkout@v2
 | 
					      - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3.1.0
 | 
				
			||||||
      - name: Set up JDK 17
 | 
					      - name: Set up JDK 17
 | 
				
			||||||
        uses: actions/setup-java@3bc31aaf88e8fc94dc1e632d48af61be5ca8721c
 | 
					        uses: actions/setup-java@de1bb2b0c5634f0fc4438d7aa9944e68f9bf86cc # v3.6.0
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
          distribution: 'temurin'
 | 
					          distribution: 'temurin'
 | 
				
			||||||
          java-version: 17
 | 
					          java-version: 17
 | 
				
			||||||
          cache: 'maven'
 | 
					          cache: 'maven'
 | 
				
			||||||
 | 
					        env:
 | 
				
			||||||
 | 
					          # work around an issue with actions/runner setting an incorrect HOME in containers, which breaks maven caching
 | 
				
			||||||
 | 
					          # https://github.com/actions/setup-java/issues/356
 | 
				
			||||||
 | 
					          HOME: /root
 | 
				
			||||||
      - name: Build with Maven
 | 
					      - name: Build with Maven
 | 
				
			||||||
        run: mvn -e -B verify
 | 
					        run: ./mvnw -e -B verify
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,93 +0,0 @@
 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * Copyright 2021 Signal Messenger, LLC
 | 
					 | 
				
			||||||
 * SPDX-License-Identifier: AGPL-3.0-only
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
package org.whispersystems.textsecuregcm.metrics;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import static com.codahale.metrics.MetricRegistry.name;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import com.fasterxml.jackson.annotation.JsonCreator;
 | 
					 | 
				
			||||||
import com.fasterxml.jackson.annotation.JsonProperty;
 | 
					 | 
				
			||||||
import com.fasterxml.jackson.databind.DeserializationFeature;
 | 
					 | 
				
			||||||
import com.fasterxml.jackson.databind.ObjectMapper;
 | 
					 | 
				
			||||||
import com.google.common.annotations.VisibleForTesting;
 | 
					 | 
				
			||||||
import io.micrometer.core.instrument.Metrics;
 | 
					 | 
				
			||||||
import java.io.IOException;
 | 
					 | 
				
			||||||
import java.time.Duration;
 | 
					 | 
				
			||||||
import java.util.Collections;
 | 
					 | 
				
			||||||
import java.util.Map;
 | 
					 | 
				
			||||||
import java.util.concurrent.ConcurrentHashMap;
 | 
					 | 
				
			||||||
import java.util.concurrent.ScheduledExecutorService;
 | 
					 | 
				
			||||||
import java.util.concurrent.TimeUnit;
 | 
					 | 
				
			||||||
import org.slf4j.Logger;
 | 
					 | 
				
			||||||
import org.slf4j.LoggerFactory;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
public class NstatCounters {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  private final Map<String, Long> networkStatistics = new ConcurrentHashMap<>();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  private static final String[] NSTAT_COMMAND_LINE = new String[] { "nstat", "--zero", "--json", "--noupdate", "--ignore" };
 | 
					 | 
				
			||||||
  private static final String[] EXCLUDE_METRIC_NAME_PREFIXES = new String[] { "Icmp", "Udp", "Ip6" };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper()
 | 
					 | 
				
			||||||
      .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  private static final Logger log = LoggerFactory.getLogger(NstatCounters.class);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  @VisibleForTesting
 | 
					 | 
				
			||||||
  static class NetworkStatistics {
 | 
					 | 
				
			||||||
    private final Map<String, Long> kernelStatistics;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @JsonCreator
 | 
					 | 
				
			||||||
    private NetworkStatistics(@JsonProperty("kernel") final Map<String, Long> kernelStatistics) {
 | 
					 | 
				
			||||||
      this.kernelStatistics = kernelStatistics;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public Map<String, Long> getKernelStatistics() {
 | 
					 | 
				
			||||||
      return kernelStatistics;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  public void registerMetrics(final ScheduledExecutorService refreshService, final Duration refreshInterval) {
 | 
					 | 
				
			||||||
    refreshNetworkStatistics();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    networkStatistics.keySet().stream()
 | 
					 | 
				
			||||||
        .filter(NstatCounters::shouldIncludeMetric)
 | 
					 | 
				
			||||||
        .forEach(metricName -> Metrics.globalRegistry.more().counter(name(getClass(), "kernel", metricName),
 | 
					 | 
				
			||||||
            Collections.emptyList(), networkStatistics, statistics -> statistics.get(metricName)));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    refreshService.scheduleAtFixedRate(this::refreshNetworkStatistics,
 | 
					 | 
				
			||||||
        refreshInterval.toMillis(), refreshInterval.toMillis(), TimeUnit.MILLISECONDS);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  private void refreshNetworkStatistics() {
 | 
					 | 
				
			||||||
    try {
 | 
					 | 
				
			||||||
      networkStatistics.putAll(loadNetworkStatistics().getKernelStatistics());
 | 
					 | 
				
			||||||
    } catch (final InterruptedException | IOException e) {
 | 
					 | 
				
			||||||
      log.warn("Failed to refresh network statistics", e);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  @VisibleForTesting
 | 
					 | 
				
			||||||
  static boolean shouldIncludeMetric(final String metricName) {
 | 
					 | 
				
			||||||
    for (final String prefix : EXCLUDE_METRIC_NAME_PREFIXES) {
 | 
					 | 
				
			||||||
      if (metricName.startsWith(prefix)) {
 | 
					 | 
				
			||||||
        return false;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return true;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  @VisibleForTesting
 | 
					 | 
				
			||||||
  static NetworkStatistics loadNetworkStatistics() throws IOException, InterruptedException {
 | 
					 | 
				
			||||||
    final Process nstatProcess = Runtime.getRuntime().exec(NSTAT_COMMAND_LINE);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (nstatProcess.waitFor() == 0) {
 | 
					 | 
				
			||||||
      return OBJECT_MAPPER.readValue(nstatProcess.getInputStream(), NetworkStatistics.class);
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
      throw new IOException("nstat process did not exit normally");
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,48 +0,0 @@
 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * Copyright 2021 Signal Messenger, LLC
 | 
					 | 
				
			||||||
 * SPDX-License-Identifier: AGPL-3.0-only
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
package org.whispersystems.textsecuregcm.metrics;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
 | 
					 | 
				
			||||||
import static org.junit.jupiter.api.Assertions.assertFalse;
 | 
					 | 
				
			||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import java.io.IOException;
 | 
					 | 
				
			||||||
import java.util.stream.Stream;
 | 
					 | 
				
			||||||
import org.junit.jupiter.api.Test;
 | 
					 | 
				
			||||||
import org.junit.jupiter.api.condition.EnabledOnOs;
 | 
					 | 
				
			||||||
import org.junit.jupiter.api.condition.OS;
 | 
					 | 
				
			||||||
import org.junit.jupiter.params.ParameterizedTest;
 | 
					 | 
				
			||||||
import org.junit.jupiter.params.provider.Arguments;
 | 
					 | 
				
			||||||
import org.junit.jupiter.params.provider.MethodSource;
 | 
					 | 
				
			||||||
import org.whispersystems.textsecuregcm.metrics.NstatCounters.NetworkStatistics;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class NstatCountersTest {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  @Test
 | 
					 | 
				
			||||||
  @EnabledOnOs(OS.LINUX)
 | 
					 | 
				
			||||||
  void loadNetworkStatistics() throws IOException, InterruptedException {
 | 
					 | 
				
			||||||
    final NetworkStatistics networkStatistics = NstatCounters.loadNetworkStatistics();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    assertNotNull(networkStatistics.getKernelStatistics());
 | 
					 | 
				
			||||||
    assertFalse(networkStatistics.getKernelStatistics().isEmpty());
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  @ParameterizedTest
 | 
					 | 
				
			||||||
  @MethodSource("shouldIncludeMetricNameProvider")
 | 
					 | 
				
			||||||
  void shouldIncludeMetric(final String metricName, final boolean expectInclude) {
 | 
					 | 
				
			||||||
    assertEquals(expectInclude, NstatCounters.shouldIncludeMetric(metricName));
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  static Stream<Arguments> shouldIncludeMetricNameProvider() {
 | 
					 | 
				
			||||||
    return Stream.of(Arguments.of("IpInReceives", true),
 | 
					 | 
				
			||||||
        Arguments.of("TcpActiveOpens", true),
 | 
					 | 
				
			||||||
        Arguments.of("UdpInDatagrams", false),
 | 
					 | 
				
			||||||
        Arguments.of("Ip6InReceives", false),
 | 
					 | 
				
			||||||
        Arguments.of("Udp6InDatagrams", false),
 | 
					 | 
				
			||||||
        Arguments.of("TcpExtSyncookiesSent", true),
 | 
					 | 
				
			||||||
        Arguments.of("IpExtInNoRoutes", true));
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
		Loading…
	
		Reference in New Issue