...

Source file src/github.com/Microsoft/hcsshim/internal/tools/uvmboot/wcow.go

Documentation: github.com/Microsoft/hcsshim/internal/tools/uvmboot

     1  //go:build windows
     2  
     3  package main
     4  
     5  import (
     6  	"context"
     7  	"encoding/json"
     8  	"fmt"
     9  	"os"
    10  	"os/exec"
    11  	"path/filepath"
    12  	"strings"
    13  
    14  	"github.com/Microsoft/hcsshim/internal/cmd"
    15  	"github.com/Microsoft/hcsshim/internal/log"
    16  	"github.com/Microsoft/hcsshim/internal/uvm"
    17  	"github.com/containerd/console"
    18  	"github.com/urfave/cli"
    19  )
    20  
    21  var (
    22  	wcowDockerImage string
    23  	wcowCommandLine string
    24  	wcowImage       string
    25  	wcowUseTerminal bool
    26  )
    27  
    28  var wcowCommand = cli.Command{
    29  	Name:  "wcow",
    30  	Usage: "boot a WCOW UVM",
    31  	Flags: []cli.Flag{
    32  		cli.StringFlag{
    33  			Name:        "exec",
    34  			Usage:       "Command to execute in the UVM.",
    35  			Destination: &wcowCommandLine,
    36  		},
    37  		cli.StringFlag{
    38  			Name:        "docker-image",
    39  			Usage:       "Docker image to use for the UVM image",
    40  			Destination: &wcowDockerImage,
    41  		},
    42  		cli.StringFlag{
    43  			Name:        "image",
    44  			Usage:       "Path for the UVM image",
    45  			Destination: &wcowImage,
    46  		},
    47  		cli.BoolFlag{
    48  			Name:        "tty,t",
    49  			Usage:       "create the process in the UVM with a TTY enabled",
    50  			Destination: &wcowUseTerminal,
    51  		},
    52  	},
    53  	Action: func(c *cli.Context) error {
    54  		runMany(c, func(id string) error {
    55  			options := uvm.NewDefaultOptionsWCOW(id, "")
    56  			setGlobalOptions(c, options.Options)
    57  			var layers []string
    58  			if wcowImage != "" {
    59  				layer, err := filepath.Abs(wcowImage)
    60  				if err != nil {
    61  					return err
    62  				}
    63  				layers = []string{layer}
    64  			} else {
    65  				if wcowDockerImage == "" {
    66  					wcowDockerImage = "mcr.microsoft.com/windows/nanoserver:1809"
    67  				}
    68  				var err error
    69  				layers, err = getLayers(wcowDockerImage)
    70  				if err != nil {
    71  					return err
    72  				}
    73  			}
    74  			tempDir, err := os.MkdirTemp("", "uvmboot")
    75  			if err != nil {
    76  				return err
    77  			}
    78  			defer os.RemoveAll(tempDir)
    79  			options.LayerFolders = append(layers, tempDir)
    80  			vm, err := uvm.CreateWCOW(context.TODO(), options)
    81  			if err != nil {
    82  				return err
    83  			}
    84  			defer vm.Close()
    85  			if err := vm.Start(context.TODO()); err != nil {
    86  				return err
    87  			}
    88  			if wcowCommandLine != "" {
    89  				cmd := cmd.Command(vm, "cmd.exe", "/c", wcowCommandLine)
    90  				cmd.Spec.User.Username = `NT AUTHORITY\SYSTEM`
    91  				cmd.Log = log.L.Dup()
    92  				if wcowUseTerminal {
    93  					cmd.Spec.Terminal = true
    94  					cmd.Stdin = os.Stdin
    95  					cmd.Stdout = os.Stdout
    96  					con, err := console.ConsoleFromFile(os.Stdin)
    97  					if err == nil {
    98  						err = con.SetRaw()
    99  						if err != nil {
   100  							return err
   101  						}
   102  						defer func() {
   103  							_ = con.Reset()
   104  						}()
   105  					}
   106  				} else {
   107  					cmd.Stdout = os.Stdout
   108  					cmd.Stderr = os.Stdout
   109  				}
   110  				err = cmd.Run()
   111  				if err != nil {
   112  					return err
   113  				}
   114  			}
   115  			_ = vm.Terminate(context.TODO())
   116  			_ = vm.Wait()
   117  			return vm.ExitError()
   118  		})
   119  		return nil
   120  	},
   121  }
   122  
   123  func getLayers(imageName string) ([]string, error) {
   124  	cmd := exec.Command("docker", "inspect", imageName, "-f", `"{{.GraphDriver.Data.dir}}"`)
   125  	out, err := cmd.Output()
   126  	if err != nil {
   127  		return nil, fmt.Errorf("failed to find layers for %s", imageName)
   128  	}
   129  	imagePath := strings.Replace(strings.TrimSpace(string(out)), `"`, ``, -1)
   130  	layers, err := getLayerChain(imagePath)
   131  	if err != nil {
   132  		return nil, err
   133  	}
   134  	return append([]string{imagePath}, layers...), nil
   135  }
   136  
   137  func getLayerChain(layerFolder string) ([]string, error) {
   138  	jPath := filepath.Join(layerFolder, "layerchain.json")
   139  	content, err := os.ReadFile(jPath)
   140  	if err != nil {
   141  		return nil, err
   142  	}
   143  	var layerChain []string
   144  	err = json.Unmarshal(content, &layerChain)
   145  	if err != nil {
   146  		return nil, fmt.Errorf("failed to unmarshal layerchain: %s", err)
   147  	}
   148  	return layerChain, nil
   149  }
   150  

View as plain text