<commit_before>package main

import (
	"errors"
	"fmt"

	"github.com/containerd/containerd/rootfs"
	"github.com/urfave/cli"
)

var snapshotCommand = cli.Command{
	Name:      "snapshot",
	Usage:     "snapshot a container into an archive",
	ArgsUsage: "",
	Flags: []cli.Flag{
		cli.StringFlag{
			Name:  "id",
			Usage: "id of the container",
		},
	},
	Action: func(clicontext *cli.Context) error {
		ctx, cancel := appContext(clicontext)
		defer cancel()

		id := clicontext.String("id")
		if id == "" {
			return errors.New("container id must be provided")
		}

		snapshotter, err := getSnapshotter(clicontext)
		if err != nil {
			return err
		}

		differ, err := getDiffService(clicontext)
		if err != nil {
			return err
		}

		contentRef := fmt.Sprintf("diff-%s", id)

		d, err := rootfs.Diff(ctx, id, contentRef, snapshotter, differ)
		if err != nil {
			return err
		}

		// TODO: Track progress
		fmt.Printf("%s %s\n", d.MediaType, d.Digest)

		return nil
	},
}
<commit_msg>Update snapshot command in ctr<commit_after>package main

import (
	"context"
	"errors"
	"fmt"
	"os"
	"text/tabwriter"

	"github.com/containerd/containerd/progress"
	"github.com/containerd/containerd/rootfs"
	"github.com/containerd/containerd/snapshot"
	"github.com/urfave/cli"
)

var snapshotCommand = cli.Command{
	Name:  "snapshot",
	Usage: "snapshot management",
	Subcommands: cli.Commands{
		archiveSnapshotCommand,
		listSnapshotCommand,
		usageSnapshotCommand,
	},
}

var archiveSnapshotCommand = cli.Command{
	Name:      "archive",
	Usage:     "Create an archive of a snapshot",
	ArgsUsage: "[flags] id",
	Flags: []cli.Flag{
		cli.StringFlag{
			Name:  "id",
			Usage: "id of the container or snapshot",
		},
	},
	Action: func(clicontext *cli.Context) error {
		ctx, cancel := appContext(clicontext)
		defer cancel()

		id := clicontext.String("id")
		if id == "" {
			return errors.New("container id must be provided")
		}

		snapshotter, err := getSnapshotter(clicontext)
		if err != nil {
			return err
		}

		differ, err := getDiffService(clicontext)
		if err != nil {
			return err
		}

		contentRef := fmt.Sprintf("diff-%s", id)

		d, err := rootfs.Diff(ctx, id, contentRef, snapshotter, differ)
		if err != nil {
			return err
		}

		// TODO: Track progress
		fmt.Printf("%s %s\n", d.MediaType, d.Digest)

		return nil
	},
}

var listSnapshotCommand = cli.Command{
	Name:    "list",
	Aliases: []string{"ls"},
	Usage:   "List snapshots",
	Action: func(clicontext *cli.Context) error {
		ctx, cancel := appContext(clicontext)
		defer cancel()

		client, err := newClient(clicontext)
		if err != nil {
			return err
		}

		snapshotter := client.SnapshotService()

		tw := tabwriter.NewWriter(os.Stdout, 1, 8, 1, ' ', 0)
		fmt.Fprintln(tw, "ID\tParent\tState\tReadonly\t")

		if err := snapshotter.Walk(ctx, func(ctx context.Context, info snapshot.Info) error {
			fmt.Fprintf(tw, "%v\t%v\t%v\t%t\t\n", info.Name, info.Parent, state(info.Kind), info.Readonly)
			return nil
		}); err != nil {
			return err
		}

		return tw.Flush()
	},
}

func state(k snapshot.Kind) string {
	switch k {
	case snapshot.KindActive:
		return "active"
	case snapshot.KindCommitted:
		return "committed"
	default:
		return ""
	}
}

var usageSnapshotCommand = cli.Command{
	Name:      "usage",
	Usage:     "Usage snapshots",
	ArgsUsage: "[flags] [id] ...",
	Flags: []cli.Flag{
		cli.BoolFlag{
			Name:  "b",
			Usage: "display size in bytes",
		},
	},
	Action: func(clicontext *cli.Context) error {
		ctx, cancel := appContext(clicontext)
		defer cancel()

		client, err := newClient(clicontext)
		if err != nil {
			return err
		}

		var displaySize func(int64) string
		if clicontext.Bool("b") {
			displaySize = func(s int64) string {
				return fmt.Sprintf("%d", s)
			}
		} else {
			displaySize = func(s int64) string {
				return progress.Bytes(s).String()
			}
		}

		snapshotter := client.SnapshotService()

		tw := tabwriter.NewWriter(os.Stdout, 1, 8, 1, ' ', 0)
		fmt.Fprintln(tw, "ID\tSize\tInodes\t")

		if clicontext.NArg() == 0 {
			if err := snapshotter.Walk(ctx, func(ctx context.Context, info snapshot.Info) error {
				usage, err := snapshotter.Usage(ctx, info.Name)
				if err != nil {
					return err
				}
				fmt.Fprintf(tw, "%v\t%s\t%d\t\n", info.Name, displaySize(usage.Size), usage.Inodes)
				return nil
			}); err != nil {
				return err
			}
		} else {
			for _, id := range clicontext.Args() {
				usage, err := snapshotter.Usage(ctx, id)
				if err != nil {
					return err
				}
				fmt.Fprintf(tw, "%v\t%s\t%d\t\n", id, displaySize(usage.Size), usage.Inodes)
			}
		}

		return tw.Flush()
	},
}
<|endoftext|>


<commit_before>package requests

import (
	// "crypto/tls"
	"github.com/astaxie/beego/httplib"
	"io/ioutil"
	"net/http"
	"strings"
	"testing"
	"time"
)

type httpBin struct {
	Args    struct{} `json:"args"`
	Data    string   `json:"data"`
	Files   struct{} `json:"files"`
	Form    struct{} `json:"form"`
	Headers struct {
		Accept_Encoding string `json:"Accept-Encoding"`
		Content_Length  string `json:"Content-Length"`
		Content_Type    string `json:"Content-Type"`
		Host            string `json:"Host"`
		User_Agent      string `json:"User-Agent"`
	} `json:"headers"`
	JSON struct {
		Hello string `json:"hello"`
	} `json:"json"`
	Origin string `json:"origin"`
	URL    string `json:"url"`
}

type httpBinXML struct {
	Slideshow struct {
		Title  string `xml:"title,attr"`
		Date   string `xml:"date,attr"`
		Author string `xml:"author,attr"`
		Slide  []struct {
			Type  string   `xml:"type,attr"`
			Title string   `xml:"title"`
			Item  []string `xml:"item"`
		} `xml:"slide"`
	} `xml:"slideshow"`
}

type echo struct {
	Hello string `json:"hello"`
}

func TestParse2StructWithJSON(t *testing.T) {
	var bin httpBin
	testJSON := `
	{
		"args": {},
		"data": "{\"hello\":\"world\"}",
		"files": {},
		"form": {},
		"headers": {
		"Accept-Encoding": "gzip",
		"Content-Length": "17",
		"Content-Type": "application/json; charset=utf-8",
		"Host": "httpbin.org",
		"User-Agent": "beegoServer"
		},
		"json": {
			"hello": "world"
		},
		"origin": "118.244.254.30",
		"url": "http://httpbin.org/post"
	}
	`
	err := Parse2Struct("json", []byte(testJSON), &bin)
	if err != nil {
		t.Fatal(err)
	}
	if bin.JSON.Hello != "world" {
		t.Errorf("want world, got %s", bin.JSON.Hello)
	}
}

func TestParse2StructWithXML(t *testing.T) {
	var binXML httpBinXML
	testXML := `
	<?xml version='1.0' encoding='utf-8'?>

	<slideshow
    	title="Sample Slide Show"
    	date="Date of publication"
    	author="Yours Truly"
    >

    <slide type="all">
      <title>Wake up to WonderWidgets!</title>
    </slide>

    <slide type="all">
        <title>Overview</title>
        <item>Why WonderWidgets are great</item>
        <item/>
        <item>Who buys WonderWidgets</item>
    </slide>

	</slideshow>
	`
	err := Parse2Struct("xml", []byte(testXML), binXML)
	if err != nil {
		t.Fatal(err)
	}
}

func TestParse2StructWithText(t *testing.T) {

}

func TestParse2Bytes(t *testing.T) {
	var bin httpBin
	bin.Headers.Content_Length = "application/json; charset=utf-8"
	b, err := Parse2Bytes("json", bin)
	if err != nil {
		t.Fatal(err)
	}
	if !strings.Contains(string(b), "application/json; charset=utf-8") {
		t.Errorf("want true, got %t", strings.Contains(string(b), "application/json; charset=utf-8"))
	}
}

func TestConvertResponseToBytes(t *testing.T) {
	resp, err := http.Get("https://api.github.com")
	if err != nil {
		t.Fatal(err)
	}
	b1, err := ConvertResponseToBytes(resp)
	if err != nil {
		t.Fatal(err)
	}
	b2, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		t.Fatal(err)
	}
	if string(b1) != string(b2) {
		t.Errorf("want true, got %t", string(b1) == string(b2))
	}
}

func TestGet(t *testing.T) {
	var bin httpBin
	var url = "http://httpbin.org/get"
	result, err := Get(url, nil, &bin)
	if err != nil {
		m, _ := ConvertResponseToBytes(result)
		t.Log(string(m))
		t.Fatal(err)
	}
	if len(strings.Split(bin.Origin, ".")) != 4 {
		t.Errorf("want 4, got %d", len(strings.Split(bin.Origin, ".")))
	}
}

func TestPost(t *testing.T) {
	var bin httpBin
	request := &echo{Hello: "world"}
	var url = "http://httpbin.org/post"

	result, err := Post(url, request, nil, &bin)
	if err != nil {
		m, _ := ConvertResponseToBytes(result)
		t.Log(string(m))
		t.Fatal(err)
	}
	if bin.JSON.Hello != request.Hello {
		t.Errorf("want %s, got %+v", request.Hello, bin.JSON.Hello)
	}
}

func TestDelete(t *testing.T) {
	var bin httpBin
	request := &echo{Hello: "world"}
	var url = "http://httpbin.org/delete"
	result, err := Delete(url, request, nil, &bin)
	if err != nil {
		m, _ := ConvertResponseToBytes(result)
		t.Log(string(m))
		t.Fatal(err)
	}
	if bin.JSON.Hello != request.Hello {
		t.Errorf("want %s, got %+v", request.Hello, bin.JSON.Hello)
	}
}

func TestPut(t *testing.T) {
	var bin httpBin
	request := &echo{Hello: "world"}
	var url = "http://httpbin.org/put"
	result, err := Put(url, request, nil, &bin)
	if err != nil {
		m, _ := ConvertResponseToBytes(result)
		t.Log(string(m))
		t.Fatal(err)
	}
	if bin.JSON.Hello != request.Hello {
		t.Errorf("want %s, got %+v", request.Hello, bin.JSON.Hello)
	}
}

func TestPostFuncs(t *testing.T) {
	// 设置超时时间
	var timeout = func(req *httplib.BeegoHttpRequest) *httplib.BeegoHttpRequest {
		return req.SetTimeout(time.Microsecond*1, time.Microsecond*1)
	}

	// var inscure = func(req *httplib.BeegoHttpRequest) *httplib.BeegoHttpRequest {
	// 	return req.SetTLSClientConfig(&tls.Config{InsecureSkipVerify: true})
	// }

	var bin httpBin
	request := &echo{Hello: "world"}
	var url = "http://httpbin.org/put"
	result, err := Put(url, request, nil, &bin, timeout)
	if err != nil {
		m, _ := ConvertResponseToBytes(result)
		t.Log(string(m))
		t.Fatal(err)
	}
	if bin.JSON.Hello != request.Hello {
		t.Errorf("want %s, got %+v", request.Hello, bin.JSON.Hello)
	}
}
<commit_msg>- fix unittest<commit_after>package requests

import (
	// "crypto/tls"

	"crypto/tls"
	"io/ioutil"
	"net/http"
	"strings"
	"testing"
	"time"

	"github.com/astaxie/beego/httplib"
)

type httpBin struct {
	Args    struct{} `json:"args"`
	Data    string   `json:"data"`
	Files   struct{} `json:"files"`
	Form    struct{} `json:"form"`
	Headers struct {
		Accept_Encoding string `json:"Accept-Encoding"`
		Content_Length  string `json:"Content-Length"`
		Content_Type    string `json:"Content-Type"`
		Host            string `json:"Host"`
		User_Agent      string `json:"User-Agent"`
	} `json:"headers"`
	JSON struct {
		Hello string `json:"hello"`
	} `json:"json"`
	Origin string `json:"origin"`
	URL    string `json:"url"`
}

