-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement the first part of 'trust launch'
Trust launch creates a new SUDI keyset, creates a machine, provisions it for that SUDI keyset, then installs it. This patchset implements the auto-provisioning, but not yet install. Signed-off-by: Serge Hallyn <[email protected]>
- Loading branch information
Showing
8 changed files
with
479 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,175 @@ | ||
package main | ||
|
||
import ( | ||
"os" | ||
"path/filepath" | ||
"strings" | ||
|
||
"github.com/pkg/errors" | ||
"github.com/project-machine/mos/pkg/provider" | ||
"github.com/project-machine/mos/pkg/trust" | ||
"github.com/urfave/cli" | ||
) | ||
|
||
var launchCmd = cli.Command{ | ||
Name: "launch", | ||
Usage: "launch a new machine", | ||
UsageText: `name install-url | ||
name: name to give the VM | ||
install-url: install.json distoci URL to install (e.g. zothub.io/machine/zot/install:1.0.0) | ||
Note that install is not yet supported.`, | ||
Action: doLaunch, | ||
Flags: []cli.Flag{ | ||
cli.StringFlag{ | ||
Name: "project", | ||
Usage: "keyset:project to which this machine will belong (TRUST_PROJECT)", | ||
}, | ||
cli.StringFlag{ | ||
Name: "serial, uuid", | ||
Usage: "Serial number UUID to assign to the machine, empty to use a random UUID", | ||
Value: "", | ||
}, | ||
cli.BoolFlag{ | ||
Name: "skip-provisioning", | ||
Usage: "Skip provisioning the machine", | ||
}, | ||
cli.BoolFlag{ | ||
Name: "skip-install", | ||
Usage: "Skip running the install ISO", | ||
}, | ||
cli.StringFlag{ | ||
Name: "type", | ||
Usage: "Type of machine to launch.", | ||
Value: "kvm", | ||
}, | ||
}, | ||
} | ||
|
||
func splitFullProject(full string) (string, string, error) { | ||
s := strings.Split(full, ":") | ||
if len(s) != 2 { | ||
return "", "", errors.Errorf("Bad project name %q, should be keyset:project, e.g. snakeoil:default.", full) | ||
} | ||
return s[0], s[1], nil | ||
} | ||
|
||
func doLaunch(ctx *cli.Context) error { | ||
args := ctx.Args() | ||
if len(args) < 1 { | ||
return errors.New("A name for the new machine is required") | ||
} | ||
|
||
if !ctx.Bool("skip-install") && len(args) != 2 { | ||
return errors.New("Install manifest URL is required") | ||
} | ||
|
||
mtype := ctx.String("type") | ||
var p provider.Provider | ||
var err error | ||
switch mtype { | ||
case "kvm": | ||
p, err = provider.NewKVMProvider() | ||
if err != nil { | ||
return errors.Wrapf(err, "Failed to instantiate machine provider for type %q", mtype) | ||
} | ||
default: | ||
return errors.Errorf("Unknown machine type: %q", mtype) | ||
} | ||
|
||
mname := args[0] | ||
if mname == "" { | ||
return errors.New("Please specify machine name") | ||
} | ||
|
||
if p.Exists(mname) { | ||
return errors.Errorf("Machine %q already exists", mname) | ||
} | ||
|
||
fullProject := ctx.String("project") | ||
keyset, project, err := splitFullProject(fullProject) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
trustDir, err := getMosKeyPath() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
keysetDir := filepath.Join(trustDir, keyset) | ||
projDir := filepath.Join(keysetDir, "manifest", project) | ||
if !PathExists(projDir) { | ||
return errors.Errorf("Project %s not found", fullProject) | ||
} | ||
|
||
uuid := ctx.String("uuid") | ||
sudiDir, err := genSudi(keysetDir, projDir, uuid) | ||
if err != nil { | ||
return errors.Wrapf(err, "Failed generating SUDI") | ||
} | ||
if uuid == "" { | ||
uuid = filepath.Base(sudiDir) | ||
} | ||
|
||
defer func() { | ||
if err != nil { | ||
os.RemoveAll(sudiDir) | ||
} | ||
}() | ||
|
||
if err := makeSudiVfat(sudiDir); err != nil { | ||
return errors.Wrapf(err, "Failed creating SUDI disk") | ||
} | ||
|
||
m, err := p.New(mname, fullProject, uuid) | ||
if err != nil { | ||
return errors.Wrapf(err, "Failed to create new machine") | ||
} | ||
|
||
defer func() { | ||
if err != nil { | ||
p.Delete(mname) | ||
} | ||
}() | ||
|
||
if err := m.RunProvision(); err != nil { | ||
return errors.Wrapf(err, "Failed to run provisioning ISO") | ||
} | ||
|
||
return nil | ||
} | ||
|
||
// Make a VFAT disk storing the already-generated SUDI cert and privkey | ||
func makeSudiVfat(sudiDir string) error { | ||
cert := filepath.Join(sudiDir, "cert.pem") | ||
key := filepath.Join(sudiDir, "privkey.pem") | ||
disk := filepath.Join(sudiDir, "sudi.vfat") | ||
if !trust.PathExists(cert) || !trust.PathExists(key) { | ||
return errors.Errorf("cert or key does not exist") | ||
} | ||
if trust.PathExists(disk) { | ||
return errors.Errorf("sudi.vfat already exists") | ||
} | ||
|
||
f, err := os.OpenFile(disk, os.O_RDWR|os.O_CREATE, 0600) | ||
if err != nil { | ||
return errors.Wrapf(err, "Failed creating sudi disk") | ||
} | ||
f.Close() | ||
|
||
if err := os.Truncate(disk, 20*1024*1024); err != nil { | ||
return errors.Wrapf(err, "Failed truncating sudi disk") | ||
} | ||
if err := trust.RunCommand("mkfs.vfat", "-n", "trust-data", disk); err != nil { | ||
return errors.Wrapf(err, "Failed formatting sudi disk") | ||
} | ||
if err := trust.RunCommand("mcopy", "-i", disk, cert, "::cert.pem"); err != nil { | ||
return errors.Wrapf(err, "Failed copying cert to sudi disk") | ||
} | ||
if err := trust.RunCommand("mcopy", "-i", disk, key, "::privkey.pem"); err != nil { | ||
return errors.Wrapf(err, "Failed copying key to sudi disk") | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.