summaryrefslogtreecommitdiffstats
path: root/src/main/java/org/openslx
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/org/openslx')
-rw-r--r--src/main/java/org/openslx/taskmanager/tasks/CompileIPxeLegacy.java (renamed from src/main/java/org/openslx/taskmanager/tasks/CompileIPxe.java)8
-rw-r--r--src/main/java/org/openslx/taskmanager/tasks/CompileIPxeNew.java194
-rw-r--r--src/main/java/org/openslx/taskmanager/tasks/RemoteReboot.java37
-rw-r--r--src/main/java/org/openslx/taskmanager/tasks/Systemctl.java3
4 files changed, 226 insertions, 16 deletions
diff --git a/src/main/java/org/openslx/taskmanager/tasks/CompileIPxe.java b/src/main/java/org/openslx/taskmanager/tasks/CompileIPxeLegacy.java
index bb69559..7002be6 100644
--- a/src/main/java/org/openslx/taskmanager/tasks/CompileIPxe.java
+++ b/src/main/java/org/openslx/taskmanager/tasks/CompileIPxeLegacy.java
@@ -13,9 +13,9 @@ import org.openslx.taskmanager.api.AbstractTask;
import com.google.gson.annotations.Expose;
-public class CompileIPxe extends AbstractTask
+public class CompileIPxeLegacy extends AbstractTask
{
- private static final Logger LOG = Logger.getLogger( CompileIPxe.class );
+ private static final Logger LOG = Logger.getLogger( CompileIPxeLegacy.class );
@Expose
private String defaultentry = null;
@@ -73,7 +73,7 @@ public class CompileIPxe extends AbstractTask
// Prepare menu
String template;
try {
- template = FileUtils.readFileToString( new File( "./data/pxemenu.template" ), StandardCharsets.UTF_8 );
+ template = FileUtils.readFileToString( new File( "./data/pxelinux-pxemenu.template" ), StandardCharsets.UTF_8 );
} catch ( IOException e ) {
status.error = e.toString();
return false;
@@ -117,7 +117,7 @@ public class CompileIPxe extends AbstractTask
// Prepare menu
String template;
try {
- template = FileUtils.readFileToString( new File( "./data/ipxe-embed.template" ), StandardCharsets.UTF_8 );
+ template = FileUtils.readFileToString( new File( "./data/pxelinux-ipxe-embed.template" ), StandardCharsets.UTF_8 );
} catch ( IOException e ) {
status.error = e.toString();
return false;
diff --git a/src/main/java/org/openslx/taskmanager/tasks/CompileIPxeNew.java b/src/main/java/org/openslx/taskmanager/tasks/CompileIPxeNew.java
new file mode 100644
index 0000000..2afa636
--- /dev/null
+++ b/src/main/java/org/openslx/taskmanager/tasks/CompileIPxeNew.java
@@ -0,0 +1,194 @@
+package org.openslx.taskmanager.tasks;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.log4j.Logger;
+import org.openslx.satserver.util.Exec;
+import org.openslx.satserver.util.Exec.ExecCallback;
+import org.openslx.taskmanager.api.AbstractTask;
+import org.openslx.taskmanager.api.BoundedLog;
+
+import com.google.gson.annotations.Expose;
+
+public class CompileIPxeNew extends AbstractTask
+{
+ private static final Logger LOG = Logger.getLogger( CompileIPxeNew.class );
+
+ @Expose
+ private String ipaddress = null;
+
+ private Output status = new Output();
+
+ private static AtomicBoolean isRunning = new AtomicBoolean();
+
+ /**
+ * Files which should be copied to the TFTP dir so they're available for netboot
+ */
+ private static final String[] FILES_NET = { "bin-i386-pcbios/undionly.kpxe", "bin-i386-pcbios/undionly.kkpxe",
+ "bin-i386-pcbios/undionly.kkkpxe", "bin-x86_64-efi/ipxe.efi", "bin-x86_64-efi/snponly.efi" };
+
+ /**
+ * Files which should be moved to the websrv so they're available for download
+ */
+ private static final String[] FILES_DL = { "bin-i386-pcbios/ipxe.usb", "bin-i386-pcbios/ipxe.hd",
+ "bin-i386-pcbios/ipxe.lkrn", "bin-x86_64-efi/ipxe.usb", "bin-x86_64-efi/ipxe.efi",
+ "bin-x86_64-efi/snp.usb", "bin-x86_64-efi/snp.efi" };
+
+ /**
+ * Combination of the two, mapping each file to false.
+ * Will be used for status object.
+ */
+ private static final Map<String, Boolean> FILES_MAP;
+
+ private static final String[] FILES_ALL;
+
+ static
+ {
+ Map<String, Boolean> map = new HashMap<>();
+ for ( String s : FILES_NET ) {
+ map.put( s, false );
+ }
+ for ( String s : FILES_DL ) {
+ map.put( s, false );
+ }
+ FILES_MAP = Collections.unmodifiableMap( map );
+ FILES_ALL = map.keySet().toArray( new String[ map.size() ] );
+ }
+
+ @Override
+ protected boolean initTask()
+ {
+ this.setStatusObject( this.status );
+ if ( this.ipaddress == null || this.ipaddress.isEmpty() ) {
+ status.addError( "No IP address given!" );
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ protected boolean execute()
+ {
+ if ( !isRunning.compareAndSet( false, true ) ) {
+ status.addError( "Another operation is already in progress." );
+ return false;
+ }
+ try {
+ boolean ret = true;
+ if ( !updateIpxe() )
+ ret = false;
+ return ret;
+ } finally {
+ isRunning.set( false );
+ }
+ }
+
+ private boolean updateIpxe()
+ {
+ // Prepare menu
+ String template;
+ try {
+ template = FileUtils.readFileToString( new File( "./data/ipxe-embed.template" ), StandardCharsets.UTF_8 );
+ } catch ( IOException e ) {
+ status.addError( e.toString() );
+ return false;
+ }
+ // Substitution
+ template = template.replace( "%ipaddress%", this.ipaddress );
+ String hybridEmbed = template.replace( "%mode%", "PXE" );
+ String usbEmbed = template.replace( "%mode%", "USB" );
+ // Write out
+ try {
+ FileUtils.writeStringToFile( new File( "/opt/openslx/ipxe/ipxelinux.ipxe" ), hybridEmbed, StandardCharsets.UTF_8 );
+ FileUtils.writeStringToFile( new File( "/opt/openslx/ipxe/usb.ipxe" ), usbEmbed, StandardCharsets.UTF_8 );
+ } catch ( IOException e ) {
+ status.addError( e.toString() );
+ return false;
+ }
+ // Compile
+ ProcLogger pl = new ProcLogger();
+ if ( 0 != Exec.syncAt( 600, pl, "/opt/openslx/ipxe/src", join( "make", "EMBED=../ipxelinux.ipxe", FILES_ALL ) ) ) {
+ status.addError( "Compiling ipxe targets failed" );
+ return false;
+ }
+ // NETBOOT
+ for ( String f : FILES_NET ) {
+ try {
+ FileUtils.copyFile( new File( "/opt/openslx/ipxe/src", f ),
+ new File( "/srv/openslx/tftp", new File( f ).getName() ) );
+ } catch ( Exception e ) {
+ status.addError( "Cannot copy " + f + " to TFTP dir: " + e.toString() );
+ }
+ }
+ // DOWNLOAD
+ for ( String f : FILES_DL ) {
+ try {
+ FileUtils.copyFile( new File( "/opt/openslx/ipxe/src/", f ),
+ new File( "/srv/openslx/www/boot/download", f.replace( '/', '-' ) ) );
+ } catch ( Exception e ) {
+ status.addError( "Cannot copy " + f + " to www-download dir: " + e.toString() );
+ }
+ }
+ return true;
+ }
+
+ private String[] join(String a, String b, String... rest)
+ {
+ String[] r = new String[rest.length + 2];
+ r[0] = a;
+ r[1] = b;
+ System.arraycopy( rest, 0, r, 2, rest.length );
+ return r;
+ }
+
+ class Output
+ {
+ protected Map<String, Boolean> files = new ConcurrentHashMap<>( FILES_MAP );
+ protected final BoundedLog log = new BoundedLog( 20, true );
+ protected String errors = "";
+
+ protected void addLog( String data )
+ {
+ log.addLog( data );
+ }
+
+ protected synchronized void addError( String err )
+ {
+ errors = errors + err + "\n";
+ }
+ }
+
+ private static final Pattern RE_FINISH = Pattern.compile( "^\\s*\\[(?:FINISH|GENEFIDSK)\\]\\s*(.*?)\\s*$" );
+
+ private class ProcLogger implements ExecCallback
+ {
+
+ @Override
+ public void processStdOut( String line )
+ {
+ status.addLog( line );
+ Matcher m = RE_FINISH.matcher( line );
+ if ( m.matches() ) {
+ status.files.put( m.group( 1 ), true );
+ }
+ }
+
+ @Override
+ public void processStdErr( String line )
+ {
+ status.addLog( line );
+ }
+
+ }
+
+}
diff --git a/src/main/java/org/openslx/taskmanager/tasks/RemoteReboot.java b/src/main/java/org/openslx/taskmanager/tasks/RemoteReboot.java
index d7f17cf..0e09a85 100644
--- a/src/main/java/org/openslx/taskmanager/tasks/RemoteReboot.java
+++ b/src/main/java/org/openslx/taskmanager/tasks/RemoteReboot.java
@@ -23,11 +23,18 @@ import com.jcraft.jsch.Session;
public class RemoteReboot extends AbstractTask
{
+
+ static enum Mode {
+ SHUTDOWN,
+ REBOOT,
+ KEXEC_REBOOT,
+ }
+
@Expose
private Client[] clients;
@Expose
- private boolean shutdown;
+ private Mode mode;
@Expose
private int minutes;
@@ -36,9 +43,6 @@ public class RemoteReboot extends AbstractTask
private String locationId;
@Expose
- private String locationName;
-
- @Expose
private String sshkey;
@Expose
@@ -48,9 +52,13 @@ public class RemoteReboot extends AbstractTask
private Output status = new Output();
- private static final String REBOOT_CMD = "/opt/openslx/scripts/idleaction-scheduled_action --detach reboot";
+ private static final String BASE_CMD = "/opt/openslx/scripts/idleaction-scheduled_action --detach";
+
+ private static final String REBOOT_CMD = BASE_CMD + " reboot";
+
+ private static final String KEXEC_CMD = BASE_CMD + " kexec-reboot";
- private static final String SHUTDOWN_CMD = "/opt/openslx/scripts/idleaction-scheduled_action --detach poweroff";
+ private static final String SHUTDOWN_CMD = BASE_CMD + " poweroff";
@Override
protected boolean initTask()
@@ -66,16 +74,19 @@ public class RemoteReboot extends AbstractTask
if ( port < 1 || port > 65535 ) {
status.addError( "Invalid port number" );
}
+ if (mode == null) {
+ status.addError( "Invalid/no mode of operation" );
+ }
if ( status.error != null )
return false;
-
+
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;
+ status.mode = mode;
JSch.setConfig( "StrictHostKeyChecking", "no" );
sshClient = new JSch();
@@ -115,11 +126,15 @@ public class RemoteReboot extends AbstractTask
channel = (ChannelExec)session.openChannel( "exec" );
String args = " " + minutes + " " + String.format( "'%s'", client.machineuuid.replace( "'", "'\\''" ) );
- if ( shutdown ) {
+ if ( mode == Mode.SHUTDOWN ) {
ret = execCommand( channel, SHUTDOWN_CMD + args );
status.clientStatus.put( client.machineuuid, minutes == 0 ? ClientStatus.SHUTDOWN : ClientStatus.SHUTDOWN_AT );
} else {
- ret = execCommand( channel, REBOOT_CMD + args );
+ if ( mode == Mode.REBOOT ) {
+ ret = execCommand( channel, REBOOT_CMD + args );
+ } else {
+ ret = execCommand( channel, KEXEC_CMD + args );
+ }
if ( ret == 0 ) {
status.clientStatus.put( client.machineuuid, minutes == 0 ? ClientStatus.REBOOTING : ClientStatus.REBOOT_AT );
rebootingClients.add( client );
@@ -255,8 +270,8 @@ public class RemoteReboot extends AbstractTask
private Client[] clients;
private String time;
private String locationId;
- private String locationName;
private String error;
+ private Mode mode;
private synchronized void addError( String e )
{
diff --git a/src/main/java/org/openslx/taskmanager/tasks/Systemctl.java b/src/main/java/org/openslx/taskmanager/tasks/Systemctl.java
index 1e2a9bf..7b09a39 100644
--- a/src/main/java/org/openslx/taskmanager/tasks/Systemctl.java
+++ b/src/main/java/org/openslx/taskmanager/tasks/Systemctl.java
@@ -50,8 +50,9 @@ public class Systemctl extends SystemCommandTask
case "dnbd3-server":
break;
case "taskmanager":
+ case "lighttpd":
if ( !operation.equals( "restart" ) ) {
- status.addMsg( "Error: Service taskmanager can only be restarted." );
+ status.addMsg( "Error: Service " + service + " can only be restarted." );
return null;
}
break;