github.com/Cloud-Foundations/Dominator@v0.3.4/cmd/builder-tool/buildRaw.go (about)

     1  // +build linux
     2  
     3  package main
     4  
     5  import (
     6  	"fmt"
     7  	"io"
     8  	"io/ioutil"
     9  	"os"
    10  	"syscall"
    11  	"time"
    12  
    13  	"github.com/Cloud-Foundations/Dominator/imagebuilder/builder"
    14  	"github.com/Cloud-Foundations/Dominator/lib/decoders"
    15  	"github.com/Cloud-Foundations/Dominator/lib/filesystem/scanner"
    16  	"github.com/Cloud-Foundations/Dominator/lib/filesystem/util"
    17  	"github.com/Cloud-Foundations/Dominator/lib/fsutil"
    18  	"github.com/Cloud-Foundations/Dominator/lib/hash"
    19  	"github.com/Cloud-Foundations/Dominator/lib/log"
    20  	"github.com/Cloud-Foundations/Dominator/lib/mbr"
    21  	"github.com/Cloud-Foundations/Dominator/lib/wsyscall"
    22  )
    23  
    24  const createFlags = os.O_CREATE | os.O_TRUNC | os.O_RDWR
    25  
    26  type dummyHasher struct{}
    27  
    28  func buildRawFromManifestSubcommand(args []string,
    29  	logger log.DebugLogger) error {
    30  	if err := buildRawFromManifest(args[0], args[1], logger); err != nil {
    31  		return fmt.Errorf("error building RAW image from manifest: %s", err)
    32  	}
    33  	return nil
    34  }
    35  
    36  func buildRawFromManifest(manifestDir, rawFilename string,
    37  	logger log.DebugLogger) error {
    38  	var variables map[string]string
    39  	if *variablesFilename != "" {
    40  		err := decoders.DecodeFile(*variablesFilename, &variables)
    41  		if err != nil {
    42  			return err
    43  		}
    44  	}
    45  	if rawSize < 1<<20 {
    46  		return fmt.Errorf("rawSize: %d too small", rawSize)
    47  	}
    48  	err := syscall.Mount("none", "/", "", syscall.MS_REC|syscall.MS_PRIVATE, "")
    49  	if err != nil {
    50  		return fmt.Errorf("error making mounts private: %s", err)
    51  	}
    52  	srpcClient := getImageServerClient()
    53  	tmpFilename := rawFilename + "~"
    54  	file, err := os.OpenFile(tmpFilename, createFlags, fsutil.PrivateFilePerms)
    55  	if err != nil {
    56  		return err
    57  	}
    58  	file.Close()
    59  	defer os.Remove(tmpFilename)
    60  	if err := os.Truncate(tmpFilename, int64(rawSize)); err != nil {
    61  		return err
    62  	}
    63  	if err := mbr.WriteDefault(tmpFilename, mbr.TABLE_TYPE_MSDOS); err != nil {
    64  		return err
    65  	}
    66  	partition := "p1"
    67  	loopDevice, err := fsutil.LoopbackSetupAndWaitForPartition(tmpFilename,
    68  		partition, time.Minute, logger)
    69  	if err != nil {
    70  		return err
    71  	}
    72  	defer fsutil.LoopbackDeleteAndWaitForPartition(loopDevice, partition,
    73  		time.Minute, logger)
    74  	rootDevice := loopDevice + partition
    75  	rootLabel := "root@test"
    76  	err = util.MakeExt4fs(rootDevice, rootLabel, nil, 0, logger)
    77  	if err != nil {
    78  		return err
    79  	}
    80  	rootDir, err := ioutil.TempDir("", "rootfs")
    81  	if err != nil {
    82  		return err
    83  	}
    84  	defer os.Remove(rootDir)
    85  	err = wsyscall.Mount(rootDevice, rootDir, "ext4", 0, "")
    86  	if err != nil {
    87  		return fmt.Errorf("error mounting: %s", rootDevice)
    88  	}
    89  	defer syscall.Unmount(rootDir, 0)
    90  	logWriter := &logWriterType{}
    91  	if *alwaysShowBuildLog {
    92  		fmt.Fprintln(os.Stderr, "Start of build log ==========================")
    93  	}
    94  	err = builder.UnpackImageAndProcessManifestWithOptions(
    95  		srpcClient,
    96  		builder.BuildLocalOptions{
    97  			BindMounts:        bindMounts,
    98  			ManifestDirectory: manifestDir,
    99  			Variables:         variables,
   100  		},
   101  		rootDir,
   102  		logWriter)
   103  	if err != nil {
   104  		if !*alwaysShowBuildLog {
   105  			fmt.Fprintln(os.Stderr,
   106  				"Start of build log ==========================")
   107  			os.Stderr.Write(logWriter.Bytes())
   108  		}
   109  		fmt.Fprintln(os.Stderr, "End of build log ============================")
   110  		return fmt.Errorf("error processing manifest: %s", err)
   111  	}
   112  	if *alwaysShowBuildLog {
   113  		fmt.Fprintln(os.Stderr, "End of build log ============================")
   114  	} else {
   115  		err := fsutil.CopyToFile("build.log", filePerms, &logWriter.buffer,
   116  			uint64(logWriter.buffer.Len()))
   117  		if err != nil {
   118  			return fmt.Errorf("error writing build log: %s", err)
   119  		}
   120  	}
   121  	fs, err := scanner.ScanFileSystem(rootDir, nil, nil, nil, &dummyHasher{},
   122  		nil)
   123  	err = util.MakeBootable(&fs.FileSystem, loopDevice, rootLabel, rootDir,
   124  		"net.ifnames=0", false, logger)
   125  	if err != nil {
   126  		return err
   127  	}
   128  	return os.Rename(tmpFilename, rawFilename)
   129  }
   130  
   131  func (h *dummyHasher) Hash(reader io.Reader, length uint64) (hash.Hash, error) {
   132  	return hash.Hash{}, nil
   133  }