type httpBinXML struct {
	Slideshow struct {
		Title  string `xml:"title,attr"`
		Date   string `xml:"date,attr"`
		Author string `xml:"author,attr"`
		Slide  []struct {
			Type  string   `xml:"type,attr"`
			Title string   `xml:"title"`
			Item  []string `xml:"item"`
		} `xml:"slide"`
	} `xml:"slideshow"`
}

type echo struct {
	Hello string `json:"hello"`
}

func TestParse2StructWithJSON(t *testing.T) {
	var bin httpBin
	testJSON := `
	{
		"args": {},
		"data": "{\"hello\":\"world\"}",
		"files": {},
		"form": {},
		"headers": {
		"Accept-Encoding": "gzip",
		"Content-Length": "17",
		"Content-Type": "application/json; charset=utf-8",
		"Host": "httpbin.org",
		"User-Agent": "beegoServer"
		},
		"json": {
			"hello": "world"
		},
		"origin": "118.244.254.30",
		"url": "http://httpbin.org/post"
	}
	`
	err := Parse2Struct("json", []byte(testJSON), &bin)
	if err != nil {
		t.Fatal(err)
	}
	if bin.JSON.Hello != "world" {
		t.Errorf("want world, got %s", bin.JSON.Hello)
	}
}

func TestParse2StructWithXML(t *testing.T) {
	var binXML httpBinXML
	testXML := `
	<?xml version='1.0' encoding='utf-8'?>

	<slideshow
    	title="Sample Slide Show"
    	date="Date of publication"
    	author="Yours Truly"
    >

    <slide type="all">
      <title>Wake up to WonderWidgets!</title>
    </slide>

    <slide type="all">
        <title>Overview</title>
        <item>Why WonderWidgets are great</item>
        <item/>
        <item>Who buys WonderWidgets</item>
    </slide>

	</slideshow>
	`
	err := Parse2Struct("xml", []byte(testXML), binXML)
	if err != nil {
		t.Fatal(err)
	}
}

func TestParse2StructWithText(t *testing.T) {

}

func TestParse2Bytes(t *testing.T) {
	var bin httpBin
	bin.Headers.Content_Length = "application/json; charset=utf-8"
	b, err := Parse2Bytes("json", bin)
	if err != nil {
		t.Fatal(err)
	}
	if !strings.Contains(string(b), "application/json; charset=utf-8") {
		t.Errorf("want true, got %t", strings.Contains(string(b), "application/json; charset=utf-8"))
	}
}

func TestConvertResponseToBytes(t *testing.T) {
	resp, err := http.Get("https://api.github.com")
	if err != nil {
		t.Fatal(err)
	}
	b1, err := ConvertResponseToBytes(resp)
	if err != nil {
		t.Fatal(err)
	}
	b2, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		t.Fatal(err)
	}
	if string(b1) != string(b2) {
		t.Errorf("want true, got %t", string(b1) == string(b2))
	}
}

func TestGet(t *testing.T) {
	var bin httpBin
	var url = "http://httpbin.org/get"
	result, err := Get(url, nil, &bin)
	if err != nil {
		m, _ := ConvertResponseToBytes(result)
		t.Log(string(m))
		t.Fatal(err)
	}
	if len(strings.Split(bin.Origin, ".")) != 4 {
		t.Errorf("want 4, got %d", len(strings.Split(bin.Origin, ".")))
	}
}

func TestPost(t *testing.T) {
	var bin httpBin
	request := &echo{Hello: "world"}
	var url = "http://httpbin.org/post"

	result, err := Post(url, request, nil, &bin)
	if err != nil {
		m, _ := ConvertResponseToBytes(result)
		t.Log(string(m))
		t.Fatal(err)
	}
	if bin.JSON.Hello != request.Hello {
		t.Errorf("want %s, got %+v", request.Hello, bin.JSON.Hello)
	}
}

func TestDelete(t *testing.T) {
	var bin httpBin
	request := &echo{Hello: "world"}
	var url = "http://httpbin.org/delete"
	result, err := Delete(url, request, nil, &bin)
	if err != nil {
		m, _ := ConvertResponseToBytes(result)
		t.Log(string(m))
		t.Fatal(err)
	}
	if bin.JSON.Hello != request.Hello {
		t.Errorf("want %s, got %+v", request.Hello, bin.JSON.Hello)
	}
}

func TestPut(t *testing.T) {
	var bin httpBin
	request := &echo{Hello: "world"}
	var url = "http://httpbin.org/put"
	result, err := Put(url, request, nil, &bin)
	if err != nil {
		m, _ := ConvertResponseToBytes(result)
		t.Log(string(m))
		t.Fatal(err)
	}
	if bin.JSON.Hello != request.Hello {
		t.Errorf("want %s, got %+v", request.Hello, bin.JSON.Hello)
	}
}

func TestPostFuncs(t *testing.T) {
	// 设置超时时间
	var timeout = func(req *httplib.BeegoHttpRequest) *httplib.BeegoHttpRequest {
		return req.SetTimeout(10*time.Second, 20*time.Second)
	}

	var insecure = func(req *httplib.BeegoHttpRequest) *httplib.BeegoHttpRequest {
		return req.SetTLSClientConfig(&tls.Config{InsecureSkipVerify: true})
	}

	var bin httpBin
	request := &echo{Hello: "world"}
	var url = "https://httpbin.org/put"
	result, err := Put(url, request, nil, &bin, timeout, insecure)
	if err != nil {
		m, _ := ConvertResponseToBytes(result)
		t.Log(string(m))
		t.Fatal(err)
	}
	if bin.JSON.Hello != request.Hello {
		t.Errorf("want %s, got %+v", request.Hello, bin.JSON.Hello)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"syscall"

	"github.com/concourse/atc"
	"github.com/concourse/baggageclaim/baggageclaimcmd"
	"github.com/concourse/baggageclaim/fs"
	"github.com/pivotal-golang/lager"
	"github.com/tedsuo/ifrit"
	"github.com/concourse/bin/bindata"
)

func (cmd *WorkerCommand) gardenRunner(logger lager.Logger, args []string) (atc.Worker, ifrit.Runner, error) {
	err := cmd.checkRoot()
	if err != nil {
		return atc.Worker{}, nil, err
	}

	err = bindata.RestoreAssets(cmd.WorkDir, "linux")
	if err != nil {
		return atc.Worker{}, nil, err
	}

	linux := filepath.Join(cmd.WorkDir, "linux")

	btrfsToolsDir := filepath.Join(linux, "btrfs")
	err = os.Setenv("PATH", btrfsToolsDir+string(os.PathListSeparator)+os.Getenv("PATH"))
	if err != nil {
		return atc.Worker{}, nil, err
	}

	gardenBin := filepath.Join(linux, "garden-linux")
	binDir := filepath.Join(linux, "bin")
	depotDir := filepath.Join(linux, "depot")
	graphDir := filepath.Join(linux, "graph")
	snapshotsDir := filepath.Join(linux, "snapshots")
	stateDir := filepath.Join(linux, "state")

	// must be readable by other users so unprivileged containers can run their
	// own `initc' process
	err = os.MkdirAll(depotDir, 0755)
	if err != nil {
		return atc.Worker{}, nil, err
	}

	err = os.MkdirAll(graphDir, 0700)
	if err != nil {
		return atc.Worker{}, nil, err
	}

	busyboxDir, err := cmd.extractBusybox(linux)

	gardenArgs := []string{
		"-listenNetwork", "tcp",
		"-listenAddr", cmd.bindAddr(),
		"-bin", binDir,
		"-depot", depotDir,
		"-graph", graphDir,
		"-snapshots", snapshotsDir,
		"-stateDir", stateDir,
		"-rootfs", busyboxDir,
		"-allowHostAccess",
	}

	gardenArgs = append(gardenArgs, args...)

	gardenCmd := exec.Command(gardenBin, gardenArgs...)
	gardenCmd.Stdout = os.Stdout
	gardenCmd.Stderr = os.Stderr

	worker := atc.Worker{
		Platform: "linux",
		Tags:     cmd.Tags,

		HTTPProxyURL:  cmd.HTTPProxy.String(),
		HTTPSProxyURL: cmd.HTTPSProxy.String(),
		NoProxy:       strings.Join(cmd.NoProxy, ","),
	}

	worker.ResourceTypes, err = cmd.extractResources(linux)

	worker.Name, err = cmd.workerName()
	if err != nil {
		return atc.Worker{}, nil, err
	}

	return worker, cmdRunner{gardenCmd}, nil
}

func (cmd *WorkerCommand) baggageclaimRunner(logger lager.Logger) (ifrit.Runner, error) {
	volumesImage := filepath.Join(cmd.WorkDir, "volumes.img")
	volumesDir := filepath.Join(cmd.WorkDir, "volumes")

	err := os.MkdirAll(volumesDir, 0755)
	if err != nil {
		return nil, err
	}

	var fsStat syscall.Statfs_t
	err = syscall.Statfs(volumesDir, &fsStat)
	if err != nil {
		return nil, fmt.Errorf("failed to stat volumes filesystem: %s", err)
	}

	filesystem := fs.New(logger.Session("fs"), volumesImage, volumesDir)

	err = filesystem.Create(fsStat.Blocks * uint64(fsStat.Bsize))
	if err != nil {
		return nil, fmt.Errorf("failed to set up volumes filesystem: %s", err)
	}

	bc := &baggageclaimcmd.BaggageclaimCommand{
		BindIP:   baggageclaimcmd.IPFlag(cmd.Baggageclaim.BindIP),
		BindPort: cmd.Baggageclaim.BindPort,

		VolumesDir: baggageclaimcmd.DirFlag(volumesDir),

		Driver: "btrfs",

		ReapInterval: cmd.Baggageclaim.ReapInterval,

		Metrics: cmd.Metrics,
	}

	return bc.Runner(nil)
}

func (cmd *WorkerCommand) extractBusybox(linux string) (string, error) {
	archive := filepath.Join(linux, "busybox.tar.gz")

	busyboxDir := filepath.Join(linux, "busybox")
	err := os.MkdirAll(busyboxDir, 0755)
	if err != nil {
		return "", err
	}

	tarBin := filepath.Join(linux, "bin", "tar")
	tar := exec.Command(tarBin, "-zxf", archive, "-C", busyboxDir)
	tar.Stdout = os.Stdout
	tar.Stderr = os.Stderr

	err = tar.Run()
	if err != nil {
		return "", err
	}

	return busyboxDir, nil
}

func (cmd *WorkerCommand) extractResources(linux string) ([]atc.WorkerResourceType, error) {
	var resourceTypes []atc.WorkerResourceType

	binDir := filepath.Join(linux, "bin")
	resourcesDir := filepath.Join(linux, "resources")
	resourceImagesDir := filepath.Join(linux, "resource-images")

	tarBin := filepath.Join(binDir, "tar")

	infos, err := ioutil.ReadDir(resourcesDir)
	if err == nil {
		for _, info := range infos {
			archive := filepath.Join(resourcesDir, info.Name())
			resourceType := info.Name()

			imageDir := filepath.Join(resourceImagesDir, resourceType)

			err := os.RemoveAll(imageDir)
			if err != nil {
				return nil, err
			}

			err = os.MkdirAll(imageDir, 0755)
			if err != nil {
				return nil, err
			}

			tar := exec.Command(tarBin, "-zxf", archive, "-C", imageDir)
			tar.Stdout = os.Stdout
			tar.Stderr = os.Stderr

			err = tar.Run()
			if err != nil {
				return nil, err
			}

			resourceTypes = append(resourceTypes, atc.WorkerResourceType{
				Type:  resourceType,
				Image: imageDir,
			})
		}
	}

	return resourceTypes, nil
}
<commit_msg>fix import<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"syscall"

	"github.com/concourse/atc"
	"github.com/concourse/baggageclaim/baggageclaimcmd"
	"github.com/concourse/baggageclaim/fs"
	"github.com/concourse/bin/bindata"
	"github.com/pivotal-golang/lager"
	"github.com/tedsuo/ifrit"
)

