Skip to content

Instantly share code, notes, and snippets.

@ashcrow
Created June 11, 2018 19:22
Show Gist options
  • Save ashcrow/4013030f3268b38a19bff5a1dddc4bca to your computer and use it in GitHub Desktop.
Save ashcrow/4013030f3268b38a19bff5a1dddc4bca to your computer and use it in GitHub Desktop.
Quick-and-dirty-direct-to-golang-port of pivot
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