func NewLibvirtLXCBackend(state *State, vman *volumemanager.Manager, volPath, logPath, initPath string, mux *logmux.LogMux) (Backend, error) { libvirtc, err := libvirt.NewVirConnection("lxc:///") if err != nil { return nil, err } pinkertonCtx, err := pinkerton.BuildContext("aufs", imageRoot) if err != nil { return nil, err } return &LibvirtLXCBackend{ LogPath: logPath, VolPath: volPath, InitPath: initPath, libvirt: libvirtc, state: state, vman: vman, pinkerton: pinkertonCtx, logs: make(map[string]*logbuf.Log), containers: make(map[string]*libvirtContainer), defaultEnv: make(map[string]string), resolvConf: "/etc/resolv.conf", mux: mux, ipalloc: ipallocator.New(), discoverdConfigured: make(chan struct{}), networkConfigured: make(chan struct{}), }, nil }
func build(name string) error { name = "flynn/" + name cmd := exec.Command("docker", "build", "-t", name, ".") cmd.Stdout = os.Stderr cmd.Stderr = os.Stderr if err := cmd.Run(); err != nil { return fmt.Errorf("error building docker image: %s", err) } context, err := pinkerton.BuildContext("aufs", "/var/lib/docker") if err != nil { return err } layerDir := "/var/lib/flynn/layer-cache" if err := os.MkdirAll(layerDir, 0755); err != nil { return err } b := &imagebuilder.Builder{ Store: &layerStore{layerDir}, Context: context, } manifest, err := b.Build(name, true) if err != nil { return err } _, err = os.Stdout.Write(manifest.RawManifest()) return err }
func main() { usage := `Pinkerton manages Docker images. Usage: pinkerton pull [options] <image-url> pinkerton checkout [options] <id> <image-id> pinkerton cleanup [options] <id> pinkerton -h | --help Commands: pull Download a Docker image checkout Create a working copy of an image cleanup Destroy a working copy of an image Examples: pinkerton pull https://registry.hub.docker.com/redis pinkerton pull https://registry.hub.docker.com/ubuntu?tag=trusty pinkerton pull https://registry.hub.docker.com/flynn/slugrunner?id=1443bd6a675b959693a1a4021d660bebbdbff688d00c65ff057c46702e4b8933 pinkerton checkout slugrunner-test 1443bd6a675b959693a1a4021d660bebbdbff688d00c65ff057c46702e4b8933 pinkerton cleanup slugrunner-test Options: -h, --help show this message and exit --driver=<name> storage driver [default: aufs] --root=<path> storage root [default: /var/lib/docker] --json emit json-formatted output ` args, _ := docopt.Parse(usage, nil, true, "", false) ctx, err := pinkerton.BuildContext(args.String["--driver"], args.String["--root"]) if err != nil { log.Fatal(err) } switch { case args.Bool["pull"]: if err := ctx.Pull(args.String["<image-url>"], pinkerton.InfoPrinter(args.Bool["--json"])); err != nil { log.Fatal(err) } case args.Bool["checkout"]: path, err := ctx.Checkout(args.String["<id>"], args.String["<image-id>"]) if err != nil { log.Fatal(err) } fmt.Println(path) case args.Bool["cleanup"]: if err := ctx.Cleanup(args.String["<id>"]); err != nil { log.Fatal(err) } } }
func NewLibvirtLXCBackend(state *State, vman *volumemanager.Manager, bridgeName, initPath, umountPath string, mux *logmux.Mux, partitionCGroups map[string]int64, logger log15.Logger) (Backend, error) { libvirtc, err := libvirt.NewVirConnection("lxc:///") if err != nil { return nil, err } pinkertonCtx, err := pinkerton.BuildContext("aufs", imageRoot) if err != nil { return nil, err } for name, shares := range partitionCGroups { if err := createCGroupPartition(name, shares); err != nil { return nil, err } } return &LibvirtLXCBackend{ InitPath: initPath, UmountPath: umountPath, libvirt: libvirtc, state: state, vman: vman, pinkerton: pinkertonCtx, logStreams: make(map[string]map[string]*logmux.LogStream), containers: make(map[string]*libvirtContainer), defaultEnv: make(map[string]string), resolvConf: "/etc/resolv.conf", mux: mux, ipalloc: ipallocator.New(), bridgeName: bridgeName, discoverdConfigured: make(chan struct{}), networkConfigured: make(chan struct{}), partitionCGroups: partitionCGroups, logger: logger, }, nil }
func NewLibcontainerBackend(state *State, vman *volumemanager.Manager, bridgeName, initPath string, mux *logmux.Mux, partitionCGroups map[string]int64, logger log15.Logger) (Backend, error) { factory, err := libcontainer.New( containerRoot, libcontainer.Cgroupfs, libcontainer.InitArgs(os.Args[0], "libcontainer-init"), ) pinkertonCtx, err := pinkerton.BuildContext("aufs", imageRoot) if err != nil { return nil, err } if err := setupCGroups(partitionCGroups); err != nil { return nil, err } return &LibcontainerBackend{ InitPath: initPath, factory: factory, state: state, vman: vman, pinkerton: pinkertonCtx, logStreams: make(map[string]map[string]*logmux.LogStream), containers: make(map[string]*Container), defaultEnv: make(map[string]string), resolvConf: "/etc/resolv.conf", mux: mux, ipalloc: ipallocator.New(), bridgeName: bridgeName, discoverdConfigured: make(chan struct{}), networkConfigured: make(chan struct{}), partitionCGroups: partitionCGroups, logger: logger, globalState: &libcontainerGlobalState{}, }, nil }
func runDownload(args *docopt.Args) error { if err := os.MkdirAll(args.String["--root"], 0755); err != nil { return fmt.Errorf("error creating root dir: %s", err) } var manifest map[string]string if err := cliutil.DecodeJSONArg(args.String["<manifest>"], &manifest); err != nil { return err } ctx, err := pinkerton.BuildContext(args.String["--driver"], args.String["--root"]) if err != nil { return err } for image, id := range manifest { fmt.Printf("Downloading %s %s...\n", image, id) image += "?id=" + id if err := ctx.Pull(image, pinkerton.InfoPrinter(false)); err != nil { return err } } return nil }
func NewLibvirtLXCBackend(state *State, portAlloc map[string]*ports.Allocator, volPath, logPath, initPath string) (Backend, error) { libvirtc, err := libvirt.NewVirConnection("lxc:///") if err != nil { return nil, err } pinkertonCtx, err := pinkerton.BuildContext("aufs", "/var/lib/docker") if err != nil { return nil, err } if err := writeResolvConf("/etc/flynn/resolv.conf"); err != nil { return nil, fmt.Errorf("Could not create resolv.conf: %s", err) } b := random.Bytes(5) bridgeMAC := fmt.Sprintf("fe:%02x:%02x:%02x:%02x:%02x", b[0], b[1], b[2], b[3], b[4]) network, err := libvirtc.LookupNetworkByName(libvirtNetName) if err != nil { n := <.Network{ Name: libvirtNetName, Bridge: lt.Bridge{Name: bridgeName, STP: "off"}, IP: lt.IP{Address: bridgeAddr.String(), Netmask: bridgeMask}, MAC: lt.MAC{Address: bridgeMAC}, } network, err = libvirtc.NetworkDefineXML(string(n.XML())) if err != nil { return nil, err } } active, err := network.IsActive() if err != nil { return nil, err } if !active { if err := network.Create(); err != nil { return nil, err } } // We need to explicitly assign the MAC address to avoid it changing to a lower value // See: https://github.com/flynn/flynn/issues/223 if err := netlink.NetworkSetMacAddress(bridgeName, bridgeMAC); err != nil { return nil, err } iptables.RemoveExistingChain("FLYNN", bridgeName) chain, err := iptables.NewChain("FLYNN", bridgeName) if err != nil { return nil, err } if err := ioutil.WriteFile("/proc/sys/net/ipv4/conf/"+bridgeName+"/route_localnet", []byte("1"), 0666); err != nil { return nil, err } return &LibvirtLXCBackend{ LogPath: logPath, VolPath: volPath, InitPath: initPath, libvirt: libvirtc, state: state, ports: portAlloc, pinkerton: pinkertonCtx, forwarder: ports.NewForwarder(net.ParseIP("0.0.0.0"), chain), logs: make(map[string]*logbuf.Log), containers: make(map[string]*libvirtContainer), }, nil }
func run(url string) error { client, err := controller.NewClient("", os.Getenv("CONTROLLER_KEY")) if err != nil { return err } context, err := pinkerton.BuildContext("flynn", "/tmp/docker") if err != nil { return err } builder := &imagebuilder.Builder{ Store: &layerStore{}, Context: context, } // pull the docker image ref, err := pinkerton.NewRef(url) if err != nil { return err } if _, err := context.PullDocker(url, ioutil.Discard); err != nil { return err } // create squashfs for each layer image, err := builder.Build(ref.DockerRef(), false) if err != nil { return err } // add the app name to the manifest to change its resulting ID so // pushing the same image to multiple apps leads to different artifacts // in the controller (and hence distinct artifact events) if image.Meta == nil { image.Meta = make(map[string]string, 1) } image.Meta["docker-receive.repository"] = ref.Name() // upload manifest to blobstore rawManifest := image.RawManifest() imageURL := fmt.Sprintf("http://blobstore.discoverd/docker-receive/images/%s.json", image.ID()) if err := upload(bytes.NewReader(rawManifest), imageURL); err != nil { return err } // create the artifact artifact := &ct.Artifact{ ID: os.Getenv("ARTIFACT_ID"), Type: ct.ArtifactTypeFlynn, URI: imageURL, Meta: map[string]string{ "blobstore": "true", "docker-receive.uri": url, "docker-receive.repository": ref.Name(), "docker-receive.digest": ref.ID(), }, RawManifest: rawManifest, Hashes: image.Hashes(), Size: int64(len(rawManifest)), LayerURLTemplate: layerURLTemplate, } return client.CreateArtifact(artifact) }