func (cmd *WorkerCommand) gardenRunner(logger lager.Logger, args []string) (atc.Worker, ifrit.Runner, error) {
	err := cmd.checkRoot()
	if err != nil {
		return atc.Worker{}, nil, err
	}

	err = bindata.RestoreAssets(cmd.WorkDir, "linux")
	if err != nil {
		return atc.Worker{}, nil, err
	}

	linux := filepath.Join(cmd.WorkDir, "linux")

	btrfsToolsDir := filepath.Join(linux, "btrfs")
	err = os.Setenv("PATH", btrfsToolsDir+string(os.PathListSeparator)+os.Getenv("PATH"))
	if err != nil {
		return atc.Worker{}, nil, err
	}

	gardenBin := filepath.Join(linux, "garden-linux")
	binDir := filepath.Join(linux, "bin")
	depotDir := filepath.Join(linux, "depot")
	graphDir := filepath.Join(linux, "graph")
	snapshotsDir := filepath.Join(linux, "snapshots")
	stateDir := filepath.Join(linux, "state")

	// must be readable by other users so unprivileged containers can run their
	// own `initc' process
	err = os.MkdirAll(depotDir, 0755)
	if err != nil {
		return atc.Worker{}, nil, err
	}

	err = os.MkdirAll(graphDir, 0700)
	if err != nil {
		return atc.Worker{}, nil, err
	}

	busyboxDir, err := cmd.extractBusybox(linux)

	gardenArgs := []string{
		"-listenNetwork", "tcp",
		"-listenAddr", cmd.bindAddr(),
		"-bin", binDir,
		"-depot", depotDir,
		"-graph", graphDir,
		"-snapshots", snapshotsDir,
		"-stateDir", stateDir,
		"-rootfs", busyboxDir,
		"-allowHostAccess",
	}

	gardenArgs = append(gardenArgs, args...)

	gardenCmd := exec.Command(gardenBin, gardenArgs...)
	gardenCmd.Stdout = os.Stdout
	gardenCmd.Stderr = os.Stderr

	worker := atc.Worker{
		Platform: "linux",
		Tags:     cmd.Tags,

		HTTPProxyURL:  cmd.HTTPProxy.String(),
		HTTPSProxyURL: cmd.HTTPSProxy.String(),
		NoProxy:       strings.Join(cmd.NoProxy, ","),
	}

	worker.ResourceTypes, err = cmd.extractResources(linux)

	worker.Name, err = cmd.workerName()
	if err != nil {
		return atc.Worker{}, nil, err
	}

	return worker, cmdRunner{gardenCmd}, nil
}

func (cmd *WorkerCommand) baggageclaimRunner(logger lager.Logger) (ifrit.Runner, error) {
	volumesImage := filepath.Join(cmd.WorkDir, "volumes.img")
	volumesDir := filepath.Join(cmd.WorkDir, "volumes")

	err := os.MkdirAll(volumesDir, 0755)
	if err != nil {
		return nil, err
	}

	var fsStat syscall.Statfs_t
	err = syscall.Statfs(volumesDir, &fsStat)
	if err != nil {
		return nil, fmt.Errorf("failed to stat volumes filesystem: %s", err)
	}

	filesystem := fs.New(logger.Session("fs"), volumesImage, volumesDir)

	err = filesystem.Create(fsStat.Blocks * uint64(fsStat.Bsize))
	if err != nil {
		return nil, fmt.Errorf("failed to set up volumes filesystem: %s", err)
	}

	bc := &baggageclaimcmd.BaggageclaimCommand{
		BindIP:   baggageclaimcmd.IPFlag(cmd.Baggageclaim.BindIP),
		BindPort: cmd.Baggageclaim.BindPort,

		VolumesDir: baggageclaimcmd.DirFlag(volumesDir),

		Driver: "btrfs",

		ReapInterval: cmd.Baggageclaim.ReapInterval,

		Metrics: cmd.Metrics,
	}

	return bc.Runner(nil)
}

func (cmd *WorkerCommand) extractBusybox(linux string) (string, error) {
	archive := filepath.Join(linux, "busybox.tar.gz")

	busyboxDir := filepath.Join(linux, "busybox")
	err := os.MkdirAll(busyboxDir, 0755)
	if err != nil {
		return "", err
	}

	tarBin := filepath.Join(linux, "bin", "tar")
	tar := exec.Command(tarBin, "-zxf", archive, "-C", busyboxDir)
	tar.Stdout = os.Stdout
	tar.Stderr = os.Stderr

	err = tar.Run()
	if err != nil {
		return "", err
	}

	return busyboxDir, nil
}

func (cmd *WorkerCommand) extractResources(linux string) ([]atc.WorkerResourceType, error) {
	var resourceTypes []atc.WorkerResourceType

	binDir := filepath.Join(linux, "bin")
	resourcesDir := filepath.Join(linux, "resources")
	resourceImagesDir := filepath.Join(linux, "resource-images")

	tarBin := filepath.Join(binDir, "tar")

	infos, err := ioutil.ReadDir(resourcesDir)
	if err == nil {
		for _, info := range infos {
			archive := filepath.Join(resourcesDir, info.Name())
			resourceType := info.Name()

			imageDir := filepath.Join(resourceImagesDir, resourceType)

			err := os.RemoveAll(imageDir)
			if err != nil {
				return nil, err
			}

			err = os.MkdirAll(imageDir, 0755)
			if err != nil {
				return nil, err
			}

			tar := exec.Command(tarBin, "-zxf", archive, "-C", imageDir)
			tar.Stdout = os.Stdout
			tar.Stderr = os.Stderr

			err = tar.Run()
			if err != nil {
				return nil, err
			}

			resourceTypes = append(resourceTypes, atc.WorkerResourceType{
				Type:  resourceType,
				Image: imageDir,
			})
		}
	}

	return resourceTypes, nil
}
<|endoftext|>


<commit_before>package main_test

import (
	"encoding/json"
	"fmt"
	"os"
	"os/exec"
	"strings"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gbytes"
	"github.com/onsi/gomega/gexec"
)

var (
	cliPath string
)

var _ = FDescribe("concourse-up", func() {
	BeforeSuite(func() {
		compilationVars := map[string]string{}

		file, err := os.Open("compilation-vars.json")
		Expect(err).To(Succeed())
		defer file.Close()

		err = json.NewDecoder(file).Decode(&compilationVars)
		Expect(err).To(Succeed())

		ldflags := []string{
			fmt.Sprintf("-X main.ConcourseUpVersion=%s", "0.0.0"),
			fmt.Sprintf("-X github.com/EngineerBetter/concourse-up/bosh.ConcourseStemcellURL=%s", compilationVars["concourse_stemcell_url"]),
			fmt.Sprintf("-X github.com/EngineerBetter/concourse-up/bosh.ConcourseStemcellVersion=%s", compilationVars["concourse_stemcell_version"]),
			fmt.Sprintf("-X github.com/EngineerBetter/concourse-up/bosh.ConcourseStemcellSHA1=%s", compilationVars["concourse_stemcell_sha1"]),
			fmt.Sprintf("-X github.com/EngineerBetter/concourse-up/bosh.ConcourseReleaseURL=%s", compilationVars["concourse_release_url"]),
			fmt.Sprintf("-X github.com/EngineerBetter/concourse-up/bosh.ConcourseReleaseVersion=%s", compilationVars["concourse_release_version"]),
			fmt.Sprintf("-X github.com/EngineerBetter/concourse-up/bosh.ConcourseReleaseSHA1=%s", compilationVars["concourse_release_sha1"]),
			fmt.Sprintf("-X github.com/EngineerBetter/concourse-up/bosh.GardenReleaseURL=%s", compilationVars["garden_release_url"]),
			fmt.Sprintf("-X github.com/EngineerBetter/concourse-up/bosh.GardenReleaseVersion=%s", compilationVars["garden_release_version"]),
			fmt.Sprintf("-X github.com/EngineerBetter/concourse-up/bosh.GardenReleaseSHA1=%s", compilationVars["garden_release_sha1"]),
			fmt.Sprintf("-X github.com/EngineerBetter/concourse-up/bosh.DirectorStemcellURL=%s", compilationVars["director_stemcell_url"]),
			fmt.Sprintf("-X github.com/EngineerBetter/concourse-up/bosh.DirectorStemcellSHA1=%s", compilationVars["director_stemcell_sha1"]),
			fmt.Sprintf("-X github.com/EngineerBetter/concourse-up/bosh.DirectorStemcellVersion=%s", compilationVars["director_stemcell_version"]),
			fmt.Sprintf("-X github.com/EngineerBetter/concourse-up/bosh.DirectorCPIReleaseURL=%s", compilationVars["director_bosh_cpi_release_url"]),
			fmt.Sprintf("-X github.com/EngineerBetter/concourse-up/bosh.DirectorCPIReleaseVersion=%s", compilationVars["director_bosh_cpi_release_version"]),
			fmt.Sprintf("-X github.com/EngineerBetter/concourse-up/bosh.DirectorCPIReleaseSHA1=%s", compilationVars["director_bosh_cpi_release_sha1"]),
			fmt.Sprintf("-X github.com/EngineerBetter/concourse-up/bosh.DirectorReleaseURL=%s", compilationVars["director_bosh_release_url"]),
			fmt.Sprintf("-X github.com/EngineerBetter/concourse-up/bosh.DirectorReleaseVersion=%s", compilationVars["director_bosh_release_version"]),
			fmt.Sprintf("-X github.com/EngineerBetter/concourse-up/bosh.DirectorReleaseSHA1=%s", compilationVars["director_bosh_release_sha1"]),
		}

		cliPath, err = gexec.Build("github.com/EngineerBetter/concourse-up", "-ldflags", strings.Join(ldflags, " "))
		Expect(err).ToNot(HaveOccurred(), "Error building source")
	})

	AfterSuite(func() {
		gexec.CleanupBuildArtifacts()
	})

	It("displays usage instructions on --help", func() {
		command := exec.Command(cliPath, "--help")
		session, err := gexec.Start(command, GinkgoWriter, GinkgoWriter)
		Expect(err).ToNot(HaveOccurred(), "Error running CLI: "+cliPath)
		Eventually(session).Should(gexec.Exit(0))
		Expect(session.Out).To(Say("Concourse-Up - A CLI tool to deploy Concourse CI"))
		Expect(session.Out).To(Say("deploy, d   Deploys or updates a Concourse"))
		Expect(session.Out).To(Say("destroy, x  Destroys a Concourse"))
	})
})
<commit_msg>remove test focus<commit_after>package main_test

import (
	"encoding/json"
	"fmt"
	"os"
	"os/exec"
	"strings"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gbytes"
	"github.com/onsi/gomega/gexec"
)

var (
	cliPath string
)

