Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
packer: pick up extra command-line flags from flags/<pkg>/flags.txt
The file format is one flag per line (\n-separated).

Preparation example:

mkdir -p flags/github.com/gokrazy/timestamps
echo '--ohai' > flags/github.com/gokrazy/timestamps/flags.txt

Packer example:

gokr-packer -update=yes -hostname=gokrazy \
  github.com/gokrazy/breakglass \
  github.com/gokrazy/timestamps \
  github.com/gokrazy/serial-busybox

Resulting stderr:

1970/01/01 01:00:09 gokrazy: attempt 0, starting [/user/timestamps --ohai]

You can check the effect locally by adding -overwrite_init=/tmp/init.go to your
gokr-packer invocation and examining /tmp/init.go afterwards.

related to gokrazy/gokrazy#65
  • Loading branch information
stapelberg committed Jan 4, 2021
1 parent f17e3ee commit fdd90fc
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 28 deletions.
60 changes: 34 additions & 26 deletions cmd/gokr-packer/buildinit.go
Expand Up @@ -8,6 +8,7 @@ import (
"os"
"os/exec"
"path/filepath"
"strings"
"text/template"
"time"
)
Expand Down Expand Up @@ -45,7 +46,7 @@ func main() {
cmds := []*exec.Cmd{
{{- range $idx, $path := .Binaries }}
{{- if ne $path "/gokrazy/init" }}
exec.Command({{ printf "%#v" $path }}),
exec.Command({{ CommandFor $.Flags $path }}),
{{- end }}
{{- end }}
}
Expand All @@ -56,7 +57,16 @@ func main() {
}
`

var initTmpl = template.Must(template.New("").Parse(initTmplContents))
var initTmpl = template.Must(template.New("").Funcs(template.FuncMap{
"CommandFor": func(flags map[string]string, path string) string {
contents := strings.TrimSpace(flags[filepath.Base(path)])
if contents == "" {
return fmt.Sprintf("%#v", path) // no flags
}
lines := strings.Split(contents, "\n")
return fmt.Sprintf("%#v, %#v...", path, lines)
},
}).Parse(initTmplContents))

func flattenFiles(prefix string, root *fileInfo) []string {
var result []string
Expand All @@ -70,63 +80,61 @@ func flattenFiles(prefix string, root *fileInfo) []string {
return result
}

func dumpInit(path string, root *fileInfo) error {
f, err := os.Create(path)
if err != nil {
return err
}
defer f.Close()

func genInit(root *fileInfo, flagFileContents map[string]string) ([]byte, error) {
var buf bytes.Buffer

if err := initTmpl.Execute(&buf, struct {
Binaries []string
BuildTimestamp string
Flags map[string]string
}{
Binaries: flattenFiles("/", root),
BuildTimestamp: time.Now().Format(time.RFC3339),
Flags: flagFileContents,
}); err != nil {
return nil, err
}

return format.Source(buf.Bytes())
}

func dumpInit(path string, root *fileInfo, flagFileContents map[string]string) error {
f, err := os.Create(path)
if err != nil {
return err
}
defer f.Close()

formatted, err := format.Source(buf.Bytes())
b, err := genInit(root, flagFileContents)
if err != nil {
return err
}

if _, err := f.Write(formatted); err != nil {
if _, err := f.Write(b); err != nil {
return err
}

return f.Close()
}

func buildInit(root *fileInfo) (tmpdir string, err error) {
func buildInit(root *fileInfo, flagFileContents map[string]string) (tmpdir string, err error) {
tmpdir, err = ioutil.TempDir("", "gokr-packer")
if err != nil {
return "", err
}

code, err := os.Create(filepath.Join(tmpdir, "init.go"))
b, err := genInit(root, flagFileContents)
if err != nil {
return "", err
}
defer os.Remove(code.Name())

if err := initTmpl.Execute(code, struct {
Binaries []string
BuildTimestamp string
}{
Binaries: flattenFiles("/", root),
BuildTimestamp: time.Now().Format(time.RFC3339),
}); err != nil {
return "", err
}

if err := code.Close(); err != nil {
initGo := filepath.Join(tmpdir, "init.go")
if err := ioutil.WriteFile(initGo, b, 0644); err != nil {
return "", err
}
defer os.Remove(initGo)

cmd := exec.Command("go", "build", "-o", filepath.Join(tmpdir, "init"), code.Name())
cmd := exec.Command("go", "build", "-o", filepath.Join(tmpdir, "init"), initGo)
cmd.Env = env
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
Expand Down
59 changes: 57 additions & 2 deletions cmd/gokr-packer/packer.go
Expand Up @@ -106,6 +106,56 @@ func findCACerts() (string, error) {
return "", fmt.Errorf("did not find any of: %s", strings.Join(certFiles, ", "))
}

func findFlagFiles() (map[string]string, error) {
var flagFilePaths []string
err := filepath.Walk("flags", func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if info != nil && !info.Mode().IsRegular() {
return nil
}
if strings.HasSuffix(path, "/flags.txt") {
flagFilePaths = append(flagFilePaths, path)
}
return nil
})
if err != nil {
if os.IsNotExist(err) {
return nil, nil // no flags/ directory found
}
}

if len(flagFilePaths) == 0 {
return nil, nil // no flags.txt files found
}

buildPackages := make(map[string]bool)
for _, pkg := range flag.Args() {
buildPackages[pkg] = true
}

contents := make(map[string]string)
for _, p := range flagFilePaths {
pkg := strings.TrimSuffix(strings.TrimPrefix(p, "flags/"), "/flags.txt")
if !buildPackages[pkg] {
log.Printf("WARNING: flag file %s does not match any specified package (%s)", pkg, flag.Args())
continue
}
log.Printf("package %s will be started with command-line flags from %s", pkg, p)

b, err := ioutil.ReadFile(p)
if err != nil {
return nil, err
}
// NOTE: ideally we would use the full package here, but our init
// template only deals with base names right now.
contents[filepath.Base(pkg)] = string(b)
}

return contents, nil
}

type countingWriter int64

func (cw *countingWriter) Write(p []byte) (n int, err error) {
Expand Down Expand Up @@ -367,12 +417,17 @@ func logic() error {
return err
}

flagFileContents, err := findFlagFiles()
if err != nil {
return err
}

if *initPkg == "" {
if *overwriteInit != "" {
return dumpInit(*overwriteInit, root)
return dumpInit(*overwriteInit, root, flagFileContents)
}

tmpdir, err := buildInit(root)
tmpdir, err := buildInit(root, flagFileContents)
if err != nil {
return err
}
Expand Down

0 comments on commit fdd90fc

Please sign in to comment.