forked from coreos/coreos-assembler
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This creates an initial skeleton for Go code at the very toplevel of the project. What is currently the `coreos-assembler` shell script entrypoint is changed to be embedded via Go file embedding into `/usr/bin/cosa`. This is a pattern I think we'll use to aid the transition; rather than trying to rewrite things wholesale in Go, we'll continue to exec some shell scripts. There's an embryonic `bashexec` internal Go module that is designed to help with this. Closes: coreos#2821
- Loading branch information
Showing
6 changed files
with
208 additions
and
80 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
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,3 +10,4 @@ maipo/ | |
.coverage | ||
tools/bin | ||
.idea | ||
bin/ |
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,137 @@ | ||
package main | ||
|
||
import ( | ||
_ "embed" | ||
"fmt" | ||
"io/ioutil" | ||
"os" | ||
"os/exec" | ||
"sort" | ||
"strings" | ||
) | ||
|
||
// commands we'd expect to use in the local dev path | ||
var buildCommands = []string{"init", "fetch", "build", "run", "prune", "clean", "list"} | ||
var advancedBuildCommands = []string{"buildfetch", "buildupload", "oc-adm-release", "push-container", "upload-oscontainer"} | ||
var buildextendCommands = []string{"aliyun", "aws", "azure", "digitalocean", "exoscale", "gcp", "ibmcloud", "kubevirt", "live", "metal", "metal4k", "nutanix", "openstack", "qemu", "secex", "virtualbox", "vmware", "vultr"} | ||
var utilityCommands = []string{"aws-replicate", "compress", "generate-hashlist", "koji-upload", "kola", "remote-build-container", "remote-prune", "sign", "tag"} | ||
var otherCommands = []string{"shell", "meta"} | ||
|
||
func init() { | ||
// Note buildCommands is intentionally listed in frequency order | ||
sort.Strings(advancedBuildCommands) | ||
sort.Strings(buildextendCommands) | ||
sort.Strings(utilityCommands) | ||
sort.Strings(otherCommands) | ||
} | ||
|
||
func printCommands(title string, cmds []string) { | ||
fmt.Printf("%s:\n", title) | ||
for _, cmd := range cmds { | ||
fmt.Printf(" %s\n", cmd) | ||
} | ||
} | ||
|
||
func printUsage() { | ||
fmt.Println("Usage: coreos-assembler CMD ...") | ||
printCommands("Build commands", buildCommands) | ||
printCommands("Advanced build commands", advancedBuildCommands) | ||
printCommands("Platform builds", buildextendCommands) | ||
printCommands("Utility commands", utilityCommands) | ||
printCommands("Other commands", otherCommands) | ||
} | ||
|
||
func run(argv []string) error { | ||
var cmd string | ||
if len(argv) > 0 { | ||
cmd = argv[0] | ||
argv = argv[1:] | ||
} | ||
|
||
if cmd == "" { | ||
printUsage() | ||
os.Exit(1) | ||
} | ||
|
||
target := fmt.Sprintf("/usr/lib/coreos-assembler/cmd-%s", cmd) | ||
_, err := os.Stat(target) | ||
if err != nil { | ||
if os.IsNotExist(err) { | ||
return fmt.Errorf("unknown command: %s", cmd) | ||
} | ||
return fmt.Errorf("failed to stat %s: %w", target, err) | ||
} | ||
|
||
c := exec.Command(target, argv...) | ||
c.Stdin = os.Stdin | ||
c.Stdout = os.Stdout | ||
c.Stderr = os.Stderr | ||
return c.Run() | ||
} | ||
|
||
func initializeGlobalState() error { | ||
// Set PYTHONUNBUFFERED=1 so that we get unbuffered output. We should | ||
// be able to do this on the shebang lines but env doesn't support args | ||
// right now. In Fedora we should be able to use the `env -S` option. | ||
os.Setenv("export PYTHONUNBUFFERED", "1") | ||
|
||
// docker/podman don't run through PAM, but we want this set for the privileged | ||
// (non-virtualized) path | ||
|
||
user, ok := os.LookupEnv("USER") | ||
if !ok { | ||
b, err := exec.Command("id", "-nu").Output() | ||
if err != nil { | ||
return err | ||
} | ||
user = strings.TrimSpace(string(b)) | ||
os.Setenv("USER", user) | ||
} | ||
|
||
// When trying to connect to libvirt we get "Failed to find user record | ||
// for uid" errors if there is no entry for our UID in /etc/passwd. | ||
// This was taken from 'Support Arbitrary User IDs' section of: | ||
// https://docs.openshift.com/container-platform/3.10/creating_images/guidelines.html | ||
c := exec.Command("whoami") | ||
c.Stdout = ioutil.Discard | ||
c.Stderr = ioutil.Discard | ||
if err := c.Run(); err != nil { | ||
home := fmt.Sprintf("/var/tmp/%s", user) | ||
err := os.MkdirAll(home, 0755) | ||
if err != nil { | ||
return err | ||
} | ||
f, err := os.OpenFile("/etc/passwd", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) | ||
if err != nil { | ||
return err | ||
} | ||
defer f.Close() | ||
id := os.Getuid() | ||
buf := fmt.Sprintf("%s:x:%d:0:%s user:%s:/sbin/nologin", user, id, user, home) | ||
if _, err = f.WriteString(buf); err != nil { | ||
return err | ||
} | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func sanityCheckEnvironment() error { | ||
// https://github.com/containers/libpod/issues/1448 | ||
if _, err := os.Stat("/sys/fs/selinux/status"); err == nil { | ||
return fmt.Errorf("/sys/fs/selinux appears to be mounted but should not be") | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func main() { | ||
sanityCheckEnvironment() | ||
initializeGlobalState() | ||
|
||
err := run(os.Args[1:]) | ||
if err != nil { | ||
fmt.Fprintf(os.Stderr, "error: %v\n", err) | ||
os.Exit(1) | ||
} | ||
} |
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,3 @@ | ||
module github.com/coreos/coreos-assembler | ||
|
||
go 1.15 |
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,60 @@ | ||
package bashexec | ||
|
||
import ( | ||
"fmt" | ||
"io" | ||
"os" | ||
"os/exec" | ||
"strings" | ||
) | ||
|
||
// BashRunner is a wrapper for executing in-memory bash scripts | ||
type BashRunner struct { | ||
name string | ||
cmd *exec.Cmd | ||
} | ||
|
||
// NewBashRunner creates a bash executor from in-memory shell script. | ||
func NewBashRunner(name, src string, args ...string) (*BashRunner, error) { | ||
f, err := os.CreateTemp("", name) | ||
if err != nil { | ||
return nil, err | ||
} | ||
if _, err := io.Copy(f, strings.NewReader(src)); err != nil { | ||
return nil, err | ||
} | ||
if err := os.Remove(f.Name()); err != nil { | ||
return nil, err | ||
} | ||
|
||
fullargs := append([]string{"-c", ". /proc/self/fd/3", name}, args...) | ||
cmd := exec.Command("/bin/bash", fullargs...) | ||
cmd.Stdin = os.Stdin | ||
cmd.ExtraFiles = append(cmd.ExtraFiles, f) | ||
|
||
return &BashRunner{ | ||
name: name, | ||
cmd: cmd, | ||
}, nil | ||
} | ||
|
||
// Exec synchronously spawns the child process, passing stdin/stdout/stderr directly. | ||
func (r *BashRunner) Exec() error { | ||
r.cmd.Stdin = os.Stdin | ||
r.cmd.Stdout = os.Stdout | ||
r.cmd.Stderr = os.Stderr | ||
err := r.cmd.Run() | ||
if err != nil { | ||
return fmt.Errorf("failed to execute internal script %s: %w", r.name, err) | ||
} | ||
return nil | ||
} | ||
|
||
// Run spawns the script, gathering stdout/stderr into a buffer that is displayed only on error. | ||
func (r *BashRunner) Run() error { | ||
buf, err := r.cmd.CombinedOutput() | ||
if err != nil { | ||
return fmt.Errorf("failed to execute internal script %s: %w\n%s", r.name, err, buf) | ||
} | ||
return nil | ||
} |
This file was deleted.
Oops, something went wrong.