var _ = Describe("concourse-up", func() {
	BeforeSuite(func() {
		compilationVars := map[string]string{}

		file, err := os.Open("compilation-vars.json")
		Expect(err).To(Succeed())
		defer file.Close()

		err = json.NewDecoder(file).Decode(&compilationVars)
		Expect(err).To(Succeed())

		ldflags := []string{
			fmt.Sprintf("-X main.ConcourseUpVersion=%s", "0.0.0"),
			fmt.Sprintf("-X github.com/EngineerBetter/concourse-up/bosh.ConcourseStemcellURL=%s", compilationVars["concourse_stemcell_url"]),
			fmt.Sprintf("-X github.com/EngineerBetter/concourse-up/bosh.ConcourseStemcellVersion=%s", compilationVars["concourse_stemcell_version"]),
			fmt.Sprintf("-X github.com/EngineerBetter/concourse-up/bosh.ConcourseStemcellSHA1=%s", compilationVars["concourse_stemcell_sha1"]),
			fmt.Sprintf("-X github.com/EngineerBetter/concourse-up/bosh.ConcourseReleaseURL=%s", compilationVars["concourse_release_url"]),
			fmt.Sprintf("-X github.com/EngineerBetter/concourse-up/bosh.ConcourseReleaseVersion=%s", compilationVars["concourse_release_version"]),
			fmt.Sprintf("-X github.com/EngineerBetter/concourse-up/bosh.ConcourseReleaseSHA1=%s", compilationVars["concourse_release_sha1"]),
			fmt.Sprintf("-X github.com/EngineerBetter/concourse-up/bosh.GardenReleaseURL=%s", compilationVars["garden_release_url"]),
			fmt.Sprintf("-X github.com/EngineerBetter/concourse-up/bosh.GardenReleaseVersion=%s", compilationVars["garden_release_version"]),
			fmt.Sprintf("-X github.com/EngineerBetter/concourse-up/bosh.GardenReleaseSHA1=%s", compilationVars["garden_release_sha1"]),
			fmt.Sprintf("-X github.com/EngineerBetter/concourse-up/bosh.DirectorStemcellURL=%s", compilationVars["director_stemcell_url"]),
			fmt.Sprintf("-X github.com/EngineerBetter/concourse-up/bosh.DirectorStemcellSHA1=%s", compilationVars["director_stemcell_sha1"]),
			fmt.Sprintf("-X github.com/EngineerBetter/concourse-up/bosh.DirectorStemcellVersion=%s", compilationVars["director_stemcell_version"]),
			fmt.Sprintf("-X github.com/EngineerBetter/concourse-up/bosh.DirectorCPIReleaseURL=%s", compilationVars["director_bosh_cpi_release_url"]),
			fmt.Sprintf("-X github.com/EngineerBetter/concourse-up/bosh.DirectorCPIReleaseVersion=%s", compilationVars["director_bosh_cpi_release_version"]),
			fmt.Sprintf("-X github.com/EngineerBetter/concourse-up/bosh.DirectorCPIReleaseSHA1=%s", compilationVars["director_bosh_cpi_release_sha1"]),
			fmt.Sprintf("-X github.com/EngineerBetter/concourse-up/bosh.DirectorReleaseURL=%s", compilationVars["director_bosh_release_url"]),
			fmt.Sprintf("-X github.com/EngineerBetter/concourse-up/bosh.DirectorReleaseVersion=%s", compilationVars["director_bosh_release_version"]),
			fmt.Sprintf("-X github.com/EngineerBetter/concourse-up/bosh.DirectorReleaseSHA1=%s", compilationVars["director_bosh_release_sha1"]),
		}

		cliPath, err = gexec.Build("github.com/EngineerBetter/concourse-up", "-ldflags", strings.Join(ldflags, " "))
		Expect(err).ToNot(HaveOccurred(), "Error building source")
	})

	AfterSuite(func() {
		gexec.CleanupBuildArtifacts()
	})

	It("displays usage instructions on --help", func() {
		command := exec.Command(cliPath, "--help")
		session, err := gexec.Start(command, GinkgoWriter, GinkgoWriter)
		Expect(err).ToNot(HaveOccurred(), "Error running CLI: "+cliPath)
		Eventually(session).Should(gexec.Exit(0))
		Expect(session.Out).To(Say("Concourse-Up - A CLI tool to deploy Concourse CI"))
		Expect(session.Out).To(Say("deploy, d   Deploys or updates a Concourse"))
		Expect(session.Out).To(Say("destroy, x  Destroys a Concourse"))
	})
})
<|endoftext|>


<commit_before>package plugins

import (
	"bytes"
	"encoding/json"
	"io"
	"io/ioutil"
	"net/http"
	"strings"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/docker/go-connections/sockets"
	"github.com/docker/go-connections/tlsconfig"
)

const (
	versionMimetype = "application/vnd.docker.plugins.v1.2+json"
	defaultTimeOut  = 30
)

// NewClient creates a new plugin client (http).
func NewClient(addr string, tlsConfig tlsconfig.Options) (*Client, error) {
	tr := &http.Transport{}

	c, err := tlsconfig.Client(tlsConfig)
	if err != nil {
		return nil, err
	}
	tr.TLSClientConfig = c

	protoAndAddr := strings.Split(addr, "://")
	sockets.ConfigureTCPTransport(tr, protoAndAddr[0], protoAndAddr[1])

	scheme := protoAndAddr[0]
	if scheme != "https" {
		scheme = "http"
	}
	return &Client{&http.Client{Transport: tr}, scheme, protoAndAddr[1]}, nil
}

// Client represents a plugin client.
type Client struct {
	http   *http.Client // http client to use
	scheme string       // scheme protocol of the plugin
	addr   string       // http address of the plugin
}

// Call calls the specified method with the specified arguments for the plugin.
// It will retry for 30 seconds if a failure occurs when calling.
func (c *Client) Call(serviceMethod string, args interface{}, ret interface{}) error {
	var buf bytes.Buffer
	if args != nil {
		if err := json.NewEncoder(&buf).Encode(args); err != nil {
			return err
		}
	}
	body, err := c.callWithRetry(serviceMethod, &buf, true)
	if err != nil {
		return err
	}
	defer body.Close()
	if ret != nil {
		if err := json.NewDecoder(body).Decode(&ret); err != nil {
			logrus.Errorf("%s: error reading plugin resp: %v", serviceMethod, err)
			return err
		}
	}
	return nil
}

// Stream calls the specified method with the specified arguments for the plugin and returns the response body
func (c *Client) Stream(serviceMethod string, args interface{}) (io.ReadCloser, error) {
	var buf bytes.Buffer
	if err := json.NewEncoder(&buf).Encode(args); err != nil {
		return nil, err
	}
	return c.callWithRetry(serviceMethod, &buf, true)
}

// SendFile calls the specified method, and passes through the IO stream
func (c *Client) SendFile(serviceMethod string, data io.Reader, ret interface{}) error {
	body, err := c.callWithRetry(serviceMethod, data, true)
	if err != nil {
		return err
	}
	if err := json.NewDecoder(body).Decode(&ret); err != nil {
		logrus.Errorf("%s: error reading plugin resp: %v", serviceMethod, err)
		return err
	}
	return nil
}

func (c *Client) callWithRetry(serviceMethod string, data io.Reader, retry bool) (io.ReadCloser, error) {
	req, err := http.NewRequest("POST", "/"+serviceMethod, data)
	if err != nil {
		return nil, err
	}
	req.Header.Add("Accept", versionMimetype)
	req.URL.Scheme = c.scheme
	req.URL.Host = c.addr

	var retries int
	start := time.Now()

	for {
		resp, err := c.http.Do(req)
		if err != nil {
			if !retry {
				return nil, err
			}

			timeOff := backoff(retries)
			if abort(start, timeOff) {
				return nil, err
			}
			retries++
			logrus.Warnf("Unable to connect to plugin: %s, retrying in %v", c.addr, timeOff)
			time.Sleep(timeOff)
			continue
		}

		if resp.StatusCode != http.StatusOK {
			b, err := ioutil.ReadAll(resp.Body)
			if err != nil {
				return nil, &statusError{resp.StatusCode, serviceMethod, err.Error()}
			}

			// Plugins' Response(s) should have an Err field indicating what went
			// wrong. Try to unmarshal into ResponseErr. Otherwise fallback to just
			// return the string(body)
			type responseErr struct {
				Err string
			}
			remoteErr := responseErr{}
			if err := json.Unmarshal(b, &remoteErr); err == nil {
				if remoteErr.Err != "" {
					return nil, &statusError{resp.StatusCode, serviceMethod, remoteErr.Err}
				}
			}
			// old way...
			return nil, &statusError{resp.StatusCode, serviceMethod, string(b)}
		}
		return resp.Body, nil
	}
}

func backoff(retries int) time.Duration {
	b, max := 1, defaultTimeOut
	for b < max && retries > 0 {
		b *= 2
		retries--
	}
	if b > max {
		b = max
	}
	return time.Duration(b) * time.Second
}

func abort(start time.Time, timeOff time.Duration) bool {
	return timeOff+time.Since(start) >= time.Duration(defaultTimeOut)*time.Second
}
<commit_msg>Close resp body on plugin call error<commit_after>package plugins

import (
	"bytes"
	"encoding/json"
	"io"
	"io/ioutil"
	"net/http"
	"strings"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/docker/go-connections/sockets"
	"github.com/docker/go-connections/tlsconfig"
)

const (
	versionMimetype = "application/vnd.docker.plugins.v1.2+json"
	defaultTimeOut  = 30
)

// NewClient creates a new plugin client (http).
func NewClient(addr string, tlsConfig tlsconfig.Options) (*Client, error) {
	tr := &http.Transport{}

	c, err := tlsconfig.Client(tlsConfig)
	if err != nil {
		return nil, err
	}
	tr.TLSClientConfig = c

	protoAndAddr := strings.Split(addr, "://")
	sockets.ConfigureTCPTransport(tr, protoAndAddr[0], protoAndAddr[1])

	scheme := protoAndAddr[0]
	if scheme != "https" {
		scheme = "http"
	}
	return &Client{&http.Client{Transport: tr}, scheme, protoAndAddr[1]}, nil
}

// Client represents a plugin client.
type Client struct {
	http   *http.Client // http client to use
	scheme string       // scheme protocol of the plugin
	addr   string       // http address of the plugin
}

// Call calls the specified method with the specified arguments for the plugin.
// It will retry for 30 seconds if a failure occurs when calling.
func (c *Client) Call(serviceMethod string, args interface{}, ret interface{}) error {
	var buf bytes.Buffer
	if args != nil {
		if err := json.NewEncoder(&buf).Encode(args); err != nil {
			return err
		}
	}
	body, err := c.callWithRetry(serviceMethod, &buf, true)
	if err != nil {
		return err
	}
	defer body.Close()
	if ret != nil {
		if err := json.NewDecoder(body).Decode(&ret); err != nil {
			logrus.Errorf("%s: error reading plugin resp: %v", serviceMethod, err)
			return err
		}
	}
	return nil
}

// Stream calls the specified method with the specified arguments for the plugin and returns the response body
func (c *Client) Stream(serviceMethod string, args interface{}) (io.ReadCloser, error) {
	var buf bytes.Buffer
	if err := json.NewEncoder(&buf).Encode(args); err != nil {
		return nil, err
	}
	return c.callWithRetry(serviceMethod, &buf, true)
}

// SendFile calls the specified method, and passes through the IO stream
func (c *Client) SendFile(serviceMethod string, data io.Reader, ret interface{}) error {
	body, err := c.callWithRetry(serviceMethod, data, true)
	if err != nil {
		return err
	}
	if err := json.NewDecoder(body).Decode(&ret); err != nil {
		logrus.Errorf("%s: error reading plugin resp: %v", serviceMethod, err)
		return err
	}
	return nil
}

func (c *Client) callWithRetry(serviceMethod string, data io.Reader, retry bool) (io.ReadCloser, error) {
	req, err := http.NewRequest("POST", "/"+serviceMethod, data)
	if err != nil {
		return nil, err
	}
	req.Header.Add("Accept", versionMimetype)
	req.URL.Scheme = c.scheme
	req.URL.Host = c.addr

	var retries int
	start := time.Now()

	for {
		resp, err := c.http.Do(req)
		if err != nil {
			if !retry {
				return nil, err
			}

			timeOff := backoff(retries)
			if abort(start, timeOff) {
				return nil, err
			}
			retries++
			logrus.Warnf("Unable to connect to plugin: %s, retrying in %v", c.addr, timeOff)
			time.Sleep(timeOff)
			continue
		}

		if resp.StatusCode != http.StatusOK {
			b, err := ioutil.ReadAll(resp.Body)
			resp.Body.Close()
			if err != nil {
				return nil, &statusError{resp.StatusCode, serviceMethod, err.Error()}
			}

			// Plugins' Response(s) should have an Err field indicating what went
			// wrong. Try to unmarshal into ResponseErr. Otherwise fallback to just
			// return the string(body)
			type responseErr struct {
				Err string
			}
			remoteErr := responseErr{}
			if err := json.Unmarshal(b, &remoteErr); err == nil {
				if remoteErr.Err != "" {
					return nil, &statusError{resp.StatusCode, serviceMethod, remoteErr.Err}
				}
			}
			// old way...
			return nil, &statusError{resp.StatusCode, serviceMethod, string(b)}
		}
		return resp.Body, nil
	}
}

func backoff(retries int) time.Duration {
	b, max := 1, defaultTimeOut
	for b < max && retries > 0 {
		b *= 2
		retries--
	}
	if b > max {
		b = max
	}
	return time.Duration(b) * time.Second
}

func abort(start time.Time, timeOff time.Duration) bool {
	return timeOff+time.Since(start) >= time.Duration(defaultTimeOut)*time.Second
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"log"
	"net/http"
	"os"
	"strings"

	_ "net/http/pprof"

	"github.com/Debian/debiman/internal/archive"
	"github.com/Debian/debiman/internal/bundled"
	"github.com/Debian/debiman/internal/commontmpl"
)

var (
	servingDir = flag.String("serving_dir",
		"/srv/man",
		"Directory in which to place the manpages which should be served")

	indexPath = flag.String("index",
		"<serving_dir>/auxserver.idx",
		"Path to an auxserver index to generate")

	syncCodenames = flag.String("sync_codenames",
		"",
		"Debian codenames to synchronize (e.g. wheezy, jessie, …)")

	syncSuites = flag.String("sync_suites",
		"testing",
		"Debian suites to synchronize (e.g. testing, unstable)")

	onlyRender = flag.String("only_render_pkgs",
		"",
		"If non-empty, a comma-separated whitelist of packages to render (for developing)")

	forceRerender = flag.Bool("force_rerender",
		false,
		"Forces all manpages to be re-rendered, even if they are up to date")

	forceReextract = flag.Bool("force_reextract",
		false,
		"Forces all manpages to be re-extracted, even if there is no newer package version")

	localMirror = flag.String("local_mirror",
		"",
		"If non-empty, a file system path to a Debian mirror, e.g. /srv/mirrors/debian on DSA-maintained machines")

	injectAssets = flag.String("inject_assets",
		"",
		"If non-empty, a file system path to a directory containing assets to overwrite")

	showVersion = flag.Bool("version",
		false,
		"Show debiman version and exit")
)

// use go build -ldflags "-X main.debimanVersion=<version>" to set the version
var debimanVersion = "HEAD"

// TODO: handle deleted packages, i.e. packages which are present on
// disk but not in pkgs

// TODO(later): add memory usage estimates to the big structures, set
// parallelism level according to available memory on the system
func logic() error {
	ar := &archive.Getter{
		ConnectionsPerMirror: 10,
		LocalMirror:          *localMirror,
	}

	// Stage 1: all Debian packages of all architectures of the
	// specified suites are discovered.
	globalView, err := buildGlobalView(ar, distributions(
		strings.Split(*syncCodenames, ","),
		strings.Split(*syncSuites, ",")))
	if err != nil {
		return err
	}

	log.Printf("gathered packages of all suites, total %d packages", len(globalView.pkgs))

	// Stage 2: man pages and auxilliary files (e.g. content fragment
	// files which are included by a number of manpages) are extracted
	// from the identified Debian packages.
	if err := parallelDownload(ar, globalView); err != nil {
		return err
	}

	// Stage 3: all man pages are rendered into an HTML representation
	// using mandoc(1), directory index files are rendered, contents
	// files are rendered.
	if err := renderAll(globalView); err != nil {
		return err
	}

	// Stage 4: write the index only after all rendering is complete,
	// otherwise debiman-auxserver might serve redirects to pages
	// which cannot be served yet.
	path := strings.Replace(*indexPath, "<serving_dir>", *servingDir, -1)
	log.Printf("Writing debiman-auxserver index to %q", path)
	if err := writeIndex(path, globalView); err != nil {
		return err
	}

	if err := renderAux(*servingDir, globalView); err != nil {
		return err
	}

	return nil
}

func main() {
	flag.Parse()

	log.SetFlags(log.LstdFlags | log.Lshortfile)

	if *showVersion {
		fmt.Printf("debiman %s\n", debimanVersion)
		return
	}

	if *injectAssets != "" {
		if err := bundled.Inject(*injectAssets); err != nil {
			log.Fatal(err)
		}

		commonTmpls = commontmpl.MustParseCommonTmpls()
		contentsTmpl = mustParseContentsTmpl()
		pkgindexTmpl = mustParsePkgindexTmpl()
		indexTmpl = mustParseIndexTmpl()
		faqTmpl = mustParseFaqTmpl()
		manpageTmpl = mustParseManpageTmpl()
		manpageerrorTmpl = mustParseManpageerrorTmpl()
	}

	// All of our .so references are relative to *servingDir. For
	// mandoc(1) to find the files, we need to change the working
	// directory now.
	if err := os.Chdir(*servingDir); err != nil {
		log.Fatal(err)
	}

	go http.ListenAndServe(":4414", nil)

	if err := logic(); err != nil {
		log.Fatal(err)
	}
}
<commit_msg>Add log messages for separating the phases<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"net/http"
	"os"
	"strings"

	_ "net/http/pprof"

	"github.com/Debian/debiman/internal/archive"
	"github.com/Debian/debiman/internal/bundled"
	"github.com/Debian/debiman/internal/commontmpl"
)

var (
	servingDir = flag.String("serving_dir",
		"/srv/man",
		"Directory in which to place the manpages which should be served")

	indexPath = flag.String("index",
		"<serving_dir>/auxserver.idx",
		"Path to an auxserver index to generate")

	syncCodenames = flag.String("sync_codenames",
		"",
		"Debian codenames to synchronize (e.g. wheezy, jessie, …)")

	syncSuites = flag.String("sync_suites",
		"testing",
		"Debian suites to synchronize (e.g. testing, unstable)")

	onlyRender = flag.String("only_render_pkgs",
		"",
		"If non-empty, a comma-separated whitelist of packages to render (for developing)")

	forceRerender = flag.Bool("force_rerender",
		false,
		"Forces all manpages to be re-rendered, even if they are up to date")

	forceReextract = flag.Bool("force_reextract",
		false,
		"Forces all manpages to be re-extracted, even if there is no newer package version")

	localMirror = flag.String("local_mirror",
		"",
		"If non-empty, a file system path to a Debian mirror, e.g. /srv/mirrors/debian on DSA-maintained machines")

	injectAssets = flag.String("inject_assets",
		"",
		"If non-empty, a file system path to a directory containing assets to overwrite")

	showVersion = flag.Bool("version",
		false,
		"Show debiman version and exit")
)

// use go build -ldflags "-X main.debimanVersion=<version>" to set the version
var debimanVersion = "HEAD"

// TODO: handle deleted packages, i.e. packages which are present on
// disk but not in pkgs

// TODO(later): add memory usage estimates to the big structures, set
// parallelism level according to available memory on the system
func logic() error {
	ar := &archive.Getter{
		ConnectionsPerMirror: 10,
		LocalMirror:          *localMirror,
	}

	// Stage 1: all Debian packages of all architectures of the
	// specified suites are discovered.
	globalView, err := buildGlobalView(ar, distributions(
		strings.Split(*syncCodenames, ","),
		strings.Split(*syncSuites, ",")))
	if err != nil {
		return err
	}

	log.Printf("gathered packages of all suites, total %d packages", len(globalView.pkgs))

	// Stage 2: man pages and auxilliary files (e.g. content fragment
	// files which are included by a number of manpages) are extracted
	// from the identified Debian packages.
	if err := parallelDownload(ar, globalView); err != nil {
		return err
	}

	log.Printf("Extracted all manpages, now rendering")

	// Stage 3: all man pages are rendered into an HTML representation
	// using mandoc(1), directory index files are rendered, contents
	// files are rendered.
	if err := renderAll(globalView); err != nil {
		return err
	}

	log.Printf("Rendered all manpages, writing index")

	// Stage 4: write the index only after all rendering is complete,
	// otherwise debiman-auxserver might serve redirects to pages
	// which cannot be served yet.
	path := strings.Replace(*indexPath, "<serving_dir>", *servingDir, -1)
	log.Printf("Writing debiman-auxserver index to %q", path)
	if err := writeIndex(path, globalView); err != nil {
		return err
	}

	if err := renderAux(*servingDir, globalView); err != nil {
		return err
	}

	return nil
}

func main() {
	flag.Parse()

	log.SetFlags(log.LstdFlags | log.Lshortfile)

	if *showVersion {
		fmt.Printf("debiman %s\n", debimanVersion)
		return
	}

	if *injectAssets != "" {
		if err := bundled.Inject(*injectAssets); err != nil {
			log.Fatal(err)
		}

		commonTmpls = commontmpl.MustParseCommonTmpls()
		contentsTmpl = mustParseContentsTmpl()
		pkgindexTmpl = mustParsePkgindexTmpl()
		indexTmpl = mustParseIndexTmpl()
		faqTmpl = mustParseFaqTmpl()
		manpageTmpl = mustParseManpageTmpl()
		manpageerrorTmpl = mustParseManpageerrorTmpl()
	}

	// All of our .so references are relative to *servingDir. For
	// mandoc(1) to find the files, we need to change the working
	// directory now.
	if err := os.Chdir(*servingDir); err != nil {
		log.Fatal(err)
	}

	go http.ListenAndServe(":4414", nil)

	if err := logic(); err != nil {
		log.Fatal(err)
	}
}
<|endoftext|>


<commit_before>package cmd

import (
	"github.com/drud/ddev/pkg/dockerutil"
	"github.com/drud/ddev/pkg/nodeps"
	"github.com/drud/ddev/pkg/util"
	"github.com/drud/ddev/pkg/version"
	docker "github.com/fsouza/go-dockerclient"
	"github.com/spf13/cobra"
	"os"
	"sort"
	"strings"
)

// noConfirm: If true, --yes, we won't stop and prompt before each deletion
var deleteImagesNocConfirm bool

// DeleteImagesCmd implements the ddev delete images command
var DeleteImagesCmd = &cobra.Command{
	Use:   "images",
	Short: "Delete docker images not currently in use",
	Example: `ddev delete images
ddev delete images -y`,
	Args: cobra.NoArgs,
	Run: func(cmd *cobra.Command, args []string) {
		if !deleteImagesNocConfirm {
			if !util.Confirm("Deleting unused ddev images. \nThis is a non-destructive operation, \nbut it may require that the images be downloaded again when you need them. \nOK to continue?") {
				os.Exit(1)
			}
		}
		util.Success("Powering off ddev to avoid conflicts")
		powerOff()

		client := dockerutil.GetDockerClient()

		images, err := client.ListImages(docker.ListImagesOptions{
			All: true,
		})
		if err != nil {
			util.Failed("Failed to list images: %v", err)
		}
		// Sort so that images that have -built on the end
		// come up before their parent images that don't
		sort.Slice(images, func(i, j int) bool {
			if images[i].RepoTags == nil || images[j].RepoTags == nil {
				return false
			}
			return images[i].RepoTags[0] > images[j].RepoTags[0]
		})

		webimg := version.GetWebImage()
		dbaimage := version.GetDBAImage()
		routerimage := version.RouterImage + ":" + version.RouterTag
		sshimage := version.SSHAuthImage + ":" + version.SSHAuthTag

		nameAry := strings.Split(version.GetDBImage(nodeps.MariaDB), ":")
		keepDBImageTag := "notagfound"
		if len(nameAry) > 1 {
			keepDBImageTag = nameAry[1]
		}

		// Too much code inside this loop, but complicated by multiple db images
		// and discrete names of images
		for _, image := range images {
			for _, tag := range image.RepoTags {
				// If a webimage, but doesn't match our webimage, delete it
				if strings.HasPrefix(tag, version.WebImg) && !strings.HasPrefix(tag, webimg) && !strings.HasPrefix(tag, webimg+"-built") {
					if err = dockerutil.RemoveImage(tag); err != nil {
						util.Warning("Failed to remove %s: %v", tag, err)
					}
				}
				if strings.HasPrefix(tag, "drud/ddev-dbserver") && !strings.HasSuffix(tag, keepDBImageTag) && !strings.HasSuffix(tag, keepDBImageTag+"-built") {
					if err = dockerutil.RemoveImage(tag); err != nil {
						util.Warning("Unable to remove %s: %v", tag, err)
					}
				}
				// If a dbaimage, but doesn't match our dbaimage, delete it
				if strings.HasPrefix(tag, version.DBAImg) && !strings.HasPrefix(tag, dbaimage) {
					if err = dockerutil.RemoveImage(tag); err != nil {
						util.Warning("Failed to remove %s: %v", tag, err)
					}
				}
				// If a routerImage, but doesn't match our routerimage, delete it
				if strings.HasPrefix(tag, version.RouterImage) && !strings.HasPrefix(tag, routerimage) {
					if err = dockerutil.RemoveImage(tag); err != nil {
						util.Warning("Failed to remove %s: %v", tag, err)
					}
				}
				// If a sshAgentImage, but doesn't match our sshAgentImage, delete it
				if strings.HasPrefix(tag, version.SSHAuthImage) && !strings.HasPrefix(tag, sshimage) && !strings.HasPrefix(tag, sshimage+"-built") {
					if err = dockerutil.RemoveImage(tag); err != nil {
						util.Warning("Failed to remove %s: %v", tag, err)
					}
				}
			}
		}
		util.Success("Any non-current images discovered were deleted.")
	},
}

func init() {
	DeleteImagesCmd.Flags().BoolVarP(&deleteImagesNocConfirm, "yes", "y", false, "Yes - skip confirmation prompt")
	DeleteCmd.AddCommand(DeleteImagesCmd)
}
<commit_msg>Adds `ddev delete images --all flag`, fixes #2968 (#3615)<commit_after>package cmd

import (
	"os"
	"sort"
	"strings"

	"github.com/drud/ddev/pkg/dockerutil"
	"github.com/drud/ddev/pkg/nodeps"
	"github.com/drud/ddev/pkg/util"
	"github.com/drud/ddev/pkg/version"
	docker "github.com/fsouza/go-dockerclient"
	"github.com/spf13/cobra"
)

// noConfirm: If true, --yes, we won't stop and prompt before each deletion
var deleteImagesNocConfirm bool

