summaryrefslogblamecommitdiffstats
path: root/src/main/java/org/openslx/taskmanager/tasks/CompileIPxeNew.java
blob: 2afa636e1531df3a26fedc44c71cf05792ee9584 (plain) (tree)

































































































































































































                                                                                                                                           
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 );
		}

	}

}