├── .gitignore ├── .package ├── Dockerfile.dapper ├── LICENSE ├── Makefile ├── README.md ├── app ├── exec.go ├── files.go ├── health.go ├── ip.go ├── leader.go ├── probe.go └── service.go ├── election ├── proxy.go ├── tcp.go └── timeout_conn.go ├── main.go ├── package ├── Dockerfile └── entrypoint.sh ├── scripts ├── build ├── ci ├── clean ├── entry ├── package ├── test ├── validate └── version ├── trash.yml ├── vendor ├── github.com │ ├── Sirupsen │ │ └── logrus │ │ │ ├── .gitignore │ │ │ ├── .travis.yml │ │ │ ├── CHANGELOG.md │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── alt_exit.go │ │ │ ├── appveyor.yml │ │ │ ├── doc.go │ │ │ ├── entry.go │ │ │ ├── exported.go │ │ │ ├── formatter.go │ │ │ ├── hooks.go │ │ │ ├── json_formatter.go │ │ │ ├── logger.go │ │ │ ├── logrus.go │ │ │ ├── terminal_bsd.go │ │ │ ├── terminal_linux.go │ │ │ ├── text_formatter.go │ │ │ └── writer.go │ ├── coreos │ │ └── yaml │ │ │ ├── LICENSE │ │ │ ├── LICENSE.libyaml │ │ │ ├── README.md │ │ │ ├── apic.go │ │ │ ├── decode.go │ │ │ ├── emitterc.go │ │ │ ├── encode.go │ │ │ ├── parserc.go │ │ │ ├── readerc.go │ │ │ ├── resolve.go │ │ │ ├── scannerc.go │ │ │ ├── sorter.go │ │ │ ├── writerc.go │ │ │ ├── yaml.go │ │ │ ├── yamlh.go │ │ │ └── yamlprivateh.go │ ├── rancher │ │ ├── go-rancher-metadata │ │ │ ├── .gitignore │ │ │ ├── README.md │ │ │ └── metadata │ │ │ │ ├── change.go │ │ │ │ ├── metadata.go │ │ │ │ ├── types.go │ │ │ │ └── utils.go │ │ └── os │ │ │ └── config │ │ │ └── cloudinit │ │ │ ├── .gitignore │ │ │ ├── .travis.yml │ │ │ ├── CONTRIBUTING.md │ │ │ ├── DCO │ │ │ ├── LICENSE │ │ │ ├── MAINTAINERS │ │ │ ├── NOTICE │ │ │ ├── README.md │ │ │ ├── build │ │ │ ├── config │ │ │ ├── config.go │ │ │ ├── decode.go │ │ │ ├── etc_hosts.go │ │ │ ├── etcd.go │ │ │ ├── etcd2.go │ │ │ ├── file.go │ │ │ ├── flannel.go │ │ │ ├── fleet.go │ │ │ ├── ignition.go │ │ │ ├── locksmith.go │ │ │ ├── oem.go │ │ │ ├── script.go │ │ │ ├── unit.go │ │ │ ├── update.go │ │ │ └── user.go │ │ │ ├── cover │ │ │ ├── system │ │ │ ├── env.go │ │ │ ├── env_file.go │ │ │ ├── etc_hosts.go │ │ │ ├── etcd.go │ │ │ ├── etcd2.go │ │ │ ├── file.go │ │ │ ├── flannel.go │ │ │ ├── fleet.go │ │ │ ├── locksmith.go │ │ │ ├── oem.go │ │ │ ├── ssh_key.go │ │ │ ├── unit.go │ │ │ ├── update.go │ │ │ └── user.go │ │ │ ├── test │ │ │ └── vendor.manifest │ └── urfave │ │ └── cli │ │ ├── .gitignore │ │ ├── .travis.yml │ │ ├── CHANGELOG.md │ │ ├── LICENSE │ │ ├── README.md │ │ ├── app.go │ │ ├── appveyor.yml │ │ ├── category.go │ │ ├── cli.go │ │ ├── command.go │ │ ├── context.go │ │ ├── errors.go │ │ ├── flag.go │ │ ├── funcs.go │ │ ├── help.go │ │ └── runtests └── golang.org │ └── x │ ├── crypto │ ├── .gitattributes │ ├── .gitignore │ ├── AUTHORS │ ├── CONTRIBUTING.md │ ├── CONTRIBUTORS │ ├── LICENSE │ ├── PATENTS │ ├── README │ ├── codereview.cfg │ └── ssh │ │ └── terminal │ │ ├── terminal.go │ │ ├── util.go │ │ ├── util_bsd.go │ │ ├── util_linux.go │ │ └── util_windows.go │ └── sys │ ├── .gitattributes │ ├── .gitignore │ ├── AUTHORS │ ├── CONTRIBUTING.md │ ├── CONTRIBUTORS │ ├── LICENSE │ ├── PATENTS │ ├── README │ ├── codereview.cfg │ └── unix │ ├── .gitignore │ ├── asm.s │ ├── asm_darwin_386.s │ ├── asm_darwin_amd64.s │ ├── asm_darwin_arm.s │ ├── asm_darwin_arm64.s │ ├── asm_dragonfly_amd64.s │ ├── asm_freebsd_386.s │ ├── asm_freebsd_amd64.s │ ├── asm_freebsd_arm.s │ ├── asm_linux_386.s │ ├── asm_linux_amd64.s │ ├── asm_linux_arm.s │ ├── asm_linux_arm64.s │ ├── asm_linux_mips64x.s │ ├── asm_linux_ppc64x.s │ ├── asm_linux_s390x.s │ ├── asm_netbsd_386.s │ ├── asm_netbsd_amd64.s │ ├── asm_netbsd_arm.s │ ├── asm_openbsd_386.s │ ├── asm_openbsd_amd64.s │ ├── asm_solaris_amd64.s │ ├── bluetooth_linux.go │ ├── constants.go │ ├── env_unix.go │ ├── env_unset.go │ ├── flock.go │ ├── flock_linux_32bit.go │ ├── gccgo.go │ ├── gccgo_c.c │ ├── gccgo_linux_amd64.go │ ├── mkall.sh │ ├── mkerrors.sh │ ├── mkpost.go │ ├── mksyscall.pl │ ├── mksyscall_solaris.pl │ ├── mksysctl_openbsd.pl │ ├── mksysnum_darwin.pl │ ├── mksysnum_dragonfly.pl │ ├── mksysnum_freebsd.pl │ ├── mksysnum_linux.pl │ ├── mksysnum_netbsd.pl │ ├── mksysnum_openbsd.pl │ ├── race.go │ ├── race0.go │ ├── sockcmsg_linux.go │ ├── sockcmsg_unix.go │ ├── str.go │ ├── syscall.go │ ├── syscall_bsd.go │ ├── syscall_darwin.go │ ├── syscall_darwin_386.go │ ├── syscall_darwin_amd64.go │ ├── syscall_darwin_arm.go │ ├── syscall_darwin_arm64.go │ ├── syscall_dragonfly.go │ ├── syscall_dragonfly_amd64.go │ ├── syscall_freebsd.go │ ├── syscall_freebsd_386.go │ ├── syscall_freebsd_amd64.go │ ├── syscall_freebsd_arm.go │ ├── syscall_linux.go │ ├── syscall_linux_386.go │ ├── syscall_linux_amd64.go │ ├── syscall_linux_arm.go │ ├── syscall_linux_arm64.go │ ├── syscall_linux_mips64x.go │ ├── syscall_linux_ppc64x.go │ ├── syscall_linux_s390x.go │ ├── syscall_netbsd.go │ ├── syscall_netbsd_386.go │ ├── syscall_netbsd_amd64.go │ ├── syscall_netbsd_arm.go │ ├── syscall_no_getwd.go │ ├── syscall_openbsd.go │ ├── syscall_openbsd_386.go │ ├── syscall_openbsd_amd64.go │ ├── syscall_solaris.go │ ├── syscall_solaris_amd64.go │ ├── syscall_unix.go │ ├── types_darwin.go │ ├── types_dragonfly.go │ ├── types_freebsd.go │ ├── types_linux.go │ ├── types_netbsd.go │ ├── types_openbsd.go │ ├── types_solaris.go │ ├── zerrors_darwin_386.go │ ├── zerrors_darwin_amd64.go │ ├── zerrors_darwin_arm.go │ ├── zerrors_darwin_arm64.go │ ├── zerrors_dragonfly_amd64.go │ ├── zerrors_freebsd_386.go │ ├── zerrors_freebsd_amd64.go │ ├── zerrors_freebsd_arm.go │ ├── zerrors_linux_386.go │ ├── zerrors_linux_amd64.go │ ├── zerrors_linux_arm.go │ ├── zerrors_linux_arm64.go │ ├── zerrors_linux_mips64.go │ ├── zerrors_linux_mips64le.go │ ├── zerrors_linux_ppc64.go │ ├── zerrors_linux_ppc64le.go │ ├── zerrors_linux_s390x.go │ ├── zerrors_netbsd_386.go │ ├── zerrors_netbsd_amd64.go │ ├── zerrors_netbsd_arm.go │ ├── zerrors_openbsd_386.go │ ├── zerrors_openbsd_amd64.go │ ├── zerrors_solaris_amd64.go │ ├── zsyscall_darwin_386.go │ ├── zsyscall_darwin_amd64.go │ ├── zsyscall_darwin_arm.go │ ├── zsyscall_darwin_arm64.go │ ├── zsyscall_dragonfly_amd64.go │ ├── zsyscall_freebsd_386.go │ ├── zsyscall_freebsd_amd64.go │ ├── zsyscall_freebsd_arm.go │ ├── zsyscall_linux_386.go │ ├── zsyscall_linux_amd64.go │ ├── zsyscall_linux_arm.go │ ├── zsyscall_linux_arm64.go │ ├── zsyscall_linux_mips64.go │ ├── zsyscall_linux_mips64le.go │ ├── zsyscall_linux_ppc64.go │ ├── zsyscall_linux_ppc64le.go │ ├── zsyscall_linux_s390x.go │ ├── zsyscall_netbsd_386.go │ ├── zsyscall_netbsd_amd64.go │ ├── zsyscall_netbsd_arm.go │ ├── zsyscall_openbsd_386.go │ ├── zsyscall_openbsd_amd64.go │ ├── zsyscall_solaris_amd64.go │ ├── zsysctl_openbsd.go │ ├── zsysnum_darwin_386.go │ ├── zsysnum_darwin_amd64.go │ ├── zsysnum_darwin_arm.go │ ├── zsysnum_darwin_arm64.go │ ├── zsysnum_dragonfly_amd64.go │ ├── zsysnum_freebsd_386.go │ ├── zsysnum_freebsd_amd64.go │ ├── zsysnum_freebsd_arm.go │ ├── zsysnum_linux_386.go │ ├── zsysnum_linux_amd64.go │ ├── zsysnum_linux_arm.go │ ├── zsysnum_linux_arm64.go │ ├── zsysnum_linux_mips64.go │ ├── zsysnum_linux_mips64le.go │ ├── zsysnum_linux_ppc64.go │ ├── zsysnum_linux_ppc64le.go │ ├── zsysnum_linux_s390x.go │ ├── zsysnum_netbsd_386.go │ ├── zsysnum_netbsd_amd64.go │ ├── zsysnum_netbsd_arm.go │ ├── zsysnum_openbsd_386.go │ ├── zsysnum_openbsd_amd64.go │ ├── zsysnum_solaris_amd64.go │ ├── ztypes_darwin_386.go │ ├── ztypes_darwin_amd64.go │ ├── ztypes_darwin_arm.go │ ├── ztypes_darwin_arm64.go │ ├── ztypes_dragonfly_amd64.go │ ├── ztypes_freebsd_386.go │ ├── ztypes_freebsd_amd64.go │ ├── ztypes_freebsd_arm.go │ ├── ztypes_linux_386.go │ ├── ztypes_linux_amd64.go │ ├── ztypes_linux_arm.go │ ├── ztypes_linux_arm64.go │ ├── ztypes_linux_mips64.go │ ├── ztypes_linux_mips64le.go │ ├── ztypes_linux_ppc64.go │ ├── ztypes_linux_ppc64le.go │ ├── ztypes_linux_s390x.go │ ├── ztypes_netbsd_386.go │ ├── ztypes_netbsd_amd64.go │ ├── ztypes_netbsd_arm.go │ ├── ztypes_openbsd_386.go │ ├── ztypes_openbsd_amd64.go │ └── ztypes_solaris_amd64.go └── version └── version.go /.gitignore: -------------------------------------------------------------------------------- 1 | /.dapper 2 | /bin 3 | /dist 4 | *.swp 5 | /.trash-cache 6 | -------------------------------------------------------------------------------- /.package: -------------------------------------------------------------------------------- 1 | github.com/cloudnautique/giddyup 2 | -------------------------------------------------------------------------------- /Dockerfile.dapper: -------------------------------------------------------------------------------- 1 | FROM ubuntu:16.04 2 | # FROM arm=armhf/ubuntu:16.04 3 | 4 | ARG DAPPER_HOST_ARCH 5 | ENV HOST_ARCH=${DAPPER_HOST_ARCH} ARCH=${DAPPER_HOST_ARCH} 6 | 7 | RUN apt-get update && \ 8 | apt-get install -y gcc ca-certificates git wget curl vim less file && \ 9 | rm -f /bin/sh && ln -s /bin/bash /bin/sh 10 | 11 | ENV GOLANG_ARCH_amd64=amd64 GOLANG_ARCH_arm=armv6l GOLANG_ARCH=GOLANG_ARCH_${ARCH} \ 12 | GOPATH=/go PATH=/go/bin:/usr/local/go/bin:${PATH} SHELL=/bin/bash 13 | 14 | RUN wget -O - https://storage.googleapis.com/golang/go1.8.3.linux-${!GOLANG_ARCH}.tar.gz | tar -xzf - -C /usr/local && \ 15 | go get github.com/rancher/trash && go get github.com/golang/lint/golint 16 | 17 | ENV DOCKER_URL_amd64=https://get.docker.com/builds/Linux/x86_64/docker-1.10.3 \ 18 | DOCKER_URL_arm=https://github.com/rancher/docker/releases/download/v1.10.3-ros1/docker-1.10.3_arm \ 19 | DOCKER_URL=DOCKER_URL_${ARCH} 20 | 21 | RUN wget -O - ${!DOCKER_URL} > /usr/bin/docker && chmod +x /usr/bin/docker 22 | 23 | ENV DAPPER_SOURCE /go/src/github.com/rancher/giddyup/ 24 | ENV DAPPER_OUTPUT ./bin ./dist 25 | ENV DAPPER_DOCKER_SOCKET true 26 | ENV TRASH_CACHE ${DAPPER_SOURCE}/.trash-cache 27 | ENV HOME ${DAPPER_SOURCE} 28 | WORKDIR ${DAPPER_SOURCE} 29 | 30 | ENTRYPOINT ["./scripts/entry"] 31 | CMD ["ci"] 32 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | TARGETS := $(shell ls scripts) 2 | 3 | .dapper: 4 | @echo Downloading dapper 5 | @curl -sL https://releases.rancher.com/dapper/latest/dapper-`uname -s`-`uname -m` > .dapper.tmp 6 | @@chmod +x .dapper.tmp 7 | @./.dapper.tmp -v 8 | @mv .dapper.tmp .dapper 9 | 10 | $(TARGETS): .dapper 11 | ./.dapper $@ 12 | 13 | trash: .dapper 14 | ./.dapper -m bind trash 15 | 16 | trash-keep: .dapper 17 | ./.dapper -m bind trash -k 18 | 19 | deps: trash 20 | 21 | .DEFAULT_GOAL := ci 22 | 23 | .PHONY: $(TARGETS) 24 | -------------------------------------------------------------------------------- /app/exec.go: -------------------------------------------------------------------------------- 1 | package app 2 | 3 | import ( 4 | "bufio" 5 | "io/ioutil" 6 | "os" 7 | "path" 8 | "strings" 9 | "syscall" 10 | "time" 11 | 12 | "os/exec" 13 | 14 | "github.com/Sirupsen/logrus" 15 | "github.com/rancher/go-rancher-metadata/metadata" 16 | "github.com/urfave/cli" 17 | ) 18 | 19 | func ExecCommand() cli.Command { 20 | return cli.Command{ 21 | Name: "exec", 22 | Usage: "exec out to a command", 23 | Action: execCommand, 24 | Flags: []cli.Flag{ 25 | cli.BoolFlag{ 26 | Name: "secret-envs", 27 | Usage: "reads /run/secrets and sets env vars", 28 | }, 29 | cli.BoolFlag{ 30 | Name: "cloud-init", 31 | Usage: "Process /self/service/metadata/cloud-init (currently only write_files)", 32 | }, 33 | cli.StringSliceFlag{ 34 | Name: "wait-for-file", 35 | Usage: "wait for a file to exist, assumes something else is creating it. This flag can be used more then once for multiple files", 36 | }, 37 | cli.StringSliceFlag{ 38 | Name: "source-file", 39 | Usage: "Source an environment file before executing. Can use the flag multiple times", 40 | }, 41 | }, 42 | } 43 | } 44 | 45 | func execCommand(c *cli.Context) error { 46 | if c.Bool("secret-envs") { 47 | envs, err := filesToMap("/run/secrets") 48 | if err != nil { 49 | logrus.Error(err) 50 | return err 51 | } 52 | 53 | for key, val := range envs { 54 | os.Setenv(strings.ToUpper(key), val) 55 | } 56 | } 57 | 58 | if c.Bool("cloud-init") { 59 | mdClient, err := metadata.NewClientAndWait(c.GlobalString("metadata-url")) 60 | if err != nil { 61 | return err 62 | } 63 | ProcessCloudInit(mdClient) 64 | } 65 | 66 | // This is a fairly naive approach for now. 67 | if len(c.StringSlice("wait-for-file")) > 0 { 68 | err := waitForFiles(c.StringSlice("wait-for-file")) 69 | if err != nil { 70 | return err 71 | } 72 | } 73 | 74 | if len(c.StringSlice("source-file")) > 0 { 75 | envs, err := readSourceFiles(c.StringSlice("source-file")) 76 | if err != nil { 77 | return err 78 | } 79 | 80 | for key, val := range envs { 81 | os.Setenv(key, val) 82 | } 83 | } 84 | 85 | name, err := exec.LookPath(c.Args().Get(0)) 86 | if err != nil { 87 | return err 88 | } 89 | 90 | return syscall.Exec(name, c.Args(), os.Environ()) 91 | } 92 | 93 | func filesToMap(dirPath string) (map[string]string, error) { 94 | vals := map[string]string{} 95 | files, err := ioutil.ReadDir(dirPath) 96 | if err != nil { 97 | return vals, err 98 | } 99 | 100 | for _, file := range files { 101 | content, err := ioutil.ReadFile(path.Join(dirPath, file.Name())) 102 | if err != nil { 103 | return vals, err 104 | } 105 | vals[file.Name()] = string(content) 106 | } 107 | return vals, nil 108 | } 109 | 110 | func waitForFiles(files []string) error { 111 | for true { 112 | seenCount := 0 113 | for idx, file := range files { 114 | if file != "seen" { 115 | if _, err := os.Stat(file); os.IsNotExist(err) { 116 | break 117 | } 118 | // set the seen value and increment the counter 119 | files[idx] = "seen" 120 | seenCount++ 121 | 122 | continue 123 | } 124 | seenCount++ 125 | } 126 | if seenCount == len(files) { 127 | break 128 | } 129 | time.Sleep(1 * time.Second) 130 | } 131 | return nil 132 | } 133 | 134 | func readSourceFiles(files []string) (map[string]string, error) { 135 | envs := map[string]string{} 136 | for _, file := range files { 137 | // the Close() will not be deferred to avoid large number of open files... 138 | f, err := os.Open(file) 139 | if err != nil { 140 | return envs, err 141 | } 142 | 143 | scanner := bufio.NewScanner(f) 144 | for scanner.Scan() { 145 | pair := strings.SplitN(scanner.Text(), "=", 2) 146 | if len(pair) == 2 { 147 | envs[pair[0]] = pair[1] 148 | } 149 | } 150 | f.Close() 151 | } 152 | return envs, nil 153 | } 154 | -------------------------------------------------------------------------------- /app/files.go: -------------------------------------------------------------------------------- 1 | package app 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "github.com/rancher/go-rancher-metadata/metadata" 7 | "github.com/rancher/os/config/cloudinit/config" 8 | "github.com/rancher/os/config/cloudinit/system" 9 | ) 10 | 11 | func ProcessCloudInit(mdClient metadata.Client) error { 12 | self, err := mdClient.GetSelfService() 13 | if err != nil { 14 | return err 15 | } 16 | jsonBytes, err := json.Marshal(self.Metadata["cloud-init"]) 17 | if err != nil { 18 | return err 19 | } 20 | 21 | cloudConfig, err := config.NewCloudConfig(string(jsonBytes)) 22 | if err != nil { 23 | return err 24 | } 25 | 26 | for _, file := range cloudConfig.WriteFiles { 27 | _, err := system.WriteFile(&system.File{file}, "/") 28 | if err != nil { 29 | return err 30 | } 31 | } 32 | 33 | return nil 34 | } 35 | -------------------------------------------------------------------------------- /app/health.go: -------------------------------------------------------------------------------- 1 | package app 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | "os" 7 | "os/exec" 8 | 9 | "github.com/Sirupsen/logrus" 10 | "github.com/urfave/cli" 11 | ) 12 | 13 | func HealthCommand() cli.Command { 14 | return cli.Command{ 15 | Name: "health", 16 | Usage: "simple healthcheck", 17 | Action: simpleHealthCheck, 18 | Flags: []cli.Flag{ 19 | cli.IntFlag{ 20 | Name: "listen-port,p", 21 | Usage: "set port to listen on", 22 | Value: 1620, 23 | }, 24 | cli.StringFlag{ 25 | Name: "check-command", 26 | Usage: "command to execute check", 27 | }, 28 | cli.StringFlag{ 29 | Name: "on-failure-command", 30 | Usage: "command to execute if command fails", 31 | }, 32 | }, 33 | } 34 | } 35 | 36 | type HealthContext struct { 37 | port string 38 | checkCommand string 39 | failureCommand string 40 | } 41 | 42 | func NewHealthContext(c *cli.Context) *HealthContext { 43 | context := &HealthContext{} 44 | context.port = c.String("listen-port") 45 | context.checkCommand = c.String("check-command") 46 | context.failureCommand = c.String("on-failure-command") 47 | 48 | return context 49 | } 50 | 51 | func simpleHealthCheck(c *cli.Context) error { 52 | context := NewHealthContext(c) 53 | logrus.Infof("Listening on port: %s", context.port) 54 | 55 | http.Handle("/ping", context) 56 | done := make(chan error) 57 | 58 | go func() { 59 | done <- http.ListenAndServe(fmt.Sprintf(":%s", context.port), nil) 60 | }() 61 | 62 | if len(c.Args()) > 0 { 63 | go func() { 64 | done <- runCommand(c.Args()[0], c.Args()[1:]...) 65 | }() 66 | } 67 | 68 | err := <-done 69 | if err != nil { 70 | logrus.Fatal(err) 71 | } 72 | return nil 73 | } 74 | 75 | func (h *HealthContext) ServeHTTP(w http.ResponseWriter, r *http.Request) { 76 | message := "OK" 77 | code := http.StatusOK 78 | 79 | if err := runCommand(h.checkCommand); err != nil { 80 | code = http.StatusServiceUnavailable 81 | message = "Failed Health Check. Attempting to Run: " + h.failureCommand 82 | cmdStatus := "....[Success]" 83 | if err = runCommand(h.failureCommand); err != nil { 84 | cmdStatus = "....[Failed]" 85 | } 86 | message += cmdStatus 87 | } 88 | 89 | w.WriteHeader(code) 90 | fmt.Fprintln(w, message) 91 | } 92 | 93 | func runCommand(command string, args ...string) error { 94 | if command != "" { 95 | cmd := exec.Command(command, args...) 96 | cmd.Stdout = os.Stdout 97 | cmd.Stderr = os.Stderr 98 | return cmd.Run() 99 | } 100 | return nil 101 | } 102 | -------------------------------------------------------------------------------- /app/leader.go: -------------------------------------------------------------------------------- 1 | package app 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | 7 | "github.com/Sirupsen/logrus" 8 | "github.com/rancher/giddyup/election" 9 | "github.com/rancher/go-rancher-metadata/metadata" 10 | "github.com/urfave/cli" 11 | ) 12 | 13 | var ( 14 | port = "proxy-tcp-port" 15 | dstPort = "dst-port" 16 | srcPort = "src-port" 17 | check = "check" 18 | ) 19 | 20 | func LeaderCommand() cli.Command { 21 | return cli.Command{ 22 | Name: "leader", 23 | Usage: "Provides a deterministic way to elect, route traffic, and get a leader of a service", 24 | Subcommands: []cli.Command{ 25 | { 26 | Name: "check", 27 | Usage: "Check if we are leader and exit.", 28 | Action: appActionCheck, 29 | Flags: []cli.Flag{ 30 | cli.StringFlag{ 31 | Name: "service", 32 | Usage: "Get the leader of another service in the stack", 33 | }, 34 | }, 35 | }, 36 | { 37 | Name: "elect", 38 | Usage: "Simple leader election with Rancher", 39 | Action: appActionElect, 40 | Flags: []cli.Flag{ 41 | cli.IntFlag{ 42 | Name: port, 43 | Usage: "Port to proxy to the leader", 44 | }, 45 | }, 46 | }, 47 | { 48 | Name: "forward", 49 | Usage: "Listen and forward all port traffic to leader.", 50 | Action: appActionForward, 51 | Flags: []cli.Flag{ 52 | cli.IntFlag{ 53 | Name: dstPort, 54 | Usage: "Leader destination port", 55 | }, 56 | cli.IntFlag{ 57 | Name: srcPort, 58 | Usage: "Local source port", 59 | }, 60 | }, 61 | }, 62 | { 63 | Name: "get", 64 | Usage: "Get Rancher IP the leader of service. If you want, you can get can get underlying hostname or agent_ip", 65 | Action: appActionGet, 66 | }, 67 | }, 68 | } 69 | } 70 | 71 | func appActionCheck(cli *cli.Context) error { 72 | client, err := metadata.NewClientAndWait(cli.GlobalString("metadata-url")) 73 | if err != nil { 74 | logrus.Fatal(err) 75 | } 76 | 77 | w := election.New(client, cli.Int(port), cli.Args()) 78 | 79 | if w.IsLeader() { 80 | os.Exit(0) 81 | } else { 82 | os.Exit(1) 83 | } 84 | return nil 85 | } 86 | 87 | func appActionGet(cli *cli.Context) error { 88 | client, err := metadata.NewClientAndWait(cli.GlobalString("metadata-url")) 89 | if err != nil { 90 | logrus.Fatal(err) 91 | } 92 | 93 | w := election.New(client, cli.Int(port), cli.Args()) 94 | 95 | leader, _, err := w.GetSelfServiceLeader() 96 | if err != nil { 97 | logrus.Fatalf("Could not get leader. %s", err) 98 | } 99 | 100 | switch { 101 | case len(cli.Args()) == 0: 102 | fmt.Printf("%s", leader.PrimaryIp) 103 | os.Exit(0) 104 | 105 | case cli.Args()[0] == "host": 106 | host, err := client.GetHost(leader.HostUUID) 107 | if err != nil { 108 | return err 109 | } 110 | 111 | fmt.Printf("%s", host.Hostname) 112 | os.Exit(0) 113 | 114 | case cli.Args()[0] == "agent_ip": 115 | host, err := client.GetHost(leader.HostUUID) 116 | if err != nil { 117 | return err 118 | } 119 | 120 | fmt.Printf("%s", host.AgentIP) 121 | os.Exit(0) 122 | 123 | } 124 | 125 | return fmt.Errorf("Unrecognized arg: (%s) nothing, host and agent_ip are only allowed args", cli.Args()[0]) 126 | } 127 | 128 | func appActionForward(cli *cli.Context) error { 129 | client, err := metadata.NewClientAndWait(cli.GlobalString("metadata-url")) 130 | if err != nil { 131 | logrus.Fatal(err) 132 | } 133 | 134 | dst := cli.Int(dstPort) 135 | 136 | if dst == 0 { 137 | dst = cli.Int(srcPort) 138 | } 139 | 140 | w := election.NewSrcDstWatcher(client, cli.Int(srcPort), dst) 141 | if err := w.Forwarder(); err != nil { 142 | logrus.Fatal(err) 143 | } 144 | return nil 145 | } 146 | 147 | func appActionElect(cli *cli.Context) error { 148 | client, err := metadata.NewClientAndWait(cli.GlobalString("metadata-url")) 149 | if err != nil { 150 | logrus.Fatal(err) 151 | } 152 | 153 | w := election.New(client, cli.Int(port), cli.Args()) 154 | if err := w.Watch(); err != nil { 155 | logrus.Fatal(err) 156 | } 157 | return nil 158 | } 159 | -------------------------------------------------------------------------------- /app/probe.go: -------------------------------------------------------------------------------- 1 | package app 2 | 3 | import ( 4 | "github.com/urfave/cli" 5 | "net/http" 6 | "net/url" 7 | "errors" 8 | "time" 9 | "math" 10 | "net" 11 | "fmt" 12 | "os" 13 | ) 14 | 15 | func ProbeCommand() cli.Command { 16 | 17 | return cli.Command{ 18 | Name: "probe", 19 | Usage: "Probe a TCP/HTTP(S) endpoint to determine if it is healthy", 20 | ArgsUsage: "", 21 | Action: probe, 22 | Flags: []cli.Flag{ 23 | cli.DurationFlag{ 24 | Name: "timeout, t", 25 | Usage: "Connection timeout in seconds", 26 | Value: 5 * time.Second, 27 | }, 28 | cli.BoolFlag{ 29 | Name: "loop", 30 | Usage: "Continuously probe endpoint until it is healthy", 31 | }, 32 | cli.Float64Flag{ 33 | Name: "backoff, b", 34 | Usage: "(Loop) Rate at which to back off from retries, must be >= 1", 35 | Value: 1.0, 36 | }, 37 | cli.DurationFlag{ 38 | Name: "min, m", 39 | Usage: "(Loop) Minimum time to wait before retrying", 40 | Value: 1 * time.Second, 41 | }, 42 | cli.DurationFlag{ 43 | Name: "max, x", 44 | Usage: "(Loop) Maximum time to wait before retrying", 45 | Value: 120 * time.Second, 46 | }, 47 | cli.IntFlag{ 48 | Name: "num, n", 49 | Usage: "(Loop) Maximum number of requests to perform before declaring unhealthy. 0 for infinite", 50 | Value: 0, 51 | }, 52 | }, 53 | } 54 | } 55 | 56 | func probe(c *cli.Context) error { 57 | if c.Args().First() == "" { 58 | cli.ShowCommandHelp(c, "probe") 59 | os.Exit(1) 60 | } 61 | 62 | if c.Bool("loop") { 63 | min := c.Duration("min") 64 | max := c.Duration("max") 65 | backoff := c.Float64("backoff") 66 | num := c.Int("num") 67 | loops := 0 68 | delay := min 69 | 70 | for err := healthCheck(c); err != nil; err = healthCheck(c) { 71 | fmt.Println(err) 72 | loops += 1 73 | if num != 0 && loops == num { 74 | os.Exit(1) 75 | } 76 | time.Sleep(delay) 77 | 78 | if delay < max { 79 | delay = time.Duration(float64(min) * math.Pow(backoff, float64(loops))) 80 | } 81 | if delay > max { 82 | delay = max 83 | } 84 | } 85 | fmt.Println("OK") 86 | 87 | } else { 88 | if err := healthCheck(c); err != nil { 89 | fmt.Println(err) 90 | os.Exit(1) 91 | } 92 | fmt.Println("OK") 93 | } 94 | return nil 95 | } 96 | 97 | func healthCheck(c *cli.Context) error { 98 | endpoint := c.Args().First() 99 | timeout := c.Duration("timeout") 100 | 101 | url, err := url.Parse(endpoint) 102 | if err != nil { 103 | return err 104 | } 105 | 106 | switch url.Scheme { 107 | case "tcp": 108 | var conn net.Conn 109 | if conn, err = net.DialTimeout(url.Scheme, url.Host, timeout); err != nil { 110 | return err 111 | } 112 | conn.Close() 113 | case "http", "https": 114 | client := &http.Client{ 115 | Timeout: timeout, 116 | } 117 | var resp *http.Response 118 | resp, err = client.Get(endpoint) 119 | 120 | switch { 121 | case err != nil: 122 | return err 123 | case resp.StatusCode >= 200 && resp.StatusCode <= 299: 124 | return nil 125 | default: 126 | return errors.New(fmt.Sprintf("HTTP %d\n", resp.StatusCode)) 127 | } 128 | default: 129 | return errors.New(fmt.Sprintf("Unsupported URL scheme: %s\n", url.Scheme)) 130 | } 131 | return nil 132 | } 133 | -------------------------------------------------------------------------------- /election/proxy.go: -------------------------------------------------------------------------------- 1 | package election 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "os" 7 | "os/exec" 8 | "syscall" 9 | 10 | "github.com/Sirupsen/logrus" 11 | "github.com/rancher/go-rancher-metadata/metadata" 12 | ) 13 | 14 | type Watcher struct { 15 | leader metadata.Container 16 | command []string 17 | port int 18 | dstPort int 19 | client metadata.Client 20 | forward *TcpProxy 21 | } 22 | 23 | func New(client metadata.Client, port int, command []string) *Watcher { 24 | return &Watcher{ 25 | command: command, 26 | port: port, 27 | client: client, 28 | } 29 | } 30 | 31 | func NewSrcDstWatcher(client metadata.Client, srcPort, dstPort int) *Watcher { 32 | return &Watcher{ 33 | command: []string{}, 34 | port: srcPort, 35 | dstPort: dstPort, 36 | client: client, 37 | } 38 | } 39 | 40 | func (w *Watcher) GetSelfServiceLeader() (metadata.Container, bool, error) { 41 | return w.getLeader() 42 | } 43 | 44 | func (w *Watcher) getLeader() (metadata.Container, bool, error) { 45 | selfContainer, err := w.client.GetSelfContainer() 46 | if err != nil { 47 | return metadata.Container{}, false, err 48 | } 49 | 50 | index := selfContainer.CreateIndex 51 | leader := selfContainer 52 | 53 | containers, err := w.client.GetServiceContainers( 54 | selfContainer.ServiceName, 55 | selfContainer.StackName, 56 | ) 57 | if err != nil { 58 | return metadata.Container{}, false, err 59 | } 60 | 61 | for _, container := range containers { 62 | if container.CreateIndex < index { 63 | index = container.CreateIndex 64 | leader = container 65 | } 66 | } 67 | 68 | w.leader = leader 69 | return leader, leader.UUID == selfContainer.UUID, nil 70 | } 71 | 72 | func (w *Watcher) Forwarder() error { 73 | //initialize leader 74 | if _, _, err := w.getLeader(); err != nil { 75 | return err 76 | } 77 | 78 | w.forward = NewTcpProxy(w.port, func() string { 79 | return fmt.Sprintf("%s:%d", w.leader.PrimaryIp, w.dstPort) 80 | }) 81 | 82 | go w.client.OnChange(1, func(version string) { 83 | currentLeaderIp := w.leader.PrimaryIp 84 | if _, _, err := w.getLeader(); err != nil { 85 | logrus.Error("Error getting leader: %s", err) 86 | } 87 | 88 | if w.leader.PrimaryIp != currentLeaderIp { 89 | if err := w.forward.Close(); err == nil { 90 | w.forward.Reset() 91 | } 92 | } 93 | }) 94 | 95 | for { 96 | if w.port > 0 && w.dstPort > 0 { 97 | if err := w.forward.Forward(); err != nil { 98 | return err 99 | } 100 | } else { 101 | return errors.New("Ports not specified: src:" + string(w.port) + ", dst:" + string(w.dstPort)) 102 | } 103 | } 104 | 105 | return errors.New("Unexpected loop termination") 106 | } 107 | 108 | func (w *Watcher) Watch() error { 109 | w.forward = NewTcpProxy(w.port, func() string { 110 | return fmt.Sprintf("%s:%d", w.leader.PrimaryIp, w.port) 111 | }) 112 | 113 | go w.client.OnChange(2, func(version string) { 114 | if w.IsLeader() { 115 | w.forward.Close() 116 | } 117 | }) 118 | 119 | if w.port > 0 { 120 | if err := w.forward.Forward(); err != nil { 121 | return err 122 | } 123 | } 124 | 125 | if w.IsLeader() { 126 | if len(w.command) == 0 { 127 | return errors.New("No command") 128 | } 129 | 130 | prog, err := exec.LookPath(w.command[0]) 131 | if err != nil { 132 | return err 133 | } 134 | return syscall.Exec(prog, w.command, os.Environ()) 135 | } 136 | 137 | return errors.New("Unexpected loop termination") 138 | } 139 | 140 | func (w *Watcher) IsLeader() bool { 141 | _, leader, err := w.getLeader() 142 | return leader && err == nil 143 | } 144 | -------------------------------------------------------------------------------- /election/tcp.go: -------------------------------------------------------------------------------- 1 | package election 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "io" 7 | "net" 8 | "sync" 9 | "time" 10 | 11 | "github.com/Sirupsen/logrus" 12 | ) 13 | 14 | type TcpProxy struct { 15 | done chan bool 16 | port int 17 | to func() string 18 | } 19 | 20 | func NewTcpProxy(port int, to func() string) *TcpProxy { 21 | return &TcpProxy{ 22 | port: port, 23 | to: to, 24 | done: make(chan bool), 25 | } 26 | } 27 | 28 | func (t *TcpProxy) Close() error { 29 | t.done <- true 30 | return nil 31 | } 32 | 33 | func (t *TcpProxy) Reset() error { 34 | t.done <- false 35 | return nil 36 | } 37 | 38 | func (t *TcpProxy) Forward() error { 39 | strAddr := fmt.Sprintf("0.0.0.0:%d", t.port) 40 | 41 | addr, err := net.ResolveTCPAddr("tcp", strAddr) 42 | if err != nil { 43 | return err 44 | } 45 | 46 | l, err := net.ListenTCP("tcp", addr) 47 | if err != nil { 48 | return err 49 | } 50 | defer l.Close() 51 | logrus.Infof("Listening on %s", strAddr) 52 | logrus.Infof("Forwarding setup to: %s", t.to()) 53 | 54 | wg := sync.WaitGroup{} 55 | 56 | for { 57 | select { 58 | case <-t.done: 59 | return nil 60 | default: 61 | break 62 | } 63 | 64 | l.SetDeadline(time.Now().Add(1 * time.Second)) 65 | conn, err := l.AcceptTCP() 66 | if acceptErr, ok := err.(*net.OpError); ok && acceptErr.Timeout() { 67 | continue 68 | } 69 | if err != nil { 70 | return err 71 | } 72 | 73 | wg.Add(1) 74 | go func(conn *net.TCPConn) { 75 | defer wg.Done() 76 | if err := t.forward(conn); err != nil { 77 | logrus.Errorf("Failed handling TCP forwarding: %v", err) 78 | } 79 | }(conn) 80 | } 81 | 82 | wg.Wait() 83 | return nil 84 | } 85 | 86 | func (t *TcpProxy) forward(cConn *net.TCPConn) error { 87 | //cConn is the incoming client connection. 88 | defer cConn.Close() 89 | ip := t.to() 90 | if ip == "" { 91 | return errors.New("Target unknown") 92 | } 93 | 94 | raddr, err := net.ResolveTCPAddr("tcp", ip) 95 | if err != nil { 96 | return err 97 | } 98 | rConn, err := net.DialTCP("tcp", nil, raddr) 99 | if err != nil { 100 | return err 101 | } 102 | defer rConn.Close() 103 | 104 | cClose := make(chan bool) 105 | rClose := make(chan bool) 106 | 107 | go connectionBroker(rConn, cConn, cClose) 108 | go connectionBroker(cConn, rConn, rClose) 109 | 110 | done := make(chan bool) 111 | select { 112 | case <-cClose: 113 | rConn.SetLinger(0) 114 | rConn.CloseRead() 115 | done = rClose 116 | case <-rClose: 117 | cConn.CloseRead() 118 | done = cClose 119 | } 120 | 121 | <-done 122 | 123 | return err 124 | } 125 | 126 | func connectionBroker(dst, src net.Conn, srcClosed chan bool) { 127 | _, err := io.Copy(dst, src) 128 | if err != nil { 129 | logrus.Error(err) 130 | } 131 | 132 | if err := src.Close(); err != nil { 133 | logrus.Errorf("Connection close error: %s", err) 134 | } 135 | 136 | srcClosed <- true 137 | } 138 | -------------------------------------------------------------------------------- /election/timeout_conn.go: -------------------------------------------------------------------------------- 1 | package election 2 | 3 | import ( 4 | "net" 5 | "time" 6 | ) 7 | 8 | type TimeoutConn struct { 9 | Conn net.Conn 10 | Timeout time.Duration 11 | } 12 | 13 | func (i TimeoutConn) Read(buf []byte) (int, error) { 14 | i.Conn.SetDeadline(time.Now().Add(i.Timeout * time.Second)) 15 | return i.Conn.Read(buf) 16 | } 17 | 18 | func (i TimeoutConn) Write(buf []byte) (int, error) { 19 | i.Conn.SetDeadline(time.Now().Add(i.Timeout * time.Second)) 20 | return i.Conn.Write(buf) 21 | } 22 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "os" 5 | 6 | giddyupApp "github.com/rancher/giddyup/app" 7 | "github.com/rancher/giddyup/version" 8 | "github.com/urfave/cli" 9 | ) 10 | 11 | const metadataURL = "http://rancher-metadata/2015-12-19" 12 | 13 | func main() { 14 | app := cli.NewApp() 15 | app.Version = version.VERSION 16 | app.Name = "giddyup" 17 | app.Usage = "Entrypoint functions for Rancher" 18 | app.Flags = []cli.Flag{ 19 | cli.StringFlag{ 20 | Name: "metadata-url", 21 | Usage: "override default MetadataURL", 22 | Value: metadataURL, 23 | }, 24 | } 25 | 26 | app.Commands = []cli.Command{ 27 | giddyupApp.ExecCommand(), 28 | giddyupApp.HealthCommand(), 29 | giddyupApp.IPCommand(), 30 | giddyupApp.LeaderCommand(), 31 | giddyupApp.ProbeCommand(), 32 | giddyupApp.ServiceCommand(), 33 | } 34 | 35 | app.Run(os.Args) 36 | } 37 | -------------------------------------------------------------------------------- /package/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:jessie 2 | COPY giddyup /opt/rancher/bin/ 3 | COPY ./entrypoint.sh /entrypoint.sh 4 | RUN ln -s /opt/rancher/bin/giddyup /usr/bin/giddyup 5 | 6 | VOLUME /opt/rancher/bin 7 | 8 | ENTRYPOINT ["/entrypoint.sh"] 9 | CMD ["giddyup"] 10 | -------------------------------------------------------------------------------- /package/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -n "$TARGET" ]; then 4 | cp /usr/bin/giddyup ${TARGET} 5 | fi 6 | 7 | exec "$@" 8 | -------------------------------------------------------------------------------- /scripts/build: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | cd $(dirname $0)/.. 6 | PACKAGE=./gopath/src/$(<.package) 7 | if [ -L "${PACKAGE}" ]; then 8 | rm ${PACKAGE} 9 | fi 10 | 11 | if [ ! -e "${PACKAGE}" ]; then 12 | mkdir -p $(dirname ${PACKAGE}) 13 | ln -s $(pwd) ${PACKAGE} 14 | fi 15 | 16 | export GO15VENDOREXPERIMENT=1 17 | 18 | get_version() 19 | { 20 | VERSION=$(git tag -l --contains HEAD | head -n 1) 21 | if [ -z "$VERSION" ]; then 22 | VERSION=$(git rev-parse --short HEAD) 23 | fi 24 | } 25 | 26 | get_version 27 | 28 | mkdir -p bin 29 | echo Building Giddyup 30 | CGO_ENABLED=0 go build -o bin/giddyup -ldflags="-w -X github.com/rancher/giddyup/version.VERSION=${VERSION}" 31 | -------------------------------------------------------------------------------- /scripts/ci: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | cd $(dirname $0) 5 | 6 | ./build 7 | ./test 8 | ./validate 9 | ./package 10 | -------------------------------------------------------------------------------- /scripts/clean: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | cd $(dirname $0)/.. 6 | 7 | rm -rf build dist bin gopath 8 | -------------------------------------------------------------------------------- /scripts/entry: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | mkdir -p bin dist 5 | if [ -e ./scripts/$1 ]; then 6 | ./scripts/"$@" 7 | else 8 | exec "$@" 9 | fi 10 | 11 | chown -R $DAPPER_UID:$DAPPER_GID . 12 | -------------------------------------------------------------------------------- /scripts/package: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | source $(dirname $0)/version 5 | 6 | ARCH=${ARCH:?"ARCH not set"} 7 | SUFFIX="" 8 | [ "${ARCH}" != "amd64" ] && SUFFIX="_${ARCH}" 9 | 10 | cd $(dirname $0)/../package 11 | 12 | TAG=${TAG:-${VERSION}${SUFFIX}} 13 | REPO=${REPO:-rancher} 14 | 15 | cp ../bin/giddyup . 16 | docker build -t ${REPO}/giddyup:${TAG} . 17 | 18 | echo Built ${REPO}/giddyup:${TAG} 19 | -------------------------------------------------------------------------------- /scripts/test: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | cd $(dirname $0)/.. 5 | 6 | echo Running tests 7 | 8 | PACKAGES=". $(find -name '*.go' | xargs -I{} dirname {} | cut -f2 -d/ | sort -u | grep -Ev '(^\.$|.git|.trash-cache|vendor|bin)' | sed -e 's!^!./!' -e 's!$!/...!')" 9 | 10 | [ "${ARCH}" == "amd64" ] && RACE=-race 11 | go test ${RACE} -cover -tags=test ${PACKAGES} 12 | -------------------------------------------------------------------------------- /scripts/validate: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | cd $(dirname $0)/.. 5 | 6 | echo Running validation 7 | 8 | PACKAGES=". $(find -name '*.go' | xargs -I{} dirname {} | cut -f2 -d/ | sort -u | grep -Ev '(^\.$|.git|.trash-cache|vendor|bin)' | sed -e 's!^!./!' -e 's!$!/...!')" 9 | 10 | echo Running: go vet 11 | go vet ${PACKAGES} 12 | echo Running: golint 13 | for i in ${PACKAGES}; do 14 | if [ -n "$(golint $i | grep -v 'should have comment.*or be unexported' | tee /dev/stderr)" ]; then 15 | failed=true 16 | fi 17 | done 18 | test -z "$failed" 19 | echo Running: go fmt 20 | test -z "$(go fmt ${PACKAGES} | tee /dev/stderr)" 21 | -------------------------------------------------------------------------------- /scripts/version: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -n "$(git status --porcelain --untracked-files=no)" ]; then 4 | DIRTY="-dirty" 5 | fi 6 | 7 | COMMIT=$(git rev-parse --short HEAD) 8 | GIT_TAG=$(git tag -l --contains HEAD | head -n 1) 9 | 10 | if [[ -z "$DIRTY" && -n "$GIT_TAG" ]]; then 11 | VERSION=$GIT_TAG 12 | else 13 | VERSION="${COMMIT}${DIRTY}" 14 | fi 15 | 16 | if [ -z "$ARCH" ]; then 17 | ARCH=amd64 18 | fi 19 | -------------------------------------------------------------------------------- /trash.yml: -------------------------------------------------------------------------------- 1 | # trash.conf 2 | 3 | # package 4 | github.com/rancher/giddyup 5 | 6 | github.com/Sirupsen/logrus v1.0.3 7 | github.com/rancher/go-rancher-metadata 60977d6 8 | github.com/urfave/cli v1.17.0-85-g4205e9c 9 | golang.org/x/sys 62bee03 10 | github.com/rancher/os/config/cloudinit be2c404 11 | github.com/coreos/yaml v1 12 | github.com/coreos/go-systemd v4 13 | github.com/docker/docker b40c87254f587af7cad8e8128f061a2a7f367343 https://github.com/rancher/docker 14 | github.com/godbus/dbus v3 15 | golang.org/x/crypto 2f3083f6163ef51179ad42ed523a18c9a1141467 -------------------------------------------------------------------------------- /vendor/github.com/Sirupsen/logrus/.gitignore: -------------------------------------------------------------------------------- 1 | logrus 2 | -------------------------------------------------------------------------------- /vendor/github.com/Sirupsen/logrus/.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | go: 3 | - 1.6.x 4 | - 1.7.x 5 | - 1.8.x 6 | - tip 7 | env: 8 | - GOMAXPROCS=4 GORACE=halt_on_error=1 9 | install: 10 | - go get github.com/stretchr/testify/assert 11 | - go get gopkg.in/gemnasium/logrus-airbrake-hook.v2 12 | - go get golang.org/x/sys/unix 13 | - go get golang.org/x/sys/windows 14 | script: 15 | - go test -race -v ./... 16 | -------------------------------------------------------------------------------- /vendor/github.com/Sirupsen/logrus/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 1.0.3 2 | 3 | * Replace example files with testable examples 4 | 5 | # 1.0.2 6 | 7 | * bug: quote non-string values in text formatter (#583) 8 | * Make (*Logger) SetLevel a public method 9 | 10 | # 1.0.1 11 | 12 | * bug: fix escaping in text formatter (#575) 13 | 14 | # 1.0.0 15 | 16 | * Officially changed name to lower-case 17 | * bug: colors on Windows 10 (#541) 18 | * bug: fix race in accessing level (#512) 19 | 20 | # 0.11.5 21 | 22 | * feature: add writer and writerlevel to entry (#372) 23 | 24 | # 0.11.4 25 | 26 | * bug: fix undefined variable on solaris (#493) 27 | 28 | # 0.11.3 29 | 30 | * formatter: configure quoting of empty values (#484) 31 | * formatter: configure quoting character (default is `"`) (#484) 32 | * bug: fix not importing io correctly in non-linux environments (#481) 33 | 34 | # 0.11.2 35 | 36 | * bug: fix windows terminal detection (#476) 37 | 38 | # 0.11.1 39 | 40 | * bug: fix tty detection with custom out (#471) 41 | 42 | # 0.11.0 43 | 44 | * performance: Use bufferpool to allocate (#370) 45 | * terminal: terminal detection for app-engine (#343) 46 | * feature: exit handler (#375) 47 | 48 | # 0.10.0 49 | 50 | * feature: Add a test hook (#180) 51 | * feature: `ParseLevel` is now case-insensitive (#326) 52 | * feature: `FieldLogger` interface that generalizes `Logger` and `Entry` (#308) 53 | * performance: avoid re-allocations on `WithFields` (#335) 54 | 55 | # 0.9.0 56 | 57 | * logrus/text_formatter: don't emit empty msg 58 | * logrus/hooks/airbrake: move out of main repository 59 | * logrus/hooks/sentry: move out of main repository 60 | * logrus/hooks/papertrail: move out of main repository 61 | * logrus/hooks/bugsnag: move out of main repository 62 | * logrus/core: run tests with `-race` 63 | * logrus/core: detect TTY based on `stderr` 64 | * logrus/core: support `WithError` on logger 65 | * logrus/core: Solaris support 66 | 67 | # 0.8.7 68 | 69 | * logrus/core: fix possible race (#216) 70 | * logrus/doc: small typo fixes and doc improvements 71 | 72 | 73 | # 0.8.6 74 | 75 | * hooks/raven: allow passing an initialized client 76 | 77 | # 0.8.5 78 | 79 | * logrus/core: revert #208 80 | 81 | # 0.8.4 82 | 83 | * formatter/text: fix data race (#218) 84 | 85 | # 0.8.3 86 | 87 | * logrus/core: fix entry log level (#208) 88 | * logrus/core: improve performance of text formatter by 40% 89 | * logrus/core: expose `LevelHooks` type 90 | * logrus/core: add support for DragonflyBSD and NetBSD 91 | * formatter/text: print structs more verbosely 92 | 93 | # 0.8.2 94 | 95 | * logrus: fix more Fatal family functions 96 | 97 | # 0.8.1 98 | 99 | * logrus: fix not exiting on `Fatalf` and `Fatalln` 100 | 101 | # 0.8.0 102 | 103 | * logrus: defaults to stderr instead of stdout 104 | * hooks/sentry: add special field for `*http.Request` 105 | * formatter/text: ignore Windows for colors 106 | 107 | # 0.7.3 108 | 109 | * formatter/\*: allow configuration of timestamp layout 110 | 111 | # 0.7.2 112 | 113 | * formatter/text: Add configuration option for time format (#158) 114 | -------------------------------------------------------------------------------- /vendor/github.com/Sirupsen/logrus/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Simon Eskildsen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /vendor/github.com/Sirupsen/logrus/alt_exit.go: -------------------------------------------------------------------------------- 1 | package logrus 2 | 3 | // The following code was sourced and modified from the 4 | // https://github.com/tebeka/atexit package governed by the following license: 5 | // 6 | // Copyright (c) 2012 Miki Tebeka . 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy of 9 | // this software and associated documentation files (the "Software"), to deal in 10 | // the Software without restriction, including without limitation the rights to 11 | // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 12 | // the Software, and to permit persons to whom the Software is furnished to do so, 13 | // subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in all 16 | // copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 20 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 21 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 22 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 23 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | 25 | import ( 26 | "fmt" 27 | "os" 28 | ) 29 | 30 | var handlers = []func(){} 31 | 32 | func runHandler(handler func()) { 33 | defer func() { 34 | if err := recover(); err != nil { 35 | fmt.Fprintln(os.Stderr, "Error: Logrus exit handler error:", err) 36 | } 37 | }() 38 | 39 | handler() 40 | } 41 | 42 | func runHandlers() { 43 | for _, handler := range handlers { 44 | runHandler(handler) 45 | } 46 | } 47 | 48 | // Exit runs all the Logrus atexit handlers and then terminates the program using os.Exit(code) 49 | func Exit(code int) { 50 | runHandlers() 51 | os.Exit(code) 52 | } 53 | 54 | // RegisterExitHandler adds a Logrus Exit handler, call logrus.Exit to invoke 55 | // all handlers. The handlers will also be invoked when any Fatal log entry is 56 | // made. 57 | // 58 | // This method is useful when a caller wishes to use logrus to log a fatal 59 | // message but also needs to gracefully shutdown. An example usecase could be 60 | // closing database connections, or sending a alert that the application is 61 | // closing. 62 | func RegisterExitHandler(handler func()) { 63 | handlers = append(handlers, handler) 64 | } 65 | -------------------------------------------------------------------------------- /vendor/github.com/Sirupsen/logrus/appveyor.yml: -------------------------------------------------------------------------------- 1 | version: "{build}" 2 | platform: x64 3 | clone_folder: c:\gopath\src\github.com\sirupsen\logrus 4 | environment: 5 | GOPATH: c:\gopath 6 | branches: 7 | only: 8 | - master 9 | install: 10 | - set PATH=%GOPATH%\bin;c:\go\bin;%PATH% 11 | - go version 12 | build_script: 13 | - go get -t 14 | - go test 15 | -------------------------------------------------------------------------------- /vendor/github.com/Sirupsen/logrus/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package logrus is a structured logger for Go, completely API compatible with the standard library logger. 3 | 4 | 5 | The simplest way to use Logrus is simply the package-level exported logger: 6 | 7 | package main 8 | 9 | import ( 10 | log "github.com/sirupsen/logrus" 11 | ) 12 | 13 | func main() { 14 | log.WithFields(log.Fields{ 15 | "animal": "walrus", 16 | "number": 1, 17 | "size": 10, 18 | }).Info("A walrus appears") 19 | } 20 | 21 | Output: 22 | time="2015-09-07T08:48:33Z" level=info msg="A walrus appears" animal=walrus number=1 size=10 23 | 24 | For a full guide visit https://github.com/sirupsen/logrus 25 | */ 26 | package logrus 27 | -------------------------------------------------------------------------------- /vendor/github.com/Sirupsen/logrus/formatter.go: -------------------------------------------------------------------------------- 1 | package logrus 2 | 3 | import "time" 4 | 5 | const defaultTimestampFormat = time.RFC3339 6 | 7 | // The Formatter interface is used to implement a custom Formatter. It takes an 8 | // `Entry`. It exposes all the fields, including the default ones: 9 | // 10 | // * `entry.Data["msg"]`. The message passed from Info, Warn, Error .. 11 | // * `entry.Data["time"]`. The timestamp. 12 | // * `entry.Data["level"]. The level the entry was logged at. 13 | // 14 | // Any additional fields added with `WithField` or `WithFields` are also in 15 | // `entry.Data`. Format is expected to return an array of bytes which are then 16 | // logged to `logger.Out`. 17 | type Formatter interface { 18 | Format(*Entry) ([]byte, error) 19 | } 20 | 21 | // This is to not silently overwrite `time`, `msg` and `level` fields when 22 | // dumping it. If this code wasn't there doing: 23 | // 24 | // logrus.WithField("level", 1).Info("hello") 25 | // 26 | // Would just silently drop the user provided level. Instead with this code 27 | // it'll logged as: 28 | // 29 | // {"level": "info", "fields.level": 1, "msg": "hello", "time": "..."} 30 | // 31 | // It's not exported because it's still using Data in an opinionated way. It's to 32 | // avoid code duplication between the two default formatters. 33 | func prefixFieldClashes(data Fields) { 34 | if t, ok := data["time"]; ok { 35 | data["fields.time"] = t 36 | } 37 | 38 | if m, ok := data["msg"]; ok { 39 | data["fields.msg"] = m 40 | } 41 | 42 | if l, ok := data["level"]; ok { 43 | data["fields.level"] = l 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /vendor/github.com/Sirupsen/logrus/hooks.go: -------------------------------------------------------------------------------- 1 | package logrus 2 | 3 | // A hook to be fired when logging on the logging levels returned from 4 | // `Levels()` on your implementation of the interface. Note that this is not 5 | // fired in a goroutine or a channel with workers, you should handle such 6 | // functionality yourself if your call is non-blocking and you don't wish for 7 | // the logging calls for levels returned from `Levels()` to block. 8 | type Hook interface { 9 | Levels() []Level 10 | Fire(*Entry) error 11 | } 12 | 13 | // Internal type for storing the hooks on a logger instance. 14 | type LevelHooks map[Level][]Hook 15 | 16 | // Add a hook to an instance of logger. This is called with 17 | // `log.Hooks.Add(new(MyHook))` where `MyHook` implements the `Hook` interface. 18 | func (hooks LevelHooks) Add(hook Hook) { 19 | for _, level := range hook.Levels() { 20 | hooks[level] = append(hooks[level], hook) 21 | } 22 | } 23 | 24 | // Fire all the hooks for the passed level. Used by `entry.log` to fire 25 | // appropriate hooks for a log entry. 26 | func (hooks LevelHooks) Fire(level Level, entry *Entry) error { 27 | for _, hook := range hooks[level] { 28 | if err := hook.Fire(entry); err != nil { 29 | return err 30 | } 31 | } 32 | 33 | return nil 34 | } 35 | -------------------------------------------------------------------------------- /vendor/github.com/Sirupsen/logrus/json_formatter.go: -------------------------------------------------------------------------------- 1 | package logrus 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | ) 7 | 8 | type fieldKey string 9 | 10 | // FieldMap allows customization of the key names for default fields. 11 | type FieldMap map[fieldKey]string 12 | 13 | // Default key names for the default fields 14 | const ( 15 | FieldKeyMsg = "msg" 16 | FieldKeyLevel = "level" 17 | FieldKeyTime = "time" 18 | ) 19 | 20 | func (f FieldMap) resolve(key fieldKey) string { 21 | if k, ok := f[key]; ok { 22 | return k 23 | } 24 | 25 | return string(key) 26 | } 27 | 28 | // JSONFormatter formats logs into parsable json 29 | type JSONFormatter struct { 30 | // TimestampFormat sets the format used for marshaling timestamps. 31 | TimestampFormat string 32 | 33 | // DisableTimestamp allows disabling automatic timestamps in output 34 | DisableTimestamp bool 35 | 36 | // FieldMap allows users to customize the names of keys for default fields. 37 | // As an example: 38 | // formatter := &JSONFormatter{ 39 | // FieldMap: FieldMap{ 40 | // FieldKeyTime: "@timestamp", 41 | // FieldKeyLevel: "@level", 42 | // FieldKeyMsg: "@message", 43 | // }, 44 | // } 45 | FieldMap FieldMap 46 | } 47 | 48 | // Format renders a single log entry 49 | func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) { 50 | data := make(Fields, len(entry.Data)+3) 51 | for k, v := range entry.Data { 52 | switch v := v.(type) { 53 | case error: 54 | // Otherwise errors are ignored by `encoding/json` 55 | // https://github.com/sirupsen/logrus/issues/137 56 | data[k] = v.Error() 57 | default: 58 | data[k] = v 59 | } 60 | } 61 | prefixFieldClashes(data) 62 | 63 | timestampFormat := f.TimestampFormat 64 | if timestampFormat == "" { 65 | timestampFormat = defaultTimestampFormat 66 | } 67 | 68 | if !f.DisableTimestamp { 69 | data[f.FieldMap.resolve(FieldKeyTime)] = entry.Time.Format(timestampFormat) 70 | } 71 | data[f.FieldMap.resolve(FieldKeyMsg)] = entry.Message 72 | data[f.FieldMap.resolve(FieldKeyLevel)] = entry.Level.String() 73 | 74 | serialized, err := json.Marshal(data) 75 | if err != nil { 76 | return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err) 77 | } 78 | return append(serialized, '\n'), nil 79 | } 80 | -------------------------------------------------------------------------------- /vendor/github.com/Sirupsen/logrus/logrus.go: -------------------------------------------------------------------------------- 1 | package logrus 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "strings" 7 | ) 8 | 9 | // Fields type, used to pass to `WithFields`. 10 | type Fields map[string]interface{} 11 | 12 | // Level type 13 | type Level uint32 14 | 15 | // Convert the Level to a string. E.g. PanicLevel becomes "panic". 16 | func (level Level) String() string { 17 | switch level { 18 | case DebugLevel: 19 | return "debug" 20 | case InfoLevel: 21 | return "info" 22 | case WarnLevel: 23 | return "warning" 24 | case ErrorLevel: 25 | return "error" 26 | case FatalLevel: 27 | return "fatal" 28 | case PanicLevel: 29 | return "panic" 30 | } 31 | 32 | return "unknown" 33 | } 34 | 35 | // ParseLevel takes a string level and returns the Logrus log level constant. 36 | func ParseLevel(lvl string) (Level, error) { 37 | switch strings.ToLower(lvl) { 38 | case "panic": 39 | return PanicLevel, nil 40 | case "fatal": 41 | return FatalLevel, nil 42 | case "error": 43 | return ErrorLevel, nil 44 | case "warn", "warning": 45 | return WarnLevel, nil 46 | case "info": 47 | return InfoLevel, nil 48 | case "debug": 49 | return DebugLevel, nil 50 | } 51 | 52 | var l Level 53 | return l, fmt.Errorf("not a valid logrus Level: %q", lvl) 54 | } 55 | 56 | // A constant exposing all logging levels 57 | var AllLevels = []Level{ 58 | PanicLevel, 59 | FatalLevel, 60 | ErrorLevel, 61 | WarnLevel, 62 | InfoLevel, 63 | DebugLevel, 64 | } 65 | 66 | // These are the different logging levels. You can set the logging level to log 67 | // on your instance of logger, obtained with `logrus.New()`. 68 | const ( 69 | // PanicLevel level, highest level of severity. Logs and then calls panic with the 70 | // message passed to Debug, Info, ... 71 | PanicLevel Level = iota 72 | // FatalLevel level. Logs and then calls `os.Exit(1)`. It will exit even if the 73 | // logging level is set to Panic. 74 | FatalLevel 75 | // ErrorLevel level. Logs. Used for errors that should definitely be noted. 76 | // Commonly used for hooks to send errors to an error tracking service. 77 | ErrorLevel 78 | // WarnLevel level. Non-critical entries that deserve eyes. 79 | WarnLevel 80 | // InfoLevel level. General operational entries about what's going on inside the 81 | // application. 82 | InfoLevel 83 | // DebugLevel level. Usually only enabled when debugging. Very verbose logging. 84 | DebugLevel 85 | ) 86 | 87 | // Won't compile if StdLogger can't be realized by a log.Logger 88 | var ( 89 | _ StdLogger = &log.Logger{} 90 | _ StdLogger = &Entry{} 91 | _ StdLogger = &Logger{} 92 | ) 93 | 94 | // StdLogger is what your logrus-enabled library should take, that way 95 | // it'll accept a stdlib logger and a logrus logger. There's no standard 96 | // interface, this is the closest we get, unfortunately. 97 | type StdLogger interface { 98 | Print(...interface{}) 99 | Printf(string, ...interface{}) 100 | Println(...interface{}) 101 | 102 | Fatal(...interface{}) 103 | Fatalf(string, ...interface{}) 104 | Fatalln(...interface{}) 105 | 106 | Panic(...interface{}) 107 | Panicf(string, ...interface{}) 108 | Panicln(...interface{}) 109 | } 110 | 111 | // The FieldLogger interface generalizes the Entry and Logger types 112 | type FieldLogger interface { 113 | WithField(key string, value interface{}) *Entry 114 | WithFields(fields Fields) *Entry 115 | WithError(err error) *Entry 116 | 117 | Debugf(format string, args ...interface{}) 118 | Infof(format string, args ...interface{}) 119 | Printf(format string, args ...interface{}) 120 | Warnf(format string, args ...interface{}) 121 | Warningf(format string, args ...interface{}) 122 | Errorf(format string, args ...interface{}) 123 | Fatalf(format string, args ...interface{}) 124 | Panicf(format string, args ...interface{}) 125 | 126 | Debug(args ...interface{}) 127 | Info(args ...interface{}) 128 | Print(args ...interface{}) 129 | Warn(args ...interface{}) 130 | Warning(args ...interface{}) 131 | Error(args ...interface{}) 132 | Fatal(args ...interface{}) 133 | Panic(args ...interface{}) 134 | 135 | Debugln(args ...interface{}) 136 | Infoln(args ...interface{}) 137 | Println(args ...interface{}) 138 | Warnln(args ...interface{}) 139 | Warningln(args ...interface{}) 140 | Errorln(args ...interface{}) 141 | Fatalln(args ...interface{}) 142 | Panicln(args ...interface{}) 143 | } 144 | -------------------------------------------------------------------------------- /vendor/github.com/Sirupsen/logrus/terminal_bsd.go: -------------------------------------------------------------------------------- 1 | // +build darwin freebsd openbsd netbsd dragonfly 2 | // +build !appengine 3 | 4 | package logrus 5 | 6 | import "golang.org/x/sys/unix" 7 | 8 | const ioctlReadTermios = unix.TIOCGETA 9 | 10 | type Termios unix.Termios 11 | -------------------------------------------------------------------------------- /vendor/github.com/Sirupsen/logrus/terminal_linux.go: -------------------------------------------------------------------------------- 1 | // Based on ssh/terminal: 2 | // Copyright 2013 The Go Authors. All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | // +build !appengine 7 | 8 | package logrus 9 | 10 | import "golang.org/x/sys/unix" 11 | 12 | const ioctlReadTermios = unix.TCGETS 13 | 14 | type Termios unix.Termios 15 | -------------------------------------------------------------------------------- /vendor/github.com/Sirupsen/logrus/writer.go: -------------------------------------------------------------------------------- 1 | package logrus 2 | 3 | import ( 4 | "bufio" 5 | "io" 6 | "runtime" 7 | ) 8 | 9 | func (logger *Logger) Writer() *io.PipeWriter { 10 | return logger.WriterLevel(InfoLevel) 11 | } 12 | 13 | func (logger *Logger) WriterLevel(level Level) *io.PipeWriter { 14 | return NewEntry(logger).WriterLevel(level) 15 | } 16 | 17 | func (entry *Entry) Writer() *io.PipeWriter { 18 | return entry.WriterLevel(InfoLevel) 19 | } 20 | 21 | func (entry *Entry) WriterLevel(level Level) *io.PipeWriter { 22 | reader, writer := io.Pipe() 23 | 24 | var printFunc func(args ...interface{}) 25 | 26 | switch level { 27 | case DebugLevel: 28 | printFunc = entry.Debug 29 | case InfoLevel: 30 | printFunc = entry.Info 31 | case WarnLevel: 32 | printFunc = entry.Warn 33 | case ErrorLevel: 34 | printFunc = entry.Error 35 | case FatalLevel: 36 | printFunc = entry.Fatal 37 | case PanicLevel: 38 | printFunc = entry.Panic 39 | default: 40 | printFunc = entry.Print 41 | } 42 | 43 | go entry.writerScanner(reader, printFunc) 44 | runtime.SetFinalizer(writer, writerFinalizer) 45 | 46 | return writer 47 | } 48 | 49 | func (entry *Entry) writerScanner(reader *io.PipeReader, printFunc func(args ...interface{})) { 50 | scanner := bufio.NewScanner(reader) 51 | for scanner.Scan() { 52 | printFunc(scanner.Text()) 53 | } 54 | if err := scanner.Err(); err != nil { 55 | entry.Errorf("Error while reading from Writer: %s", err) 56 | } 57 | reader.Close() 58 | } 59 | 60 | func writerFinalizer(writer *io.PipeWriter) { 61 | writer.Close() 62 | } 63 | -------------------------------------------------------------------------------- /vendor/github.com/coreos/yaml/LICENSE.libyaml: -------------------------------------------------------------------------------- 1 | The following files were ported to Go from C files of libyaml, and thus 2 | are still covered by their original copyright and license: 3 | 4 | apic.go 5 | emitterc.go 6 | parserc.go 7 | readerc.go 8 | scannerc.go 9 | writerc.go 10 | yamlh.go 11 | yamlprivateh.go 12 | 13 | Copyright (c) 2006 Kirill Simonov 14 | 15 | Permission is hereby granted, free of charge, to any person obtaining a copy of 16 | this software and associated documentation files (the "Software"), to deal in 17 | the Software without restriction, including without limitation the rights to 18 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 19 | of the Software, and to permit persons to whom the Software is furnished to do 20 | so, subject to the following conditions: 21 | 22 | The above copyright notice and this permission notice shall be included in all 23 | copies or substantial portions of the Software. 24 | 25 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 26 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 27 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 28 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 29 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 30 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 31 | SOFTWARE. 32 | -------------------------------------------------------------------------------- /vendor/github.com/coreos/yaml/README.md: -------------------------------------------------------------------------------- 1 | Note: This is a fork of https://github.com/go-yaml/yaml. The following README 2 | doesn't necessarily apply to this fork. 3 | 4 | # YAML support for the Go language 5 | 6 | Introduction 7 | ------------ 8 | 9 | The yaml package enables Go programs to comfortably encode and decode YAML 10 | values. It was developed within [Canonical](https://www.canonical.com) as 11 | part of the [juju](https://juju.ubuntu.com) project, and is based on a 12 | pure Go port of the well-known [libyaml](http://pyyaml.org/wiki/LibYAML) 13 | C library to parse and generate YAML data quickly and reliably. 14 | 15 | Compatibility 16 | ------------- 17 | 18 | The yaml package supports most of YAML 1.1 and 1.2, including support for 19 | anchors, tags, map merging, etc. Multi-document unmarshalling is not yet 20 | implemented, and base-60 floats from YAML 1.1 are purposefully not 21 | supported since they're a poor design and are gone in YAML 1.2. 22 | 23 | Installation and usage 24 | ---------------------- 25 | 26 | The import path for the package is *gopkg.in/yaml.v1*. 27 | 28 | To install it, run: 29 | 30 | go get gopkg.in/yaml.v1 31 | 32 | API documentation 33 | ----------------- 34 | 35 | If opened in a browser, the import path itself leads to the API documentation: 36 | 37 | * [https://gopkg.in/yaml.v1](https://gopkg.in/yaml.v1) 38 | 39 | API stability 40 | ------------- 41 | 42 | The package API for yaml v1 will remain stable as described in [gopkg.in](https://gopkg.in). 43 | 44 | 45 | License 46 | ------- 47 | 48 | The yaml package is licensed under the LGPL with an exception that allows it to be linked statically. Please see the LICENSE file for details. 49 | 50 | 51 | Example 52 | ------- 53 | 54 | ```Go 55 | package main 56 | 57 | import ( 58 | "fmt" 59 | "log" 60 | 61 | "gopkg.in/yaml.v1" 62 | ) 63 | 64 | var data = ` 65 | a: Easy! 66 | b: 67 | c: 2 68 | d: [3, 4] 69 | ` 70 | 71 | type T struct { 72 | A string 73 | B struct{C int; D []int ",flow"} 74 | } 75 | 76 | func main() { 77 | t := T{} 78 | 79 | err := yaml.Unmarshal([]byte(data), &t) 80 | if err != nil { 81 | log.Fatalf("error: %v", err) 82 | } 83 | fmt.Printf("--- t:\n%v\n\n", t) 84 | 85 | d, err := yaml.Marshal(&t) 86 | if err != nil { 87 | log.Fatalf("error: %v", err) 88 | } 89 | fmt.Printf("--- t dump:\n%s\n\n", string(d)) 90 | 91 | m := make(map[interface{}]interface{}) 92 | 93 | err = yaml.Unmarshal([]byte(data), &m) 94 | if err != nil { 95 | log.Fatalf("error: %v", err) 96 | } 97 | fmt.Printf("--- m:\n%v\n\n", m) 98 | 99 | d, err = yaml.Marshal(&m) 100 | if err != nil { 101 | log.Fatalf("error: %v", err) 102 | } 103 | fmt.Printf("--- m dump:\n%s\n\n", string(d)) 104 | } 105 | ``` 106 | 107 | This example will generate the following output: 108 | 109 | ``` 110 | --- t: 111 | {Easy! {2 [3 4]}} 112 | 113 | --- t dump: 114 | a: Easy! 115 | b: 116 | c: 2 117 | d: [3, 4] 118 | 119 | 120 | --- m: 121 | map[a:Easy! b:map[c:2 d:[3 4]]] 122 | 123 | --- m dump: 124 | a: Easy! 125 | b: 126 | c: 2 127 | d: 128 | - 3 129 | - 4 130 | ``` 131 | 132 | -------------------------------------------------------------------------------- /vendor/github.com/coreos/yaml/sorter.go: -------------------------------------------------------------------------------- 1 | package yaml 2 | 3 | import ( 4 | "reflect" 5 | "unicode" 6 | ) 7 | 8 | type keyList []reflect.Value 9 | 10 | func (l keyList) Len() int { return len(l) } 11 | func (l keyList) Swap(i, j int) { l[i], l[j] = l[j], l[i] } 12 | func (l keyList) Less(i, j int) bool { 13 | a := l[i] 14 | b := l[j] 15 | ak := a.Kind() 16 | bk := b.Kind() 17 | for (ak == reflect.Interface || ak == reflect.Ptr) && !a.IsNil() { 18 | a = a.Elem() 19 | ak = a.Kind() 20 | } 21 | for (bk == reflect.Interface || bk == reflect.Ptr) && !b.IsNil() { 22 | b = b.Elem() 23 | bk = b.Kind() 24 | } 25 | af, aok := keyFloat(a) 26 | bf, bok := keyFloat(b) 27 | if aok && bok { 28 | if af != bf { 29 | return af < bf 30 | } 31 | if ak != bk { 32 | return ak < bk 33 | } 34 | return numLess(a, b) 35 | } 36 | if ak != reflect.String || bk != reflect.String { 37 | return ak < bk 38 | } 39 | ar, br := []rune(a.String()), []rune(b.String()) 40 | for i := 0; i < len(ar) && i < len(br); i++ { 41 | if ar[i] == br[i] { 42 | continue 43 | } 44 | al := unicode.IsLetter(ar[i]) 45 | bl := unicode.IsLetter(br[i]) 46 | if al && bl { 47 | return ar[i] < br[i] 48 | } 49 | if al || bl { 50 | return bl 51 | } 52 | var ai, bi int 53 | var an, bn int64 54 | for ai = i; ai < len(ar) && unicode.IsDigit(ar[ai]); ai++ { 55 | an = an*10 + int64(ar[ai]-'0') 56 | } 57 | for bi = i; bi < len(br) && unicode.IsDigit(br[bi]); bi++ { 58 | bn = bn*10 + int64(br[bi]-'0') 59 | } 60 | if an != bn { 61 | return an < bn 62 | } 63 | if ai != bi { 64 | return ai < bi 65 | } 66 | return ar[i] < br[i] 67 | } 68 | return len(ar) < len(br) 69 | } 70 | 71 | // keyFloat returns a float value for v if it is a number/bool 72 | // and whether it is a number/bool or not. 73 | func keyFloat(v reflect.Value) (f float64, ok bool) { 74 | switch v.Kind() { 75 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 76 | return float64(v.Int()), true 77 | case reflect.Float32, reflect.Float64: 78 | return v.Float(), true 79 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 80 | return float64(v.Uint()), true 81 | case reflect.Bool: 82 | if v.Bool() { 83 | return 1, true 84 | } 85 | return 0, true 86 | } 87 | return 0, false 88 | } 89 | 90 | // numLess returns whether a < b. 91 | // a and b must necessarily have the same kind. 92 | func numLess(a, b reflect.Value) bool { 93 | switch a.Kind() { 94 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 95 | return a.Int() < b.Int() 96 | case reflect.Float32, reflect.Float64: 97 | return a.Float() < b.Float() 98 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 99 | return a.Uint() < b.Uint() 100 | case reflect.Bool: 101 | return !a.Bool() && b.Bool() 102 | } 103 | panic("not a number") 104 | } 105 | -------------------------------------------------------------------------------- /vendor/github.com/coreos/yaml/writerc.go: -------------------------------------------------------------------------------- 1 | package yaml 2 | 3 | // Set the writer error and return false. 4 | func yaml_emitter_set_writer_error(emitter *yaml_emitter_t, problem string) bool { 5 | emitter.error = yaml_WRITER_ERROR 6 | emitter.problem = problem 7 | return false 8 | } 9 | 10 | // Flush the output buffer. 11 | func yaml_emitter_flush(emitter *yaml_emitter_t) bool { 12 | if emitter.write_handler == nil { 13 | panic("write handler not set") 14 | } 15 | 16 | // Check if the buffer is empty. 17 | if emitter.buffer_pos == 0 { 18 | return true 19 | } 20 | 21 | // If the output encoding is UTF-8, we don't need to recode the buffer. 22 | if emitter.encoding == yaml_UTF8_ENCODING { 23 | if err := emitter.write_handler(emitter, emitter.buffer[:emitter.buffer_pos]); err != nil { 24 | return yaml_emitter_set_writer_error(emitter, "write error: "+err.Error()) 25 | } 26 | emitter.buffer_pos = 0 27 | return true 28 | } 29 | 30 | // Recode the buffer into the raw buffer. 31 | var low, high int 32 | if emitter.encoding == yaml_UTF16LE_ENCODING { 33 | low, high = 0, 1 34 | } else { 35 | high, low = 1, 0 36 | } 37 | 38 | pos := 0 39 | for pos < emitter.buffer_pos { 40 | // See the "reader.c" code for more details on UTF-8 encoding. Note 41 | // that we assume that the buffer contains a valid UTF-8 sequence. 42 | 43 | // Read the next UTF-8 character. 44 | octet := emitter.buffer[pos] 45 | 46 | var w int 47 | var value rune 48 | switch { 49 | case octet&0x80 == 0x00: 50 | w, value = 1, rune(octet&0x7F) 51 | case octet&0xE0 == 0xC0: 52 | w, value = 2, rune(octet&0x1F) 53 | case octet&0xF0 == 0xE0: 54 | w, value = 3, rune(octet&0x0F) 55 | case octet&0xF8 == 0xF0: 56 | w, value = 4, rune(octet&0x07) 57 | } 58 | for k := 1; k < w; k++ { 59 | octet = emitter.buffer[pos+k] 60 | value = (value << 6) + (rune(octet) & 0x3F) 61 | } 62 | pos += w 63 | 64 | // Write the character. 65 | if value < 0x10000 { 66 | var b [2]byte 67 | b[high] = byte(value >> 8) 68 | b[low] = byte(value & 0xFF) 69 | emitter.raw_buffer = append(emitter.raw_buffer, b[0], b[1]) 70 | } else { 71 | // Write the character using a surrogate pair (check "reader.c"). 72 | var b [4]byte 73 | value -= 0x10000 74 | b[high] = byte(0xD8 + (value >> 18)) 75 | b[low] = byte((value >> 10) & 0xFF) 76 | b[high+2] = byte(0xDC + ((value >> 8) & 0xFF)) 77 | b[low+2] = byte(value & 0xFF) 78 | emitter.raw_buffer = append(emitter.raw_buffer, b[0], b[1], b[2], b[3]) 79 | } 80 | } 81 | 82 | // Write the raw buffer. 83 | if err := emitter.write_handler(emitter, emitter.raw_buffer); err != nil { 84 | return yaml_emitter_set_writer_error(emitter, "write error: "+err.Error()) 85 | } 86 | emitter.buffer_pos = 0 87 | emitter.raw_buffer = emitter.raw_buffer[:0] 88 | return true 89 | } 90 | -------------------------------------------------------------------------------- /vendor/github.com/rancher/go-rancher-metadata/.gitignore: -------------------------------------------------------------------------------- 1 | go-rancher-metadata 2 | -------------------------------------------------------------------------------- /vendor/github.com/rancher/go-rancher-metadata/README.md: -------------------------------------------------------------------------------- 1 | # Go bindings for Rancher-metadata 2 | 3 | This library is incomplete, but implements a variety of calls against [rancher-metadata](https://github.com/rancher/rancher-metadata) service 4 | 5 | #Example usage 6 | 7 | ```go 8 | package main 9 | 10 | import ( 11 | "time" 12 | 13 | "github.com/Sirupsen/logrus" 14 | "github.com/rancher/go-rancher-metadata/metadata" 15 | ) 16 | 17 | const ( 18 | metadataUrl = "http://rancher-metadata/2015-12-19" 19 | ) 20 | 21 | func main() { 22 | 23 | m := metadata.NewClient(metadataUrl) 24 | 25 | version := "init" 26 | 27 | for { 28 | newVersion, err := m.GetVersion() 29 | if err != nil { 30 | logrus.Errorf("Error reading metadata version: %v", err) 31 | } else if version == newVersion { 32 | logrus.Debug("No changes in metadata version") 33 | } else { 34 | logrus.Debugf("Metadata Version has been changed. Old version: %s. New version: %s.", version, newVersion) 35 | version = newVersion 36 | } 37 | time.Sleep(5 * time.Second) 38 | } 39 | } 40 | ``` 41 | -------------------------------------------------------------------------------- /vendor/github.com/rancher/go-rancher-metadata/metadata/change.go: -------------------------------------------------------------------------------- 1 | package metadata 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "time" 7 | 8 | "github.com/Sirupsen/logrus" 9 | ) 10 | 11 | func (m *client) OnChangeWithError(intervalSeconds int, do func(string)) error { 12 | return m.onChangeFromVersionWithError("init", intervalSeconds, do) 13 | } 14 | 15 | func (m *client) onChangeFromVersionWithError(version string, intervalSeconds int, do func(string)) error { 16 | for { 17 | newVersion, err := m.waitVersion(intervalSeconds, version) 18 | if err != nil { 19 | return err 20 | } else if version == newVersion { 21 | logrus.Debug("No changes in metadata version") 22 | } else { 23 | logrus.Debugf("Metadata Version has been changed. Old version: %s. New version: %s.", version, newVersion) 24 | version = newVersion 25 | do(newVersion) 26 | } 27 | } 28 | 29 | return nil 30 | } 31 | 32 | func (m *client) OnChange(intervalSeconds int, do func(string)) { 33 | version := "init" 34 | updateVersionAndDo := func(v string) { 35 | version = v 36 | do(version) 37 | } 38 | interval := time.Duration(intervalSeconds) 39 | for { 40 | if err := m.onChangeFromVersionWithError(version, intervalSeconds, updateVersionAndDo); err != nil { 41 | logrus.Errorf("Error reading metadata version: %v", err) 42 | } 43 | time.Sleep(interval * time.Second) 44 | } 45 | } 46 | 47 | type timeout interface { 48 | Timeout() bool 49 | } 50 | 51 | func (m *client) waitVersion(maxWait int, version string) (string, error) { 52 | for { 53 | resp, err := m.SendRequest(fmt.Sprintf("/version?wait=true&value=%s&maxWait=%d", version, maxWait)) 54 | if err != nil { 55 | t, ok := err.(timeout) 56 | if ok && t.Timeout() { 57 | continue 58 | } 59 | return "", err 60 | } 61 | err = json.Unmarshal(resp, &version) 62 | return version, err 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /vendor/github.com/rancher/go-rancher-metadata/metadata/utils.go: -------------------------------------------------------------------------------- 1 | package metadata 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | func testConnection(mdClient Client) error { 8 | var err error 9 | maxTime := 20 * time.Second 10 | 11 | for i := 1 * time.Second; i < maxTime; i *= time.Duration(2) { 12 | if _, err = mdClient.GetVersion(); err != nil { 13 | time.Sleep(i) 14 | } else { 15 | return nil 16 | } 17 | } 18 | return err 19 | } 20 | -------------------------------------------------------------------------------- /vendor/github.com/rancher/os/config/cloudinit/.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | bin/ 3 | coverage/ 4 | gopath/ 5 | -------------------------------------------------------------------------------- /vendor/github.com/rancher/os/config/cloudinit/.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | matrix: 3 | include: 4 | - go: 1.5 5 | env: GO15VENDOREXPERIMENT=1 6 | - go: 1.6 7 | 8 | script: 9 | - ./test 10 | -------------------------------------------------------------------------------- /vendor/github.com/rancher/os/config/cloudinit/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to Contribute 2 | 3 | CoreOS projects are [Apache 2.0 licensed](LICENSE) and accept contributions via 4 | GitHub pull requests. This document outlines some of the conventions on 5 | development workflow, commit message formatting, contact points and other 6 | resources to make it easier to get your contribution accepted. 7 | 8 | # Certificate of Origin 9 | 10 | By contributing to this project you agree to the Developer Certificate of 11 | Origin (DCO). This document was created by the Linux Kernel community and is a 12 | simple statement that you, as a contributor, have the legal right to make the 13 | contribution. See the [DCO](DCO) file for details. 14 | 15 | # Email and Chat 16 | 17 | The project currently uses the general CoreOS email list and IRC channel: 18 | - Email: [coreos-dev](https://groups.google.com/forum/#!forum/coreos-dev) 19 | - IRC: #[coreos](irc://irc.freenode.org:6667/#coreos) IRC channel on freenode.org 20 | 21 | ## Getting Started 22 | 23 | - Fork the repository on GitHub 24 | - Read the [README](README.md) for build and test instructions 25 | - Play with the project, submit bugs, submit patches! 26 | 27 | ## Contribution Flow 28 | 29 | This is a rough outline of what a contributor's workflow looks like: 30 | 31 | - Create a topic branch from where you want to base your work (usually master). 32 | - Make commits of logical units. 33 | - Make sure your commit messages are in the proper format (see below). 34 | - Push your changes to a topic branch in your fork of the repository. 35 | - Make sure the tests pass, and add any new tests as appropriate. 36 | - Submit a pull request to the original repository. 37 | 38 | Thanks for your contributions! 39 | 40 | ### Format of the Commit Message 41 | 42 | We follow a rough convention for commit messages that is designed to answer two 43 | questions: what changed and why. The subject line should feature the what and 44 | the body of the commit should describe the why. 45 | 46 | ``` 47 | environment: write new keys in consistent order 48 | 49 | Go 1.3 randomizes the ordering of keys when iterating over a map. 50 | Sort the keys to make this ordering consistent. 51 | 52 | Fixes #38 53 | ``` 54 | 55 | The format can be described more formally as follows: 56 | 57 | ``` 58 | : 59 | 60 | 61 | 62 |