// deleteAllImages: If set, deletes all images created by ddev
var deleteAllImages bool

// DeleteImagesCmd implements the ddev delete images command
var DeleteImagesCmd = &cobra.Command{
	Use:   "images",
	Short: "Deletes ddev docker images not in use by current ddev version",
	Long:  "with --all it deletes all ddev docker images",
	Example: `ddev delete images
ddev delete images -y
ddev delete images --all`,

	Args: cobra.NoArgs,
	Run: func(cmd *cobra.Command, args []string) {
		if !deleteImagesNocConfirm {
			if !util.Confirm("Deleting unused ddev images. \nThis is a non-destructive operation, \nbut it may require that the images be downloaded again when you need them. \nOK to continue?") {
				os.Exit(1)
			}
		}
		util.Success("Powering off ddev to avoid conflicts")
		powerOff()

		client := dockerutil.GetDockerClient()

		images, err := client.ListImages(docker.ListImagesOptions{
			All: true,
		})
		if err != nil {
			util.Failed("Failed to list images: %v", err)
		}

		// The user can select to delete all ddev images.
		if deleteAllImages {
			// Attempt to find ddev images by tag, searching for "drud/ddev-".
			// Some ddev images will not be found by this tag, future work will
			// be done to improve finding database images.
			for _, image := range images {
				for _, tag := range image.RepoTags {
					if strings.HasPrefix(tag, "drud/ddev-") {
						if err = dockerutil.RemoveImage(tag); err != nil {
							util.Warning("Failed to remove %s: %v", tag, err)
						}
					}
				}
			}
			util.Success("All ddev images discovered were deleted.")
			os.Exit(0)
		}

		// Sort so that images that have -built on the end
		// come up before their parent images that don't
		sort.Slice(images, func(i, j int) bool {
			if images[i].RepoTags == nil || images[j].RepoTags == nil {
				return false
			}
			return images[i].RepoTags[0] > images[j].RepoTags[0]
		})

		webimg := version.GetWebImage()
		dbaimage := version.GetDBAImage()
		routerimage := version.RouterImage + ":" + version.RouterTag
		sshimage := version.SSHAuthImage + ":" + version.SSHAuthTag

		nameAry := strings.Split(version.GetDBImage(nodeps.MariaDB), ":")
		keepDBImageTag := "notagfound"
		if len(nameAry) > 1 {
			keepDBImageTag = nameAry[1]
		}

		// Too much code inside this loop, but complicated by multiple db images
		// and discrete names of images
		for _, image := range images {
			for _, tag := range image.RepoTags {
				// If a webimage, but doesn't match our webimage, delete it
				if strings.HasPrefix(tag, version.WebImg) && !strings.HasPrefix(tag, webimg) && !strings.HasPrefix(tag, webimg+"-built") {
					if err = dockerutil.RemoveImage(tag); err != nil {
						util.Warning("Failed to remove %s: %v", tag, err)
					}
				}
				if strings.HasPrefix(tag, "drud/ddev-dbserver") && !strings.HasSuffix(tag, keepDBImageTag) && !strings.HasSuffix(tag, keepDBImageTag+"-built") {
					if err = dockerutil.RemoveImage(tag); err != nil {
						util.Warning("Failed to remove %s: %v", tag, err)
					}
				}
				// If a dbaimage, but doesn't match our dbaimage, delete it
				if strings.HasPrefix(tag, version.DBAImg) && !strings.HasPrefix(tag, dbaimage) {
					if err = dockerutil.RemoveImage(tag); err != nil {
						util.Warning("Failed to remove %s: %v", tag, err)
					}
				}
				// If a routerImage, but doesn't match our routerimage, delete it
				if strings.HasPrefix(tag, version.RouterImage) && !strings.HasPrefix(tag, routerimage) {
					if err = dockerutil.RemoveImage(tag); err != nil {
						util.Warning("Failed to remove %s: %v", tag, err)
					}
				}
				// If a sshAgentImage, but doesn't match our sshAgentImage, delete it
				if strings.HasPrefix(tag, version.SSHAuthImage) && !strings.HasPrefix(tag, sshimage) && !strings.HasPrefix(tag, sshimage+"-built") {
					if err = dockerutil.RemoveImage(tag); err != nil {
						util.Warning("Failed to remove %s: %v", tag, err)
					}
				}
			}
		}
		util.Success("Any non-current images discovered were deleted.")
	},
}

func init() {
	DeleteImagesCmd.Flags().BoolVarP(&deleteImagesNocConfirm, "yes", "y", false, "Yes - skip confirmation prompt")
	DeleteImagesCmd.Flags().BoolVarP(&deleteAllImages, "all", "a", false, "If set, deletes all Docker images created by ddev.")
	DeleteCmd.AddCommand(DeleteImagesCmd)
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"github.com/nightlyone/lockfile"
	"log"
	"math/rand"
	"os"
	"os/exec"
	"path/filepath"
	"time"
)

// FIXME(nightlyone) Hook up passive monitoring solution here
func monitor(state, msg string) {}

// Avoid thundering herd problem on remote services used by this command.
// Spectrum will be 0, if this is not an issue.
func SpreadWait(spectrum time.Duration) {
	// Seed random generator with current process ID
	rand.Seed(int64(os.Getpid()))
	time.Sleep(time.Duration(rand.Int63n(int64(spectrum))))
}

// Ok states that execution went well. Logs debug output and reports ok to
// monitoring.
func Ok() {
	log.Println("Ok")
	monitor("OK", "")
}

// NotAvailable states that the command could not be started successfully. It
// might not be installed or has other problems.
func NotAvailable(err error) {
	s := fmt.Sprintln("Cannot start command: ", err)
	log.Println("FATAL:", s)
	monitor("UNKNOWN", s)
}

// TimedOut states that the command took too long and reports failure to the
// monitoring.
func TimedOut() {
	s := "execution took too long"
	log.Println("FATAL:", s)
	monitor("CRITICAL", s)
}

// Busy states that the command hangs and reports failure to the monitoring.
// Those tasks should be automatically killed, if it happens often.
func Busy() {
	s := "previous invocation of command still running"
	log.Println("FATAL:", s)
	monitor("CRITICAL", s)
}

// Failed states that the command didn't execute successfully and reports
// failure to the monitoring. Also Logs error output.
func Failed(err error) {
	s := fmt.Sprintln("Failed to execute: ", err)
	log.Println("FATAL:", s)
	monitor("CRITICAL", s)
}

func main() {
	var cmd *exec.Cmd
	var interval, spectrum time.Duration

	// FIXME(mlafeldt) add command-line options for
	//                 - spectrum (optional)
	//                 - monitoring command (optional)
	//                 - kill or wait on busy state (optional)
	//                 - help
	log.SetFlags(0)

	flag.DurationVar(&interval, "i", 1*time.Minute, "set execution interval for command, e.g. 45s, 2m, 1h30m")
	flag.Parse()

	if flag.NArg() < 1 {
		log.Fatal("FATAL: no command to execute")
		return
	}

	command := flag.Arg(0)

	if spectrum >= interval {
		log.Fatal("FATAL: no spectrum >= interval, no time left for actual command execution")
		return
	}

	if spectrum == 0*time.Minute {
		spectrum = interval / 10
	}

	// FIXME(nightlyone) try two intervals instead of one?
	timeout := time.AfterFunc(interval, func() {
		TimedOut()
		if cmd != nil && cmd.Process != nil {
			cmd.Process.Kill()
		}
		os.Exit(0)
	})

	SpreadWait(spectrum)

	// Ensures that only one of these command runs concurrently on this
	// machine.  Also cleans up stale locks of dead instances.
	base := filepath.Base(command)
	lock_dir := os.TempDir()
	os.Mkdir(filepath.Join(lock_dir, base), 0700)
	lock, _ := lockfile.New(filepath.Join(lock_dir, base, base+".lock"))
	if err := lock.TryLock(); err != nil {
		if err != lockfile.ErrBusy {
			log.Printf("ERROR: locking %s: reason: %v\n", lock, err)
		}
		timeout.Stop()
		Busy()
		return
	}
	defer lock.Unlock()

	// FIXME(nightlyone) capture at least cmd.Stderr, and optionally
	// cmd.Stdout
	cmd = exec.Command(command, flag.Args()[1:]...)

	if err := cmd.Start(); err != nil {
		timeout.Stop()
		NotAvailable(err)
		return
	}

	if err := cmd.Wait(); err != nil {
		timeout.Stop()
		Failed(err)
	} else {
		timeout.Stop()
		Ok()
	}
}
<commit_msg>Rename interval to timeout for clarity<commit_after>package main

import (
	"flag"
	"fmt"
	"github.com/nightlyone/lockfile"
	"log"
	"math/rand"
	"os"
	"os/exec"
	"path/filepath"
	"time"
)

// FIXME(nightlyone) Hook up passive monitoring solution here
func monitor(state, msg string) {}

// Avoid thundering herd problem on remote services used by this command.
// Spectrum will be 0, if this is not an issue.
func SpreadWait(spectrum time.Duration) {
	// Seed random generator with current process ID
	rand.Seed(int64(os.Getpid()))
	time.Sleep(time.Duration(rand.Int63n(int64(spectrum))))
}

// Ok states that execution went well. Logs debug output and reports ok to
// monitoring.
func Ok() {
	log.Println("Ok")
	monitor("OK", "")
}

// NotAvailable states that the command could not be started successfully. It
// might not be installed or has other problems.
func NotAvailable(err error) {
	s := fmt.Sprintln("Cannot start command: ", err)
	log.Println("FATAL:", s)
	monitor("UNKNOWN", s)
}

// TimedOut states that the command took too long and reports failure to the
// monitoring.
func TimedOut() {
	s := "execution took too long"
	log.Println("FATAL:", s)
	monitor("CRITICAL", s)
}

// Busy states that the command hangs and reports failure to the monitoring.
// Those tasks should be automatically killed, if it happens often.
func Busy() {
	s := "previous invocation of command still running"
	log.Println("FATAL:", s)
	monitor("CRITICAL", s)
}

// Failed states that the command didn't execute successfully and reports
// failure to the monitoring. Also Logs error output.
func Failed(err error) {
	s := fmt.Sprintln("Failed to execute: ", err)
	log.Println("FATAL:", s)
	monitor("CRITICAL", s)
}

func main() {
	var cmd *exec.Cmd
	var timeout, spectrum time.Duration

	// FIXME(mlafeldt) add command-line options for
	//                 - spectrum (optional)
	//                 - monitoring command (optional)
	//                 - kill or wait on busy state (optional)
	//                 - help
	log.SetFlags(0)

	flag.DurationVar(&timeout, "t", 1*time.Minute, "set execution timeout for command, e.g. 45s, 2m, 1h30m")
	flag.Parse()

	if flag.NArg() < 1 {
		log.Fatal("FATAL: no command to execute")
		return
	}

	command := flag.Arg(0)

	if spectrum >= timeout {
		log.Fatal("FATAL: no spectrum >= interval, no time left for actual command execution")
		return
	}

	if spectrum == 0*time.Minute {
		spectrum = timeout / 10
	}

	// FIXME(nightlyone) try two intervals instead of one?
	timer := time.AfterFunc(timeout, func() {
		TimedOut()
		if cmd != nil && cmd.Process != nil {
			cmd.Process.Kill()
		}
		os.Exit(0)
	})

	SpreadWait(spectrum)

	// Ensures that only one of these command runs concurrently on this
	// machine.  Also cleans up stale locks of dead instances.
	base := filepath.Base(command)
	lock_dir := os.TempDir()
	os.Mkdir(filepath.Join(lock_dir, base), 0700)
	lock, _ := lockfile.New(filepath.Join(lock_dir, base, base+".lock"))
	if err := lock.TryLock(); err != nil {
		if err != lockfile.ErrBusy {
			log.Printf("ERROR: locking %s: reason: %v\n", lock, err)
		}
		timer.Stop()
		Busy()
		return
	}
	defer lock.Unlock()

	// FIXME(nightlyone) capture at least cmd.Stderr, and optionally
	// cmd.Stdout
	cmd = exec.Command(command, flag.Args()[1:]...)

	if err := cmd.Start(); err != nil {
		timer.Stop()
		NotAvailable(err)
		return
	}

	if err := cmd.Wait(); err != nil {
		timer.Stop()
		Failed(err)
	} else {
		timer.Stop()
		Ok()
	}
}
<|endoftext|>


<commit_before>// Copyright 2014 The ql Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSES/QL-LICENSE file.

// Copyright 2015 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

package plans

