Created
June 11, 2018 19:22
-
-
Save ashcrow/4013030f3268b38a19bff5a1dddc4bca to your computer and use it in GitHub Desktop.
Quick-and-dirty-direct-to-golang-port of pivot
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
package main | |
/* | |
* WARNING!! This isn't tested. It's just a port of https://github.com/openshift/os/pull/95 to start with. | |
* Look for "TODO"s. | |
*/ | |
import ( | |
"flag" | |
"fmt" | |
"io/ioutil" | |
"os" | |
"os/exec" | |
"strings" | |
) | |
const ( | |
// PivotDonePath is the path to the file used to denote pivot work | |
PivotDonePath = "/etc/os-container-pivot.stamp" | |
// PivotName is literally the name of the new pivot | |
PivotName = "ostree-container-pivot" | |
) | |
func fatal(msg string) { | |
fmt.Fprintln(os.Stderr, msg) | |
os.Exit(1) | |
} | |
func runGetOutln(command string, args ...string) string { | |
rawOut := run(command, args...) | |
return strings.TrimSpace(string(rawOut)) | |
} | |
func run(command string, args ...string) string { | |
rawOut, err := exec.Command(command, args...).Output() | |
if err != nil { | |
fatal(fmt.Sprintf("Unable to run command %s: %s", command, err)) | |
} | |
return string(rawOut) | |
} | |
func podmanRemove(cid string) { | |
exec.Command("podman", "kill", cid) | |
exec.Command("podman", "rm", "-f", cid) | |
} | |
func main() { | |
// flags | |
var touchIfChanged bool | |
var keep bool | |
var reboot bool | |
var container string | |
flag.BoolVar(&touchIfChanged, "touch-if-changed", false, "if changed, touch a file") | |
flag.BoolVar(&keep, "keep", false, "Do not remove container image") | |
flag.BoolVar(&reboot, "reboot", false, "reboot if changed") | |
flag.Parse() | |
// Parse the flags into variables | |
arguments := flag.Args() | |
if len(arguments) != 1 { | |
fatal("Only one container name may be provided") | |
} | |
container = arguments[0] | |
// Logic | |
// This file holds the imageid (container name + sha256) that | |
// we successfully used for a previous pivot. | |
previousPivot := "" | |
if _, err := os.Stat(PivotDonePath); err == nil { | |
content, err := ioutil.ReadFile(PivotDonePath) | |
if err != nil { | |
fatal(fmt.Sprintf("Unable to read %s: %s", PivotDonePath, err)) | |
} | |
previousPivot = strings.TrimSpace(string(content)) | |
} | |
fmt.Printf("Previous pivot: %s\n", previousPivot) | |
// Use skopeo to find the sha256, so we can refer to it reliably | |
// TODO: Import skopeo? Make a type and load it? | |
//imgdata = json.loads(run_with( | |
output, err := exec.Command( | |
"skopeo", "inspect", fmt.Sprintf("docker://%s", container)).Output() | |
if err != nil { | |
fatal(fmt.Sprintf("Unable to run skopeo: %s", err)) | |
} | |
// TODO: | |
// ImageData type? | |
// imagedata := json deserialize | |
imagedata := "" | |
imgid := fmt.Sprintf("%s@%s", container, imagedata.Digest) | |
if previousPivot == imgid { | |
fmt.Printf("Already pivoted to: %s", imgid) | |
os.Exit(0) | |
} | |
// Pull the image | |
exec.Command("podman", "pull", imgid) | |
fmt.Printf("Pivoting to: %s", imgid) | |
//Clean up a previous container | |
podmanRemove(PivotName) | |
// `podman mount` wants a running container, so let's make a dummy one | |
cid := runGetOutln("podman", "run", "-d", "--name", | |
PivotName, "--entrypoint", "sleep", imgid, "infinity") | |
// Use the container ID to find its mount point | |
mnt := runGetOutln("podman", "mount", cid) | |
os.Chdir(mnt) | |
// List all refs from the OSTree repository embedded in the container | |
refsCombined := run("ostree", "--repo=srv/tree/repo", "refs") | |
refs := strings.Split(refsCombined, "\n") | |
rlen := len(refs) | |
// Today, we only support one ref. Down the line we may do multiple. | |
if rlen != 1 { | |
fatal(fmt.Sprintf("Found %i refs, expected exactly 1", rlen)) | |
} | |
targetRef := refs[0] | |
// Find the concrete OSTree commit | |
rev := runGetOutln("ostree", "--repo=srv/tree/repo", "rev-parse", targetRef) | |
// Use pull-local to extract the data into the system repo; this is *significantly* | |
// faster than talking to the container over HTTP. | |
run("ostree", "pull-local", "srv/tree/repo", rev) | |
// The leading ':' here means "no remote". See also | |
// https://github.com/projectatomic/rpm-ostree/pull/1396 | |
run("rpm-ostree", "rebase", fmt.Sprintf(":%s", rev)) | |
// Done! Write our stamp file. TODO: Teach rpm-ostree how to encode | |
// this data in the origin. | |
err = ioutil.WriteFile(PivotDonePath, []byte(fmt.Sprintf("%s\n", imgid)), 0644) | |
if err != nil { | |
fatal(fmt.Sprintf("Unable to write the new imgid of %s to %s", imgid, PivotDonePath)) | |
} | |
// Kill our dummy container | |
podmanRemove(PivotName) | |
// By default, delete the image. | |
if keep { | |
run("podman", "rmi", imgid) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment