func main() { kingpin.Version(version.VERSION) kingpin.Parse() localMan, err := ioutil.TempFile("", "tempmanifest") defer os.Remove(localMan.Name()) if err != nil { log.Fatalln("Couldn't create tempfile") } err = uri.URICopy(*manifestURI, localMan.Name()) if err != nil { log.Fatalf("Could not fetch manifest: %s", err) } manifest, err := pods.ManifestFromPath(localMan.Name()) if err != nil { log.Fatalf("Invalid manifest: %s", err) } pod := pods.NewPod(manifest.ID(), pods.PodPath(*podRoot, manifest.ID())) err = pod.Install(manifest) if err != nil { log.Fatalf("Could not install manifest %s: %s", manifest.ID(), err) } success, err := pod.Launch(manifest) if err != nil { log.Fatalf("Could not launch manifest %s: %s", manifest.ID(), err) } if !success { log.Fatalln("Unsuccessful launch of one or more things in the manifest") } }
func makeTar(workingDir string) (string, error) { tarContents := path.Join(workingDir, fmt.Sprintf("%s.workd", podID())) err := os.MkdirAll(tarContents, 0744) defer os.RemoveAll(tarContents) if err != nil { return "", fmt.Errorf("Couldn't make a new working directory %s for tarring: %s", tarContents, err) } err = os.MkdirAll(path.Join(tarContents, "bin"), 0744) if err != nil { return "", fmt.Errorf("Couldn't make bin directory in %s: %s", tarContents, err) } launchablePath := path.Join(tarContents, "bin", "launch") err = uri.URICopy(*executable, launchablePath) if err != nil { return "", fmt.Errorf("Couldn't copy from %s.: %s", *executable, err) } err = os.Chmod(launchablePath, 0755) // make file executable by all. if err != nil { return "", fmt.Errorf("Couldn't make %s executable: %s", launchablePath, err) } tarPath := path.Join(workingDir, fmt.Sprintf("%s_%s.tar.gz", path.Base((**executable).Path), randomSuffix())) cmd := exec.Command("tar", "-czvf", tarPath, "-C", tarContents, ".") err = cmd.Run() if err != nil { return "", fmt.Errorf("Couldn't build tar: %s", err) } return tarPath, nil }
func (pod *Pod) WriteCurrentManifest(manifest manifest.Manifest) (string, error) { // write the old manifest to a temporary location in case a launch fails. tmpDir, err := ioutil.TempDir("", "manifests") if err != nil { return "", util.Errorf("could not create a tempdir to write old manifest: %s", err) } lastManifest := filepath.Join(tmpDir, "last_manifest.yaml") if _, err := os.Stat(pod.currentPodManifestPath()); err == nil { podManifestURL, err := url.Parse(pod.currentPodManifestPath()) if err != nil { return "", util.Errorf("Couldn't parse manifest path '%s' as URL: %s", pod.currentPodManifestPath(), err) } err = uri.URICopy(podManifestURL, lastManifest) if err != nil && !os.IsNotExist(err) { return "", err } } f, err := os.OpenFile(pod.currentPodManifestPath(), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644) if err != nil { pod.logError(err, "Unable to open current manifest file") err = pod.revertCurrentManifest(lastManifest) if err != nil { pod.logError(err, "Couldn't replace old manifest as current") } return "", err } defer f.Close() err = manifest.Write(f) if err != nil { pod.logError(err, "Unable to write current manifest file") err = pod.revertCurrentManifest(lastManifest) if err != nil { pod.logError(err, "Couldn't replace old manifest as current") } return "", err } uid, gid, err := user.IDs(manifest.RunAsUser()) if err != nil { pod.logError(err, "Unable to find pod UID/GID") // the write was still successful so we are not going to revert return "", err } err = f.Chown(uid, gid) if err != nil { pod.logError(err, "Unable to chown current manifest") return "", err } return lastManifest, nil }
func main() { replicate.Version(version.VERSION) replicate.Parse(os.Args[1:]) opts := kp.Options{ Address: *consulUrl, Token: *consulToken, Client: net.NewHeaderClient(*headers, http.DefaultTransport), HTTPS: *https, } store := kp.NewConsulStore(opts) healthChecker := health.NewConsulHealthChecker(opts) // Fetch manifest (could be URI) into temp file localMan, err := ioutil.TempFile("", "tempmanifest") defer os.Remove(localMan.Name()) if err != nil { log.Fatalln("Couldn't create tempfile") } if err := uri.URICopy(*manifestUri, localMan.Name()); err != nil { log.Fatalf("Could not fetch manifest: %s", err) } manifest, err := pods.ManifestFromPath(localMan.Name()) if err != nil { log.Fatalf("Invalid manifest: %s", err) } healthResults, err := healthChecker.Service(manifest.ID()) if err != nil { log.Fatalf("Could not get initial health results: %s", err) } order := health.SortOrder{ Nodes: *hosts, Health: healthResults, } sort.Sort(order) repl := replication.Replicator{ Manifest: *manifest, Store: store, Health: healthChecker, Nodes: *hosts, // sorted by the health.SortOrder Active: len(*hosts) - *minNodes, Logger: logging.NewLogger(logrus.Fields{ "pod": manifest.ID(), }), Threshold: health.HealthState(*threshold), } repl.Logger.Logger.Formatter = &logrus.TextFormatter{ DisableTimestamp: false, FullTimestamp: true, TimestampFormat: "15:04:05.000", } if err := repl.CheckPreparers(); err != nil { log.Fatalf("Preparer check failed: %s", err) } // create a lock with a meaningful name and set up a renewal loop for it thisHost, err := os.Hostname() if err != nil { log.Fatalf("Could not retrieve hostname: %s", err) } thisUser, err := user.Current() if err != nil { log.Fatalf("Could not retrieve user: %s", err) } lock, err := store.NewLock(fmt.Sprintf("%q from %q at %q", thisUser.Username, thisHost, time.Now())) if err != nil { log.Fatalf("Could not generate lock: %s", err) } // deferring on main is not particularly useful, since os.Exit will skip // the defer, so we have to manually destroy the lock at the right exit // paths go func() { for range time.Tick(10 * time.Second) { if err := lock.Renew(); err != nil { // if the renewal failed, then either the lock is already dead // or the consul agent cannot be reached log.Fatalf("Lock could not be renewed: %s", err) } } }() if err := repl.LockHosts(lock, *overrideLock); err != nil { lock.Destroy() log.Fatalf("Could not lock all hosts: %s", err) } // auto-drain this channel errs := make(chan error) go func() { for range errs { } }() quitch := make(chan struct{}) go func() { // clear lock immediately on ctrl-C signals := make(chan os.Signal, 1) signal.Notify(signals, os.Interrupt) <-signals close(quitch) lock.Destroy() os.Exit(1) }() repl.Enact(errs, quitch) lock.Destroy() }