import (
	"fmt"
	"sort"
	"strings"

	"github.com/juju/errors"
	"github.com/ngaut/log"
	"github.com/pingcap/tidb/context"
	"github.com/pingcap/tidb/expression"
	"github.com/pingcap/tidb/expression/expressions"
	"github.com/pingcap/tidb/field"
	"github.com/pingcap/tidb/plan"
	"github.com/pingcap/tidb/util/format"
	"github.com/pingcap/tidb/util/types"
)

var _ plan.Plan = (*OrderByDefaultPlan)(nil)

// OrderByDefaultPlan handles ORDER BY statement, it uses an array to store
// results temporarily, and sorts them by given expression.
type OrderByDefaultPlan struct {
	*SelectList
	By       []expression.Expression
	Ascs     []bool
	Src      plan.Plan
	ordTable *orderByTable
	cursor   int
}

// Explain implements plan.Plan Explain interface.
func (r *OrderByDefaultPlan) Explain(w format.Formatter) {
	r.Src.Explain(w)
	w.Format("┌Order by")

	items := make([]string, len(r.By))
	for i, v := range r.By {
		order := "ASC"
		if !r.Ascs[i] {
			order = "DESC"
		}
		items[i] = fmt.Sprintf(" %s %s", v, order)
	}
	w.Format("%s", strings.Join(items, ","))
	w.Format("\n└Output field names %v\n", field.RFQNames(r.ResultFields))
}

// Filter implements plan.Plan Filter interface.
func (r *OrderByDefaultPlan) Filter(ctx context.Context, expr expression.Expression) (plan.Plan, bool, error) {
	return r, false, nil
}

type orderByRow struct {
	Key []interface{}
	Row *plan.Row
}

func (o *orderByRow) String() string {
	if o == nil {
		return "<nil>"
	}
	return fmt.Sprintf("[orderByRow](%+v)", *o)
}

type orderByTable struct {
	Rows []*orderByRow
	Ascs []bool
}

// String implements fmt.Stringer interface. Just for debugging.
func (t *orderByTable) String() string {
	if t == nil {
		return "<nil>"
	}
	return fmt.Sprintf("[orderByTable](%+v)", *t)
}

// Len returns the number of rows.
func (t *orderByTable) Len() int {
	return len(t.Rows)
}

// Swap implements sort.Interface Swap interface.
func (t *orderByTable) Swap(i, j int) {
	t.Rows[i], t.Rows[j] = t.Rows[j], t.Rows[i]
}

// Less implements sort.Interface Less interface.
func (t *orderByTable) Less(i, j int) bool {
	for index, asc := range t.Ascs {
		v1 := t.Rows[i].Key[index]
		v2 := t.Rows[j].Key[index]

		ret, err := types.Compare(v1, v2)
		if err != nil {
			// we just have to log this error and skip it.
			// TODO: record this error and handle it out later.
			log.Errorf("compare %v %v err %v", v1, v2, err)
		}

		if !asc {
			ret = -ret
		}

		if ret < 0 {
			return true
		} else if ret > 0 {
			return false
		}
	}

	return false
}

// Do implements plan.Plan Do interface, all records are added into an
// in-memory array, and sorted in ASC/DESC order.
func (r *OrderByDefaultPlan) Do(ctx context.Context, f plan.RowIterFunc) error {
	t := &orderByTable{Ascs: r.Ascs}

	m := map[interface{}]interface{}{}
	err := r.Src.Do(ctx, func(rid interface{}, in []interface{}) (bool, error) {
		m[expressions.ExprEvalIdentFunc] = func(name string) (interface{}, error) {
			return getIdentValue(name, r.ResultFields, in, field.CheckFieldFlag)
		}

		m[expressions.ExprEvalPositionFunc] = func(position int) (interface{}, error) {
			// position is in [1, len(fields)], so we must decrease 1 to get correct index
			// TODO: check position invalidation
			return in[position-1], nil
		}

		row := &orderByRow{
			Row: &plan.Row{Data: in},
			Key: make([]interface{}, 0, len(r.By)),
		}

		for _, by := range r.By {
			// err1 is used for passing `go tool vet --shadow` check.
			val, err1 := by.Eval(ctx, m)
			if err1 != nil {
				return false, err1
			}

			if val != nil {
				if !types.IsOrderedType(val) {
					return false, errors.Errorf("cannot order by %v (type %T)", val, val)
				}
			}

			row.Key = append(row.Key, val)
		}

		t.Rows = append(t.Rows, row)
		return true, nil
	})
	if err != nil {
		return err
	}

	sort.Sort(t)

	var more bool
	for _, row := range t.Rows {
		if more, err = f(nil, row.Row.Data); !more || err != nil {
			break
		}
	}
	return types.EOFAsNil(err)
}

// Next implements plan.Plan Next interface.
func (r *OrderByDefaultPlan) Next(ctx context.Context) (row *plan.Row, err error) {
	if r.ordTable == nil {
		r.ordTable = &orderByTable{Ascs: r.Ascs}
		err = r.fetchAll(ctx)
		if err != nil {
			return nil, errors.Trace(err)
		}
	}
	if r.cursor == len(r.ordTable.Rows) {
		return
	}
	row = r.ordTable.Rows[r.cursor].Row
	r.cursor++
	return
}

func (r *OrderByDefaultPlan) fetchAll(ctx context.Context) error {
	evalArgs := map[interface{}]interface{}{}
	for {
		row, err := r.Src.Next(ctx)
		if err != nil {
			return errors.Trace(err)
		}
		if row == nil {
			break
		}
		evalArgs[expressions.ExprEvalIdentFunc] = func(name string) (interface{}, error) {
			return getIdentValue(name, r.ResultFields, row.Data, field.CheckFieldFlag)
		}

		evalArgs[expressions.ExprEvalPositionFunc] = func(position int) (interface{}, error) {
			// position is in [1, len(fields)], so we must decrease 1 to get correct index
			// TODO: check position invalidation
			return row.Data[position-1], nil
		}
		ordRow := &orderByRow{
			Row: row,
			Key: make([]interface{}, 0, len(r.By)),
		}
		for _, by := range r.By {
			// err1 is used for passing `go tool vet --shadow` check.
			val, err1 := by.Eval(ctx, evalArgs)
			if err1 != nil {
				return err1
			}

			if val != nil {
				var ordered bool
				val, ordered, err1 = types.IsOrderedType(val)
				if err1 != nil {
					return err1
				}

				if !ordered {
					return errors.Errorf("cannot order by %v (type %T)", val, val)
				}
			}

			ordRow.Key = append(ordRow.Key, val)
		}
		r.ordTable.Rows = append(r.ordTable.Rows, ordRow)
	}
	sort.Sort(r.ordTable)
	return nil
}

// Close implements plan.Plan Close interface.
func (r *OrderByDefaultPlan) Close() error {
	r.ordTable = nil
	r.cursor = 0
	return r.Src.Close()
}
<commit_msg>plans: Fix build error<commit_after>// Copyright 2014 The ql Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSES/QL-LICENSE file.

// Copyright 2015 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

package plans

import (
	"fmt"
	"sort"
	"strings"

	"github.com/juju/errors"
	"github.com/ngaut/log"
	"github.com/pingcap/tidb/context"
	"github.com/pingcap/tidb/expression"
	"github.com/pingcap/tidb/expression/expressions"
	"github.com/pingcap/tidb/field"
	"github.com/pingcap/tidb/plan"
	"github.com/pingcap/tidb/util/format"
	"github.com/pingcap/tidb/util/types"
)

var _ plan.Plan = (*OrderByDefaultPlan)(nil)

// OrderByDefaultPlan handles ORDER BY statement, it uses an array to store
// results temporarily, and sorts them by given expression.
type OrderByDefaultPlan struct {
	*SelectList
	By       []expression.Expression
	Ascs     []bool
	Src      plan.Plan
	ordTable *orderByTable
	cursor   int
}

// Explain implements plan.Plan Explain interface.
func (r *OrderByDefaultPlan) Explain(w format.Formatter) {
	r.Src.Explain(w)
	w.Format("┌Order by")

	items := make([]string, len(r.By))
	for i, v := range r.By {
		order := "ASC"
		if !r.Ascs[i] {
			order = "DESC"
		}
		items[i] = fmt.Sprintf(" %s %s", v, order)
	}
	w.Format("%s", strings.Join(items, ","))
	w.Format("\n└Output field names %v\n", field.RFQNames(r.ResultFields))
}

// Filter implements plan.Plan Filter interface.
func (r *OrderByDefaultPlan) Filter(ctx context.Context, expr expression.Expression) (plan.Plan, bool, error) {
	return r, false, nil
}

type orderByRow struct {
	Key []interface{}
	Row *plan.Row
}

func (o *orderByRow) String() string {
	if o == nil {
		return "<nil>"
	}
	return fmt.Sprintf("[orderByRow](%+v)", *o)
}

type orderByTable struct {
	Rows []*orderByRow
	Ascs []bool
}

// String implements fmt.Stringer interface. Just for debugging.
func (t *orderByTable) String() string {
	if t == nil {
		return "<nil>"
	}
	return fmt.Sprintf("[orderByTable](%+v)", *t)
}

// Len returns the number of rows.
func (t *orderByTable) Len() int {
	return len(t.Rows)
}

// Swap implements sort.Interface Swap interface.
func (t *orderByTable) Swap(i, j int) {
	t.Rows[i], t.Rows[j] = t.Rows[j], t.Rows[i]
}

// Less implements sort.Interface Less interface.
func (t *orderByTable) Less(i, j int) bool {
	for index, asc := range t.Ascs {
		v1 := t.Rows[i].Key[index]
		v2 := t.Rows[j].Key[index]

		ret, err := types.Compare(v1, v2)
		if err != nil {
			// we just have to log this error and skip it.
			// TODO: record this error and handle it out later.
			log.Errorf("compare %v %v err %v", v1, v2, err)
		}

		if !asc {
			ret = -ret
		}

		if ret < 0 {
			return true
		} else if ret > 0 {
			return false
		}
	}

	return false
}

// Do implements plan.Plan Do interface, all records are added into an
// in-memory array, and sorted in ASC/DESC order.
func (r *OrderByDefaultPlan) Do(ctx context.Context, f plan.RowIterFunc) error {
	t := &orderByTable{Ascs: r.Ascs}

	m := map[interface{}]interface{}{}
	err := r.Src.Do(ctx, func(rid interface{}, in []interface{}) (bool, error) {
		m[expressions.ExprEvalIdentFunc] = func(name string) (interface{}, error) {
			return getIdentValue(name, r.ResultFields, in, field.CheckFieldFlag)
		}

		m[expressions.ExprEvalPositionFunc] = func(position int) (interface{}, error) {
			// position is in [1, len(fields)], so we must decrease 1 to get correct index
			// TODO: check position invalidation
			return in[position-1], nil
		}

		row := &orderByRow{
			Row: &plan.Row{Data: in},
			Key: make([]interface{}, 0, len(r.By)),
		}

		for _, by := range r.By {
			// err1 is used for passing `go tool vet --shadow` check.
			val, err1 := by.Eval(ctx, m)
			if err1 != nil {
				return false, err1
			}

			if val != nil {
				if !types.IsOrderedType(val) {
					return false, errors.Errorf("cannot order by %v (type %T)", val, val)
				}
			}

			row.Key = append(row.Key, val)
		}

		t.Rows = append(t.Rows, row)
		return true, nil
	})
	if err != nil {
		return err
	}

	sort.Sort(t)

	var more bool
	for _, row := range t.Rows {
		if more, err = f(nil, row.Row.Data); !more || err != nil {
			break
		}
	}
	return types.EOFAsNil(err)
}

// Next implements plan.Plan Next interface.
func (r *OrderByDefaultPlan) Next(ctx context.Context) (row *plan.Row, err error) {
	if r.ordTable == nil {
		r.ordTable = &orderByTable{Ascs: r.Ascs}
		err = r.fetchAll(ctx)
		if err != nil {
			return nil, errors.Trace(err)
		}
	}
	if r.cursor == len(r.ordTable.Rows) {
		return
	}
	row = r.ordTable.Rows[r.cursor].Row
	r.cursor++
	return
}

