Skip to content

Commit

Permalink
feat: add step and platform commands for device network
Browse files Browse the repository at this point in the history
  • Loading branch information
urvashijain18 committed Oct 24, 2023
1 parent 5095919 commit 75de3df
Show file tree
Hide file tree
Showing 8 changed files with 175 additions and 19 deletions.
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) {
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

0 comments on commit 75de3df

Please sign in to comment.