diff options
author | Simon Rettberg | 2019-02-12 15:03:04 +0100 |
---|---|---|
committer | Simon Rettberg | 2019-02-12 15:03:04 +0100 |
commit | 6581210de2a1644fcf665b93819b5cb08aa9b1b2 (patch) | |
tree | f09c1956c9cc9687ee626f75b7de4e692a63b76f /src | |
parent | [CreateLdapConfig] Fix detection of valid CN (diff) | |
download | tmlite-bwlp-6581210de2a1644fcf665b93819b5cb08aa9b1b2.tar.gz tmlite-bwlp-6581210de2a1644fcf665b93819b5cb08aa9b1b2.tar.xz tmlite-bwlp-6581210de2a1644fcf665b93819b5cb08aa9b1b2.zip |
[CompileIPxe*] Separate legacy pxelinux and new ipxe-only approach
Diffstat (limited to 'src')
-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.java | 194 | ||||
-rw-r--r-- | src/main/java/org/openslx/taskmanager/tasks/RemoteReboot.java | 37 | ||||
-rw-r--r-- | src/main/java/org/openslx/taskmanager/tasks/Systemctl.java | 3 |
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; |