func (r *OrderByDefaultPlan) fetchAll(ctx context.Context) error {
	evalArgs := map[interface{}]interface{}{}
	for {
		row, err := r.Src.Next(ctx)
		if err != nil {
			return errors.Trace(err)
		}
		if row == nil {
			break
		}
		evalArgs[expressions.ExprEvalIdentFunc] = func(name string) (interface{}, error) {
			return getIdentValue(name, r.ResultFields, row.Data, field.CheckFieldFlag)
		}

		evalArgs[expressions.ExprEvalPositionFunc] = func(position int) (interface{}, error) {
			// position is in [1, len(fields)], so we must decrease 1 to get correct index
			// TODO: check position invalidation
			return row.Data[position-1], nil
		}
		ordRow := &orderByRow{
			Row: row,
			Key: make([]interface{}, 0, len(r.By)),
		}
		for _, by := range r.By {
			// err1 is used for passing `go tool vet --shadow` check.
			val, err1 := by.Eval(ctx, evalArgs)
			if err1 != nil {
				return err1
			}

			if val != nil {
				if !types.IsOrderedType(val) {
					return errors.Errorf("cannot order by %v (type %T)", val, val)
				}
			}

			ordRow.Key = append(ordRow.Key, val)
		}
		r.ordTable.Rows = append(r.ordTable.Rows, ordRow)
	}
	sort.Sort(r.ordTable)
	return nil
}

// Close implements plan.Plan Close interface.
func (r *OrderByDefaultPlan) Close() error {
	r.ordTable = nil
	r.cursor = 0
	return r.Src.Close()
}
<|endoftext|>


<commit_before>package engine

import (
	"fmt"
	"regexp"
	"strings"

	fleetSchema "github.com/coreos/fleet/schema"
	"github.com/monder/kaylee/spec"
)

type RktEngine struct{}

func (*RktEngine) IsValidSpecType(s *spec.Spec) bool {
	return s.Engine == "" || s.Engine == "rkt"
}

func (*RktEngine) ValidateSpec(s *spec.Spec) error {
	if len(s.Apps) == 0 {
		return fmt.Errorf("There should be at least one app")
	}
	return nil
}

func (*RktEngine) GetFleetUnit(spec *spec.Spec, name string, conflicts []string) *fleetSchema.Unit {
	uuidFileName := regexp.MustCompile("[^a-zA-Z0-9_.-]").ReplaceAllLiteralString(name, "_")
	uuidFileName = regexp.MustCompile("\\.service$").ReplaceAllLiteralString(uuidFileName, "")
	uuidFile := "/var/run/kaylee_" + uuidFileName

	var args []string

	for _, arg := range spec.Args {
		args = append(args, arg)
	}

	var options []*fleetSchema.UnitOption
	options = append(options, &fleetSchema.UnitOption{
		Section: "Unit", Name: "Requires", Value: "flanneld.service",
	})
	options = append(options, &fleetSchema.UnitOption{
		Section: "Unit", Name: "After", Value: "flanneld.service",
	})

	for _, env := range spec.EnvFiles {
		options = append(options, &fleetSchema.UnitOption{
			Section: "Service", Name: "EnvironmentFile", Value: env,
		})
	}
	for _, env := range spec.Env {
		options = append(options, &fleetSchema.UnitOption{
			Section: "Service", Name: "Environment", Value: fmt.Sprintf("%s=%s", env.Name, env.Value),
		})
	}
	options = append(options, &fleetSchema.UnitOption{
		Section: "Service", Name: "Environment", Value: fmt.Sprintf("KAYLEE_ID=%s", uuidFileName),
	})

	options = append(options, &fleetSchema.UnitOption{
		Section: "Service", Name: "TimeoutStartSec", Value: "0",
	})

	for _, volume := range spec.Volumes {
		options = append(options, &fleetSchema.UnitOption{
			Section: "Service",
			Name:    "ExecStartPre",
			Value:   fmt.Sprintf("/var/lib/kaylee/plugins/volumes/%s %s %s", volume.Driver, volume.ID, volume.Options),
		})
		options = append(options, &fleetSchema.UnitOption{
			Section: "Service",
			Name:    "ExecStopPost",
			Value:   fmt.Sprintf("/var/lib/kaylee/plugins/volumes/%s -u %s", volume.Driver, volume.ID),
		})

		args = append(args, fmt.Sprintf("--volume %s,kind=host,source=/mnt/%s/%s", volume.ID, volume.Driver, volume.ID))
		args = append(args, fmt.Sprintf("--mount volume=%s,target=%s", volume.ID, volume.Path))
	}

	options = append(options, &fleetSchema.UnitOption{
		Section: "Service", Name: "ExecStartPre", Value: fmt.Sprintf("-/usr/bin/rkt stop --force=true --uuid-file=%s", uuidFile),
	})

	if spec.Net != "" {
		args = append(args, fmt.Sprintf("--net=%s", spec.Net))
	}
	args = append(args, "--insecure-options=image")
	args = append(args, "--inherit-env")
	args = append(args, fmt.Sprintf("--uuid-file-save=%s", uuidFile))

	for _, app := range spec.Apps {
		options = append(options, &fleetSchema.UnitOption{
			Section: "Service", Name: "ExecStartPre", Value: fmt.Sprintf("/usr/bin/rkt fetch --insecure-options=image %s", app.Image),
		})
		args = append(args, fmt.Sprintf("%s -- %s ---", app.Image, strings.Join(app.Args, " ")))
	}

	options = append(options, &fleetSchema.UnitOption{
		Section: "Service",
		Name:    "ExecStart",
		Value:   fmt.Sprintf("/usr/bin/rkt run %s", strings.Join(args, " ")),
	})

	options = append(options, &fleetSchema.UnitOption{
		Section: "Service", Name: "ExecStop", Value: fmt.Sprintf("-/usr/bin/rkt stop --uuid-file=%s", uuidFile),
	})
	options = append(options, &fleetSchema.UnitOption{
		Section: "Service", Name: "ExecStop", Value: fmt.Sprintf("-/usr/bin/rkt rm --uuid-file=%s", uuidFile),
	})
	options = append(options, &fleetSchema.UnitOption{
		Section: "Service", Name: "ExecStop", Value: fmt.Sprintf("-/usr/bin/rm %s", uuidFile),
	})
	options = append(options, &fleetSchema.UnitOption{
		Section: "Service", Name: "Restart", Value: "always",
	})
	options = append(options, &fleetSchema.UnitOption{
		Section: "Service", Name: "RestartSec", Value: "30",
	})

	for _, machine := range spec.Machine {
		options = append(options, &fleetSchema.UnitOption{
			Section: "X-Fleet", Name: "MachineMetadata", Value: machine,
		})
	}
	if spec.MachineID != "" {
		options = append(options, &fleetSchema.UnitOption{
			Section: "X-Fleet", Name: "MachineID", Value: spec.MachineID,
		})
	}
	if spec.Global {
		options = append(options, &fleetSchema.UnitOption{
			Section: "X-Fleet", Name: "Global", Value: "true",
		})
	}

	for _, c := range conflicts {
		options = append(options, &fleetSchema.UnitOption{
			Section: "X-Fleet", Name: "Conflicts", Value: c,
		})
	}
	return &fleetSchema.Unit{
		DesiredState: "launched",
		Options:      options,
		Name:         name,
	}
}
<commit_msg>Correctly escape env<commit_after>package engine

import (
	"fmt"
	"regexp"
	"strings"

	fleetSchema "github.com/coreos/fleet/schema"
	"github.com/monder/kaylee/spec"
)

type RktEngine struct{}

func (*RktEngine) IsValidSpecType(s *spec.Spec) bool {
	return s.Engine == "" || s.Engine == "rkt"
}

func (*RktEngine) ValidateSpec(s *spec.Spec) error {
	if len(s.Apps) == 0 {
		return fmt.Errorf("There should be at least one app")
	}
	return nil
}

func (*RktEngine) GetFleetUnit(spec *spec.Spec, name string, conflicts []string) *fleetSchema.Unit {
	uuidFileName := regexp.MustCompile("[^a-zA-Z0-9_.-]").ReplaceAllLiteralString(name, "_")
	uuidFileName = regexp.MustCompile("\\.service$").ReplaceAllLiteralString(uuidFileName, "")
	uuidFile := "/var/run/kaylee_" + uuidFileName

	var args []string

	for _, arg := range spec.Args {
		args = append(args, arg)
	}

	var options []*fleetSchema.UnitOption
	options = append(options, &fleetSchema.UnitOption{
		Section: "Unit", Name: "Requires", Value: "flanneld.service",
	})
	options = append(options, &fleetSchema.UnitOption{
		Section: "Unit", Name: "After", Value: "flanneld.service",
	})

	for _, env := range spec.EnvFiles {
		options = append(options, &fleetSchema.UnitOption{
			Section: "Service", Name: "EnvironmentFile", Value: env,
		})
	}
	for _, env := range spec.Env {
		options = append(options, &fleetSchema.UnitOption{
			Section: "Service", Name: "Environment", Value: fmt.Sprintf("%q", fmt.Sprintf("%s=%s", env.Name, env.Value)),
		})
	}
	options = append(options, &fleetSchema.UnitOption{
		Section: "Service", Name: "Environment", Value: fmt.Sprintf("KAYLEE_ID=%s", uuidFileName),
	})

	options = append(options, &fleetSchema.UnitOption{
		Section: "Service", Name: "TimeoutStartSec", Value: "0",
	})

	for _, volume := range spec.Volumes {
		options = append(options, &fleetSchema.UnitOption{
			Section: "Service",
			Name:    "ExecStartPre",
			Value:   fmt.Sprintf("/var/lib/kaylee/plugins/volumes/%s %s %s", volume.Driver, volume.ID, volume.Options),
		})
		options = append(options, &fleetSchema.UnitOption{
			Section: "Service",
			Name:    "ExecStopPost",
			Value:   fmt.Sprintf("/var/lib/kaylee/plugins/volumes/%s -u %s", volume.Driver, volume.ID),
		})

		args = append(args, fmt.Sprintf("--volume %s,kind=host,source=/mnt/%s/%s", volume.ID, volume.Driver, volume.ID))
		args = append(args, fmt.Sprintf("--mount volume=%s,target=%s", volume.ID, volume.Path))
	}

	options = append(options, &fleetSchema.UnitOption{
		Section: "Service", Name: "ExecStartPre", Value: fmt.Sprintf("-/usr/bin/rkt stop --force=true --uuid-file=%s", uuidFile),
	})

	if spec.Net != "" {
		args = append(args, fmt.Sprintf("--net=%s", spec.Net))
	}
	args = append(args, "--insecure-options=image")
	args = append(args, "--inherit-env")
	args = append(args, fmt.Sprintf("--uuid-file-save=%s", uuidFile))

	for _, app := range spec.Apps {
		options = append(options, &fleetSchema.UnitOption{
			Section: "Service", Name: "ExecStartPre", Value: fmt.Sprintf("/usr/bin/rkt fetch --insecure-options=image %s", app.Image),
		})
		args = append(args, fmt.Sprintf("%s -- %s ---", app.Image, strings.Join(app.Args, " ")))
	}

	options = append(options, &fleetSchema.UnitOption{
		Section: "Service",
		Name:    "ExecStart",
		Value:   fmt.Sprintf("/usr/bin/rkt run %s", strings.Join(args, " ")),
	})

	options = append(options, &fleetSchema.UnitOption{
		Section: "Service", Name: "ExecStop", Value: fmt.Sprintf("-/usr/bin/rkt stop --uuid-file=%s", uuidFile),
	})
	options = append(options, &fleetSchema.UnitOption{
		Section: "Service", Name: "ExecStop", Value: fmt.Sprintf("-/usr/bin/rkt rm --uuid-file=%s", uuidFile),
	})
	options = append(options, &fleetSchema.UnitOption{
		Section: "Service", Name: "ExecStop", Value: fmt.Sprintf("-/usr/bin/rm %s", uuidFile),
	})
	options = append(options, &fleetSchema.UnitOption{
		Section: "Service", Name: "Restart", Value: "always",
	})
	options = append(options, &fleetSchema.UnitOption{
		Section: "Service", Name: "RestartSec", Value: "30",
	})

	for _, machine := range spec.Machine {
		options = append(options, &fleetSchema.UnitOption{
			Section: "X-Fleet", Name: "MachineMetadata", Value: machine,
		})
	}
	if spec.MachineID != "" {
		options = append(options, &fleetSchema.UnitOption{
			Section: "X-Fleet", Name: "MachineID", Value: spec.MachineID,
		})
	}
	if spec.Global {
		options = append(options, &fleetSchema.UnitOption{
			Section: "X-Fleet", Name: "Global", Value: "true",
		})
	}

	for _, c := range conflicts {
		options = append(options, &fleetSchema.UnitOption{
			Section: "X-Fleet", Name: "Conflicts", Value: c,
		})
	}
	return &fleetSchema.Unit{
		DesiredState: "launched",
		Options:      options,
		Name:         name,
	}
}
<|endoftext|>