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

feat: add step and platform commands for device network #227

Merged
merged 1 commit into from
Oct 24, 2023
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
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import com.google.common.annotations.VisibleForTesting;
import io.cucumber.guice.ScenarioScoped;
import io.cucumber.java.en.And;
import io.cucumber.java.en.When;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

Expand Down Expand Up @@ -74,10 +75,15 @@ public void verifyCliInstallation() {
* @param componentName name of the component
* @param status {RUNNING, BROKEN, FINISHED}
* @throws InterruptedException {@link InterruptedException}
* @throws IllegalStateException {@link IllegalStateException}
*/
@And("I verify the {word} component is {word} using the greengrass-cli")
public void verifyComponentIsRunning(String componentName, String status) throws InterruptedException {
waitSteps.untilTrue(() -> this.isComponentInState(componentName, status), 30, TimeUnit.SECONDS);
if (!waitSteps.untilTrue(() -> this.isComponentInState(componentName, status),
60,
TimeUnit.SECONDS)) {
throw new IllegalStateException("Component status is not in " + status + " status");
}
}

/**
Expand All @@ -97,6 +103,28 @@ public void verifyLocalDeployment(String status, int value, String unit) throws
terminalStatuses::contains, value, timeUnit);
}

/**
* Use greengrass-cli to start or stop the component.
*
* @param componentName Name of the component
* @param action Action to take: stop or restart
* @throws UnsupportedOperationException if action word is other than stop or restart
*/
@When("I use greengrass-cli to {word} the component {word}")
public void restartOrStopComponent(String action, String componentName) {
urvashijain18 marked this conversation as resolved.
Show resolved Hide resolved
if (action.matches("stop|restart")) {
platform.commands().executeToString(CommandInput.builder()
.line(testContext.installRoot().resolve("bin").resolve("greengrass-cli").toString())
.addAllArgs(Arrays.asList("component", action, "--names", componentName))
.build());
LOGGER.debug("Performing {} on component {}", action, componentName);
} else {
throw new UnsupportedOperationException("Invalid action: "
+ action + ". Please use restart or stop action words.");
}

}

@VisibleForTesting
String getLocalDeploymentStatus() {
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ public class NetworkUtilsSteps {

private final Platform platform;
private final AtomicBoolean mqttConnectivity = new AtomicBoolean(true);
private final AtomicBoolean networkConnectivity = new AtomicBoolean(true);
private final Set<String> addedIPs = new HashSet<>();

@Inject
Expand Down Expand Up @@ -61,7 +62,7 @@ public boolean connectivityValue(String status) {
}

/**
* Disables or dnables device MQTT connectivity to IoT Core by blocking traffic on ports 8883 and 443.
* Disables or enables device MQTT connectivity to IoT Core by blocking traffic on ports 8883.
*
* @param connectivity the value of connectivity to set
* @throws IOException on IO errors
Expand Down Expand Up @@ -109,6 +110,27 @@ public void removeLoopBackAddress(final String address) throws IOException, Inte
addedIPs.remove(address);
}

/**
* Disables or enables device internet connectivity by blocking traffic on ports 443.
*
* @param connectivity the value of connectivity to set
* @throws IOException on IO errors
* @throws InterruptedException when thread has been interrupted
*/
@When("I set device network connectivity to {connectivityValue}")
public void setDeviceNetwork(final boolean connectivity) throws IOException, InterruptedException {
boolean changed = networkConnectivity.compareAndSet(!connectivity, connectivity);
if (changed) {
if (connectivity) {
LOGGER.info("Restoring Network connection");
platform.networkUtils().recoverNetwork();
} else {
LOGGER.info("Disconnecting Network connection");
platform.networkUtils().disconnectNetwork();
}
}
}

/**
* Restore settings to defaults.
*
Expand All @@ -118,12 +140,18 @@ public void removeLoopBackAddress(final String address) throws IOException, Inte
@After(order = Integer.MAX_VALUE)
public void restoreDefaultSettings() throws IOException, InterruptedException {
// rollback firewall changes
boolean changed = mqttConnectivity.compareAndSet(false, true);
if (changed) {
boolean mqttChange = mqttConnectivity.compareAndSet(false, true);
if (mqttChange) {
LOGGER.info("Automatically unblocking blocked MQTT connections");
platform.networkUtils().recoverMqtt();
}

boolean networkChange = networkConnectivity.compareAndSet(false, true);
if (networkChange) {
LOGGER.info("Automatically unblocking blocked Network connection");
platform.networkUtils().recoverNetwork();
}

// rollback lo interface changes
Set<String> ipsToRemove = new HashSet<>(addedIPs);
for (String ip : ipsToRemove) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

public abstract class NetworkUtils {
protected static final String[] MQTT_PORTS = {"8883"};
protected static final String[] NETWORK_PORTS = {"443"};

/**
* Disables incoming and outgoing MQTT connections by apply firewall rules.
Expand All @@ -29,4 +30,8 @@ public abstract class NetworkUtils {
public abstract void addLoopbackAddress(String address) throws IOException, InterruptedException;

public abstract void deleteLoopbackAddress(String address) throws IOException, InterruptedException;

public abstract void disconnectNetwork() throws InterruptedException, IOException;

public abstract void recoverNetwork() throws InterruptedException, IOException;
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,13 @@
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class LinuxNetworkUtils extends NetworkUtils {
private static final Logger LOGGER = LogManager.getLogger(LinuxNetworkUtils.class);
private static final long TIMEOUT_IN_SECONDS = 2L;

private static final String DISABLE_OPTION = "--delete";
private static final String APPEND_OPTION = "-A";
private static final String IPTABLES = "iptables";
Expand All @@ -31,11 +29,8 @@ public class LinuxNetworkUtils extends NetworkUtils {
"OUTPUT -p tcp -d localhost --dport %s -j ACCEPT",
"OUTPUT -p tcp --dport %s -j DROP"
};

private static final String ADD_LOOPBACK_ADDRESS_TEMPLATE = "addr add %s/32 dev lo";
private static final String DELETE_LOOPBACK_ADDRESS_TEMPLATE = "addr delete %s/32 dev lo";
private static final String COMMAND_FAILED_TO_RUN = "Command (%s) failed to run.";

private final LinuxCommands commands;

LinuxNetworkUtils(final Device device, final PillboxContext pillboxContext) {
Expand All @@ -47,13 +42,13 @@ public class LinuxNetworkUtils extends NetworkUtils {
* On Linux connections to/from 127.0.0.1 will still be allowed.
*/
@Override
public void disconnectMqtt() throws InterruptedException, IOException {
modifyMqttConnection(APPEND_OPTION);
public void disconnectMqtt() {
modifyConnection(APPEND_OPTION, MQTT_PORTS);
}

@Override
public void recoverMqtt() throws InterruptedException, IOException {
modifyMqttConnection(DISABLE_OPTION);
public void recoverMqtt() {
modifyConnection(DISABLE_OPTION, MQTT_PORTS);
}

@Override
Expand Down Expand Up @@ -81,13 +76,13 @@ public void deleteLoopbackAddress(String address) {
commands.execute(commandInput);
}

private void modifyMqttConnection(String action) throws IOException, InterruptedException {
private void modifyConnection(String action, String[] ports) {
for (String template : TEMPLATES) {
for (String port : MQTT_PORTS) {
for (String port : ports) {
List<String> arguments = new ArrayList<>();
arguments.add(action);
String cmd = String.format(template, port);
LOGGER.info("Running {} command: {}", IPTABLES, cmd);
LOGGER.debug("Running {} command: {}", IPTABLES, cmd);
arguments.addAll(Arrays.asList(cmd.split(" ")));

CommandInput commandInput = CommandInput.builder()
Expand All @@ -100,4 +95,14 @@ private void modifyMqttConnection(String action) throws IOException, Interrupted
}
}
}

@Override
public void disconnectNetwork() {
modifyConnection(APPEND_OPTION, NETWORK_PORTS);
}

@Override
public void recoverNetwork() {
modifyConnection(DISABLE_OPTION, NETWORK_PORTS);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,34 @@

package com.aws.greengrass.testing.platform.macos;

import com.aws.greengrass.testing.api.device.Device;
import com.aws.greengrass.testing.api.device.model.CommandInput;
import com.aws.greengrass.testing.api.model.PillboxContext;
import com.aws.greengrass.testing.platform.NetworkUtils;
import org.apache.logging.log4j.LogManager;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;

public class MacosNetworkUtils extends NetworkUtils {
private static final org.apache.logging.log4j.Logger LOGGER = LogManager.getLogger(MacosNetworkUtils.class);
private static final String NETWORK_SETUP_COMMAND = "networksetup";
private static final String DOWN_OPERATION = "off";
private static final String UP_OPERATION = "on";
private static final String ACTIVE_SERVICE = "Active";
private static final String INACTIVE_SERVICE = "Inactive";
private static final long TIMEOUT_IN_SECONDS = 2L;
private static final AtomicBoolean networkDown = new AtomicBoolean(false);
private final MacosCommands commands;

MacosNetworkUtils(final Device device, final PillboxContext pillboxContext) {
this.commands = new MacosCommands(device, pillboxContext);
}

@Override
public void disconnectMqtt() throws InterruptedException, IOException {
throw new UnsupportedOperationException("Operation not supported");
Expand All @@ -29,4 +52,61 @@ public void addLoopbackAddress(String address) {
public void deleteLoopbackAddress(String address) {
throw new UnsupportedOperationException("Operation not supported");
}

@Override
public void disconnectNetwork() {
List<String> activeNetworkServices = networkServicesList().get(ACTIVE_SERVICE);
LOGGER.debug("Active network service {}", activeNetworkServices);
if (!activeNetworkServices.isEmpty()) {
for (String networkService : activeNetworkServices) {
commands.execute(CommandInput.builder()
.line(NETWORK_SETUP_COMMAND)
.addArgs("-setnetworkserviceenabled", networkService, DOWN_OPERATION)
.timeout(TIMEOUT_IN_SECONDS)
.build());
}
networkDown.set(true);
}
}

@Override
public void recoverNetwork() {
if (networkDown.get()) {
List<String> inactiveNetworkServices = networkServicesList().get(INACTIVE_SERVICE);
LOGGER.debug("Inactive network service {}", inactiveNetworkServices);
if (!inactiveNetworkServices.isEmpty()) {
for (String networkService : inactiveNetworkServices) {
commands.execute(CommandInput.builder()
.line(NETWORK_SETUP_COMMAND)
.addArgs("-setnetworkserviceenabled", networkService, UP_OPERATION)
.timeout(TIMEOUT_IN_SECONDS)
.build());
}
}
}
}

/**
* Gets list of all network services and creates a map with Active and Inactive status.
* @return Map of list of active and inactive network services
*/
private Map<String, List<String>> networkServicesList() {
Map<String, List<String>> networkList = new HashMap<>();
String response = commands.executeToString(CommandInput.builder()
.line(NETWORK_SETUP_COMMAND)
.addArgs("-listallnetworkservices")
.build());
String[] networkServiceList = response.split("\\r?\\n|\\r");
for (int i = 1; i < networkServiceList.length; i++) {
String netService = networkServiceList[i];
if (netService.startsWith("*")) {
netService = "\"".concat(netService.substring(1, netService.length())).concat("\"");
networkList.computeIfAbsent(INACTIVE_SERVICE, k -> new ArrayList<>()).add(netService);
} else {
netService = "\"".concat(netService).concat("\"");
networkList.computeIfAbsent(ACTIVE_SERVICE, k -> new ArrayList<>()).add(netService);
}
}
return networkList;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,6 @@ public MacosCommands commands() {

@Override
public NetworkUtils networkUtils() {
return new MacosNetworkUtils();
return new MacosNetworkUtils(device, pillboxContext);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ private void blockPorts(String... ports) throws InterruptedException, IOExceptio
}
}

private void runNetshCommand(String command, boolean ignoreError) throws IOException, InterruptedException {
private void runNetshCommand(String command, boolean ignoreError) {
LOGGER.info("Running {} command: {}", NETSH, command);

CommandInput commandInput = CommandInput.builder()
Expand All @@ -122,4 +122,14 @@ private void runNetshCommand(String command, boolean ignoreError) throws IOExcep
}
}
}

@Override
public void disconnectNetwork() {
throw new UnsupportedOperationException("Operation not supported");
}

@Override
public void recoverNetwork() {
throw new UnsupportedOperationException("Operation not supported");
}
}
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
<cucumber.version>5.7.0</cucumber.version>
<immutables.version>2.8.2</immutables.version>
<log4j.version>2.17.1</log4j.version>
<aws.sdk.version>2.20.157</aws.sdk.version>
<aws.sdk.version>2.21.6</aws.sdk.version>
<auto.service.version>1.0</auto.service.version>
<findbugs.version>3.0.2</findbugs.version>
<guice.version>5.0.1</guice.version>
Expand Down
Loading