github.com/emc-advanced-dev/unik@v0.0.0-20190717152701-a58d3e8e33b7/containers/compilers/osv/java-compiler/osv_boot_creator.go (about)

     1  package main
     2  
     3  import (
     4  	"flag"
     5  	"fmt"
     6  	"github.com/sirupsen/logrus"
     7  	"io/ioutil"
     8  	"os"
     9  	"os/exec"
    10  	"path/filepath"
    11  	"strings"
    12  	"time"
    13  )
    14  
    15  //expect project directory at /project_directory; mount w/ -v FOLDER:/project_directory
    16  //output dir will be /project_directory
    17  //output files to whatever is mounted to /project_directory
    18  const (
    19  	project_directory = "/project_directory"
    20  )
    21  
    22  var buildImageTimeout = time.Minute * 10
    23  
    24  func main() {
    25  	useEc2Bootstrap := flag.Bool("ec2", false, "indicates whether to compile using the wrapper for ec2")
    26  	mainFile := flag.String("main_file", "", "name of jar or war file (not path)")
    27  	buildCmd := flag.String("buildCmd", "", "optional build command to build project (if not a jar)")
    28  	runtimeArgs := flag.String("runtime", "", "args to pass to java runtime")
    29  	args := flag.String("args", "", "arguments to kernel")
    30  	flag.Parse()
    31  
    32  	if *buildCmd != "" {
    33  		logrus.WithField("cmd", *buildCmd).Info("running user specified build command")
    34  		buildArgs := strings.Split(*buildCmd, " ")
    35  		var params []string
    36  		if len(buildArgs) > 1 {
    37  			params = buildArgs[1:]
    38  		}
    39  		build := exec.Command(buildArgs[0], params...)
    40  		build.Dir = project_directory
    41  		build.Stdout = os.Stdout
    42  		build.Stderr = os.Stderr
    43  		printCommand(build)
    44  		if err := build.Run(); err != nil {
    45  			logrus.WithError(err).Error("failed running build command")
    46  			os.Exit(-1)
    47  		}
    48  	}
    49  
    50  	artifactFile := filepath.Join(project_directory, *mainFile)
    51  	if _, err := os.Stat(artifactFile); err != nil {
    52  		logrus.WithError(err).Error("failed to stat " + filepath.Join(project_directory, *mainFile) + "; is main_file set correctly?")
    53  		logrus.Info("listing project files for debug purposes:")
    54  		listProjectFiles := exec.Command("find", project_directory)
    55  		listProjectFiles.Stdout = os.Stdout
    56  		listProjectFiles.Stderr = os.Stderr
    57  		listProjectFiles.Run()
    58  		os.Exit(-1)
    59  	}
    60  	argsStr := ""
    61  	if *useEc2Bootstrap {
    62  		argsStr += "-bootstrapType=ec2 "
    63  	} else {
    64  		argsStr += "-bootstrapType=udp "
    65  	}
    66  	if *args != "" {
    67  		argsStr += fmt.Sprintf("-appArgs=%s ", strings.Join(strings.Split(*args, " "), ",,"))
    68  	}
    69  
    70  	if strings.HasSuffix(*mainFile, ".war") {
    71  		logrus.Infof(".war file detected. Using Apache Tomcat to deploy")
    72  		argsStr += "-tomcat "
    73  		tomcatCapstanFileContents := fmt.Sprintf(`
    74  base: unik-tomcat
    75  
    76  cmdline: /java.so %s -cp /usr/tomcat/bin/bootstrap.jar:usr/tomcat/bin/tomcat-juli.jar -jar /program.jar %s
    77  
    78  #
    79  # List of files that are included in the generated image.
    80  #
    81  files:
    82    /usr/tomcat/webapps/%s: %s`,
    83  			*runtimeArgs,
    84  			argsStr,
    85  			filepath.Base(artifactFile), artifactFile)
    86  		logrus.Info("writing capstanfile\n", tomcatCapstanFileContents)
    87  		if err := ioutil.WriteFile(filepath.Join(project_directory, "Capstanfile"), []byte(tomcatCapstanFileContents), 0644); err != nil {
    88  			logrus.WithError(err).Error("failed writing capstanfile")
    89  			os.Exit(-1)
    90  		}
    91  	} else if strings.HasSuffix(*mainFile, ".jar") {
    92  		logrus.Infof("building Java unikernel from .jar file")
    93  		argsStr += fmt.Sprintf("-jarName=/%s", *mainFile)
    94  		jarRunnerCapstanFileContents := fmt.Sprintf(`
    95  base: unik-jar-runner
    96  
    97  cmdline: /java.so %s -cp /%s -jar /program.jar %s
    98  
    99  rootfs: %s`,
   100  			*runtimeArgs,
   101  			*mainFile,
   102  			argsStr,
   103  			project_directory)
   104  		logrus.Info("writing capstanfile\n", jarRunnerCapstanFileContents)
   105  		if err := ioutil.WriteFile(filepath.Join(project_directory, "Capstanfile"), []byte(jarRunnerCapstanFileContents), 0644); err != nil {
   106  			logrus.WithError(err).Error("failed writing capstanfile")
   107  			os.Exit(-1)
   108  		}
   109  	} else {
   110  		logrus.Errorf("%s is not of type .war or .jar, exiting!", *mainFile)
   111  		os.Exit(-1)
   112  	}
   113  
   114  	go func() {
   115  		fmt.Println("capstain building")
   116  
   117  		capstanCmd := exec.Command("capstan", "run", "-p", "qemu")
   118  		capstanCmd.Dir = project_directory
   119  		capstanCmd.Stdout = os.Stdout
   120  		capstanCmd.Stderr = os.Stderr
   121  		printCommand(capstanCmd)
   122  		if err := capstanCmd.Run(); err != nil {
   123  			logrus.WithError(err).Error("capstan build failed")
   124  			os.Exit(-1)
   125  		}
   126  	}()
   127  	capstanImage := filepath.Join(os.Getenv("HOME"), ".capstan", "instances", "qemu", "project_directory", "disk.qcow2")
   128  
   129  	select {
   130  	case <-fileReady(capstanImage):
   131  		fmt.Printf("image ready at %s\n", capstanImage)
   132  		break
   133  	case <-time.After(buildImageTimeout):
   134  		logrus.Error("timed out waiting for capstan to finish building")
   135  		os.Exit(-1)
   136  	}
   137  
   138  	fmt.Println("qemu-img converting (compatibility")
   139  	convertToCompatibleCmd := exec.Command("qemu-img", "convert",
   140  		"-f", "qcow2",
   141  		"-O", "qcow2",
   142  		"-o", "compat=0.10",
   143  		capstanImage,
   144  		project_directory+"/boot.qcow2")
   145  	printCommand(convertToCompatibleCmd)
   146  	if out, err := convertToCompatibleCmd.CombinedOutput(); err != nil {
   147  		logrus.WithError(err).Error(string(out))
   148  		os.Exit(-1)
   149  	}
   150  
   151  	fmt.Println("file created at " + project_directory + "/boot.qcow2")
   152  }
   153  
   154  func fileReady(filename string) <-chan struct{} {
   155  	closeChan := make(chan struct{})
   156  	fmt.Printf("waiting for file to become ready...\n")
   157  	go func() {
   158  		count := 0
   159  		for {
   160  			if _, err := os.Stat(filename); err == nil {
   161  				close(closeChan)
   162  				return
   163  			}
   164  			//count every 5 sec
   165  			if count%5 == 0 {
   166  				fmt.Printf("waiting for file...%vs\n", count)
   167  			}
   168  			time.Sleep(time.Second * 1)
   169  			count++
   170  		}
   171  	}()
   172  	return closeChan
   173  }
   174  
   175  func printCommand(cmd *exec.Cmd) {
   176  	fmt.Printf("running command from dir %s: %v\n", cmd.Dir, cmd.Args)
   177  }