From 20350a2b7e5cfa13263b9ce41f48d9e988682909 Mon Sep 17 00:00:00 2001 From: Udo Walter Date: Tue, 14 Feb 2017 15:52:30 +0100 Subject: Add RemoteReboot task --- pom.xml | 5 + .../openslx/taskmanager/tasks/RemoteReboot.java | 162 +++++++++++++++++++++ 2 files changed, 167 insertions(+) create mode 100644 src/main/java/org/openslx/taskmanager/tasks/RemoteReboot.java diff --git a/pom.xml b/pom.xml index 324c2a3..ce899cc 100644 --- a/pom.xml +++ b/pom.xml @@ -110,5 +110,10 @@ 1.0-SNAPSHOT compile + + com.jcabi + jcabi-ssh + 1.5.2 + diff --git a/src/main/java/org/openslx/taskmanager/tasks/RemoteReboot.java b/src/main/java/org/openslx/taskmanager/tasks/RemoteReboot.java new file mode 100644 index 0000000..7e1b228 --- /dev/null +++ b/src/main/java/org/openslx/taskmanager/tasks/RemoteReboot.java @@ -0,0 +1,162 @@ +package org.openslx.taskmanager.tasks; + +import java.io.IOException; +import java.net.Socket; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +import org.openslx.taskmanager.api.AbstractTask; + +import com.jcabi.ssh.Shell; +import com.google.gson.annotations.Expose; +import com.jcabi.ssh.SSH; + +public class RemoteReboot extends AbstractTask +{ + @Expose + private HashMap[] clients; + + @Expose + private boolean shutdown = false; + + @Expose + private int minutes = 0; + + @Expose + private String locationId; + + @Expose + private String locationName; + + @Expose + private String sshkey; + + @Expose + private int port = 22; + + private Output status = new Output(); + + @Override + protected boolean initTask() + { + this.setStatusObject( this.status ); + + status.clients = clients; + Date shutdownTime = new Date(System.currentTimeMillis()+minutes*60*1000); + SimpleDateFormat sdf = new SimpleDateFormat("HH:mm"); + status.time = sdf.format(shutdownTime); + status.locationId = locationId; + status.locationName = locationName; + return true; + } + + @Override + protected boolean execute() + { + // try to connect to every client and start the reboot/shutdown process + ExecutorService tp = Executors.newFixedThreadPool( clients.length > 4 ? 4 : clients.length ); + for (HashMap client : clients) { + final String ip = client.get("ip"); + status.clientStatus.put(ip, "connecting"); + tp.submit(new Runnable() { + public void run() { + try { + Shell shell = new SSH(ip, port, "root", sshkey); + if (shutdown) { + new Shell.Empty(shell).exec("/sbin/shutdown +" + minutes); + status.clientStatus.put(ip, minutes == 0 ? "shutdown" : "shutdownat"); + } else { + new Shell.Empty(shell).exec("/sbin/reboot"); + status.clientStatus.put(ip, "rebooting"); + } + } catch (IOException e) { + status.clientStatus.put(ip, "error"); + } + } + }); + } + tp.shutdown(); + + try { + tp.awaitTermination( clients.length * 5, TimeUnit.SECONDS ); + } catch ( InterruptedException e ) { + // ... + } + + // wait for rebooting clients to finish rebooting + ArrayList rebootingClients = new ArrayList(); + for (Map.Entry entry : status.clientStatus.entrySet()) { + if (entry.getValue() == "rebooting") { + rebootingClients.add(entry.getKey()); + } + } + + if (rebootingClients.size() > 0) { + ExecutorService statusTP = Executors.newFixedThreadPool( rebootingClients.size() > 4 ? 4 : rebootingClients.size() ); + for (final String ip : rebootingClients) { + statusTP.submit(new Runnable() { + public void run() { + while (!isOnline(ip)) { + try { + Thread.sleep(3000); + } catch (InterruptedException e) { + } + } + status.clientStatus.put(ip, "online"); + } + }); + } + statusTP.shutdown(); + + try { + statusTP.awaitTermination( 180, TimeUnit.SECONDS ); + } catch ( InterruptedException e ) { + // ... + } + } + + // change status of clients that got stuck because of timeouts + for (Map.Entry entry : status.clientStatus.entrySet()) { + String value = entry.getValue(); + if (value == "connecting" || value == "rebooting") { + entry.setValue("error"); + } + } + + return true; + } + + + private boolean isOnline(String address) + { + try (Socket s = new Socket(address, port)) { + return true; + } catch (IOException ex) { + } + return false; + } + + + /** + * Output - contains additional status data of this task + */ + class Output + { + private ConcurrentHashMap clientStatus = new ConcurrentHashMap(); + private HashMap[] clients; + private String time; + private String locationId; + private String locationName; + } +} -- cgit v1.2.3-55-g7522