├── Documentation ├── api-v1-alpha.md └── examples │ ├── img │ └── subgun.png │ ├── service-discovery.md │ └── api.py ├── Godeps ├── _workspace │ ├── .gitignore │ └── src │ │ ├── github.com │ │ ├── rakyll │ │ │ ├── goini │ │ │ │ ├── empty.ini │ │ │ │ ├── .gitignore │ │ │ │ ├── Makefile │ │ │ │ └── example.ini │ │ │ └── globalconf │ │ │ │ ├── .travis.yml │ │ │ │ └── testdata │ │ │ │ ├── custom.ini │ │ │ │ ├── global.ini │ │ │ │ └── globalandcustom.ini │ │ ├── jonboulle │ │ │ └── clockwork │ │ │ │ ├── .travis.yml │ │ │ │ ├── .gitignore │ │ │ │ ├── example_test.go │ │ │ │ └── README.md │ │ ├── godbus │ │ │ └── dbus │ │ │ │ ├── transport_darwin.go │ │ │ │ ├── homedir_dynamic.go │ │ │ │ ├── homedir.go │ │ │ │ ├── conn_darwin.go │ │ │ │ ├── conn_other.go │ │ │ │ ├── auth_external.go │ │ │ │ ├── introspect │ │ │ │ └── call.go │ │ │ │ ├── transport_unixcred_linux.go │ │ │ │ ├── transport_generic.go │ │ │ │ ├── homedir_static.go │ │ │ │ ├── examples_test.go │ │ │ │ ├── README.markdown │ │ │ │ ├── transport_unix_test.go │ │ │ │ ├── sig_test.go │ │ │ │ └── LICENSE │ │ ├── docker │ │ │ └── libcontainer │ │ │ │ └── netlink │ │ │ │ ├── MAINTAINERS │ │ │ │ ├── netlink.go │ │ │ │ └── netlink_unsupported.go │ │ └── coreos │ │ │ ├── go-semver │ │ │ └── semver │ │ │ │ └── sort.go │ │ │ └── go-systemd │ │ │ ├── dbus │ │ │ ├── set.go │ │ │ ├── set_test.go │ │ │ ├── subscription_set_test.go │ │ │ ├── subscription_set.go │ │ │ ├── subscription_test.go │ │ │ └── dbus_test.go │ │ │ ├── unit │ │ │ ├── option.go │ │ │ └── serialize.go │ │ │ └── activation │ │ │ ├── packetconns.go │ │ │ ├── listeners.go │ │ │ ├── files.go │ │ │ ├── packetconns_test.go │ │ │ └── listeners_test.go │ │ ├── golang.org │ │ └── x │ │ │ └── crypto │ │ │ └── ssh │ │ │ ├── test │ │ │ ├── doc.go │ │ │ ├── tcpip_test.go │ │ │ ├── cert_test.go │ │ │ └── agent_unix_test.go │ │ │ ├── terminal │ │ │ ├── util_bsd.go │ │ │ └── util_linux.go │ │ │ ├── testdata │ │ │ ├── doc.go │ │ │ └── keys.go │ │ │ ├── tcpip_test.go │ │ │ ├── doc.go │ │ │ ├── client_test.go │ │ │ ├── kex_test.go │ │ │ ├── mac.go │ │ │ ├── cipher_test.go │ │ │ ├── agent │ │ │ └── server_test.go │ │ │ └── testdata_test.go │ │ └── google.golang.org │ │ └── api │ │ ├── googleapi │ │ ├── internal │ │ │ └── uritemplates │ │ │ │ ├── utils.go │ │ │ │ └── LICENSE │ │ ├── transport │ │ │ └── apikey.go │ │ └── types_test.go │ │ └── google-api-go-generator │ │ ├── testdata │ │ ├── arrayofmapofstrings.json │ │ ├── arrayofmapofobjects.json │ │ ├── mapofobjects.json │ │ ├── arrayofarray-1.json │ │ ├── mapofany.json │ │ ├── arrayofmapofobjects.want │ │ ├── arrayofmapofstrings.want │ │ ├── mapofobjects.want │ │ ├── arrayofarray-1.want │ │ ├── quotednum.want │ │ ├── mapofany.want │ │ ├── mapofstrings-1.json │ │ └── mapofarrayofobjects.json │ │ └── gen_test.go ├── Readme └── Godeps.json ├── .gitignore ├── MAINTAINERS ├── test-docker ├── functional ├── fixtures │ ├── units │ │ ├── hello.service │ │ ├── goodbye.service │ │ ├── ping.0.service │ │ ├── ping.1.service │ │ ├── ping.2.service │ │ ├── pin@.service │ │ ├── global.service │ │ ├── pong.0.service │ │ ├── pong.1.service │ │ ├── pong.2.service │ │ ├── conflict.0.service │ │ ├── conflict.1.service │ │ ├── conflict.2.service │ │ ├── conflict.3.service │ │ ├── conflict.4.service │ │ └── conflicts-with-hello.service │ └── id_rsa.pub ├── clean.sh ├── platform │ └── cluster.go ├── README.md └── fleetctl_test.go ├── examples ├── ping.service ├── hello.service └── pong.service ├── NOTICE ├── scripts ├── fleetctl-inject-ssh.sh ├── build-release ├── bump-release ├── schema-generator └── schema_generator_import.go ├── .travis.yml ├── cover ├── fixtures ├── bad_known_hosts ├── authorized_keys └── insecure_private_key ├── machine ├── fake.go ├── fake_test.go ├── machine.go ├── state.go └── machine_test.go ├── pkg ├── backoff.go ├── args.go ├── http.go ├── backoff_test.go ├── filesystem.go ├── filesystem_test.go ├── filepath.go ├── args_test.go ├── tls.go └── filepath_test.go ├── fleetctl ├── verify.go ├── version.go ├── destroy.go ├── submit.go ├── cat.go ├── fdforward.go ├── list_machines_test.go └── unload.go ├── version └── version.go ├── unit ├── manager.go └── fake.go ├── client └── api.go ├── heart ├── heart.go └── monitor.go ├── api ├── path.go ├── discovery.go ├── deserialization_test.go ├── mux_test.go ├── discovery_test.go ├── server.go └── mux.go ├── test ├── fleet.conf.sample ├── etcd ├── error.go ├── error_test.go └── result.go ├── config ├── config_test.go └── config.go ├── DCO ├── agent └── cache.go ├── ssh ├── proxy.go └── LICENSE ├── registry ├── registry.go ├── job_state.go ├── event_test.go ├── unit.go └── fake_test.go ├── resource ├── resource_test.go └── resource.go └── engine └── scheduler.go /Documentation/api-v1-alpha.md: -------------------------------------------------------------------------------- 1 | api-v1.md -------------------------------------------------------------------------------- /Godeps/_workspace/.gitignore: -------------------------------------------------------------------------------- 1 | /pkg 2 | /bin 3 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/rakyll/goini/empty.ini: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | coverage/ 3 | gopath/ 4 | *.swp 5 | fleet.conf 6 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/rakyll/globalconf/.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | go: 1.2 3 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/jonboulle/clockwork/.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | go: 3 | - 1.3 4 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/rakyll/globalconf/testdata/custom.ini: -------------------------------------------------------------------------------- 1 | [custom] 2 | d = Hello d 3 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/rakyll/globalconf/testdata/global.ini: -------------------------------------------------------------------------------- 1 | a = true 2 | b = 5.6 3 | c = Hello world 4 | -------------------------------------------------------------------------------- /MAINTAINERS: -------------------------------------------------------------------------------- 1 | Brian Waldon (@bcwaldon) 2 | Jonathan Boulle (@jonboulle) 3 | -------------------------------------------------------------------------------- /test-docker: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | docker run -v $PWD:/opt/fleet google/golang:1.3.1 /bin/bash -c "cd /opt/fleet && ./test" 4 | -------------------------------------------------------------------------------- /functional/fixtures/units/hello.service: -------------------------------------------------------------------------------- 1 | [Service] 2 | ExecStart=/bin/bash -c "while true; do echo Hello, World!; sleep 1; done" 3 | -------------------------------------------------------------------------------- /Documentation/examples/img/subgun.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DivideAndConquer/fleet/master/Documentation/examples/img/subgun.png -------------------------------------------------------------------------------- /functional/fixtures/units/goodbye.service: -------------------------------------------------------------------------------- 1 | [Service] 2 | ExecStart=/bin/bash -c "while true; do echo Goodbye, World!; sleep 1; done" 3 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/rakyll/goini/.gitignore: -------------------------------------------------------------------------------- 1 | .*.swp 2 | 3 | *.[689] 4 | [689].out 5 | 6 | _obj 7 | _test 8 | _testmain.go 9 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/rakyll/goini/Makefile: -------------------------------------------------------------------------------- 1 | test: 2 | go test 3 | 4 | format: 5 | gofmt -w *.go 6 | 7 | .PHONY: format test 8 | -------------------------------------------------------------------------------- /examples/ping.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=PING 3 | 4 | [Service] 5 | ExecStart=/bin/bash -c "while true; do echo \"ping\"; sleep 1; done" 6 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | CoreOS Project 2 | Copyright 2014 CoreOS, Inc 3 | 4 | This product includes software developed at CoreOS, Inc. 5 | (http://www.coreos.com/). 6 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/rakyll/globalconf/testdata/globalandcustom.ini: -------------------------------------------------------------------------------- 1 | a = true 2 | b = 5.6 3 | c = Hello world 4 | 5 | [custom] 6 | d = Hello d 7 | -------------------------------------------------------------------------------- /examples/hello.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Hello World 3 | 4 | [Service] 5 | ExecStart=/bin/bash -c "while true; do echo \"Hello, world\"; sleep 1; done" 6 | -------------------------------------------------------------------------------- /functional/fixtures/units/ping.0.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=PING 3 | 4 | [Service] 5 | ExecStart=/bin/bash -c "while true; do echo ping; sleep 1; done" 6 | -------------------------------------------------------------------------------- /functional/fixtures/units/ping.1.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=PING 3 | 4 | [Service] 5 | ExecStart=/bin/bash -c "while true; do echo ping; sleep 1; done" 6 | -------------------------------------------------------------------------------- /functional/fixtures/units/ping.2.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=PING 3 | 4 | [Service] 5 | ExecStart=/bin/bash -c "while true; do echo ping; sleep 1; done" 6 | -------------------------------------------------------------------------------- /functional/fixtures/units/pin@.service: -------------------------------------------------------------------------------- 1 | [Service] 2 | ExecStart=/bin/bash -c "while true; do echo Hello, World!; sleep 1; done" 3 | 4 | [X-Fleet] 5 | MachineID=%i 6 | -------------------------------------------------------------------------------- /Godeps/Readme: -------------------------------------------------------------------------------- 1 | This directory tree is generated automatically by godep. 2 | 3 | Please do not edit. 4 | 5 | See https://github.com/tools/godep for more information. 6 | -------------------------------------------------------------------------------- /functional/fixtures/units/global.service: -------------------------------------------------------------------------------- 1 | [Service] 2 | ExecStart=/bin/bash -c "while true; do echo Hello, Global World!; sleep 1; done" 3 | 4 | [X-Fleet] 5 | Global=true 6 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/godbus/dbus/transport_darwin.go: -------------------------------------------------------------------------------- 1 | package dbus 2 | 3 | func (t *unixTransport) SendNullByte() error { 4 | _, err := t.Write([]byte{0}) 5 | return err 6 | } 7 | -------------------------------------------------------------------------------- /examples/pong.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=PONG 3 | 4 | [Service] 5 | ExecStart=/bin/bash -c "while true; do echo \"pong\"; sleep 1; done" 6 | 7 | [X-Fleet] 8 | MachineOf=ping.service 9 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/docker/libcontainer/netlink/MAINTAINERS: -------------------------------------------------------------------------------- 1 | Michael Crosby (@crosbymichael) 2 | Guillaume J. Charmes (@creack) 3 | -------------------------------------------------------------------------------- /functional/fixtures/units/pong.0.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=PONG 3 | 4 | [Service] 5 | ExecStart=/bin/bash -c "while true; do echo pong; sleep 1; done" 6 | 7 | [X-Fleet] 8 | MachineOf=ping.0.service 9 | -------------------------------------------------------------------------------- /functional/fixtures/units/pong.1.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=PONG 3 | 4 | [Service] 5 | ExecStart=/bin/bash -c "while true; do echo pong; sleep 1; done" 6 | 7 | [X-Fleet] 8 | MachineOf=ping.1.service 9 | -------------------------------------------------------------------------------- /functional/fixtures/units/pong.2.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=PONG 3 | 4 | [Service] 5 | ExecStart=/bin/bash -c "while true; do echo pong; sleep 1; done" 6 | 7 | [X-Fleet] 8 | MachineOf=ping.2.service 9 | -------------------------------------------------------------------------------- /functional/fixtures/units/conflict.0.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Test Unit 3 | 4 | [Service] 5 | ExecStart=/bin/bash -c "while true; do echo Hello, World!; sleep 1; done" 6 | 7 | [X-Fleet] 8 | Conflicts=conflict.*.service 9 | -------------------------------------------------------------------------------- /functional/fixtures/units/conflict.1.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Test Unit 3 | 4 | [Service] 5 | ExecStart=/bin/bash -c "while true; do echo Hello, World!; sleep 1; done" 6 | 7 | [X-Fleet] 8 | Conflicts=conflict.*.service 9 | -------------------------------------------------------------------------------- /functional/fixtures/units/conflict.2.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Test Unit 3 | 4 | [Service] 5 | ExecStart=/bin/bash -c "while true; do echo Hello, World!; sleep 1; done" 6 | 7 | [X-Fleet] 8 | Conflicts=conflict.*.service 9 | -------------------------------------------------------------------------------- /functional/fixtures/units/conflict.3.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Test Unit 3 | 4 | [Service] 5 | ExecStart=/bin/bash -c "while true; do echo Hello, World!; sleep 1; done" 6 | 7 | [X-Fleet] 8 | Conflicts=conflict.*.service 9 | -------------------------------------------------------------------------------- /functional/fixtures/units/conflict.4.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Test Unit 3 | 4 | [Service] 5 | ExecStart=/bin/bash -c "while true; do echo Hello, World!; sleep 1; done" 6 | 7 | [X-Fleet] 8 | Conflicts=conflict.*.service 9 | -------------------------------------------------------------------------------- /functional/fixtures/units/conflicts-with-hello.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Test Unit 3 | 4 | [Service] 5 | ExecStart=/bin/bash -c "while true; do echo Hello, World!; sleep 1; done" 6 | 7 | [X-Fleet] 8 | Conflicts=hello.service 9 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/godbus/dbus/homedir_dynamic.go: -------------------------------------------------------------------------------- 1 | // +build !static_build 2 | 3 | package dbus 4 | 5 | import ( 6 | "os/user" 7 | ) 8 | 9 | func lookupHomeDir() string { 10 | u, err := user.Current() 11 | if err != nil { 12 | return "/" 13 | } 14 | return u.HomeDir 15 | } 16 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/golang.org/x/crypto/ssh/test/doc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // This package contains integration tests for the 6 | // code.google.com/p/go.crypto/ssh package. 7 | package test 8 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/rakyll/goini/example.ini: -------------------------------------------------------------------------------- 1 | # 2 | # This is an example of ini file 3 | # 4 | 5 | [Pizza] 6 | 7 | Ham = yes; 8 | Mushrooms = TRUE; 9 | Capres = 0; 10 | Cheese = Non; 11 | 12 | 13 | [Wine] 14 | 15 | Grape = Cabernet Sauvignon; 16 | Year = 1989; 17 | Country = Spain; 18 | Alcohol = 12.5; 19 | -------------------------------------------------------------------------------- /scripts/fleetctl-inject-ssh.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -x 2 | 3 | name=$1 4 | if [ -z $name ]; then 5 | echo "Provide a name for the injected SSH key" 6 | exit 1 7 | fi 8 | 9 | shift 1 10 | 11 | pubkey=$(cat) 12 | 13 | for machine in $(fleetctl $@ list-machines --no-legend --full | awk '{ print $1;}'); do 14 | fleetctl $@ ssh $machine "echo '${pubkey}' | update-ssh-keys -a $name -n" 15 | done 16 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/google.golang.org/api/googleapi/internal/uritemplates/utils.go: -------------------------------------------------------------------------------- 1 | package uritemplates 2 | 3 | func Expand(path string, expansions map[string]string) (string, error) { 4 | template, err := Parse(path) 5 | if err != nil { 6 | return "", err 7 | } 8 | values := make(map[string]interface{}) 9 | for k, v := range expansions { 10 | values[k] = v 11 | } 12 | return template.Expand(values) 13 | } 14 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | matrix: 3 | include: 4 | - go: 1.4 5 | env: TOOLS_CMD=golang.org/x/tools/cmd 6 | - go: 1.3 7 | env: TOOLS_CMD=code.google.com/p/go.tools/cmd 8 | - go: 1.2 9 | env: TOOLS_CMD=code.google.com/p/go.tools/cmd 10 | 11 | install: 12 | - go get ${TOOLS_CMD}/cover 13 | - go get ${TOOLS_CMD}/vet 14 | 15 | script: 16 | - ./test 17 | 18 | notifications: 19 | email: false 20 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/jonboulle/clockwork/.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | 10 | # Architecture specific extensions/prefixes 11 | *.[568vq] 12 | [568vq].out 13 | 14 | *.cgo1.go 15 | *.cgo2.c 16 | _cgo_defun.c 17 | _cgo_gotypes.go 18 | _cgo_export.* 19 | 20 | _testmain.go 21 | 22 | *.exe 23 | *.test 24 | 25 | *.swp 26 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/golang.org/x/crypto/ssh/terminal/util_bsd.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build darwin dragonfly freebsd netbsd openbsd 6 | 7 | package terminal 8 | 9 | import "syscall" 10 | 11 | const ioctlReadTermios = syscall.TIOCGETA 12 | const ioctlWriteTermios = syscall.TIOCSETA 13 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/golang.org/x/crypto/ssh/testdata/doc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // This package contains test data shared between the various subpackages of 6 | // the code.google.com/p/go.crypto/ssh package. Under no circumstance should 7 | // this data be used for production code. 8 | package testdata 9 | -------------------------------------------------------------------------------- /functional/clean.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # WARNING: This script is destructive and should only be run within the test environment 4 | # 5 | 6 | machinectl --no-legend | cut -d ' ' -f1 | sudo xargs -r machinectl terminate 7 | sudo pkill -9 systemd-nspawn 8 | sudo rm -fr /run/systemd/system/*smoke* /tmp/smoke 9 | sudo systemctl daemon-reload 10 | ip link show fleet0 &>/dev/null && sudo ip link del fleet0 11 | etcdctl rm --recursive /fleet_functional 12 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/godbus/dbus/homedir.go: -------------------------------------------------------------------------------- 1 | package dbus 2 | 3 | import ( 4 | "os" 5 | "sync" 6 | ) 7 | 8 | var ( 9 | homeDir string 10 | homeDirLock sync.Mutex 11 | ) 12 | 13 | func getHomeDir() string { 14 | homeDirLock.Lock() 15 | defer homeDirLock.Unlock() 16 | 17 | if homeDir != "" { 18 | return homeDir 19 | } 20 | 21 | homeDir = os.Getenv("HOME") 22 | if homeDir != "" { 23 | return homeDir 24 | } 25 | 26 | homeDir = lookupHomeDir() 27 | return homeDir 28 | } 29 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/coreos/go-semver/semver/sort.go: -------------------------------------------------------------------------------- 1 | package semver 2 | 3 | import ( 4 | "sort" 5 | ) 6 | 7 | type Versions []*Version 8 | 9 | func (s Versions) Len() int { 10 | return len(s) 11 | } 12 | 13 | func (s Versions) Swap(i, j int) { 14 | s[i], s[j] = s[j], s[i] 15 | } 16 | 17 | func (s Versions) Less(i, j int) bool { 18 | return s[i].LessThan(*s[j]) 19 | } 20 | 21 | // Sort sorts the given slice of Version 22 | func Sort(versions []*Version) { 23 | sort.Sort(Versions(versions)) 24 | } 25 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/godbus/dbus/conn_darwin.go: -------------------------------------------------------------------------------- 1 | package dbus 2 | 3 | import ( 4 | "errors" 5 | "os/exec" 6 | ) 7 | 8 | func sessionBusPlatform() (*Conn, error) { 9 | cmd := exec.Command("launchctl", "getenv", "DBUS_LAUNCHD_SESSION_BUS_SOCKET") 10 | b, err := cmd.CombinedOutput() 11 | 12 | if err != nil { 13 | return nil, err 14 | } 15 | 16 | if len(b) == 0 { 17 | return nil, errors.New("dbus: couldn't determine address of session bus") 18 | } 19 | 20 | return Dial("unix:path=" + string(b[:len(b)-1])) 21 | } 22 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/golang.org/x/crypto/ssh/terminal/util_linux.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package terminal 6 | 7 | // These constants are declared here, rather than importing 8 | // them from the syscall package as some syscall packages, even 9 | // on linux, for example gccgo, do not declare them. 10 | const ioctlReadTermios = 0x5401 // syscall.TCGETS 11 | const ioctlWriteTermios = 0x5402 // syscall.TCSETS 12 | -------------------------------------------------------------------------------- /cover: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | # 3 | # Generate coverage HTML for a package 4 | # e.g. PKG=./unit ./cover 5 | # 6 | 7 | if [ -z "$PKG" ]; then 8 | echo "cover only works with a single package, sorry" 9 | exit 255 10 | fi 11 | 12 | COVEROUT="coverage" 13 | 14 | if ! [ -d "$COVEROUT" ]; then 15 | mkdir "$COVEROUT" 16 | fi 17 | 18 | # strip out slashes and dots 19 | COVERPKG=${PKG//\//} 20 | COVERPKG=${COVERPKG//./} 21 | 22 | # generate arg for "go test" 23 | export COVER="-coverprofile ${COVEROUT}/${COVERPKG}.out" 24 | 25 | source ./test 26 | 27 | go tool cover -html=${COVEROUT}/${COVERPKG}.out 28 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/godbus/dbus/conn_other.go: -------------------------------------------------------------------------------- 1 | // +build !darwin 2 | 3 | package dbus 4 | 5 | import ( 6 | "bytes" 7 | "errors" 8 | "os/exec" 9 | ) 10 | 11 | func sessionBusPlatform() (*Conn, error) { 12 | cmd := exec.Command("dbus-launch") 13 | b, err := cmd.CombinedOutput() 14 | 15 | if err != nil { 16 | return nil, err 17 | } 18 | 19 | i := bytes.IndexByte(b, '=') 20 | j := bytes.IndexByte(b, '\n') 21 | 22 | if i == -1 || j == -1 { 23 | return nil, errors.New("dbus: couldn't determine address of session bus") 24 | } 25 | 26 | return Dial(string(b[i+1 : j])) 27 | } 28 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink.go: -------------------------------------------------------------------------------- 1 | // Packet netlink provide access to low level Netlink sockets and messages. 2 | // 3 | // Actual implementations are in: 4 | // netlink_linux.go 5 | // netlink_darwin.go 6 | package netlink 7 | 8 | import ( 9 | "errors" 10 | "net" 11 | ) 12 | 13 | var ( 14 | ErrWrongSockType = errors.New("Wrong socket type") 15 | ErrShortResponse = errors.New("Got short response from netlink") 16 | ) 17 | 18 | // A Route is a subnet associated with the interface to reach it. 19 | type Route struct { 20 | *net.IPNet 21 | Iface *net.Interface 22 | Default bool 23 | } 24 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/golang.org/x/crypto/ssh/tcpip_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package ssh 6 | 7 | import ( 8 | "testing" 9 | ) 10 | 11 | func TestAutoPortListenBroken(t *testing.T) { 12 | broken := "SSH-2.0-OpenSSH_5.9hh11" 13 | works := "SSH-2.0-OpenSSH_6.1" 14 | if !isBrokenOpenSSHVersion(broken) { 15 | t.Errorf("version %q not marked as broken", broken) 16 | } 17 | if isBrokenOpenSSHVersion(works) { 18 | t.Errorf("version %q marked as broken", works) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/coreos/go-systemd/dbus/set.go: -------------------------------------------------------------------------------- 1 | package dbus 2 | 3 | type set struct { 4 | data map[string]bool 5 | } 6 | 7 | func (s *set) Add(value string) { 8 | s.data[value] = true 9 | } 10 | 11 | func (s *set) Remove(value string) { 12 | delete(s.data, value) 13 | } 14 | 15 | func (s *set) Contains(value string) (exists bool) { 16 | _, exists = s.data[value] 17 | return 18 | } 19 | 20 | func (s *set) Length() (int) { 21 | return len(s.data) 22 | } 23 | 24 | func (s *set) Values() (values []string) { 25 | for val, _ := range s.data { 26 | values = append(values, val) 27 | } 28 | return 29 | } 30 | 31 | func newSet() (*set) { 32 | return &set{make(map[string] bool)} 33 | } 34 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/godbus/dbus/auth_external.go: -------------------------------------------------------------------------------- 1 | package dbus 2 | 3 | import ( 4 | "encoding/hex" 5 | ) 6 | 7 | // AuthExternal returns an Auth that authenticates as the given user with the 8 | // EXTERNAL mechanism. 9 | func AuthExternal(user string) Auth { 10 | return authExternal{user} 11 | } 12 | 13 | // AuthExternal implements the EXTERNAL authentication mechanism. 14 | type authExternal struct { 15 | user string 16 | } 17 | 18 | func (a authExternal) FirstData() ([]byte, []byte, AuthStatus) { 19 | b := make([]byte, 2*len(a.user)) 20 | hex.Encode(b, []byte(a.user)) 21 | return []byte("EXTERNAL"), b, AuthOk 22 | } 23 | 24 | func (a authExternal) HandleData(b []byte) ([]byte, AuthStatus) { 25 | return nil, AuthError 26 | } 27 | -------------------------------------------------------------------------------- /functional/fixtures/id_rsa.pub: -------------------------------------------------------------------------------- 1 | ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCrgZOtFX3mHmqp6cu44YSUa5BmNo2agooYnqHlcR5oIDPVXHwH5wwHXlJtEwTO95+sbmXCPxGDzwA5InVfDfbkDWKyhHPg/E/J5VXnFD9Obzi+yqesyFUxWnWmFvee2P8R6Yu0LfqunwWyIZ2w0PqTY/vY022qgo/pK4MBCMnbtIO85F1TO7mmFpxq4jToJTwP3KB3Dpvy3wPLBuWbR8VdJCwMHUYne0zRp/ufKRGfprXOtumjRRcODcLQ+oZTD7Dk9d5pVY2NDegHrhhfW0PIuHKvE5LX+O5PeMRzu3oQF7X0+qz7+GAN6N9UIJ4UNX6xkBW8I41kw5BmYA4CDn8AQnJkVKs/nMPNurtx3+vlpr7zr2j+ZGh4ZOkrdhdlYJPZfA1ZyuX6aCkXakG+IzflhSswxOEawlFUOx2GZ/yrgNFep01WBysJceqBGaKwqSBT2Sini/WmJDnxuj7A5L8JTUflDezwGLgKWGGip6zH75hIY/K1Gk8YRDHJDnv2tY78Eu6bYUIgHkzZJIHhkcqttups2e1fo5Tgiv5oi242bGH/h3l+FJi/DOCNMTLsogw0GGRRbXvtrSvmD+oelpPGF06VjdCSQ6PmNPG0J5oHLJ92SqYes277I+lF49ulNt/kalTvCxNi74crhPj25iTob8cEYAolarqj9BBGNhJw/Q== fleet functional testing key 2 | -------------------------------------------------------------------------------- /fixtures/bad_known_hosts: -------------------------------------------------------------------------------- 1 | 192.0.2.1ssh-rsaAAAAB3NzaC1yc2EAAAADAQABAAABAQDLksjqug/hlE29QF0YEVNydoqsHX9VeeELn1UqdZAuOYp+DBlQSBbIsb6d8quPQP8WionLFNyd7Z6bxymP7mZBE2Iu0P4G3vIhwbfMINwvAWanxnxAANSlNyeV0oDG1vjsGUGmBPlSunjoDXPvEyo4kkxBFs7dVsaLqqP/3JcxuI+RGsA8cD+JzSir4YlEOlCX96LTm83Pu9fMh8GBoGQBTiReOPm+ecakKXkrV9t7K2U1QJaFJOVGlcvhieXV3UadjfSaeKqJe3cZG8YsZZauSDrHEUwls3jtb94hRizqwokGE/gUyKRCPszefn+hV6wITcHcfGYXCmncRwljoB/D 2 | 192.0.2.2 ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAzJjWHWVDum5WukrlWTYPtPN/Ny8BTXzhHFf89vejOQukQNMPcoohjSOBkrFZXQMLQ0s/RqpTKly1omdo8TgfUE5f7rgegwPhzleuxw/Q/XJJJiiCi7KHSQv9Vs+fNlMr14VsF8JStpKei5jD/moM1Pk/q5asYtY9I4+0rJRq1KbFPR4gTGlCqZApvJWfEHlgQxwlug6zFKaVy3vG04ggvS4GREd6XQeVjAE5cPY31Yrtdgll/BETHAxvy1+ucWxiFy6BNrqPni6XSOkSZc44EEIj4TCRAQdv5nZyd2VKPQHENYLDaC9KkxllZdqNuJuXx9stRv8auwOFRnF+JSk+7Q= 3 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/godbus/dbus/introspect/call.go: -------------------------------------------------------------------------------- 1 | package introspect 2 | 3 | import ( 4 | "encoding/xml" 5 | "github.com/coreos/fleet/Godeps/_workspace/src/github.com/godbus/dbus" 6 | "strings" 7 | ) 8 | 9 | // Call calls org.freedesktop.Introspectable.Introspect on a remote object 10 | // and returns the introspection data. 11 | func Call(o *dbus.Object) (*Node, error) { 12 | var xmldata string 13 | var node Node 14 | 15 | err := o.Call("org.freedesktop.DBus.Introspectable.Introspect", 0).Store(&xmldata) 16 | if err != nil { 17 | return nil, err 18 | } 19 | err = xml.NewDecoder(strings.NewReader(xmldata)).Decode(&node) 20 | if err != nil { 21 | return nil, err 22 | } 23 | if node.Name == "" { 24 | node.Name = string(o.Path()) 25 | } 26 | return &node, nil 27 | } 28 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/godbus/dbus/transport_unixcred_linux.go: -------------------------------------------------------------------------------- 1 | // The UnixCredentials system call is currently only implemented on Linux 2 | // http://golang.org/src/pkg/syscall/sockcmsg_linux.go 3 | // https://golang.org/s/go1.4-syscall 4 | // http://code.google.com/p/go/source/browse/unix/sockcmsg_linux.go?repo=sys 5 | 6 | package dbus 7 | 8 | import ( 9 | "io" 10 | "os" 11 | "syscall" 12 | ) 13 | 14 | func (t *unixTransport) SendNullByte() error { 15 | ucred := &syscall.Ucred{Pid: int32(os.Getpid()), Uid: uint32(os.Getuid()), Gid: uint32(os.Getgid())} 16 | b := syscall.UnixCredentials(ucred) 17 | _, oobn, err := t.UnixConn.WriteMsgUnix([]byte{0}, b, nil) 18 | if err != nil { 19 | return err 20 | } 21 | if oobn != len(b) { 22 | return io.ErrShortWrite 23 | } 24 | return nil 25 | } 26 | -------------------------------------------------------------------------------- /fixtures/authorized_keys: -------------------------------------------------------------------------------- 1 | ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDMmq9hew++XUyYKDRIuq4K3VaVJUaE76LscrJ4Ov+UPJ0nTm0/VH2z0eOX9fQijmZ3c0/uMN03bdTfZG2w4TLYwxkgtIgch6nYG540oeKGHfcx3D/LYQ1isTwlLFelSAnDjaIsiLmxv0XHc4lojhLEtjf1OyHMf06snQscizYTmin29/7qSehf9WBEAPxdMuBGWYMi4yHnDn0cT4b7iowzZ+LQFjhZDthz2WTdSqofHbjPQSLGm65IotCJh8WRROKYPVLqnlZtQV7ntkzxsDSVpv5gsGMfZpuF1LGkQ89p/dCvpShoiklORMDA0Stm0wSemoKkwWvaYTbiyj1ZreXl yicheng.qin@coreos.com 2 | ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA6NF8iallvQVp22WDkTkyrtvp9eWW6A8YVr+kz4TjGYe7gHzIw+niNltGEFHzD8+v1I2YJ6oXevct1YeS0o9HZyN1Q9qgCgzUFtdOKLv6IedplqoPkcmF0aYet2PkEDo3MlTBckFXPITAMzF8dJSIFo9D8HfdOV0IAdx4O7PtixWKn5y2hMNG0zQPyUecp4pzC6kivAIhyfHilFR61RGL+GPXQ2MWZWFYbAGjyiYJnAmCP3NOTd0jMZEnDkbUvxhMmBYSdETk1rRgm+R4LOzFUGaHqHDLKLX+FIPKcF96hrucXzcWyLbIbEgE98OHlnVYCzRdK8jlqm8tehUc9c9WhQ== vagrant insecure public key 3 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/coreos/go-systemd/unit/option.go: -------------------------------------------------------------------------------- 1 | package unit 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | type UnitOption struct { 8 | Section string 9 | Name string 10 | Value string 11 | } 12 | 13 | func (uo *UnitOption) String() string { 14 | return fmt.Sprintf("{Section: %q, Name: %q, Value: %q}", uo.Section, uo.Name, uo.Value) 15 | } 16 | 17 | func (uo *UnitOption) Match(other *UnitOption) bool { 18 | return uo.Section == other.Section && 19 | uo.Name == other.Name && 20 | uo.Value == other.Value 21 | } 22 | 23 | func AllMatch(u1 []*UnitOption, u2 []*UnitOption) bool { 24 | length := len(u1) 25 | if length != len(u2) { 26 | return false 27 | } 28 | 29 | for i := 0; i < length; i++ { 30 | if !u1[i].Match(u2[i]) { 31 | return false 32 | } 33 | } 34 | 35 | return true 36 | } 37 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/golang.org/x/crypto/ssh/doc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | /* 6 | Package ssh implements an SSH client and server. 7 | 8 | SSH is a transport security protocol, an authentication protocol and a 9 | family of application protocols. The most typical application level 10 | protocol is a remote shell and this is specifically implemented. However, 11 | the multiplexed nature of SSH is exposed to users that wish to support 12 | others. 13 | 14 | References: 15 | [PROTOCOL.certkeys]: http://www.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/PROTOCOL.certkeys 16 | [SSH-PARAMETERS]: http://www.iana.org/assignments/ssh-parameters/ssh-parameters.xml#ssh-parameters-1 17 | */ 18 | package ssh 19 | -------------------------------------------------------------------------------- /machine/fake.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 CoreOS, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package machine 18 | 19 | type FakeMachine struct { 20 | MachineState MachineState 21 | } 22 | 23 | func (fm *FakeMachine) State() MachineState { 24 | return fm.MachineState 25 | } 26 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/godbus/dbus/transport_generic.go: -------------------------------------------------------------------------------- 1 | package dbus 2 | 3 | import ( 4 | "encoding/binary" 5 | "errors" 6 | "io" 7 | ) 8 | 9 | type genericTransport struct { 10 | io.ReadWriteCloser 11 | } 12 | 13 | func (t genericTransport) SendNullByte() error { 14 | _, err := t.Write([]byte{0}) 15 | return err 16 | } 17 | 18 | func (t genericTransport) SupportsUnixFDs() bool { 19 | return false 20 | } 21 | 22 | func (t genericTransport) EnableUnixFDs() {} 23 | 24 | func (t genericTransport) ReadMessage() (*Message, error) { 25 | return DecodeMessage(t) 26 | } 27 | 28 | func (t genericTransport) SendMessage(msg *Message) error { 29 | for _, v := range msg.Body { 30 | if _, ok := v.(UnixFD); ok { 31 | return errors.New("dbus: unix fd passing not enabled") 32 | } 33 | } 34 | return msg.EncodeTo(t, binary.LittleEndian) 35 | } 36 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/godbus/dbus/homedir_static.go: -------------------------------------------------------------------------------- 1 | // +build static_build 2 | 3 | package dbus 4 | 5 | import ( 6 | "bufio" 7 | "os" 8 | "strconv" 9 | "strings" 10 | ) 11 | 12 | func lookupHomeDir() string { 13 | myUid := os.Getuid() 14 | 15 | f, err := os.Open("/etc/passwd") 16 | if err != nil { 17 | return "/" 18 | } 19 | defer f.Close() 20 | 21 | s := bufio.NewScanner(f) 22 | 23 | for s.Scan() { 24 | if err := s.Err(); err != nil { 25 | break 26 | } 27 | 28 | line := strings.TrimSpace(s.Text()) 29 | if line == "" { 30 | continue 31 | } 32 | 33 | parts := strings.Split(line, ":") 34 | 35 | if len(parts) >= 6 { 36 | uid, err := strconv.Atoi(parts[2]) 37 | if err == nil && uid == myUid { 38 | return parts[5] 39 | } 40 | } 41 | } 42 | 43 | // Default to / if we can't get a better value 44 | return "/" 45 | } 46 | -------------------------------------------------------------------------------- /pkg/backoff.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 CoreOS, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package pkg 18 | 19 | import ( 20 | "time" 21 | ) 22 | 23 | func ExpBackoff(last time.Duration, max time.Duration) (next time.Duration) { 24 | next = last * 2 25 | if next > max { 26 | next = max 27 | } 28 | return 29 | } 30 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/coreos/go-systemd/dbus/set_test.go: -------------------------------------------------------------------------------- 1 | package dbus 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | // TestBasicSetActions asserts that Add & Remove behavior is correct 8 | func TestBasicSetActions(t *testing.T) { 9 | s := newSet() 10 | 11 | if s.Contains("foo") { 12 | t.Fatal("set should not contain 'foo'") 13 | } 14 | 15 | s.Add("foo") 16 | 17 | if !s.Contains("foo") { 18 | t.Fatal("set should contain 'foo'") 19 | } 20 | 21 | v := s.Values() 22 | if len(v) != 1 { 23 | t.Fatal("set.Values did not report correct number of values") 24 | } 25 | if v[0] != "foo" { 26 | t.Fatal("set.Values did not report value") 27 | } 28 | 29 | s.Remove("foo") 30 | 31 | if s.Contains("foo") { 32 | t.Fatal("set should not contain 'foo'") 33 | } 34 | 35 | v = s.Values() 36 | if len(v) != 0 { 37 | t.Fatal("set.Values did not report correct number of values") 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/google.golang.org/api/google-api-go-generator/testdata/arrayofmapofstrings.json: -------------------------------------------------------------------------------- 1 | { 2 | "kind": "discovery#restDescription", 3 | "etag": "\"kEk3sFj6Ef5_yR1-H3bAO6qw9mI/3m5rB86FE5KuW1K3jAl88AxCreg\"", 4 | "discoveryVersion": "v1", 5 | "id": "arrayofmapofstrings:v1", 6 | "name": "arrayofmapofstrings", 7 | "version": "v1", 8 | "title": "Example API", 9 | "description": "The Example API demonstrates an array of arrays.", 10 | "ownerDomain": "google.com", 11 | "ownerName": "Google", 12 | "protocol": "rest", 13 | "schemas": { 14 | "Analyze": { 15 | "id": "Analyze", 16 | "type": "object", 17 | "properties": { 18 | "errors": { 19 | "type": "array", 20 | "description": "List of errors with the data.", 21 | "items": { 22 | "type": "object", 23 | "additionalProperties": { 24 | "type": "string", 25 | "description": "Error level followed by a detailed error message." 26 | } 27 | } 28 | } 29 | } 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/google.golang.org/api/google-api-go-generator/testdata/arrayofmapofobjects.json: -------------------------------------------------------------------------------- 1 | { 2 | "kind": "discovery#restDescription", 3 | "etag": "\"kEk3sFj6Ef5_yR1-H3bAO6qw9mI/3m5rB86FE5KuW1K3jAl88AxCreg\"", 4 | "discoveryVersion": "v1", 5 | "id": "arrayofmapofstrings:v1", 6 | "name": "arrayofmapofstrings", 7 | "version": "v1", 8 | "title": "Example API", 9 | "description": "The Example API demonstrates an array of arrays.", 10 | "ownerDomain": "google.com", 11 | "ownerName": "Google", 12 | "protocol": "rest", 13 | "schemas": { 14 | "Analyze": { 15 | "id": "Analyze", 16 | "type": "object", 17 | "properties": { 18 | "errors": { 19 | "type": "array", 20 | "description": "List of errors with the data.", 21 | "items": { 22 | "type": "object", 23 | "additionalProperties": { 24 | "$ref": "Property", 25 | "description": "Error level followed by a detailed error message." 26 | } 27 | } 28 | } 29 | } 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /machine/fake_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 CoreOS, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package machine 18 | 19 | import ( 20 | "reflect" 21 | "testing" 22 | ) 23 | 24 | func TestFakeMachine(t *testing.T) { 25 | ms := MachineState{ID: "XXX"} 26 | fm := FakeMachine{ms} 27 | 28 | ret := fm.State() 29 | if !reflect.DeepEqual(ms, ret) { 30 | t.Fatalf("FakeMachine.State() returned %v, expected %v", ret, ms) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /pkg/args.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 CoreOS, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package pkg 18 | 19 | // TrimToDashes takes a slice of strings (e.g. a 20 | // command line) and returns everything after the first 21 | // double dash (--), if any are present 22 | func TrimToDashes(args []string) []string { 23 | for i, arg := range args { 24 | if arg == "--" { 25 | return args[i+1:] 26 | } 27 | } 28 | return args 29 | } 30 | -------------------------------------------------------------------------------- /fleetctl/verify.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 CoreOS, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | var cmdVerifyUnit = &Command{ 20 | Name: "verify", 21 | Summary: "DEPRECATED - No longer works", 22 | Usage: "UNIT", 23 | Run: runVerifyUnit, 24 | } 25 | 26 | func runVerifyUnit(args []string) (exit int) { 27 | stderr("WARNING: The signed/verified units feature is DEPRECATED and cannot be used.") 28 | return 2 29 | } 30 | -------------------------------------------------------------------------------- /version/version.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 CoreOS, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package version 18 | 19 | import ( 20 | "github.com/coreos/fleet/Godeps/_workspace/src/github.com/coreos/go-semver/semver" 21 | ) 22 | 23 | const Version = "0.9.0+git" 24 | 25 | var SemVersion semver.Version 26 | 27 | func init() { 28 | sv, err := semver.NewVersion(Version) 29 | if err != nil { 30 | panic("bad version string!") 31 | } 32 | SemVersion = *sv 33 | } 34 | -------------------------------------------------------------------------------- /unit/manager.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 CoreOS, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package unit 18 | 19 | import ( 20 | "github.com/coreos/fleet/pkg" 21 | ) 22 | 23 | type UnitManager interface { 24 | Load(string, UnitFile) error 25 | Unload(string) 26 | 27 | TriggerStart(string) 28 | TriggerStop(string) 29 | 30 | Units() ([]string, error) 31 | GetUnitStates(pkg.Set) (map[string]*UnitState, error) 32 | GetUnitState(string) (*UnitState, error) 33 | } 34 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/golang.org/x/crypto/ssh/test/tcpip_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build !windows 6 | 7 | package test 8 | 9 | // direct-tcpip functional tests 10 | 11 | import ( 12 | "io" 13 | "net" 14 | "testing" 15 | ) 16 | 17 | func TestDial(t *testing.T) { 18 | server := newServer(t) 19 | defer server.Shutdown() 20 | sshConn := server.Dial(clientConfig()) 21 | defer sshConn.Close() 22 | 23 | l, err := net.Listen("tcp", "127.0.0.1:0") 24 | if err != nil { 25 | t.Fatalf("Listen: %v", err) 26 | } 27 | defer l.Close() 28 | 29 | go func() { 30 | for { 31 | c, err := l.Accept() 32 | if err != nil { 33 | break 34 | } 35 | 36 | io.WriteString(c, c.RemoteAddr().String()) 37 | c.Close() 38 | } 39 | }() 40 | 41 | conn, err := sshConn.Dial("tcp", l.Addr().String()) 42 | if err != nil { 43 | t.Fatalf("Dial: %v", err) 44 | } 45 | defer conn.Close() 46 | } 47 | -------------------------------------------------------------------------------- /fleetctl/version.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 CoreOS, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "github.com/coreos/fleet/version" 21 | ) 22 | 23 | var cmdVersion = &Command{ 24 | Name: "version", 25 | Description: "Print the version and exit", 26 | Summary: "Print the version and exit", 27 | Run: runVersion, 28 | } 29 | 30 | func runVersion(args []string) (exit int) { 31 | stdout("fleetctl version %s", version.Version) 32 | return 33 | } 34 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/godbus/dbus/examples_test.go: -------------------------------------------------------------------------------- 1 | package dbus 2 | 3 | import "fmt" 4 | 5 | func ExampleConn_Emit() { 6 | conn, err := SessionBus() 7 | if err != nil { 8 | panic(err) 9 | } 10 | 11 | conn.Emit("/foo/bar", "foo.bar.Baz", uint32(0xDAEDBEEF)) 12 | } 13 | 14 | func ExampleObject_Call() { 15 | var list []string 16 | 17 | conn, err := SessionBus() 18 | if err != nil { 19 | panic(err) 20 | } 21 | 22 | err = conn.BusObject().Call("org.freedesktop.DBus.ListNames", 0).Store(&list) 23 | if err != nil { 24 | panic(err) 25 | } 26 | for _, v := range list { 27 | fmt.Println(v) 28 | } 29 | } 30 | 31 | func ExampleObject_Go() { 32 | conn, err := SessionBus() 33 | if err != nil { 34 | panic(err) 35 | } 36 | 37 | ch := make(chan *Call, 10) 38 | conn.BusObject().Go("org.freedesktop.DBus.ListActivatableNames", 0, ch) 39 | select { 40 | case call := <-ch: 41 | if call.Err != nil { 42 | panic(err) 43 | } 44 | list := call.Body[0].([]string) 45 | for _, v := range list { 46 | fmt.Println(v) 47 | } 48 | // put some other cases here 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /client/api.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 CoreOS, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package client 18 | 19 | import ( 20 | "github.com/coreos/fleet/machine" 21 | "github.com/coreos/fleet/schema" 22 | ) 23 | 24 | type API interface { 25 | Machines() ([]machine.MachineState, error) 26 | 27 | Unit(string) (*schema.Unit, error) 28 | Units() ([]*schema.Unit, error) 29 | UnitStates() ([]*schema.UnitState, error) 30 | 31 | SetUnitTargetState(name, target string) error 32 | CreateUnit(*schema.Unit) error 33 | DestroyUnit(string) error 34 | } 35 | -------------------------------------------------------------------------------- /scripts/build-release: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | function usage { 4 | echo "Usage: $0 " 5 | exit 1 6 | } 7 | 8 | function build { 9 | proj=${1} 10 | ver=${2} 11 | 12 | if [ ! -d ${proj} ]; then 13 | git clone https://github.com/coreos/${proj} 14 | fi 15 | 16 | cd ${proj} 17 | git checkout master 18 | git fetch --all 19 | git reset --hard origin/master 20 | git checkout $ver 21 | ./build 22 | cd - 23 | } 24 | 25 | function package { 26 | proj=${1} 27 | target=${2} 28 | 29 | ccdir="${proj}/bin/${GOOS}_${GOARCH}" 30 | if [ -d ${ccdir} ]; then 31 | cp ${ccdir}/${proj}* ${target} 32 | else 33 | cp ${proj}/bin/${proj}* ${target} 34 | fi 35 | 36 | cp ${proj}/README.md ${target}/README.md 37 | } 38 | 39 | VER=$1 40 | GOOS=$2 41 | 42 | GOARCH="amd64" 43 | 44 | if [ "$GOOS" == "" ]; then 45 | usage 46 | fi 47 | 48 | build fleet ${VER} 49 | 50 | TARGET="fleet-${VER}-${GOOS}-${GOARCH}" 51 | mkdir ${TARGET} 52 | 53 | package fleet ${TARGET} 54 | 55 | if [ ${GOOS} == "linux" ]; then 56 | tar cvvfz ${TARGET}.tar.gz ${TARGET} 57 | else 58 | zip -r ${TARGET}.zip ${TARGET} 59 | fi 60 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/google.golang.org/api/google-api-go-generator/testdata/mapofobjects.json: -------------------------------------------------------------------------------- 1 | { 2 | "kind": "discovery#restDescription", 3 | "etag": "\"kEk3sFj6Ef5_yR1-H3bAO6qw9mI/3m5rB86FE5KuW1K3jAl88AxCreg\"", 4 | "discoveryVersion": "v1", 5 | "id": "additionalpropsobjs:v1", 6 | "name": "additionalpropsobjs", 7 | "version": "v1", 8 | "title": "Example API", 9 | "description": "The Example API demonstrates an associative array.", 10 | "ownerDomain": "google.com", 11 | "ownerName": "Google", 12 | "protocol": "rest", 13 | "schemas": { 14 | "Entity": { 15 | "id": "Entity", 16 | "type": "object", 17 | "externalTypeName": "apphosting.client.datastoreservice.proto.Entity", 18 | "properties": { 19 | "properties": { 20 | "type": "object", 21 | "description": "The entity's properties.", 22 | "additionalProperties": { 23 | "$ref": "Property", 24 | "description": "The name of the property. Properties with names matching regex \"__.*__\" are reserved. A reserved property name is forbidden in certain documented contexts. The name cannot be \"\"." 25 | } 26 | } 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/jonboulle/clockwork/example_test.go: -------------------------------------------------------------------------------- 1 | package clockwork 2 | 3 | import ( 4 | "sync" 5 | "testing" 6 | "time" 7 | ) 8 | 9 | // my_func is an example of a time-dependent function, using an 10 | // injected clock 11 | func my_func(clock Clock, i *int) { 12 | clock.Sleep(3 * time.Second) 13 | *i += 1 14 | } 15 | 16 | // assert_state is an example of a state assertion in a test 17 | func assert_state(t *testing.T, i, j int) { 18 | if i != j { 19 | t.Fatalf("i %d, j %d", i, j) 20 | } 21 | } 22 | 23 | // TestMyFunc tests my_func's behaviour with a FakeClock 24 | func TestMyFunc(t *testing.T) { 25 | var i int 26 | c := NewFakeClock() 27 | 28 | var wg sync.WaitGroup 29 | wg.Add(1) 30 | go func() { 31 | my_func(c, &i) 32 | wg.Done() 33 | }() 34 | 35 | // Wait until my_func is actually sleeping on the clock 36 | c.BlockUntil(1) 37 | 38 | // Assert the initial state 39 | assert_state(t, i, 0) 40 | 41 | // Now advance the clock forward in time 42 | c.Advance(1 * time.Hour) 43 | 44 | // Wait until the function completes 45 | wg.Wait() 46 | 47 | // Assert the final state 48 | assert_state(t, i, 1) 49 | } 50 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/coreos/go-systemd/unit/serialize.go: -------------------------------------------------------------------------------- 1 | package unit 2 | 3 | import ( 4 | "bytes" 5 | "io" 6 | ) 7 | 8 | // Serialize encodes all of the given UnitOption objects into a unit file 9 | func Serialize(opts []*UnitOption) io.Reader { 10 | var buf bytes.Buffer 11 | 12 | if len(opts) == 0 { 13 | return &buf 14 | } 15 | 16 | curSection := opts[0].Section 17 | 18 | writeSectionHeader(&buf, curSection) 19 | writeNewline(&buf) 20 | 21 | for _, opt := range opts { 22 | if opt.Section != curSection { 23 | curSection = opt.Section 24 | 25 | writeNewline(&buf) 26 | writeSectionHeader(&buf, curSection) 27 | writeNewline(&buf) 28 | } 29 | 30 | writeOption(&buf, opt) 31 | writeNewline(&buf) 32 | } 33 | 34 | return &buf 35 | } 36 | 37 | func writeNewline(buf *bytes.Buffer) { 38 | buf.WriteRune('\n') 39 | } 40 | 41 | func writeSectionHeader(buf *bytes.Buffer, section string) { 42 | buf.WriteRune('[') 43 | buf.WriteString(section) 44 | buf.WriteRune(']') 45 | } 46 | 47 | func writeOption(buf *bytes.Buffer, opt *UnitOption) { 48 | buf.WriteString(opt.Name) 49 | buf.WriteRune('=') 50 | buf.WriteString(opt.Value) 51 | } 52 | -------------------------------------------------------------------------------- /pkg/http.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 CoreOS, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package pkg 18 | 19 | import ( 20 | "net/http" 21 | 22 | "github.com/coreos/fleet/log" 23 | ) 24 | 25 | type LoggingHTTPTransport struct { 26 | http.Transport 27 | } 28 | 29 | func (lt *LoggingHTTPTransport) RoundTrip(req *http.Request) (resp *http.Response, err error) { 30 | log.V(1).Infof("HTTP %s %s", req.Method, req.URL.String()) 31 | resp, err = lt.Transport.RoundTrip(req) 32 | if err == nil { 33 | log.V(1).Infof("HTTP %s %s %s", req.Method, req.URL.String(), resp.Status) 34 | } 35 | return 36 | } 37 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/golang.org/x/crypto/ssh/client_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package ssh 6 | 7 | import ( 8 | "net" 9 | "testing" 10 | ) 11 | 12 | func testClientVersion(t *testing.T, config *ClientConfig, expected string) { 13 | clientConn, serverConn := net.Pipe() 14 | defer clientConn.Close() 15 | receivedVersion := make(chan string, 1) 16 | go func() { 17 | version, err := readVersion(serverConn) 18 | if err != nil { 19 | receivedVersion <- "" 20 | } else { 21 | receivedVersion <- string(version) 22 | } 23 | serverConn.Close() 24 | }() 25 | NewClientConn(clientConn, "", config) 26 | actual := <-receivedVersion 27 | if actual != expected { 28 | t.Fatalf("got %s; want %s", actual, expected) 29 | } 30 | } 31 | 32 | func TestCustomClientVersion(t *testing.T) { 33 | version := "Test-Client-Version-0.0" 34 | testClientVersion(t, &ClientConfig{ClientVersion: version}, version) 35 | } 36 | 37 | func TestDefaultClientVersion(t *testing.T) { 38 | testClientVersion(t, &ClientConfig{}, packageVersion) 39 | } 40 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/google.golang.org/api/googleapi/internal/uritemplates/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 Joshua Tacoma 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software is furnished to do so, 8 | subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 15 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 16 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 17 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 18 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 19 | -------------------------------------------------------------------------------- /scripts/bump-release: -------------------------------------------------------------------------------- 1 | #!/bin/bash -eu 2 | # 3 | # $1 = version string (e.g. 0.8.0) 4 | # $2 = remote configured to track github.com/coreos/fleet (defaults to "origin" if unset) 5 | 6 | VERSION="${1:?version must be set}" 7 | if [ "${VERSION:0:1}" == "v" ]; then 8 | echo "version tag shouldn't start with v" >> /dev/stderr 9 | exit 255 10 | fi 11 | REMOTE="${2:-origin}" 12 | VERSIONTAG="v${VERSION}" 13 | 14 | MASTERBR="v${VERSION}-master" 15 | TAGBR="v${VERSION}-branch" 16 | 17 | replace_version() { 18 | sed -i -e "s/const Version.*/const Version = \"$1\"/" version/version.go 19 | git commit -m "version: bump to v$1" version/version.go 20 | } 21 | 22 | # set up a new branch tracking the latest origin 23 | git fetch ${REMOTE} 24 | git checkout -b ${MASTERBR} ${REMOTE}/master 25 | 26 | # set up our local branch for the tag and bump the version 27 | git checkout -b ${TAGBR} ${REMOTE}/master 28 | replace_version ${VERSION} 29 | git tag -s -m "${VERSIONTAG}" "${VERSIONTAG}" 30 | git push "${REMOTE}" "${VERSIONTAG}" 31 | 32 | # return to the clean master and bump the version 33 | git checkout "${MASTERBR}" 34 | git branch -D "${TAGBR}" 35 | replace_version "${VERSION}+git" 36 | git push "${REMOTE}" "${MASTERBR}":master 37 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/google.golang.org/api/googleapi/transport/apikey.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Package transport contains HTTP transports used to make 6 | // authenticated API requests. 7 | package transport 8 | 9 | import ( 10 | "errors" 11 | "net/http" 12 | ) 13 | 14 | // APIKey is an HTTP Transport which wraps an underlying transport and 15 | // appends an API Key "key" parameter to the URL of outgoing requests. 16 | type APIKey struct { 17 | // Key is the API Key to set on requests. 18 | Key string 19 | 20 | // Transport is the underlying HTTP transport. 21 | // If nil, http.DefaultTransport is used. 22 | Transport http.RoundTripper 23 | } 24 | 25 | func (t *APIKey) RoundTrip(req *http.Request) (*http.Response, error) { 26 | rt := t.Transport 27 | if rt == nil { 28 | rt = http.DefaultTransport 29 | if rt == nil { 30 | return nil, errors.New("googleapi/transport: no Transport specified or available") 31 | } 32 | } 33 | newReq := *req 34 | args := newReq.URL.Query() 35 | args.Set("key", t.Key) 36 | newReq.URL.RawQuery = args.Encode() 37 | return rt.RoundTrip(&newReq) 38 | } 39 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/google.golang.org/api/googleapi/types_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package googleapi 6 | 7 | import ( 8 | "encoding/json" 9 | "reflect" 10 | "testing" 11 | ) 12 | 13 | func TestTypes(t *testing.T) { 14 | type T struct { 15 | I32 Int32s 16 | I64 Int64s 17 | U32 Uint32s 18 | U64 Uint64s 19 | F64 Float64s 20 | } 21 | v := &T{ 22 | I32: Int32s{-1, 2, 3}, 23 | I64: Int64s{-1, 2, 1 << 33}, 24 | U32: Uint32s{1, 2}, 25 | U64: Uint64s{1, 2, 1 << 33}, 26 | F64: Float64s{1.5, 3.33}, 27 | } 28 | got, err := json.Marshal(v) 29 | if err != nil { 30 | t.Fatal(err) 31 | } 32 | want := `{"I32":["-1","2","3"],"I64":["-1","2","8589934592"],"U32":["1","2"],"U64":["1","2","8589934592"],"F64":["1.5","3.33"]}` 33 | if string(got) != want { 34 | t.Fatalf("Marshal mismatch.\n got: %s\nwant: %s\n", got, want) 35 | } 36 | 37 | v2 := new(T) 38 | if err := json.Unmarshal(got, v2); err != nil { 39 | t.Fatalf("Unmarshal: %v", err) 40 | } 41 | if !reflect.DeepEqual(v, v2) { 42 | t.Fatalf("Unmarshal didn't produce same results.\n got: %#v\nwant: %#v\n", v, v2) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/golang.org/x/crypto/ssh/kex_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package ssh 6 | 7 | // Key exchange tests. 8 | 9 | import ( 10 | "crypto/rand" 11 | "reflect" 12 | "testing" 13 | ) 14 | 15 | func TestKexes(t *testing.T) { 16 | type kexResultErr struct { 17 | result *kexResult 18 | err error 19 | } 20 | 21 | for name, kex := range kexAlgoMap { 22 | a, b := memPipe() 23 | 24 | s := make(chan kexResultErr, 1) 25 | c := make(chan kexResultErr, 1) 26 | var magics handshakeMagics 27 | go func() { 28 | r, e := kex.Client(a, rand.Reader, &magics) 29 | c <- kexResultErr{r, e} 30 | }() 31 | go func() { 32 | r, e := kex.Server(b, rand.Reader, &magics, testSigners["ecdsa"]) 33 | s <- kexResultErr{r, e} 34 | }() 35 | 36 | clientRes := <-c 37 | serverRes := <-s 38 | if clientRes.err != nil { 39 | t.Errorf("client: %v", clientRes.err) 40 | } 41 | if serverRes.err != nil { 42 | t.Errorf("server: %v", serverRes.err) 43 | } 44 | if !reflect.DeepEqual(clientRes.result, serverRes.result) { 45 | t.Errorf("kex %q: mismatch %#v, %#v", name, clientRes.result, serverRes.result) 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/godbus/dbus/README.markdown: -------------------------------------------------------------------------------- 1 | dbus 2 | ---- 3 | 4 | dbus is a simple library that implements native Go client bindings for the 5 | D-Bus message bus system. 6 | 7 | ### Features 8 | 9 | * Complete native implementation of the D-Bus message protocol 10 | * Go-like API (channels for signals / asynchronous method calls, Goroutine-safe connections) 11 | * Subpackages that help with the introspection / property interfaces 12 | 13 | ### Installation 14 | 15 | This packages requires Go 1.1. If you installed it and set up your GOPATH, just run: 16 | 17 | ``` 18 | go get github.com/godbus/dbus 19 | ``` 20 | 21 | If you want to use the subpackages, you can install them the same way. 22 | 23 | ### Usage 24 | 25 | The complete package documentation and some simple examples are available at 26 | [godoc.org](http://godoc.org/github.com/godbus/dbus). Also, the 27 | [_examples](https://github.com/godbus/dbus/tree/master/_examples) directory 28 | gives a short overview over the basic usage. 29 | 30 | Please note that the API is considered unstable for now and may change without 31 | further notice. 32 | 33 | ### License 34 | 35 | go.dbus is available under the Simplified BSD License; see LICENSE for the full 36 | text. 37 | 38 | Nearly all of the credit for this library goes to github.com/guelfey/go.dbus. 39 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/godbus/dbus/transport_unix_test.go: -------------------------------------------------------------------------------- 1 | package dbus 2 | 3 | import ( 4 | "os" 5 | "testing" 6 | ) 7 | 8 | const testString = `This is a test! 9 | This text should be read from the file that is created by this test.` 10 | 11 | type unixFDTest struct{} 12 | 13 | func (t unixFDTest) Test(fd UnixFD) (string, *Error) { 14 | var b [4096]byte 15 | file := os.NewFile(uintptr(fd), "testfile") 16 | defer file.Close() 17 | n, err := file.Read(b[:]) 18 | if err != nil { 19 | return "", &Error{"com.github.guelfey.test.Error", nil} 20 | } 21 | return string(b[:n]), nil 22 | } 23 | 24 | func TestUnixFDs(t *testing.T) { 25 | conn, err := SessionBus() 26 | if err != nil { 27 | t.Fatal(err) 28 | } 29 | r, w, err := os.Pipe() 30 | if err != nil { 31 | t.Fatal(err) 32 | } 33 | defer w.Close() 34 | if _, err := w.Write([]byte(testString)); err != nil { 35 | t.Fatal(err) 36 | } 37 | name := conn.Names()[0] 38 | test := unixFDTest{} 39 | conn.Export(test, "/com/github/guelfey/test", "com.github.guelfey.test") 40 | var s string 41 | obj := conn.Object(name, "/com/github/guelfey/test") 42 | err = obj.Call("com.github.guelfey.test.Test", 0, UnixFD(r.Fd())).Store(&s) 43 | if err != nil { 44 | t.Fatal(err) 45 | } 46 | if s != testString { 47 | t.Fatal("got", s, "wanted", testString) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /scripts/schema-generator: -------------------------------------------------------------------------------- 1 | #!/bin/bash -eu 2 | 3 | IN="schema/v1.json" 4 | OUT="schema/v1-json.go" 5 | GEN="schema/v1-gen.go" 6 | 7 | # See scripts/schema_generator_import.go for instructions on updating the dependency 8 | PKG="google.golang.org/api/google-api-go-generator" 9 | 10 | # First, write the discovery document into a go file so it can be served statically by the API 11 | cat << 'EOF' > "${OUT}" 12 | package schema 13 | // 14 | // This file is automatically generated by scripts/schema-generator 15 | // 16 | // **** DO NOT EDIT **** 17 | // 18 | EOF 19 | 20 | echo -n 'const DiscoveryJSON = `' >> ${OUT} 21 | cat ${IN} >> "${OUT}" 22 | echo -n '`' >> "${OUT}" 23 | 24 | # Now build google-api-go-generator - we vendor so this is consistently reproducible 25 | GEN_PATH="bin/google-api-go-generator" 26 | if [ ! -f ${GEN_PATH} ]; then 27 | GOPATH="${PWD}/Godeps/_workspace" go build -o ${GEN_PATH} ${PKG} 28 | fi 29 | 30 | # Build the bindings 31 | GOPATH=${PWD}/gopath ./bin/google-api-go-generator \ 32 | -googleapi_pkg "google.golang.org/api/googleapi" \ 33 | -api_json_file "${IN}" \ 34 | -output "${GEN}" 35 | 36 | 37 | # Finally, fix the import in the bindings to refer to the vendored google-api package 38 | sed -i -e "s%google.golang.org%github.com/coreos/fleet/Godeps/_workspace/src/google.golang.org%" "${GEN}" 39 | goimports -w ${GEN} 40 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/google.golang.org/api/google-api-go-generator/testdata/arrayofarray-1.json: -------------------------------------------------------------------------------- 1 | { 2 | "kind": "discovery#restDescription", 3 | "etag": "\"kEk3sFj6Ef5_yR1-H3bAO6qw9mI/3m5rB86FE5KuW1K3jAl88AxCreg\"", 4 | "discoveryVersion": "v1", 5 | "id": "arrayofarray:v1", 6 | "name": "arrayofarray", 7 | "version": "v1", 8 | "title": "Example API", 9 | "description": "The Example API demonstrates an array of arrays.", 10 | "ownerDomain": "google.com", 11 | "ownerName": "Google", 12 | "protocol": "rest", 13 | "schemas": { 14 | "GeoJsonMultiPolygon": { 15 | "id": "GeoJsonMultiPolygon", 16 | "type": "object", 17 | "description": "Multi Polygon", 18 | "properties": { 19 | "coordinates": { 20 | "type": "array", 21 | "description": "Coordinate arrays.", 22 | "items": { 23 | "type": "array", 24 | "items": { 25 | "type": "array", 26 | "items": { 27 | "type": "array", 28 | "items": { 29 | "type": "number", 30 | "format": "double" 31 | } 32 | } 33 | } 34 | } 35 | }, 36 | "type": { 37 | "type": "string", 38 | "description": "Identifies this object as a multi-polygon.", 39 | "enum": [ 40 | "MultiPolygon" 41 | ], 42 | "enumDescriptions": [ 43 | "" 44 | ] 45 | } 46 | } 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/golang.org/x/crypto/ssh/mac.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package ssh 6 | 7 | // Message authentication support 8 | 9 | import ( 10 | "crypto/hmac" 11 | "crypto/sha1" 12 | "hash" 13 | ) 14 | 15 | type macMode struct { 16 | keySize int 17 | new func(key []byte) hash.Hash 18 | } 19 | 20 | // truncatingMAC wraps around a hash.Hash and truncates the output digest to 21 | // a given size. 22 | type truncatingMAC struct { 23 | length int 24 | hmac hash.Hash 25 | } 26 | 27 | func (t truncatingMAC) Write(data []byte) (int, error) { 28 | return t.hmac.Write(data) 29 | } 30 | 31 | func (t truncatingMAC) Sum(in []byte) []byte { 32 | out := t.hmac.Sum(in) 33 | return out[:len(in)+t.length] 34 | } 35 | 36 | func (t truncatingMAC) Reset() { 37 | t.hmac.Reset() 38 | } 39 | 40 | func (t truncatingMAC) Size() int { 41 | return t.length 42 | } 43 | 44 | func (t truncatingMAC) BlockSize() int { return t.hmac.BlockSize() } 45 | 46 | var macModes = map[string]*macMode{ 47 | "hmac-sha1": {20, func(key []byte) hash.Hash { 48 | return hmac.New(sha1.New, key) 49 | }}, 50 | "hmac-sha1-96": {20, func(key []byte) hash.Hash { 51 | return truncatingMAC{12, hmac.New(sha1.New, key)} 52 | }}, 53 | } 54 | -------------------------------------------------------------------------------- /heart/heart.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 CoreOS, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package heart 18 | 19 | import ( 20 | "time" 21 | 22 | "github.com/coreos/fleet/machine" 23 | "github.com/coreos/fleet/registry" 24 | ) 25 | 26 | type Heart interface { 27 | Beat(time.Duration) (uint64, error) 28 | Clear() error 29 | } 30 | 31 | func New(reg registry.Registry, mach machine.Machine) Heart { 32 | return &machineHeart{reg, mach} 33 | } 34 | 35 | type machineHeart struct { 36 | reg registry.Registry 37 | mach machine.Machine 38 | } 39 | 40 | func (h *machineHeart) Beat(ttl time.Duration) (uint64, error) { 41 | return h.reg.SetMachineState(h.mach.State(), ttl) 42 | } 43 | 44 | func (h *machineHeart) Clear() error { 45 | return h.reg.RemoveMachineState(h.mach.State().ID) 46 | } 47 | -------------------------------------------------------------------------------- /api/path.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 CoreOS, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package api 18 | 19 | import ( 20 | "path" 21 | "strings" 22 | 23 | "github.com/coreos/fleet/log" 24 | ) 25 | 26 | func isCollectionPath(base, p string) bool { 27 | return p == base 28 | } 29 | 30 | func isItemPath(base, p string) (item string, matched bool) { 31 | if strings.HasSuffix(p, "/") { 32 | return 33 | } 34 | 35 | var err error 36 | matched, err = path.Match(path.Join(base, "*"), p) 37 | // err will only be non-nil in the event that our pattern is bad, not due 38 | // to user-provided data 39 | if err != nil { 40 | log.Errorf("Failed to determine if %q is an item path: %v", p, err) 41 | matched = false 42 | } else if matched { 43 | item = path.Base(p) 44 | } 45 | 46 | return 47 | } 48 | -------------------------------------------------------------------------------- /pkg/backoff_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 CoreOS, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package pkg 18 | 19 | import ( 20 | "testing" 21 | "time" 22 | ) 23 | 24 | func TestExpBackoff(t *testing.T) { 25 | tests := []struct { 26 | last time.Duration 27 | max time.Duration 28 | next time.Duration 29 | }{ 30 | {1 * time.Second, 10 * time.Second, 2 * time.Second}, 31 | {8 * time.Second, 10 * time.Second, 10 * time.Second}, 32 | {10 * time.Second, 10 * time.Second, 10 * time.Second}, 33 | {20 * time.Second, 10 * time.Second, 10 * time.Second}, 34 | } 35 | 36 | for i, tt := range tests { 37 | next := ExpBackoff(tt.last, tt.max) 38 | if next != tt.next { 39 | t.Errorf("case %d: last=%v, max=%v, next=%v; got next=%v", i, tt.last, tt.max, tt.next, next) 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /test: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | # 3 | # Run all fleet tests (not including functional) 4 | # ./test 5 | # ./test -v 6 | # 7 | # Run tests for one package 8 | # PKG=./unit ./test 9 | # PKG=ssh ./test 10 | # 11 | 12 | # Invoke ./cover for HTML output 13 | COVER=${COVER:-"-cover"} 14 | 15 | source ./build 16 | 17 | TESTABLE="agent api config engine etcd fleetctl job machine pkg registry ssh systemd unit" 18 | FORMATTABLE="$TESTABLE client functional heart server fleetd" 19 | 20 | # user has not provided PKG override 21 | if [ -z "$PKG" ]; then 22 | TEST=$TESTABLE 23 | FMT=$FORMATTABLE 24 | 25 | # user has provided PKG override 26 | else 27 | # strip out slashes and dots from PKG=./foo/ 28 | TEST=${PKG//\//} 29 | TEST=${TEST//./} 30 | 31 | # only run gofmt on packages provided by user 32 | FMT="$TEST" 33 | fi 34 | 35 | # split TEST into an array and prepend REPO_PATH to each local package 36 | split=(${TEST// / }) 37 | TEST=${split[@]/#/${REPO_PATH}/} 38 | 39 | echo "Running tests..." 40 | go test ${COVER} $@ ${TEST} 41 | 42 | echo "Checking gofmt..." 43 | fmtRes=$(gofmt -l $FMT) 44 | if [ -n "${fmtRes}" ]; then 45 | echo -e "gofmt checking failed:\n${fmtRes}" 46 | exit 255 47 | fi 48 | 49 | echo "Checking govet..." 50 | vetRes=$(go vet $TEST) 51 | if [ -n "${vetRes}" ]; then 52 | echo -e "govet checking failed:\n${vetRes}" 53 | exit 255 54 | fi 55 | 56 | echo "Success" 57 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/golang.org/x/crypto/ssh/test/cert_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build darwin dragonfly freebsd linux netbsd openbsd 6 | 7 | package test 8 | 9 | import ( 10 | "crypto/rand" 11 | "testing" 12 | 13 | "github.com/coreos/fleet/Godeps/_workspace/src/golang.org/x/crypto/ssh" 14 | ) 15 | 16 | func TestCertLogin(t *testing.T) { 17 | s := newServer(t) 18 | defer s.Shutdown() 19 | 20 | // Use a key different from the default. 21 | clientKey := testSigners["dsa"] 22 | caAuthKey := testSigners["ecdsa"] 23 | cert := &ssh.Certificate{ 24 | Key: clientKey.PublicKey(), 25 | ValidPrincipals: []string{username()}, 26 | CertType: ssh.UserCert, 27 | ValidBefore: ssh.CertTimeInfinity, 28 | } 29 | if err := cert.SignCert(rand.Reader, caAuthKey); err != nil { 30 | t.Fatalf("SetSignature: %v", err) 31 | } 32 | 33 | certSigner, err := ssh.NewCertSigner(cert, clientKey) 34 | if err != nil { 35 | t.Fatalf("NewCertSigner: %v", err) 36 | } 37 | 38 | conf := &ssh.ClientConfig{ 39 | User: username(), 40 | } 41 | conf.Auth = append(conf.Auth, ssh.PublicKeys(certSigner)) 42 | client, err := s.TryDial(conf) 43 | if err != nil { 44 | t.Fatalf("TryDial: %v", err) 45 | } 46 | client.Close() 47 | } 48 | -------------------------------------------------------------------------------- /fleet.conf.sample: -------------------------------------------------------------------------------- 1 | # This config file is INI-formatted 2 | 3 | # Lower the logging threshold. Acceptable values are 0, 1, and 2. A higher 4 | # value corresponds to a lower logging threshold. 5 | # verbosity=0 6 | 7 | # Provide a custom set of etcd endpoints. The default value is determined 8 | # by the underlying go-etcd library. 9 | # etcd_servers=["http://127.0.0.1:4001"] 10 | 11 | # Amount of time in seconds to allow a single etcd request before considering it failed. 12 | # etcd_request_timeout=1.0 13 | 14 | # Provide TLS configuration when SSL certificate authentication is enabled in etcd endpoints 15 | # etcd_cafile=/path/to/CAfile 16 | # etcd_keyfile=/path/to/keyfile 17 | # etcd_certfile=/path/to/certfile 18 | 19 | # IP address that should be published with any socket information. By default, 20 | # no IP address is published. 21 | # public_ip="" 22 | 23 | # Comma-delimited key/value pairs that are published to the fleet registry. 24 | # This data can be referenced in unit files to affect scheduling decisions. 25 | # An example could look like: metadata="region=us-west,az=us-west-1" 26 | # metadata="" 27 | 28 | # An Agent will be considered dead if it exceeds this amount of time to 29 | # communicate with the Registry. The agent will attempt a heartbeat at half 30 | # of this value. 31 | # agent_ttl="30s" 32 | 33 | # Interval at which the engine should reconcile the cluster schedule in etcd. 34 | # engine_reconcile_interval=2 35 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/godbus/dbus/sig_test.go: -------------------------------------------------------------------------------- 1 | package dbus 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | var sigTests = []struct { 8 | vs []interface{} 9 | sig Signature 10 | }{ 11 | { 12 | []interface{}{new(int32)}, 13 | Signature{"i"}, 14 | }, 15 | { 16 | []interface{}{new(string)}, 17 | Signature{"s"}, 18 | }, 19 | { 20 | []interface{}{new(Signature)}, 21 | Signature{"g"}, 22 | }, 23 | { 24 | []interface{}{new([]int16)}, 25 | Signature{"an"}, 26 | }, 27 | { 28 | []interface{}{new(int16), new(uint32)}, 29 | Signature{"nu"}, 30 | }, 31 | { 32 | []interface{}{new(map[byte]Variant)}, 33 | Signature{"a{yv}"}, 34 | }, 35 | { 36 | []interface{}{new(Variant), new([]map[int32]string)}, 37 | Signature{"vaa{is}"}, 38 | }, 39 | } 40 | 41 | func TestSig(t *testing.T) { 42 | for i, v := range sigTests { 43 | sig := SignatureOf(v.vs...) 44 | if sig != v.sig { 45 | t.Errorf("test %d: got %q, expected %q", i+1, sig.str, v.sig.str) 46 | } 47 | } 48 | } 49 | 50 | var getSigTest = []interface{}{ 51 | []struct { 52 | b byte 53 | i int32 54 | t uint64 55 | s string 56 | }{}, 57 | map[string]Variant{}, 58 | } 59 | 60 | func BenchmarkGetSignatureSimple(b *testing.B) { 61 | for i := 0; i < b.N; i++ { 62 | SignatureOf("", int32(0)) 63 | } 64 | } 65 | 66 | func BenchmarkGetSignatureLong(b *testing.B) { 67 | for i := 0; i < b.N; i++ { 68 | SignatureOf(getSigTest...) 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/godbus/dbus/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013, Georg Reinke () 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, 9 | this list of conditions and the following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright 12 | notice, this list of conditions and the following disclaimer in the 13 | documentation and/or other materials provided with the distribution. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 19 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 21 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 22 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 23 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 24 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /etcd/error.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 CoreOS, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package etcd 18 | 19 | import ( 20 | "encoding/json" 21 | "fmt" 22 | "net/http" 23 | ) 24 | 25 | const ( 26 | ErrorKeyNotFound = 100 27 | ErrorNodeExist = 105 28 | ErrorEventIndexCleared = 401 29 | ) 30 | 31 | type Error struct { 32 | ErrorCode int `json:"errorCode"` 33 | Message string `json:"message"` 34 | Cause string `json:"cause"` 35 | Index uint64 `json:"index"` 36 | } 37 | 38 | func (e Error) Error() string { 39 | return fmt.Sprintf("%v: %v (%v) [%v]", e.ErrorCode, e.Message, e.Cause, e.Index) 40 | } 41 | 42 | func unmarshalFailedResponse(resp *http.Response, body []byte) (*Result, error) { 43 | var etcdErr Error 44 | err := json.Unmarshal(body, &etcdErr) 45 | if err != nil { 46 | return nil, err 47 | } 48 | 49 | return nil, etcdErr 50 | } 51 | -------------------------------------------------------------------------------- /pkg/filesystem.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 CoreOS, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package pkg 18 | 19 | import ( 20 | "io/ioutil" 21 | ) 22 | 23 | // ListDirectory generates a slice of all the file names that both exist in 24 | // the provided directory and pass the filter. 25 | // The returned file names are relative to the directory argument. 26 | // filterFunc is called once for each file found in the directory. If 27 | // filterFunc returns true, the given file will ignored. 28 | func ListDirectory(dir string, filterFunc func(string) bool) ([]string, error) { 29 | fis, err := ioutil.ReadDir(dir) 30 | if err != nil { 31 | return nil, err 32 | } 33 | 34 | units := make([]string, 0) 35 | for _, fi := range fis { 36 | name := fi.Name() 37 | if filterFunc(name) { 38 | continue 39 | } 40 | units = append(units, name) 41 | } 42 | 43 | return units, nil 44 | } 45 | -------------------------------------------------------------------------------- /config/config_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 CoreOS, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package config 18 | 19 | import ( 20 | "testing" 21 | ) 22 | 23 | func TestConfigMetadata(t *testing.T) { 24 | raw := "foo=bar, ping=pong" 25 | cfg := Config{RawMetadata: raw} 26 | metadata := cfg.Metadata() 27 | 28 | if len(metadata) != 2 { 29 | t.Errorf("Parsed %d keys, expected 1", len(metadata)) 30 | } 31 | 32 | if metadata["foo"] != "bar" { 33 | t.Errorf("Incorrect value '%s' of key 'foo', expected 'bar'", metadata["foo"]) 34 | } 35 | 36 | if metadata["ping"] != "pong" { 37 | t.Errorf("Incorrect value '%s' of key 'ping', expected 'pong'", metadata["ping"]) 38 | } 39 | } 40 | 41 | func TestConfigMetadataNotSet(t *testing.T) { 42 | cfg := Config{} 43 | metadata := cfg.Metadata() 44 | 45 | if len(metadata) != 0 { 46 | t.Errorf("Parsed %d keys, expected 0", len(metadata)) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /fleetctl/destroy.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 CoreOS, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | var cmdDestroyUnit = &Command{ 20 | Name: "destroy", 21 | Summary: "Destroy one or more units in the cluster", 22 | Usage: "UNIT...", 23 | Description: `Completely remove one or more running or submitted units from the cluster. 24 | 25 | Instructs systemd on the host machine to stop the unit, deferring to systemd 26 | completely for any custom stop directives (i.e. ExecStop option in the unit 27 | file). 28 | 29 | Destroyed units are impossible to start unless re-submitted.`, 30 | Run: runDestroyUnits, 31 | } 32 | 33 | func runDestroyUnits(args []string) (exit int) { 34 | for _, v := range args { 35 | name := unitNameMangle(v) 36 | err := cAPI.DestroyUnit(name) 37 | if err != nil { 38 | continue 39 | } 40 | 41 | stdout("Destroyed %s", name) 42 | } 43 | return 44 | } 45 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/coreos/go-systemd/dbus/subscription_set_test.go: -------------------------------------------------------------------------------- 1 | package dbus 2 | 3 | import ( 4 | "testing" 5 | "time" 6 | ) 7 | 8 | // TestSubscribeUnit exercises the basics of subscription of a particular unit. 9 | func TestSubscriptionSetUnit(t *testing.T) { 10 | target := "subscribe-events-set.service" 11 | 12 | conn, err := New() 13 | 14 | if err != nil { 15 | t.Fatal(err) 16 | } 17 | 18 | err = conn.Subscribe() 19 | if err != nil { 20 | t.Fatal(err) 21 | } 22 | 23 | subSet := conn.NewSubscriptionSet() 24 | evChan, errChan := subSet.Subscribe() 25 | 26 | subSet.Add(target) 27 | setupUnit(target, conn, t) 28 | linkUnit(target, conn, t) 29 | 30 | reschan := make(chan string) 31 | _, err = conn.StartUnit(target, "replace", reschan) 32 | if err != nil { 33 | t.Fatal(err) 34 | } 35 | 36 | job := <-reschan 37 | if job != "done" { 38 | t.Fatal("Couldn't start", target) 39 | } 40 | 41 | timeout := make(chan bool, 1) 42 | go func() { 43 | time.Sleep(3 * time.Second) 44 | close(timeout) 45 | }() 46 | 47 | for { 48 | select { 49 | case changes := <-evChan: 50 | tCh, ok := changes[target] 51 | 52 | if !ok { 53 | t.Fatal("Unexpected event:", changes) 54 | } 55 | 56 | if tCh.ActiveState == "active" && tCh.Name == target { 57 | goto success 58 | } 59 | case err = <-errChan: 60 | t.Fatal(err) 61 | case <-timeout: 62 | t.Fatal("Reached timeout") 63 | } 64 | } 65 | 66 | success: 67 | return 68 | } 69 | -------------------------------------------------------------------------------- /api/discovery.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 CoreOS, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package api 18 | 19 | import ( 20 | "fmt" 21 | "net/http" 22 | "path" 23 | 24 | "github.com/coreos/fleet/log" 25 | "github.com/coreos/fleet/schema" 26 | ) 27 | 28 | func wireUpDiscoveryResource(mux *http.ServeMux, prefix string) { 29 | base := path.Join(prefix, "discovery") 30 | dr := discoveryResource{} 31 | mux.Handle(base, &dr) 32 | } 33 | 34 | type discoveryResource struct{} 35 | 36 | func (dr *discoveryResource) ServeHTTP(rw http.ResponseWriter, req *http.Request) { 37 | if req.Method != "GET" { 38 | sendError(rw, http.StatusBadRequest, fmt.Errorf("only HTTP GET supported against this resource")) 39 | return 40 | } 41 | rw.Header().Set("Content-Type", "application/json") 42 | rw.WriteHeader(200) 43 | if _, err := rw.Write([]byte(schema.DiscoveryJSON)); err != nil { 44 | log.Errorf("Failed sending HTTP response body: %v", err) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/coreos/go-systemd/activation/packetconns.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 CoreOS Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package activation 18 | 19 | import ( 20 | "net" 21 | ) 22 | 23 | // PacketConns returns a slice containing a net.PacketConn for each matching socket type 24 | // passed to this process. 25 | // 26 | // The order of the file descriptors is preserved in the returned slice. 27 | // Nil values are used to fill any gaps. For example if systemd were to return file descriptors 28 | // corresponding with "udp, tcp, udp", then the slice would contain {net.PacketConn, nil, net.PacketConn} 29 | func PacketConns(unsetEnv bool) ([]net.PacketConn, error) { 30 | files := Files(unsetEnv) 31 | conns := make([]net.PacketConn, 0) 32 | for i := 0; i < len(files); i++ { 33 | if pc, err := net.FilePacketConn(files[i]); err == nil { 34 | conns = append(conns, pc) 35 | continue 36 | } else { 37 | conns = append(conns, nil) 38 | } 39 | } 40 | return conns, nil 41 | } 42 | -------------------------------------------------------------------------------- /DCO: -------------------------------------------------------------------------------- 1 | Developer Certificate of Origin 2 | Version 1.1 3 | 4 | Copyright (C) 2004, 2006 The Linux Foundation and its contributors. 5 | 660 York Street, Suite 102, 6 | San Francisco, CA 94110 USA 7 | 8 | Everyone is permitted to copy and distribute verbatim copies of this 9 | license document, but changing it is not allowed. 10 | 11 | 12 | Developer's Certificate of Origin 1.1 13 | 14 | By making a contribution to this project, I certify that: 15 | 16 | (a) The contribution was created in whole or in part by me and I 17 | have the right to submit it under the open source license 18 | indicated in the file; or 19 | 20 | (b) The contribution is based upon previous work that, to the best 21 | of my knowledge, is covered under an appropriate open source 22 | license and I have the right under that license to submit that 23 | work with modifications, whether created in whole or in part 24 | by me, under the same open source license (unless I am 25 | permitted to submit under a different license), as indicated 26 | in the file; or 27 | 28 | (c) The contribution was provided directly to me by some other 29 | person who certified (a), (b) or (c) and I have not modified 30 | it. 31 | 32 | (d) I understand and agree that this project and the contribution 33 | are public and that a record of the contribution (including all 34 | personal information I submit with it, including my sign-off) is 35 | maintained indefinitely and may be redistributed consistent with 36 | this project or the open source license(s) involved. 37 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/coreos/go-systemd/activation/listeners.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 CoreOS Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package activation 18 | 19 | import ( 20 | "net" 21 | ) 22 | 23 | // Listeners returns a slice containing a net.Listener for each matching socket type 24 | // passed to this process. 25 | // 26 | // The order of the file descriptors is preserved in the returned slice. 27 | // Nil values are used to fill any gaps. For example if systemd were to return file descriptors 28 | // corresponding with "udp, tcp, tcp", then the slice would contain {nil, net.Listener, net.Listener} 29 | func Listeners(unsetEnv bool) ([]net.Listener, error) { 30 | files := Files(unsetEnv) 31 | listeners := make([]net.Listener, 0) 32 | 33 | for i := 0; i < len(files); i++ { 34 | if pc, err := net.FileListener(files[i]); err == nil { 35 | listeners = append(listeners, pc) 36 | continue 37 | } else { 38 | listeners = append(listeners, nil) 39 | } 40 | } 41 | return listeners, nil 42 | } 43 | -------------------------------------------------------------------------------- /api/deserialization_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 CoreOS, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package api 18 | 19 | import ( 20 | "encoding/json" 21 | "fmt" 22 | "net/http/httptest" 23 | "reflect" 24 | ) 25 | 26 | func assertErrorResponse(rr *httptest.ResponseRecorder, code int) error { 27 | if rr.Code != code { 28 | return fmt.Errorf("expected HTTP code %d, got %d", code, rr.Code) 29 | } 30 | 31 | ctypes := rr.HeaderMap["Content-Type"] 32 | expect := []string{"application/json"} 33 | if !reflect.DeepEqual(expect, ctypes) { 34 | return fmt.Errorf("Expected Content-Type %v, got %v", expect, ctypes) 35 | } 36 | 37 | var eresp errorResponse 38 | dec := json.NewDecoder(rr.Body) 39 | err := dec.Decode(&eresp) 40 | if err != nil { 41 | return fmt.Errorf("unable to decode error entity in body: %v", err) 42 | } 43 | 44 | if eresp.Error.Code != code { 45 | return fmt.Errorf("expected error entity code %d, got %d", code, eresp.Error.Code) 46 | } 47 | 48 | return nil 49 | } 50 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/google.golang.org/api/google-api-go-generator/testdata/mapofany.json: -------------------------------------------------------------------------------- 1 | { 2 | "kind": "discovery#restDescription", 3 | "etag": "\"kEk3sFj6Ef5_yR1-H3bAO6qw9mI/3m5rB86FE5KuW1K3jAl88AxCreg\"", 4 | "discoveryVersion": "v1", 5 | "id": "mapofany:v1", 6 | "name": "mapofany", 7 | "version": "v1", 8 | "title": "Example API", 9 | "description": "The Example API demonstrates an associative array.", 10 | "ownerDomain": "google.com", 11 | "ownerName": "Google", 12 | "protocol": "rest", 13 | "schemas": { 14 | "TableDataInsertAllRequest": { 15 | "id": "TableDataInsertAllRequest", 16 | "type": "object", 17 | "properties": { 18 | "kind": { 19 | "type": "string", 20 | "description": "The resource type of the response.", 21 | "default": "bigquery#tableDataInsertAllRequest" 22 | }, 23 | "rows": { 24 | "type": "array", 25 | "description": "The rows to insert.", 26 | "items": { 27 | "type": "object", 28 | "properties": { 29 | "json": { 30 | "$ref": "JsonObject", 31 | "description": "[Required] A JSON object that contains a row of data. The object's properties and values must match the destination table's schema." 32 | } 33 | } 34 | } 35 | } 36 | } 37 | }, 38 | "JsonObject": { 39 | "id": "JsonObject", 40 | "type": "object", 41 | "description": "Represents a single JSON object.", 42 | "additionalProperties": { 43 | "$ref": "JsonValue" 44 | } 45 | }, 46 | "JsonValue": { 47 | "id": "JsonValue", 48 | "type": "any" 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /machine/machine.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 CoreOS, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package machine 18 | 19 | import ( 20 | "github.com/coreos/fleet/log" 21 | "github.com/coreos/fleet/pkg" 22 | ) 23 | 24 | type Machine interface { 25 | State() MachineState 26 | } 27 | 28 | // HasMetadata determine if the Metadata of a given MachineState 29 | // matches the indicated values. 30 | func HasMetadata(state *MachineState, metadata map[string]pkg.Set) bool { 31 | for key, values := range metadata { 32 | local, ok := state.Metadata[key] 33 | if !ok { 34 | log.V(1).Infof("No local values found for Metadata(%s)", key) 35 | return false 36 | } 37 | 38 | log.V(1).Infof("Asserting local Metadata(%s) meets requirements", key) 39 | 40 | if values.Contains(local) { 41 | log.V(1).Infof("Local Metadata(%s) meets requirement", key) 42 | } else { 43 | log.V(1).Infof("Local Metadata(%s) does not match requirement", key) 44 | return false 45 | } 46 | } 47 | 48 | return true 49 | } 50 | -------------------------------------------------------------------------------- /scripts/schema_generator_import.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 CoreOS, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // +build ignore 18 | 19 | package scripts 20 | 21 | // This file exists to ensure Godep manages a vendored copy of the 22 | // `google-api-go-generator` library, used by scripts/schema-generator. 23 | // Unfortunately since this is a binary package and hence is not importable, we 24 | // need to trick godep into managing it. To update the dependency, do the following steps: 25 | // 1. Use `godep restore` to set up GOPATH with all the right package versions 26 | // 2. Uncomment the import line below 27 | // 3. Update the package in GOPATH as appropriate (e.g. `go get -u google.golang.org/api/google-api-go-generator`) 28 | // 4. Run `godep save` as usual across the entire project (e.g. `godep save -r ./...`) 29 | // 5. Revert this file (i.e. comment the line again, and revert to the original import) as it will not build properly 30 | // 31 | // import _ "google.golang.org/api/google-api-go-generator" 32 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/coreos/go-systemd/dbus/subscription_set.go: -------------------------------------------------------------------------------- 1 | package dbus 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | // SubscriptionSet returns a subscription set which is like conn.Subscribe but 8 | // can filter to only return events for a set of units. 9 | type SubscriptionSet struct { 10 | *set 11 | conn *Conn 12 | } 13 | 14 | func (s *SubscriptionSet) filter(unit string) bool { 15 | return !s.Contains(unit) 16 | } 17 | 18 | // Subscribe starts listening for dbus events for all of the units in the set. 19 | // Returns channels identical to conn.SubscribeUnits. 20 | func (s *SubscriptionSet) Subscribe() (<-chan map[string]*UnitStatus, <-chan error) { 21 | // TODO: Make fully evented by using systemd 209 with properties changed values 22 | return s.conn.SubscribeUnitsCustom(time.Second, 0, 23 | mismatchUnitStatus, 24 | func(unit string) bool { return s.filter(unit) }, 25 | ) 26 | } 27 | 28 | // NewSubscriptionSet returns a new subscription set. 29 | func (conn *Conn) NewSubscriptionSet() *SubscriptionSet { 30 | return &SubscriptionSet{newSet(), conn} 31 | } 32 | 33 | // mismatchUnitStatus returns true if the provided UnitStatus objects 34 | // are not equivalent. false is returned if the objects are equivalent. 35 | // Only the Name, Description and state-related fields are used in 36 | // the comparison. 37 | func mismatchUnitStatus(u1, u2 *UnitStatus) bool { 38 | return u1.Name != u2.Name || 39 | u1.Description != u2.Description || 40 | u1.LoadState != u2.LoadState || 41 | u1.ActiveState != u2.ActiveState || 42 | u1.SubState != u2.SubState 43 | } 44 | -------------------------------------------------------------------------------- /pkg/filesystem_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 CoreOS, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package pkg 18 | 19 | import ( 20 | "io/ioutil" 21 | "os" 22 | "path" 23 | "reflect" 24 | "testing" 25 | ) 26 | 27 | func TestListDirectory(t *testing.T) { 28 | dir, err := ioutil.TempDir("", "fleet-testing-") 29 | if err != nil { 30 | t.Fatal(err.Error()) 31 | } 32 | 33 | defer os.RemoveAll(dir) 34 | 35 | for _, name := range []string{"ping", "pong", "foo", "bar", "baz"} { 36 | err := ioutil.WriteFile(path.Join(dir, name), []byte{}, 0400) 37 | if err != nil { 38 | t.Fatal(err.Error()) 39 | } 40 | } 41 | 42 | filterFunc := func(name string) bool { 43 | return name == "foo" || name == "bar" 44 | } 45 | 46 | got, err := ListDirectory(dir, filterFunc) 47 | if err != nil { 48 | t.Fatal(err.Error()) 49 | } 50 | 51 | want := []string{"baz", "ping", "pong"} 52 | if !reflect.DeepEqual(want, got) { 53 | t.Fatalf("ListDirectory output incorrect: want=%v, got=%v", want, got) 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/google.golang.org/api/google-api-go-generator/testdata/arrayofmapofobjects.want: -------------------------------------------------------------------------------- 1 | // Package arrayofmapofstrings provides access to the Example API. 2 | // 3 | // Usage example: 4 | // 5 | // import "google.golang.org/api/arrayofmapofstrings/v1" 6 | // ... 7 | // arrayofmapofstringsService, err := arrayofmapofstrings.New(oauthHttpClient) 8 | package arrayofmapofstrings 9 | 10 | import ( 11 | "bytes" 12 | "google.golang.org/api/googleapi" 13 | "encoding/json" 14 | "errors" 15 | "fmt" 16 | "io" 17 | "net/http" 18 | "net/url" 19 | "strconv" 20 | "strings" 21 | ) 22 | 23 | // Always reference these packages, just in case the auto-generated code 24 | // below doesn't. 25 | var _ = bytes.NewBuffer 26 | var _ = strconv.Itoa 27 | var _ = fmt.Sprintf 28 | var _ = json.NewDecoder 29 | var _ = io.Copy 30 | var _ = url.Parse 31 | var _ = googleapi.Version 32 | var _ = errors.New 33 | var _ = strings.Replace 34 | 35 | const apiId = "arrayofmapofstrings:v1" 36 | const apiName = "arrayofmapofstrings" 37 | const apiVersion = "v1" 38 | const basePath = "https://www.googleapis.com/discovery/v1/apis" 39 | 40 | func New(client *http.Client) (*Service, error) { 41 | if client == nil { 42 | return nil, errors.New("client is nil") 43 | } 44 | s := &Service{client: client, BasePath: basePath} 45 | return s, nil 46 | } 47 | 48 | type Service struct { 49 | client *http.Client 50 | BasePath string // API endpoint base URL 51 | } 52 | 53 | type Analyze struct { 54 | // Errors: List of errors with the data. 55 | Errors []map[string]Property `json:"errors,omitempty"` 56 | } 57 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/google.golang.org/api/google-api-go-generator/testdata/arrayofmapofstrings.want: -------------------------------------------------------------------------------- 1 | // Package arrayofmapofstrings provides access to the Example API. 2 | // 3 | // Usage example: 4 | // 5 | // import "google.golang.org/api/arrayofmapofstrings/v1" 6 | // ... 7 | // arrayofmapofstringsService, err := arrayofmapofstrings.New(oauthHttpClient) 8 | package arrayofmapofstrings 9 | 10 | import ( 11 | "bytes" 12 | "google.golang.org/api/googleapi" 13 | "encoding/json" 14 | "errors" 15 | "fmt" 16 | "io" 17 | "net/http" 18 | "net/url" 19 | "strconv" 20 | "strings" 21 | ) 22 | 23 | // Always reference these packages, just in case the auto-generated code 24 | // below doesn't. 25 | var _ = bytes.NewBuffer 26 | var _ = strconv.Itoa 27 | var _ = fmt.Sprintf 28 | var _ = json.NewDecoder 29 | var _ = io.Copy 30 | var _ = url.Parse 31 | var _ = googleapi.Version 32 | var _ = errors.New 33 | var _ = strings.Replace 34 | 35 | const apiId = "arrayofmapofstrings:v1" 36 | const apiName = "arrayofmapofstrings" 37 | const apiVersion = "v1" 38 | const basePath = "https://www.googleapis.com/discovery/v1/apis" 39 | 40 | func New(client *http.Client) (*Service, error) { 41 | if client == nil { 42 | return nil, errors.New("client is nil") 43 | } 44 | s := &Service{client: client, BasePath: basePath} 45 | return s, nil 46 | } 47 | 48 | type Service struct { 49 | client *http.Client 50 | BasePath string // API endpoint base URL 51 | } 52 | 53 | type Analyze struct { 54 | // Errors: List of errors with the data. 55 | Errors []map[string]string `json:"errors,omitempty"` 56 | } 57 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/google.golang.org/api/google-api-go-generator/testdata/mapofobjects.want: -------------------------------------------------------------------------------- 1 | // Package additionalpropsobjs provides access to the Example API. 2 | // 3 | // Usage example: 4 | // 5 | // import "google.golang.org/api/additionalpropsobjs/v1" 6 | // ... 7 | // additionalpropsobjsService, err := additionalpropsobjs.New(oauthHttpClient) 8 | package additionalpropsobjs 9 | 10 | import ( 11 | "bytes" 12 | "google.golang.org/api/googleapi" 13 | "encoding/json" 14 | "errors" 15 | "fmt" 16 | "io" 17 | "net/http" 18 | "net/url" 19 | "strconv" 20 | "strings" 21 | ) 22 | 23 | // Always reference these packages, just in case the auto-generated code 24 | // below doesn't. 25 | var _ = bytes.NewBuffer 26 | var _ = strconv.Itoa 27 | var _ = fmt.Sprintf 28 | var _ = json.NewDecoder 29 | var _ = io.Copy 30 | var _ = url.Parse 31 | var _ = googleapi.Version 32 | var _ = errors.New 33 | var _ = strings.Replace 34 | 35 | const apiId = "additionalpropsobjs:v1" 36 | const apiName = "additionalpropsobjs" 37 | const apiVersion = "v1" 38 | const basePath = "https://www.googleapis.com/discovery/v1/apis" 39 | 40 | func New(client *http.Client) (*Service, error) { 41 | if client == nil { 42 | return nil, errors.New("client is nil") 43 | } 44 | s := &Service{client: client, BasePath: basePath} 45 | return s, nil 46 | } 47 | 48 | type Service struct { 49 | client *http.Client 50 | BasePath string // API endpoint base URL 51 | } 52 | 53 | type Entity struct { 54 | // Properties: The entity's properties. 55 | Properties map[string]Property `json:"properties,omitempty"` 56 | } 57 | -------------------------------------------------------------------------------- /fleetctl/submit.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 CoreOS, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | var cmdSubmitUnit = &Command{ 20 | Name: "submit", 21 | Summary: "Upload one or more units to the cluster without starting them", 22 | Usage: "UNIT...", 23 | Description: `Upload one or more units to the cluster without starting them. Useful 24 | for validating units before they are started. 25 | 26 | This operation is idempotent; if a named unit already exists in the cluster, it will not be resubmitted. 27 | 28 | Submit a single unit: 29 | fleetctl submit foo.service 30 | 31 | Submit a directory of units with glob matching: 32 | fleetctl submit myservice/*`, 33 | Run: runSubmitUnits, 34 | } 35 | 36 | func init() { 37 | cmdSubmitUnit.Flags.BoolVar(&sharedFlags.Sign, "sign", false, "DEPRECATED - this option cannot be used") 38 | } 39 | 40 | func runSubmitUnits(args []string) (exit int) { 41 | if err := lazyCreateUnits(args); err != nil { 42 | stderr("Error creating units: %v", err) 43 | exit = 1 44 | } 45 | return 46 | } 47 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/golang.org/x/crypto/ssh/test/agent_unix_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build darwin dragonfly freebsd linux netbsd openbsd 6 | 7 | package test 8 | 9 | import ( 10 | "bytes" 11 | "testing" 12 | 13 | "github.com/coreos/fleet/Godeps/_workspace/src/golang.org/x/crypto/ssh" 14 | "github.com/coreos/fleet/Godeps/_workspace/src/golang.org/x/crypto/ssh/agent" 15 | ) 16 | 17 | func TestAgentForward(t *testing.T) { 18 | server := newServer(t) 19 | defer server.Shutdown() 20 | conn := server.Dial(clientConfig()) 21 | defer conn.Close() 22 | 23 | keyring := agent.NewKeyring() 24 | keyring.Add(testPrivateKeys["dsa"], nil, "") 25 | pub := testPublicKeys["dsa"] 26 | 27 | sess, err := conn.NewSession() 28 | if err != nil { 29 | t.Fatalf("NewSession: %v", err) 30 | } 31 | if err := agent.RequestAgentForwarding(sess); err != nil { 32 | t.Fatalf("RequestAgentForwarding: %v", err) 33 | } 34 | 35 | if err := agent.ForwardToAgent(conn, keyring); err != nil { 36 | t.Fatalf("SetupForwardKeyring: %v", err) 37 | } 38 | out, err := sess.CombinedOutput("ssh-add -L") 39 | if err != nil { 40 | t.Fatalf("running ssh-add: %v, out %s", err, out) 41 | } 42 | key, _, _, _, err := ssh.ParseAuthorizedKey(out) 43 | if err != nil { 44 | t.Fatalf("ParseAuthorizedKey(%q): %v", out, err) 45 | } 46 | 47 | if !bytes.Equal(key.Marshal(), pub.Marshal()) { 48 | t.Fatalf("got key %s, want %s", ssh.MarshalAuthorizedKey(key), ssh.MarshalAuthorizedKey(pub)) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /config/config.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 CoreOS, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package config 18 | 19 | import ( 20 | "strings" 21 | ) 22 | 23 | type Config struct { 24 | EtcdServers []string 25 | EtcdKeyPrefix string 26 | EtcdKeyFile string 27 | EtcdCertFile string 28 | EtcdCAFile string 29 | EtcdRequestTimeout float64 30 | EngineReconcileInterval float64 31 | PublicIP string 32 | Verbosity int 33 | RawMetadata string 34 | AgentTTL string 35 | VerifyUnits bool 36 | AuthorizedKeysFile string 37 | } 38 | 39 | func (c *Config) Metadata() map[string]string { 40 | meta := make(map[string]string, 0) 41 | 42 | for _, pair := range strings.Split(c.RawMetadata, ",") { 43 | parts := strings.SplitN(pair, "=", 2) 44 | if len(parts) != 2 { 45 | continue 46 | } 47 | 48 | key := strings.TrimSpace(parts[0]) 49 | val := strings.TrimSpace(parts[1]) 50 | 51 | meta[key] = val 52 | } 53 | 54 | return meta 55 | } 56 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/google.golang.org/api/google-api-go-generator/testdata/arrayofarray-1.want: -------------------------------------------------------------------------------- 1 | // Package arrayofarray provides access to the Example API. 2 | // 3 | // Usage example: 4 | // 5 | // import "google.golang.org/api/arrayofarray/v1" 6 | // ... 7 | // arrayofarrayService, err := arrayofarray.New(oauthHttpClient) 8 | package arrayofarray 9 | 10 | import ( 11 | "bytes" 12 | "google.golang.org/api/googleapi" 13 | "encoding/json" 14 | "errors" 15 | "fmt" 16 | "io" 17 | "net/http" 18 | "net/url" 19 | "strconv" 20 | "strings" 21 | ) 22 | 23 | // Always reference these packages, just in case the auto-generated code 24 | // below doesn't. 25 | var _ = bytes.NewBuffer 26 | var _ = strconv.Itoa 27 | var _ = fmt.Sprintf 28 | var _ = json.NewDecoder 29 | var _ = io.Copy 30 | var _ = url.Parse 31 | var _ = googleapi.Version 32 | var _ = errors.New 33 | var _ = strings.Replace 34 | 35 | const apiId = "arrayofarray:v1" 36 | const apiName = "arrayofarray" 37 | const apiVersion = "v1" 38 | const basePath = "https://www.googleapis.com/discovery/v1/apis" 39 | 40 | func New(client *http.Client) (*Service, error) { 41 | if client == nil { 42 | return nil, errors.New("client is nil") 43 | } 44 | s := &Service{client: client, BasePath: basePath} 45 | return s, nil 46 | } 47 | 48 | type Service struct { 49 | client *http.Client 50 | BasePath string // API endpoint base URL 51 | } 52 | 53 | type GeoJsonMultiPolygon struct { 54 | // Coordinates: Coordinate arrays. 55 | Coordinates [][][][]float64 `json:"coordinates,omitempty"` 56 | 57 | // Type: Identifies this object as a multi-polygon. 58 | Type string `json:"type,omitempty"` 59 | } 60 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/jonboulle/clockwork/README.md: -------------------------------------------------------------------------------- 1 | clockwork 2 | ========= 3 | 4 | [![Build Status](https://travis-ci.org/jonboulle/clockwork.png?branch=master)](https://travis-ci.org/jonboulle/clockwork) 5 | [![godoc](https://godoc.org/github.com/jonboulle/clockwork?status.svg)](http://godoc.org/github.com/jonboulle/clockwork) 6 | 7 | a simple fake clock for golang 8 | 9 | # Usage 10 | 11 | Replace uses of the `time` package with the `clockwork.Clock` interface instead. 12 | 13 | For example, instead of using `time.Sleep` directly: 14 | 15 | ``` 16 | func my_func() { 17 | time.Sleep(3 * time.Second) 18 | do_something() 19 | } 20 | ``` 21 | 22 | inject a clock and use its `Sleep` method instead: 23 | 24 | ``` 25 | func my_func(clock clockwork.Clock) { 26 | clock.Sleep(3 * time.Second) 27 | do_something() 28 | } 29 | ``` 30 | 31 | Now you can easily test `my_func` with a `FakeClock`: 32 | 33 | ``` 34 | func TestMyFunc(t *testing.T) { 35 | c := clockwork.NewFakeClock() 36 | 37 | // Start our sleepy function 38 | my_func(c) 39 | 40 | // Ensure we wait until my_func is sleeping 41 | c.BlockUntil(1) 42 | 43 | assert_state() 44 | 45 | // Advance the FakeClock forward in time 46 | c.Advance(3) 47 | 48 | assert_state() 49 | } 50 | ``` 51 | 52 | and in production builds, simply inject the real clock instead: 53 | ``` 54 | my_func(clockwork.NewRealClock()) 55 | ``` 56 | 57 | See [example_test.go](example_test.go) for a full example. 58 | 59 | # Credits 60 | 61 | clockwork is inspired by @wickman's [threaded fake clock](https://gist.github.com/wickman/3840816), and the [Golang playground](http://blog.golang.org/playground#Faking time) 62 | -------------------------------------------------------------------------------- /etcd/error_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 CoreOS, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package etcd 18 | 19 | import ( 20 | "reflect" 21 | "testing" 22 | ) 23 | 24 | func TestUnmarshalFailedResponse(t *testing.T) { 25 | body := "{\"errorCode\":401,\"message\":\"foo\",\"cause\":\"bar\",\"index\":12}" 26 | expect := Error{ErrorCode: 401, Message: "foo", Cause: "bar", Index: 12} 27 | 28 | res, err := unmarshalFailedResponse(nil, []byte(body)) 29 | if res != nil { 30 | t.Errorf("*Result should always be nil") 31 | } 32 | 33 | etcdErr, ok := err.(Error) 34 | if !ok { 35 | t.Fatalf("error should be of type Error") 36 | } 37 | 38 | if !reflect.DeepEqual(etcdErr, err) { 39 | t.Fatalf("returned err %v does not match expected %v", etcdErr, expect) 40 | } 41 | } 42 | 43 | func TestUnmarshalFailedResponseGarbage(t *testing.T) { 44 | res, err := unmarshalFailedResponse(nil, []byte("garbage")) 45 | if res != nil { 46 | t.Errorf("*Result should always be nil") 47 | } 48 | 49 | if _, ok := err.(Error); ok { 50 | t.Fatalf("error should not be of type Error") 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /pkg/filepath.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 CoreOS, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package pkg 18 | 19 | import ( 20 | "os" 21 | "os/user" 22 | "path/filepath" 23 | "strings" 24 | 25 | "github.com/coreos/fleet/log" 26 | ) 27 | 28 | // ParseFilepath expands ~ and ~user constructions. 29 | // If user or $HOME is unknown, do nothing. 30 | func ParseFilepath(path string) string { 31 | if !strings.HasPrefix(path, "~") { 32 | return path 33 | } 34 | i := strings.Index(path, "/") 35 | if i < 0 { 36 | i = len(path) 37 | } 38 | var home string 39 | if i == 1 { 40 | if home = os.Getenv("HOME"); home == "" { 41 | usr, err := user.Current() 42 | if err != nil { 43 | log.V(1).Infof("Failed to get current home directory: %v", err) 44 | return path 45 | } 46 | home = usr.HomeDir 47 | } 48 | } else { 49 | usr, err := user.Lookup(path[1:i]) 50 | if err != nil { 51 | log.V(1).Infof("Failed to get %v's home directory: %v", path[1:i], err) 52 | return path 53 | } 54 | home = usr.HomeDir 55 | } 56 | path = filepath.Join(home, path[i:]) 57 | return path 58 | } 59 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/golang.org/x/crypto/ssh/cipher_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package ssh 6 | 7 | import ( 8 | "bytes" 9 | "crypto" 10 | "crypto/rand" 11 | "testing" 12 | ) 13 | 14 | func TestDefaultCiphersExist(t *testing.T) { 15 | for _, cipherAlgo := range supportedCiphers { 16 | if _, ok := cipherModes[cipherAlgo]; !ok { 17 | t.Errorf("default cipher %q is unknown", cipherAlgo) 18 | } 19 | } 20 | } 21 | 22 | func TestPacketCiphers(t *testing.T) { 23 | for cipher := range cipherModes { 24 | kr := &kexResult{Hash: crypto.SHA1} 25 | algs := directionAlgorithms{ 26 | Cipher: cipher, 27 | MAC: "hmac-sha1", 28 | Compression: "none", 29 | } 30 | client, err := newPacketCipher(clientKeys, algs, kr) 31 | if err != nil { 32 | t.Errorf("newPacketCipher(client, %q): %v", cipher, err) 33 | continue 34 | } 35 | server, err := newPacketCipher(clientKeys, algs, kr) 36 | if err != nil { 37 | t.Errorf("newPacketCipher(client, %q): %v", cipher, err) 38 | continue 39 | } 40 | 41 | want := "bla bla" 42 | input := []byte(want) 43 | buf := &bytes.Buffer{} 44 | if err := client.writePacket(0, buf, rand.Reader, input); err != nil { 45 | t.Errorf("writePacket(%q): %v", cipher, err) 46 | continue 47 | } 48 | 49 | packet, err := server.readPacket(0, buf) 50 | if err != nil { 51 | t.Errorf("readPacket(%q): %v", cipher, err) 52 | continue 53 | } 54 | 55 | if string(packet) != want { 56 | t.Errorf("roundtrip(%q): got %q, want %q", cipher, packet, want) 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /fleetctl/cat.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 CoreOS, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "fmt" 21 | 22 | "github.com/coreos/fleet/schema" 23 | ) 24 | 25 | var ( 26 | cmdCatUnit = &Command{ 27 | Name: "cat", 28 | Summary: "Output the contents of a submitted unit", 29 | Usage: "UNIT", 30 | Description: `Outputs the unit file that is currently loaded in the cluster. Useful to verify 31 | the correct version of a unit is running.`, 32 | Run: runCatUnit, 33 | } 34 | ) 35 | 36 | func runCatUnit(args []string) (exit int) { 37 | if len(args) != 1 { 38 | stderr("One unit file must be provided") 39 | return 1 40 | } 41 | 42 | name := unitNameMangle(args[0]) 43 | u, err := cAPI.Unit(name) 44 | if err != nil { 45 | stderr("Error retrieving Unit %s: %v", name, err) 46 | return 1 47 | } 48 | if u == nil { 49 | stderr("Unit %s not found", name) 50 | return 1 51 | } 52 | 53 | uf := schema.MapSchemaUnitOptionsToUnitFile(u.Options) 54 | 55 | // Must not add a newline here. The contents of the unit file 56 | // must not be modified. 57 | fmt.Print(uf.String()) 58 | 59 | return 60 | } 61 | -------------------------------------------------------------------------------- /functional/platform/cluster.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 CoreOS, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package platform 18 | 19 | import ( 20 | "github.com/coreos/fleet/functional/util" 21 | ) 22 | 23 | type Member interface { 24 | ID() string 25 | IP() string 26 | Endpoint() string 27 | } 28 | 29 | type Cluster interface { 30 | CreateMember() (Member, error) 31 | DestroyMember(Member) error 32 | ReplaceMember(Member) (Member, error) 33 | Members() []Member 34 | MemberCommand(Member, ...string) (string, error) 35 | Destroy() error 36 | 37 | // client operations 38 | Fleetctl(m Member, args ...string) (string, string, error) 39 | FleetctlWithInput(m Member, input string, args ...string) (string, string, error) 40 | WaitForNActiveUnits(Member, int) (map[string][]util.UnitState, error) 41 | WaitForNMachines(Member, int) ([]string, error) 42 | } 43 | 44 | func CreateNClusterMembers(cl Cluster, count int) ([]Member, error) { 45 | ms := make([]Member, 0) 46 | for i := 0; i < count; i++ { 47 | m, err := cl.CreateMember() 48 | if err != nil { 49 | return nil, err 50 | } 51 | ms = append(ms, m) 52 | } 53 | return ms, nil 54 | } 55 | -------------------------------------------------------------------------------- /pkg/args_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 CoreOS, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package pkg 18 | 19 | import "testing" 20 | 21 | func TestTrimToDashes(t *testing.T) { 22 | var argtests = []struct { 23 | input []string 24 | output []string 25 | }{ 26 | {[]string{"foo", "bar", "baz"}, []string{"foo", "bar", "baz"}}, 27 | {[]string{"abc", "def", "--", "ghi"}, []string{"ghi"}}, 28 | {[]string{"abc", "def", "--"}, []string{}}, 29 | {[]string{"--"}, []string{}}, 30 | {[]string{"--", "abc", "def", "ghi"}, []string{"abc", "def", "ghi"}}, 31 | {[]string{"--", "bar", "--", "baz"}, []string{"bar", "--", "baz"}}, 32 | {[]string{"--flagname", "--", "ghi"}, []string{"ghi"}}, 33 | {[]string{"--", "--flagname", "ghi"}, []string{"--flagname", "ghi"}}, 34 | } 35 | for _, test := range argtests { 36 | args := TrimToDashes(test.input) 37 | if len(test.output) != len(args) { 38 | t.Fatalf("error trimming dashes: expected %s, got %s", test.output, args) 39 | } 40 | for i, v := range args { 41 | if v != test.output[i] { 42 | t.Fatalf("error trimming dashes: expected %s, got %s", test.output, args) 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/coreos/go-systemd/activation/files.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2013 CoreOS Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Package activation implements primitives for systemd socket activation. 18 | package activation 19 | 20 | import ( 21 | "os" 22 | "strconv" 23 | "syscall" 24 | ) 25 | 26 | // based on: https://gist.github.com/alberts/4640792 27 | const ( 28 | listenFdsStart = 3 29 | ) 30 | 31 | func Files(unsetEnv bool) []*os.File { 32 | if unsetEnv { 33 | // there is no way to unset env in golang os package for now 34 | // https://code.google.com/p/go/issues/detail?id=6423 35 | defer os.Setenv("LISTEN_PID", "") 36 | defer os.Setenv("LISTEN_FDS", "") 37 | } 38 | 39 | pid, err := strconv.Atoi(os.Getenv("LISTEN_PID")) 40 | if err != nil || pid != os.Getpid() { 41 | return nil 42 | } 43 | 44 | nfds, err := strconv.Atoi(os.Getenv("LISTEN_FDS")) 45 | if err != nil || nfds == 0 { 46 | return nil 47 | } 48 | 49 | var files []*os.File 50 | for fd := listenFdsStart; fd < listenFdsStart+nfds; fd++ { 51 | syscall.CloseOnExec(fd) 52 | files = append(files, os.NewFile(uintptr(fd), "LISTEN_FD_"+strconv.Itoa(fd))) 53 | } 54 | 55 | return files 56 | } 57 | -------------------------------------------------------------------------------- /agent/cache.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 CoreOS, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package agent 18 | 19 | import ( 20 | "encoding/json" 21 | 22 | "github.com/coreos/fleet/job" 23 | ) 24 | 25 | type agentCache map[string]job.JobState 26 | 27 | func (ac *agentCache) MarshalJSON() ([]byte, error) { 28 | type ds struct { 29 | TargetStates map[string]job.JobState 30 | } 31 | data := ds{ 32 | TargetStates: map[string]job.JobState(*ac), 33 | } 34 | return json.Marshal(data) 35 | } 36 | 37 | func (ac *agentCache) setTargetState(jobName string, state job.JobState) { 38 | (*ac)[jobName] = state 39 | } 40 | 41 | func (ac *agentCache) dropTargetState(jobName string) { 42 | delete(*ac, jobName) 43 | } 44 | 45 | func (ac *agentCache) launchedJobs() []string { 46 | jobs := make([]string, 0) 47 | for j, ts := range *ac { 48 | if ts == job.JobStateLaunched { 49 | jobs = append(jobs, j) 50 | } 51 | } 52 | return jobs 53 | } 54 | 55 | func (ac *agentCache) loadedJobs() []string { 56 | jobs := make([]string, 0) 57 | for j, ts := range *ac { 58 | if ts == job.JobStateLoaded { 59 | jobs = append(jobs, j) 60 | } 61 | } 62 | return jobs 63 | } 64 | -------------------------------------------------------------------------------- /fixtures/insecure_private_key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEogIBAAKCAQEA6NF8iallvQVp22WDkTkyrtvp9eWW6A8YVr+kz4TjGYe7gHzI 3 | w+niNltGEFHzD8+v1I2YJ6oXevct1YeS0o9HZyN1Q9qgCgzUFtdOKLv6IedplqoP 4 | kcmF0aYet2PkEDo3MlTBckFXPITAMzF8dJSIFo9D8HfdOV0IAdx4O7PtixWKn5y2 5 | hMNG0zQPyUecp4pzC6kivAIhyfHilFR61RGL+GPXQ2MWZWFYbAGjyiYJnAmCP3NO 6 | Td0jMZEnDkbUvxhMmBYSdETk1rRgm+R4LOzFUGaHqHDLKLX+FIPKcF96hrucXzcW 7 | yLbIbEgE98OHlnVYCzRdK8jlqm8tehUc9c9WhQIBIwKCAQEA4iqWPJXtzZA68mKd 8 | ELs4jJsdyky+ewdZeNds5tjcnHU5zUYE25K+ffJED9qUWICcLZDc81TGWjHyAqD1 9 | Bw7XpgUwFgeUJwUlzQurAv+/ySnxiwuaGJfhFM1CaQHzfXphgVml+fZUvnJUTvzf 10 | TK2Lg6EdbUE9TarUlBf/xPfuEhMSlIE5keb/Zz3/LUlRg8yDqz5w+QWVJ4utnKnK 11 | iqwZN0mwpwU7YSyJhlT4YV1F3n4YjLswM5wJs2oqm0jssQu/BT0tyEXNDYBLEF4A 12 | sClaWuSJ2kjq7KhrrYXzagqhnSei9ODYFShJu8UWVec3Ihb5ZXlzO6vdNQ1J9Xsf 13 | 4m+2ywKBgQD6qFxx/Rv9CNN96l/4rb14HKirC2o/orApiHmHDsURs5rUKDx0f9iP 14 | cXN7S1uePXuJRK/5hsubaOCx3Owd2u9gD6Oq0CsMkE4CUSiJcYrMANtx54cGH7Rk 15 | EjFZxK8xAv1ldELEyxrFqkbE4BKd8QOt414qjvTGyAK+OLD3M2QdCQKBgQDtx8pN 16 | CAxR7yhHbIWT1AH66+XWN8bXq7l3RO/ukeaci98JfkbkxURZhtxV/HHuvUhnPLdX 17 | 3TwygPBYZFNo4pzVEhzWoTtnEtrFueKxyc3+LjZpuo+mBlQ6ORtfgkr9gBVphXZG 18 | YEzkCD3lVdl8L4cw9BVpKrJCs1c5taGjDgdInQKBgHm/fVvv96bJxc9x1tffXAcj 19 | 3OVdUN0UgXNCSaf/3A/phbeBQe9xS+3mpc4r6qvx+iy69mNBeNZ0xOitIjpjBo2+ 20 | dBEjSBwLk5q5tJqHmy/jKMJL4n9ROlx93XS+njxgibTvU6Fp9w+NOFD/HvxB3Tcz 21 | 6+jJF85D5BNAG3DBMKBjAoGBAOAxZvgsKN+JuENXsST7F89Tck2iTcQIT8g5rwWC 22 | P9Vt74yboe2kDT531w8+egz7nAmRBKNM751U/95P9t88EDacDI/Z2OwnuFQHCPDF 23 | llYOUI+SpLJ6/vURRbHSnnn8a/XG+nzedGH5JGqEJNQsz+xT2axM0/W/CRknmGaJ 24 | kda/AoGANWrLCz708y7VYgAtW2Uf1DPOIYMdvo6fxIB5i9ZfISgcJ/bbCUkFrhoH 25 | +vq/5CIWxCPp0f85R4qxxQ5ihxJ0YDQT9Jpx4TMss4PSavPaBH3RXow5Ohe+bYoQ 26 | NE5OgEXk2wVfZczCZpigBKbKZHNYcelXtTt/nP3rsCuGcM4h53s= 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /ssh/proxy.go: -------------------------------------------------------------------------------- 1 | package ssh 2 | 3 | import ( 4 | "io" 5 | "net" 6 | 7 | gossh "github.com/coreos/fleet/Godeps/_workspace/src/golang.org/x/crypto/ssh" 8 | ) 9 | 10 | func DialCommand(client *SSHForwardingClient, cmd string) (net.Conn, error) { 11 | session, err := client.NewSession() 12 | if err != nil { 13 | return nil, err 14 | } 15 | 16 | stdout, err := session.StdoutPipe() 17 | if err != nil { 18 | return nil, err 19 | } 20 | 21 | stdin, err := session.StdinPipe() 22 | if err != nil { 23 | return nil, err 24 | } 25 | 26 | err = client.ForwardAgentAuthentication(session) 27 | if err != nil { 28 | return nil, err 29 | } 30 | 31 | err = session.Start(cmd) 32 | if err != nil { 33 | return nil, err 34 | } 35 | 36 | pc := &proxyConn{ 37 | session: session, 38 | writer: stdin, 39 | reader: stdout, 40 | errchan: make(chan error), 41 | } 42 | 43 | go func() { 44 | if err := session.Wait(); err != nil { 45 | pc.errchan <- err 46 | } 47 | close(pc.errchan) 48 | }() 49 | 50 | return pc, nil 51 | } 52 | 53 | type proxyConn struct { 54 | session *gossh.Session 55 | writer io.WriteCloser 56 | reader io.Reader 57 | errchan chan error 58 | 59 | // proxyConn does not fully implement the net.Conn 60 | // interface, so we have to embed it here. 61 | net.Conn 62 | } 63 | 64 | func (pc *proxyConn) Read(b []byte) (int, error) { 65 | n, err := pc.reader.Read(b) 66 | if err == nil { 67 | return n, err 68 | } 69 | 70 | perr := <-pc.errchan 71 | if perr != nil { 72 | err = perr 73 | } 74 | 75 | return n, err 76 | } 77 | 78 | func (pc *proxyConn) Write(b []byte) (int, error) { 79 | return pc.writer.Write(b) 80 | } 81 | 82 | func (pc *proxyConn) Close() error { 83 | pc.session.Signal(gossh.SIGTERM) 84 | pc.session.Close() 85 | pc.writer.Close() 86 | return nil 87 | } 88 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink_unsupported.go: -------------------------------------------------------------------------------- 1 | // +build !linux !amd64 2 | 3 | package netlink 4 | 5 | import ( 6 | "errors" 7 | "net" 8 | ) 9 | 10 | var ( 11 | ErrNotImplemented = errors.New("not implemented") 12 | ) 13 | 14 | func NetworkGetRoutes() ([]Route, error) { 15 | return nil, ErrNotImplemented 16 | } 17 | 18 | func NetworkLinkAdd(name string, linkType string) error { 19 | return ErrNotImplemented 20 | } 21 | 22 | func NetworkLinkUp(iface *net.Interface) error { 23 | return ErrNotImplemented 24 | } 25 | 26 | func NetworkLinkAddIp(iface *net.Interface, ip net.IP, ipNet *net.IPNet) error { 27 | return ErrNotImplemented 28 | } 29 | 30 | func AddRoute(destination, source, gateway, device string) error { 31 | return ErrNotImplemented 32 | } 33 | 34 | func AddDefaultGw(ip, device string) error { 35 | return ErrNotImplemented 36 | } 37 | 38 | func NetworkSetMTU(iface *net.Interface, mtu int) error { 39 | return ErrNotImplemented 40 | } 41 | 42 | func NetworkCreateVethPair(name1, name2 string) error { 43 | return ErrNotImplemented 44 | } 45 | 46 | func NetworkChangeName(iface *net.Interface, newName string) error { 47 | return ErrNotImplemented 48 | } 49 | 50 | func NetworkSetNsFd(iface *net.Interface, fd int) error { 51 | return ErrNotImplemented 52 | } 53 | 54 | func NetworkSetNsPid(iface *net.Interface, nspid int) error { 55 | return ErrNotImplemented 56 | } 57 | 58 | func NetworkSetMaster(iface, master *net.Interface) error { 59 | return ErrNotImplemented 60 | } 61 | 62 | func NetworkLinkDown(iface *net.Interface) error { 63 | return ErrNotImplemented 64 | } 65 | 66 | func CreateBridge(name string, setMacAddr bool) error { 67 | return ErrNotImplemented 68 | } 69 | 70 | func AddToBridge(iface, master *net.Interface) error { 71 | return ErrNotImplemented 72 | } 73 | -------------------------------------------------------------------------------- /Documentation/examples/service-discovery.md: -------------------------------------------------------------------------------- 1 | # Service Discovery 2 | 3 | Since applications and networking environments vary widely between customer deployments, fleet does not provide a generalized, integrated solution for service discovery. However, there are a number of patterns available which can easily be implemented on top of fleet to provide automated and reliable service discovery. One such pattern, the _sidekick model_, is described below. 4 | 5 | ## Sidekick model 6 | 7 | The sidekick model works in a very similar fashion to [Synapse](https://github.com/airbnb/synapse), which runs a separate discovery agent next to the main container that is being run. This can be easily accomplished in fleet with the `MachineOf` option. 8 | 9 | Instead of guessing when an application is healthy and ready to serve traffic, you can write agent to be as simple or complex as you see fit. For example, your agent might want to check the applications `/v1/health` endpoint after deployment before declaring the instance healthy and announcing it. For another application, you might want to announce each instance by public IP address intead of a private IP. 10 | 11 | ## Sample Discovery Unit 12 | 13 | Here's an extremely simple bash agent that blindly announces our Nginx container after it is started: 14 | 15 | ``` 16 | [Unit] 17 | Description=Announce nginx1.service 18 | # Binds this unit and nginx1 together. When nginx1 is stopped, this unit will be stopped too. 19 | BindsTo=nginx1.service 20 | 21 | [Service] 22 | ExecStart=/bin/sh -c "while true; do etcdctl set /services/website/nginx1 '{ \"host\": \"%H\", \"port\": 8080, \"version\": \"52c7248a14\" }' --ttl 60;sleep 45;done" 23 | ExecStop=/usr/bin/etcdctl delete /services/website/nginx1 24 | 25 | [X-Fleet] 26 | # This unit will always be colocated with nginx1.service 27 | MachineOf=nginx1.service 28 | ``` 29 | -------------------------------------------------------------------------------- /pkg/tls.go: -------------------------------------------------------------------------------- 1 | package pkg 2 | 3 | import ( 4 | "crypto/tls" 5 | "crypto/x509" 6 | "encoding/pem" 7 | "io/ioutil" 8 | ) 9 | 10 | type keypairFunc func(certPEMBlock, keyPEMBlock []byte) (cert tls.Certificate, err error) 11 | 12 | func buildTLSClientConfig(ca, cert, key []byte, parseKeyPair keypairFunc) (*tls.Config, error) { 13 | if len(cert) == 0 && len(key) == 0 { 14 | return &tls.Config{InsecureSkipVerify: true}, nil 15 | } 16 | 17 | tlsCert, err := parseKeyPair(cert, key) 18 | if err != nil { 19 | return nil, err 20 | } 21 | 22 | cfg := tls.Config{ 23 | Certificates: []tls.Certificate{tlsCert}, 24 | MinVersion: tls.VersionTLS10, 25 | } 26 | 27 | if len(ca) != 0 { 28 | cp, err := newCertPool(ca) 29 | if err != nil { 30 | return nil, err 31 | } 32 | cfg.RootCAs = cp 33 | } 34 | 35 | return &cfg, nil 36 | } 37 | 38 | func newCertPool(ca []byte) (*x509.CertPool, error) { 39 | certPool := x509.NewCertPool() 40 | for { 41 | var block *pem.Block 42 | block, ca = pem.Decode(ca) 43 | if block == nil { 44 | break 45 | } 46 | cert, err := x509.ParseCertificate(block.Bytes) 47 | if err != nil { 48 | return nil, err 49 | } 50 | certPool.AddCert(cert) 51 | } 52 | return certPool, nil 53 | } 54 | 55 | func ReadTLSConfigFiles(cafile, certfile, keyfile string) (cfg *tls.Config, err error) { 56 | var ca, cert, key []byte 57 | 58 | if certfile != "" { 59 | cert, err = ioutil.ReadFile(certfile) 60 | if err != nil { 61 | return 62 | } 63 | } 64 | 65 | if keyfile != "" { 66 | key, err = ioutil.ReadFile(keyfile) 67 | if err != nil { 68 | return 69 | } 70 | } 71 | 72 | if cafile != "" { 73 | ca, err = ioutil.ReadFile(cafile) 74 | if err != nil { 75 | return 76 | } 77 | } 78 | 79 | cfg, err = buildTLSClientConfig(ca, cert, key, tls.X509KeyPair) 80 | 81 | return 82 | } 83 | -------------------------------------------------------------------------------- /pkg/filepath_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 CoreOS, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package pkg 18 | 19 | import ( 20 | "os" 21 | "strings" 22 | "testing" 23 | ) 24 | 25 | var pathtests = []struct { 26 | in string 27 | home string 28 | prefix string 29 | suffix string 30 | full string 31 | }{ 32 | {"~/a", "", "/", "/a", ""}, 33 | {"~", "", "/", "", ""}, 34 | {"~~", "", "", "", "~~"}, 35 | {"~/a", "/home/foo", "", "", "/home/foo/a"}, 36 | } 37 | 38 | // TestParseFilepath tests parsing filepath 39 | func TestParseFilepath(t *testing.T) { 40 | for _, test := range pathtests { 41 | oldHome := os.Getenv("HOME") 42 | if err := os.Setenv("HOME", test.home); err != nil { 43 | t.Fatalf("Failed setting $HOME") 44 | } 45 | path := ParseFilepath(test.in) 46 | if !strings.HasPrefix(path, test.prefix) { 47 | t.Errorf("Failed parsing out prefix %v for %v", test.prefix, test.in) 48 | } 49 | if !strings.HasSuffix(path, test.suffix) { 50 | t.Errorf("Failed parsing out suffix %v for %v", test.suffix, test.in) 51 | } 52 | if test.full != "" && path != test.full { 53 | t.Errorf("Failed parsing out %v for %v", test.full, test.in) 54 | } 55 | if err := os.Setenv("HOME", oldHome); err != nil { 56 | t.Fatalf("Failed recovering $HOME") 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/coreos/go-systemd/dbus/subscription_test.go: -------------------------------------------------------------------------------- 1 | package dbus 2 | 3 | import ( 4 | "testing" 5 | "time" 6 | ) 7 | 8 | // TestSubscribe exercises the basics of subscription 9 | func TestSubscribe(t *testing.T) { 10 | conn, err := New() 11 | 12 | if err != nil { 13 | t.Fatal(err) 14 | } 15 | 16 | err = conn.Subscribe() 17 | if err != nil { 18 | t.Fatal(err) 19 | } 20 | 21 | err = conn.Unsubscribe() 22 | if err != nil { 23 | t.Fatal(err) 24 | } 25 | } 26 | 27 | // TestSubscribeUnit exercises the basics of subscription of a particular unit. 28 | func TestSubscribeUnit(t *testing.T) { 29 | target := "subscribe-events.service" 30 | 31 | conn, err := New() 32 | 33 | if err != nil { 34 | t.Fatal(err) 35 | } 36 | 37 | err = conn.Subscribe() 38 | if err != nil { 39 | t.Fatal(err) 40 | } 41 | 42 | err = conn.Unsubscribe() 43 | if err != nil { 44 | t.Fatal(err) 45 | } 46 | 47 | evChan, errChan := conn.SubscribeUnits(time.Second) 48 | 49 | setupUnit(target, conn, t) 50 | linkUnit(target, conn, t) 51 | 52 | reschan := make(chan string) 53 | _, err = conn.StartUnit(target, "replace", reschan) 54 | if err != nil { 55 | t.Fatal(err) 56 | } 57 | 58 | job := <-reschan 59 | if job != "done" { 60 | t.Fatal("Couldn't start", target) 61 | } 62 | 63 | timeout := make(chan bool, 1) 64 | go func() { 65 | time.Sleep(3 * time.Second) 66 | close(timeout) 67 | }() 68 | 69 | for { 70 | select { 71 | case changes := <-evChan: 72 | tCh, ok := changes[target] 73 | 74 | // Just continue until we see our event. 75 | if !ok { 76 | continue 77 | } 78 | 79 | if tCh.ActiveState == "active" && tCh.Name == target { 80 | goto success 81 | } 82 | case err = <-errChan: 83 | t.Fatal(err) 84 | case <-timeout: 85 | t.Fatal("Reached timeout") 86 | } 87 | } 88 | 89 | success: 90 | return 91 | } 92 | -------------------------------------------------------------------------------- /registry/registry.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 CoreOS, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package registry 18 | 19 | import ( 20 | "encoding/json" 21 | "fmt" 22 | 23 | "github.com/coreos/fleet/etcd" 24 | ) 25 | 26 | const DefaultKeyPrefix = "/_coreos.com/fleet/" 27 | 28 | // EtcdRegistry fulfils the Registry interface and uses etcd as a backend 29 | type EtcdRegistry struct { 30 | etcd etcd.Client 31 | keyPrefix string 32 | } 33 | 34 | func NewEtcdRegistry(client etcd.Client, keyPrefix string) *EtcdRegistry { 35 | return &EtcdRegistry{client, keyPrefix} 36 | } 37 | 38 | func marshal(obj interface{}) (string, error) { 39 | encoded, err := json.Marshal(obj) 40 | if err == nil { 41 | return string(encoded), nil 42 | } 43 | return "", fmt.Errorf("unable to JSON-serialize object: %s", err) 44 | } 45 | 46 | func unmarshal(val string, obj interface{}) error { 47 | err := json.Unmarshal([]byte(val), &obj) 48 | if err == nil { 49 | return nil 50 | } 51 | return fmt.Errorf("unable to JSON-deserialize object: %s", err) 52 | } 53 | 54 | func isKeyNotFound(err error) bool { 55 | e, ok := err.(etcd.Error) 56 | return ok && e.ErrorCode == etcd.ErrorKeyNotFound 57 | } 58 | 59 | func isNodeExist(err error) bool { 60 | e, ok := err.(etcd.Error) 61 | return ok && e.ErrorCode == etcd.ErrorNodeExist 62 | } 63 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/google.golang.org/api/google-api-go-generator/testdata/quotednum.want: -------------------------------------------------------------------------------- 1 | // Package adexchangebuyer provides access to the Ad Exchange Buyer API. 2 | // 3 | // See https://developers.google.com/ad-exchange/buyer-rest 4 | // 5 | // Usage example: 6 | // 7 | // import "google.golang.org/api/adexchangebuyer/v1.1" 8 | // ... 9 | // adexchangebuyerService, err := adexchangebuyer.New(oauthHttpClient) 10 | package adexchangebuyer 11 | 12 | import ( 13 | "bytes" 14 | "google.golang.org/api/googleapi" 15 | "encoding/json" 16 | "errors" 17 | "fmt" 18 | "io" 19 | "net/http" 20 | "net/url" 21 | "strconv" 22 | "strings" 23 | ) 24 | 25 | // Always reference these packages, just in case the auto-generated code 26 | // below doesn't. 27 | var _ = bytes.NewBuffer 28 | var _ = strconv.Itoa 29 | var _ = fmt.Sprintf 30 | var _ = json.NewDecoder 31 | var _ = io.Copy 32 | var _ = url.Parse 33 | var _ = googleapi.Version 34 | var _ = errors.New 35 | var _ = strings.Replace 36 | 37 | const apiId = "adexchangebuyer:v1.1" 38 | const apiName = "adexchangebuyer" 39 | const apiVersion = "v1.1" 40 | const basePath = "https://www.googleapis.com/adexchangebuyer/v1.1/" 41 | 42 | // OAuth2 scopes used by this API. 43 | const ( 44 | // Manage your Ad Exchange buyer account configuration 45 | AdexchangeBuyerScope = "https://www.googleapis.com/auth/adexchange.buyer" 46 | ) 47 | 48 | func New(client *http.Client) (*Service, error) { 49 | if client == nil { 50 | return nil, errors.New("client is nil") 51 | } 52 | s := &Service{client: client, BasePath: basePath} 53 | return s, nil 54 | } 55 | 56 | type Service struct { 57 | client *http.Client 58 | BasePath string // API endpoint base URL 59 | } 60 | 61 | type Creative struct { 62 | // AdvertiserId: Detected advertiser id, if any. Read-only. This field 63 | // should not be set in requests. 64 | AdvertiserId googleapi.Int64s `json:"advertiserId,omitempty"` 65 | } 66 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/google.golang.org/api/google-api-go-generator/testdata/mapofany.want: -------------------------------------------------------------------------------- 1 | // Package mapofany provides access to the Example API. 2 | // 3 | // Usage example: 4 | // 5 | // import "google.golang.org/api/mapofany/v1" 6 | // ... 7 | // mapofanyService, err := mapofany.New(oauthHttpClient) 8 | package mapofany 9 | 10 | import ( 11 | "bytes" 12 | "google.golang.org/api/googleapi" 13 | "encoding/json" 14 | "errors" 15 | "fmt" 16 | "io" 17 | "net/http" 18 | "net/url" 19 | "strconv" 20 | "strings" 21 | ) 22 | 23 | // Always reference these packages, just in case the auto-generated code 24 | // below doesn't. 25 | var _ = bytes.NewBuffer 26 | var _ = strconv.Itoa 27 | var _ = fmt.Sprintf 28 | var _ = json.NewDecoder 29 | var _ = io.Copy 30 | var _ = url.Parse 31 | var _ = googleapi.Version 32 | var _ = errors.New 33 | var _ = strings.Replace 34 | 35 | const apiId = "mapofany:v1" 36 | const apiName = "mapofany" 37 | const apiVersion = "v1" 38 | const basePath = "https://www.googleapis.com/discovery/v1/apis" 39 | 40 | func New(client *http.Client) (*Service, error) { 41 | if client == nil { 42 | return nil, errors.New("client is nil") 43 | } 44 | s := &Service{client: client, BasePath: basePath} 45 | return s, nil 46 | } 47 | 48 | type Service struct { 49 | client *http.Client 50 | BasePath string // API endpoint base URL 51 | } 52 | 53 | type JsonValue interface{} 54 | 55 | type TableDataInsertAllRequest struct { 56 | // Kind: The resource type of the response. 57 | Kind string `json:"kind,omitempty"` 58 | 59 | // Rows: The rows to insert. 60 | Rows []*TableDataInsertAllRequestRows `json:"rows,omitempty"` 61 | } 62 | 63 | type TableDataInsertAllRequestRows struct { 64 | // Json: [Required] A JSON object that contains a row of data. The 65 | // object's properties and values must match the destination table's 66 | // schema. 67 | Json map[string]JsonValue `json:"json,omitempty"` 68 | } 69 | -------------------------------------------------------------------------------- /Godeps/Godeps.json: -------------------------------------------------------------------------------- 1 | { 2 | "ImportPath": "github.com/coreos/fleet", 3 | "GoVersion": "go1.3.3", 4 | "Packages": [ 5 | "./..." 6 | ], 7 | "Deps": [ 8 | { 9 | "ImportPath": "github.com/coreos/go-semver/semver", 10 | "Rev": "a9a0c39c7e4a2929f73d4b757d1860fbb8e66d06" 11 | }, 12 | { 13 | "ImportPath": "github.com/coreos/go-systemd/activation", 14 | "Comment": "v2-35-gcf3cdf7", 15 | "Rev": "cf3cdf77462baaad163ad2d5d1984b9c1b493701" 16 | }, 17 | { 18 | "ImportPath": "github.com/coreos/go-systemd/dbus", 19 | "Comment": "v2-35-gcf3cdf7", 20 | "Rev": "cf3cdf77462baaad163ad2d5d1984b9c1b493701" 21 | }, 22 | { 23 | "ImportPath": "github.com/coreos/go-systemd/unit", 24 | "Comment": "v2-35-gcf3cdf7", 25 | "Rev": "cf3cdf77462baaad163ad2d5d1984b9c1b493701" 26 | }, 27 | { 28 | "ImportPath": "github.com/docker/libcontainer/netlink", 29 | "Comment": "v1.1.0-44-g8c0303d", 30 | "Rev": "8c0303d92862eccc4bb9a07d7dac9065e4a32014" 31 | }, 32 | { 33 | "ImportPath": "github.com/godbus/dbus", 34 | "Comment": "0-11-gcfab99a", 35 | "Rev": "cfab99a9500db4ba03067996059d2fc425090bf3" 36 | }, 37 | { 38 | "ImportPath": "github.com/jonboulle/clockwork", 39 | "Rev": "b473f398c464f1988327f67c9e6aa7fba62f80d2" 40 | }, 41 | { 42 | "ImportPath": "github.com/rakyll/globalconf", 43 | "Rev": "fd9ff89130a682478a0c94e893ff4affe570b002" 44 | }, 45 | { 46 | "ImportPath": "github.com/rakyll/goini", 47 | "Rev": "907cca0f578a5316fb864ec6992dc3d9730ec58c" 48 | }, 49 | { 50 | "ImportPath": "golang.org/x/crypto/ssh", 51 | "Comment": "null-234", 52 | "Rev": "60a80aaa50ff0e8506f61b1fa35078a24941be50" 53 | }, 54 | { 55 | "ImportPath": "google.golang.org/api/google-api-go-generator", 56 | "Rev": "d3edb0282bde692467788c50070a9211afe75cf3" 57 | }, 58 | { 59 | "ImportPath": "google.golang.org/api/googleapi", 60 | "Rev": "d3edb0282bde692467788c50070a9211afe75cf3" 61 | } 62 | ] 63 | } 64 | -------------------------------------------------------------------------------- /machine/state.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 CoreOS, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package machine 18 | 19 | const ( 20 | shortIDLen = 8 21 | ) 22 | 23 | // MachineState represents a point-in-time snapshot of the 24 | // state of the local host. 25 | type MachineState struct { 26 | ID string 27 | PublicIP string 28 | Metadata map[string]string 29 | Version string 30 | } 31 | 32 | func (ms MachineState) ShortID() string { 33 | if len(ms.ID) <= shortIDLen { 34 | return ms.ID 35 | } 36 | return ms.ID[0:shortIDLen] 37 | } 38 | 39 | func (ms MachineState) MatchID(ID string) bool { 40 | return ms.ID == ID || ms.ShortID() == ID 41 | } 42 | 43 | // stackState is used to merge two MachineStates. Values configured on the top 44 | // MachineState always take precedence over those on the bottom. 45 | func stackState(top, bottom MachineState) MachineState { 46 | state := MachineState(bottom) 47 | 48 | if top.PublicIP != "" { 49 | state.PublicIP = top.PublicIP 50 | } 51 | 52 | if top.ID != "" { 53 | state.ID = top.ID 54 | } 55 | 56 | //FIXME: This will *always* overwrite the bottom's metadata, 57 | // but the only use-case we have today does not ever have 58 | // metadata on the bottom. 59 | if len(top.Metadata) > 0 { 60 | state.Metadata = top.Metadata 61 | } 62 | 63 | if top.Version != "" { 64 | state.Version = top.Version 65 | } 66 | 67 | return state 68 | } 69 | -------------------------------------------------------------------------------- /api/mux_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 CoreOS, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package api 18 | 19 | import ( 20 | "fmt" 21 | "net/http" 22 | "net/http/httptest" 23 | "testing" 24 | 25 | "github.com/coreos/fleet/registry" 26 | "github.com/coreos/fleet/version" 27 | ) 28 | 29 | func TestDefaultHandlers(t *testing.T) { 30 | tests := []struct { 31 | method string 32 | path string 33 | code int 34 | }{ 35 | {"GET", "/", http.StatusMethodNotAllowed}, 36 | {"GET", "/v1-alpha", http.StatusMethodNotAllowed}, 37 | {"GET", "/fleet/v1", http.StatusMethodNotAllowed}, 38 | {"GET", "/bogus", http.StatusNotFound}, 39 | } 40 | 41 | for i, tt := range tests { 42 | fr := registry.NewFakeRegistry() 43 | hdlr := NewServeMux(fr) 44 | rr := httptest.NewRecorder() 45 | 46 | req, err := http.NewRequest(tt.method, tt.path, nil) 47 | if err != nil { 48 | t.Errorf("case %d: failed setting up http.Request for test: %v", i, err) 49 | continue 50 | } 51 | 52 | hdlr.ServeHTTP(rr, req) 53 | 54 | err = assertErrorResponse(rr, tt.code) 55 | if err != nil { 56 | t.Errorf("case %d: %v", i, err) 57 | } 58 | 59 | wantServer := fmt.Sprintf("fleetd/%s", version.Version) 60 | gotServer := rr.HeaderMap["Server"][0] 61 | if wantServer != gotServer { 62 | t.Errorf("case %d: received incorrect Server header: want=%s, got=%s", i, wantServer, gotServer) 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /etcd/result.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 CoreOS, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package etcd 18 | 19 | import ( 20 | "encoding/json" 21 | "fmt" 22 | "net/http" 23 | "time" 24 | ) 25 | 26 | type Result struct { 27 | Action string `json:"action"` 28 | Node *Node `json:"node"` 29 | PrevNode *Node `json:"prevNode"` 30 | Raw []byte `json:"-"` 31 | } 32 | 33 | func (r *Result) String() string { 34 | return fmt.Sprintf("{Action: %s, Node: %v, PrevNode: %v}", r.Action, r.Node, r.PrevNode) 35 | } 36 | 37 | type Nodes []Node 38 | type Node struct { 39 | Key string `json:"key"` 40 | Value string `json:"value"` 41 | TTL int `json:"ttl"` 42 | Nodes Nodes `json:"nodes"` 43 | ModifiedIndex uint64 `json:"modifiedIndex"` 44 | CreatedIndex uint64 `json:"createdIndex"` 45 | } 46 | 47 | func (n Node) TTLDuration() time.Duration { 48 | dur := time.Duration(n.TTL) * time.Second 49 | if dur < 0 { 50 | dur = 0 51 | } 52 | return dur 53 | } 54 | 55 | func (n *Node) String() string { 56 | return fmt.Sprintf("{Key: %s, CreatedIndex: %d, ModifiedIndex: %d}", n.Key, n.CreatedIndex, n.ModifiedIndex) 57 | } 58 | 59 | func unmarshalSuccessfulResponse(resp *http.Response, body []byte) (*Result, error) { 60 | var res Result 61 | err := json.Unmarshal(body, &res) 62 | if err != nil { 63 | return nil, err 64 | } 65 | 66 | res.Raw = body 67 | return &res, nil 68 | } 69 | -------------------------------------------------------------------------------- /resource/resource_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 CoreOS, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package resource 18 | 19 | import "reflect" 20 | import "testing" 21 | 22 | func TestSum(t *testing.T) { 23 | for i, tt := range []struct { 24 | in []ResourceTuple 25 | want ResourceTuple 26 | }{ 27 | { 28 | []ResourceTuple{ResourceTuple{10, 24, 1024}}, 29 | ResourceTuple{10, 24, 1024}, 30 | }, 31 | { 32 | []ResourceTuple{ResourceTuple{10, 24, 1024}, ResourceTuple{10, 24, 1024}}, 33 | ResourceTuple{20, 48, 2048}, 34 | }, 35 | { 36 | []ResourceTuple{}, 37 | ResourceTuple{0, 0, 0}, 38 | }, 39 | } { 40 | got := Sum(tt.in...) 41 | if !reflect.DeepEqual(got, tt.want) { 42 | t.Errorf("case %d: got %v, want %v", i, got, tt.want) 43 | } 44 | } 45 | } 46 | 47 | func TestSub(t *testing.T) { 48 | for i, tt := range []struct { 49 | r1 ResourceTuple 50 | r2 ResourceTuple 51 | want ResourceTuple 52 | }{ 53 | { 54 | ResourceTuple{10, 24, 1024}, 55 | ResourceTuple{10, 24, 1024}, 56 | ResourceTuple{0, 0, 0}, 57 | }, 58 | { 59 | ResourceTuple{20, 48, 2048}, 60 | ResourceTuple{15, 36, 2048}, 61 | ResourceTuple{5, 12, 0}, 62 | }, 63 | { 64 | ResourceTuple{0, 0, 0}, 65 | ResourceTuple{0, 0, 0}, 66 | ResourceTuple{0, 0, 0}, 67 | }, 68 | } { 69 | got := Sub(tt.r1, tt.r2) 70 | if !reflect.DeepEqual(got, tt.want) { 71 | t.Errorf("case %d: got %v, want %v", i, got, tt.want) 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/coreos/go-systemd/activation/packetconns_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 CoreOS Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package activation 18 | 19 | import ( 20 | "net" 21 | "os" 22 | "os/exec" 23 | "testing" 24 | ) 25 | 26 | // TestActivation forks out a copy of activation.go example and reads back two 27 | // strings from the pipes that are passed in. 28 | func TestPacketConns(t *testing.T) { 29 | cmd := exec.Command("go", "run", "../examples/activation/udpconn.go") 30 | 31 | u1, err := net.ListenUDP("udp", &net.UDPAddr{Port: 9999}) 32 | if err != nil { 33 | t.Fatalf(err.Error()) 34 | } 35 | u2, err := net.ListenUDP("udp", &net.UDPAddr{Port: 1234}) 36 | if err != nil { 37 | t.Fatalf(err.Error()) 38 | } 39 | 40 | f1, _ := u1.File() 41 | f2, _ := u2.File() 42 | 43 | cmd.ExtraFiles = []*os.File{ 44 | f1, 45 | f2, 46 | } 47 | 48 | r1, err := net.Dial("udp", "127.0.0.1:9999") 49 | if err != nil { 50 | t.Fatalf(err.Error()) 51 | } 52 | r1.Write([]byte("Hi")) 53 | 54 | r2, err := net.Dial("udp", "127.0.0.1:1234") 55 | if err != nil { 56 | t.Fatalf(err.Error()) 57 | } 58 | r2.Write([]byte("Hi")) 59 | 60 | cmd.Env = os.Environ() 61 | cmd.Env = append(cmd.Env, "LISTEN_FDS=2", "FIX_LISTEN_PID=1") 62 | 63 | out, err := cmd.CombinedOutput() 64 | if err != nil { 65 | t.Fatalf("Cmd output '%s', err: '%s'\n", out, err) 66 | } 67 | 68 | correctStringWrittenNet(t, r1, "Hello world") 69 | correctStringWrittenNet(t, r2, "Goodbye world") 70 | } 71 | -------------------------------------------------------------------------------- /fleetctl/fdforward.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 CoreOS, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "io" 21 | "net" 22 | "os" 23 | ) 24 | 25 | var ( 26 | cmdFDForward = &Command{ 27 | Name: "fd-forward", 28 | Summary: "Proxy stdin and stdout to a unix domain socket", 29 | Usage: "SOCKET", 30 | Description: `fleetctl utilizes fd-forward when --tunnel is used and --endpoint is a unix socket. This command is not intended to be called by users directly.`, 31 | Run: runFDForward, 32 | } 33 | ) 34 | 35 | func runFDForward(args []string) (exit int) { 36 | if len(args) != 1 { 37 | stderr("Provide a single argument") 38 | return 1 39 | } 40 | 41 | to := args[0] 42 | 43 | raddr, err := net.ResolveUnixAddr("unix", to) 44 | if err != nil { 45 | stderr("Unable to use %q as unix address: %v", to, err) 46 | return 1 47 | } 48 | 49 | sock, err := net.DialUnix("unix", nil, raddr) 50 | if err != nil { 51 | stderr("Failed dialing remote address: %v", err) 52 | return 53 | } 54 | defer sock.Close() 55 | 56 | errchan := make(chan error) 57 | go cp(os.Stdout, sock, errchan) 58 | go cp(sock, os.Stdin, errchan) 59 | 60 | select { 61 | case err := <-errchan: 62 | if err != nil { 63 | stderr("Encountered error during copy: %v", err) 64 | return 1 65 | } 66 | } 67 | 68 | return 69 | } 70 | 71 | func cp(to io.Writer, from io.Reader, errchan chan error) { 72 | _, err := io.Copy(to, from) 73 | errchan <- err 74 | } 75 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/golang.org/x/crypto/ssh/agent/server_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package agent 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/coreos/fleet/Godeps/_workspace/src/golang.org/x/crypto/ssh" 11 | ) 12 | 13 | func TestServer(t *testing.T) { 14 | c1, c2, err := netPipe() 15 | if err != nil { 16 | t.Fatalf("netPipe: %v", err) 17 | } 18 | defer c1.Close() 19 | defer c2.Close() 20 | client := NewClient(c1) 21 | 22 | go ServeAgent(NewKeyring(), c2) 23 | 24 | testAgentInterface(t, client, testPrivateKeys["rsa"], nil) 25 | } 26 | 27 | func TestLockServer(t *testing.T) { 28 | testLockAgent(NewKeyring(), t) 29 | } 30 | 31 | func TestSetupForwardAgent(t *testing.T) { 32 | a, b, err := netPipe() 33 | if err != nil { 34 | t.Fatalf("netPipe: %v", err) 35 | } 36 | 37 | defer a.Close() 38 | defer b.Close() 39 | 40 | _, socket, cleanup := startAgent(t) 41 | defer cleanup() 42 | 43 | serverConf := ssh.ServerConfig{ 44 | NoClientAuth: true, 45 | } 46 | serverConf.AddHostKey(testSigners["rsa"]) 47 | incoming := make(chan *ssh.ServerConn, 1) 48 | go func() { 49 | conn, _, _, err := ssh.NewServerConn(a, &serverConf) 50 | if err != nil { 51 | t.Fatalf("Server: %v", err) 52 | } 53 | incoming <- conn 54 | }() 55 | 56 | conf := ssh.ClientConfig{} 57 | conn, chans, reqs, err := ssh.NewClientConn(b, "", &conf) 58 | if err != nil { 59 | t.Fatalf("NewClientConn: %v", err) 60 | } 61 | client := ssh.NewClient(conn, chans, reqs) 62 | 63 | if err := ForwardToRemote(client, socket); err != nil { 64 | t.Fatalf("SetupForwardAgent: %v", err) 65 | } 66 | 67 | server := <-incoming 68 | ch, reqs, err := server.OpenChannel(channelType, nil) 69 | if err != nil { 70 | t.Fatalf("OpenChannel(%q): %v", channelType, err) 71 | } 72 | go ssh.DiscardRequests(reqs) 73 | 74 | agentClient := NewClient(ch) 75 | testAgentInterface(t, agentClient, testPrivateKeys["rsa"], nil) 76 | conn.Close() 77 | } 78 | -------------------------------------------------------------------------------- /api/discovery_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 CoreOS, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package api 18 | 19 | import ( 20 | "net/http" 21 | "net/http/httptest" 22 | "testing" 23 | 24 | "github.com/coreos/fleet/schema" 25 | ) 26 | 27 | func TestDiscoveryJson(t *testing.T) { 28 | url := "http://example.com/discovery" 29 | for _, verb := range []string{"POST", "PUT", "DELETE"} { 30 | res := &discoveryResource{} 31 | rw := httptest.NewRecorder() 32 | req, err := http.NewRequest(verb, url, nil) 33 | if err != nil { 34 | t.Fatalf("Failed creating http.Request: %v", err) 35 | } 36 | res.ServeHTTP(rw, req) 37 | if rw.Code != http.StatusBadRequest { 38 | t.Errorf("Expected 400 for %s, got %d", verb, rw.Code) 39 | } 40 | } 41 | res := &discoveryResource{} 42 | rw := httptest.NewRecorder() 43 | req, err := http.NewRequest("GET", url, nil) 44 | if err != nil { 45 | t.Fatalf("Failed creating http.Request: %v", err) 46 | } 47 | res.ServeHTTP(rw, req) 48 | if rw.Code != http.StatusOK { 49 | t.Errorf("Expected 200, got %d", rw.Code) 50 | } 51 | ct := rw.HeaderMap["Content-Type"] 52 | if len(ct) != 1 { 53 | t.Errorf("Response has wrong number of Content-Type values: %v", ct) 54 | } else if ct[0] != "application/json" { 55 | t.Errorf("Expected application/json, got %s", ct) 56 | } 57 | if rw.Body == nil { 58 | t.Error("Received nil response body") 59 | } else { 60 | if rw.Body.String() != schema.DiscoveryJSON { 61 | t.Error("Received unexpected body!") 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /api/server.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 CoreOS, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package api 18 | 19 | import ( 20 | "errors" 21 | "net" 22 | "net/http" 23 | 24 | "github.com/coreos/fleet/log" 25 | ) 26 | 27 | var unavailable = &unavailableHdlr{} 28 | 29 | func NewServer(listeners []net.Listener, hdlr http.Handler) *Server { 30 | return &Server{ 31 | listeners: listeners, 32 | api: hdlr, 33 | cur: unavailable, 34 | } 35 | } 36 | 37 | type Server struct { 38 | listeners []net.Listener 39 | api http.Handler 40 | cur http.Handler 41 | } 42 | 43 | func (s *Server) ServeHTTP(rw http.ResponseWriter, req *http.Request) { 44 | s.cur.ServeHTTP(rw, req) 45 | } 46 | 47 | func (s *Server) Serve() { 48 | for i, _ := range s.listeners { 49 | l := s.listeners[i] 50 | go func() { 51 | err := http.Serve(l, s) 52 | if err != nil { 53 | log.Errorf("Failed serving HTTP on listener: %v", l.Addr()) 54 | } 55 | }() 56 | } 57 | } 58 | 59 | // Available switches the Server's HTTP handler from a generic 503 Unavailable 60 | // response to the actual API. Once the provided channel is closed, the API is 61 | // torn back down and 503 responses are served. 62 | func (s *Server) Available(stop chan bool) { 63 | s.cur = s.api 64 | <-stop 65 | s.cur = unavailable 66 | } 67 | 68 | type unavailableHdlr struct{} 69 | 70 | func (uh *unavailableHdlr) ServeHTTP(rw http.ResponseWriter, req *http.Request) { 71 | sendError(rw, http.StatusServiceUnavailable, errors.New("fleet server currently unavailable")) 72 | } 73 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/golang.org/x/crypto/ssh/testdata/keys.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package testdata 6 | 7 | var PEMBytes = map[string][]byte{ 8 | "dsa": []byte(`-----BEGIN DSA PRIVATE KEY----- 9 | MIIBuwIBAAKBgQD6PDSEyXiI9jfNs97WuM46MSDCYlOqWw80ajN16AohtBncs1YB 10 | lHk//dQOvCYOsYaE+gNix2jtoRjwXhDsc25/IqQbU1ahb7mB8/rsaILRGIbA5WH3 11 | EgFtJmXFovDz3if6F6TzvhFpHgJRmLYVR8cqsezL3hEZOvvs2iH7MorkxwIVAJHD 12 | nD82+lxh2fb4PMsIiaXudAsBAoGAQRf7Q/iaPRn43ZquUhd6WwvirqUj+tkIu6eV 13 | 2nZWYmXLlqFQKEy4Tejl7Wkyzr2OSYvbXLzo7TNxLKoWor6ips0phYPPMyXld14r 14 | juhT24CrhOzuLMhDduMDi032wDIZG4Y+K7ElU8Oufn8Sj5Wge8r6ANmmVgmFfynr 15 | FhdYCngCgYEA3ucGJ93/Mx4q4eKRDxcWD3QzWyqpbRVRRV1Vmih9Ha/qC994nJFz 16 | DQIdjxDIT2Rk2AGzMqFEB68Zc3O+Wcsmz5eWWzEwFxaTwOGWTyDqsDRLm3fD+QYj 17 | nOwuxb0Kce+gWI8voWcqC9cyRm09jGzu2Ab3Bhtpg8JJ8L7gS3MRZK4CFEx4UAfY 18 | Fmsr0W6fHB9nhS4/UXM8 19 | -----END DSA PRIVATE KEY----- 20 | `), 21 | "ecdsa": []byte(`-----BEGIN EC PRIVATE KEY----- 22 | MHcCAQEEINGWx0zo6fhJ/0EAfrPzVFyFC9s18lBt3cRoEDhS3ARooAoGCCqGSM49 23 | AwEHoUQDQgAEi9Hdw6KvZcWxfg2IDhA7UkpDtzzt6ZqJXSsFdLd+Kx4S3Sx4cVO+ 24 | 6/ZOXRnPmNAlLUqjShUsUBBngG0u2fqEqA== 25 | -----END EC PRIVATE KEY----- 26 | `), 27 | "rsa": []byte(`-----BEGIN RSA PRIVATE KEY----- 28 | MIIBOwIBAAJBALdGZxkXDAjsYk10ihwU6Id2KeILz1TAJuoq4tOgDWxEEGeTrcld 29 | r/ZwVaFzjWzxaf6zQIJbfaSEAhqD5yo72+sCAwEAAQJBAK8PEVU23Wj8mV0QjwcJ 30 | tZ4GcTUYQL7cF4+ezTCE9a1NrGnCP2RuQkHEKxuTVrxXt+6OF15/1/fuXnxKjmJC 31 | nxkCIQDaXvPPBi0c7vAxGwNY9726x01/dNbHCE0CBtcotobxpwIhANbbQbh3JHVW 32 | 2haQh4fAG5mhesZKAGcxTyv4mQ7uMSQdAiAj+4dzMpJWdSzQ+qGHlHMIBvVHLkqB 33 | y2VdEyF7DPCZewIhAI7GOI/6LDIFOvtPo6Bj2nNmyQ1HU6k/LRtNIXi4c9NJAiAr 34 | rrxx26itVhJmcvoUhOjwuzSlP2bE5VHAvkGB352YBg== 35 | -----END RSA PRIVATE KEY----- 36 | `), 37 | "user": []byte(`-----BEGIN EC PRIVATE KEY----- 38 | MHcCAQEEILYCAeq8f7V4vSSypRw7pxy8yz3V5W4qg8kSC3zJhqpQoAoGCCqGSM49 39 | AwEHoUQDQgAEYcO2xNKiRUYOLEHM7VYAp57HNyKbOdYtHD83Z4hzNPVC4tM5mdGD 40 | PLL8IEwvYu2wq+lpXfGQnNMbzYf9gspG0w== 41 | -----END EC PRIVATE KEY----- 42 | `), 43 | } 44 | -------------------------------------------------------------------------------- /registry/job_state.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 CoreOS, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package registry 18 | 19 | import ( 20 | "path" 21 | "time" 22 | 23 | "github.com/coreos/fleet/etcd" 24 | "github.com/coreos/fleet/job" 25 | "github.com/coreos/fleet/unit" 26 | ) 27 | 28 | // determineJobState decides what the State field of a Job object should 29 | // be, based on three parameters: 30 | // - heartbeat should be the machine ID that is known to have recently 31 | // heartbeaten (see UnitHeartbeat) the Unit. 32 | // - tgt should be the machine ID to which the Job is currently scheduled 33 | // - us should be the most recent UnitState 34 | func determineJobState(heartbeat, tgt string, us *unit.UnitState) (state job.JobState) { 35 | state = job.JobStateInactive 36 | 37 | if tgt == "" || us == nil { 38 | return 39 | } 40 | 41 | state = job.JobStateLoaded 42 | 43 | if heartbeat != tgt { 44 | return 45 | } 46 | 47 | state = job.JobStateLaunched 48 | return 49 | } 50 | 51 | func (r *EtcdRegistry) UnitHeartbeat(name, machID string, ttl time.Duration) error { 52 | req := etcd.Set{ 53 | Key: r.jobHeartbeatPath(name), 54 | Value: machID, 55 | TTL: ttl, 56 | } 57 | _, err := r.etcd.Do(&req) 58 | return err 59 | } 60 | 61 | func (r *EtcdRegistry) ClearUnitHeartbeat(name string) { 62 | req := etcd.Delete{ 63 | Key: r.jobHeartbeatPath(name), 64 | } 65 | r.etcd.Do(&req) 66 | } 67 | 68 | func (r *EtcdRegistry) jobHeartbeatPath(jobName string) string { 69 | return path.Join(r.keyPrefix, jobPrefix, jobName, "job-state") 70 | } 71 | -------------------------------------------------------------------------------- /machine/machine_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 CoreOS, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package machine 18 | 19 | import ( 20 | "testing" 21 | 22 | "github.com/coreos/fleet/pkg" 23 | ) 24 | 25 | func TestHasMetadata(t *testing.T) { 26 | testCases := []struct { 27 | metadata map[string]string 28 | match map[string]pkg.Set 29 | want bool 30 | }{ 31 | { 32 | map[string]string{ 33 | "region": "us-east-1", 34 | }, 35 | map[string]pkg.Set{ 36 | "region": pkg.NewUnsafeSet("us-east-1"), 37 | }, 38 | true, 39 | }, 40 | { 41 | map[string]string{ 42 | "groups": "ping", 43 | }, 44 | map[string]pkg.Set{ 45 | "groups": pkg.NewUnsafeSet("ping", "pong"), 46 | }, 47 | true, 48 | }, 49 | { 50 | map[string]string{ 51 | "groups": "ping", 52 | }, 53 | map[string]pkg.Set{ 54 | "groups": pkg.NewUnsafeSet("pong"), 55 | }, 56 | false, 57 | }, 58 | { 59 | map[string]string{ 60 | "region": "us-east-1", 61 | "groups": "ping", 62 | }, 63 | map[string]pkg.Set{ 64 | "region": pkg.NewUnsafeSet("us-east-1"), 65 | "groups": pkg.NewUnsafeSet("pong"), 66 | }, 67 | false, 68 | }, 69 | { 70 | map[string]string{}, 71 | map[string]pkg.Set{ 72 | "groups": pkg.NewUnsafeSet("pong"), 73 | }, 74 | false, 75 | }, 76 | } 77 | 78 | for i, tt := range testCases { 79 | ms := &MachineState{Metadata: tt.metadata} 80 | got := HasMetadata(ms, tt.match) 81 | if got != tt.want { 82 | t.Errorf("case %d: HasMetadata returned %t, expected %t", i, got, tt.want) 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/google.golang.org/api/google-api-go-generator/testdata/mapofstrings-1.json: -------------------------------------------------------------------------------- 1 | { 2 | "kind": "discovery#restDescription", 3 | "etag": "\"kEk3sFj6Ef5_yR1-H3bAO6qw9mI/3m5rB86FE5KuW1K3jAl88AxCreg\"", 4 | "discoveryVersion": "v1", 5 | "id": "additionalprops:v1", 6 | "name": "additionalprops", 7 | "version": "v1", 8 | "title": "Example API", 9 | "description": "The Example API demonstrates an associative array.", 10 | "ownerDomain": "google.com", 11 | "ownerName": "Google", 12 | "protocol": "rest", 13 | "schemas": { 14 | "TimeseriesDescriptor": { 15 | "id": "TimeseriesDescriptor", 16 | "type": "object", 17 | "description": "The descriptions of a time series.", 18 | "properties": { 19 | "labels": { 20 | "type": "object", 21 | "description": "The set of key-value pairs that describe this time series, including target-specific labels and metric-specific labels.", 22 | "additionalProperties": { 23 | "type": "string", 24 | "description": "The label's name." 25 | } 26 | }, 27 | "metric": { 28 | "type": "string", 29 | "description": "The name of the metric." 30 | }, 31 | "project": { 32 | "type": "string", 33 | "description": "The project ID to which this time series belongs." 34 | }, 35 | "tags": { 36 | "type": "object", 37 | "description": "A map of additional information.", 38 | "additionalProperties": { 39 | "type": "array", 40 | "description": "A string which maps to an array of values.", 41 | "items": { 42 | "type": "string" 43 | } 44 | } 45 | } 46 | } 47 | }, 48 | "GetMapResponse": { 49 | "id": "GetMapResponse", 50 | "type": "object", 51 | "description": "Response of getting a map.", 52 | "additionalProperties": { 53 | "type": "string" 54 | } 55 | } 56 | }, 57 | "resources": { 58 | "atlas": { 59 | "methods": { 60 | "getMap": { 61 | "id": "mapofstrings.getMap", 62 | "path": "map", 63 | "httpMethod": "GET", 64 | "description": "Get a map.", 65 | "response": { 66 | "$ref": "GetMapResponse" 67 | } 68 | } 69 | } 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/google.golang.org/api/google-api-go-generator/testdata/mapofarrayofobjects.json: -------------------------------------------------------------------------------- 1 | { 2 | "kind": "discovery#restDescription", 3 | "etag": "\"kEk3sFj6Ef5_yR1-H3bAO6qw9mI/3m5rB86FE5KuW1K3jAl88AxCreg\"", 4 | "discoveryVersion": "v1", 5 | "id": "additionalprops:v1", 6 | "name": "additionalprops", 7 | "version": "v1", 8 | "title": "Example API", 9 | "description": "The Example API demonstrates an associative array.", 10 | "ownerDomain": "google.com", 11 | "ownerName": "Google", 12 | "protocol": "rest", 13 | "schemas": { 14 | "TimeseriesDescriptor": { 15 | "id": "TimeseriesDescriptor", 16 | "type": "object", 17 | "description": "The descriptions of a time series.", 18 | "properties": { 19 | "labels": { 20 | "type": "object", 21 | "description": "The set of key-value pairs that describe this time series, including target-specific labels and metric-specific labels.", 22 | "additionalProperties": { 23 | "type": "string", 24 | "description": "The label's name." 25 | } 26 | }, 27 | "metric": { 28 | "type": "string", 29 | "description": "The name of the metric." 30 | }, 31 | "project": { 32 | "type": "string", 33 | "description": "The project ID to which this time series belongs." 34 | }, 35 | "tags": { 36 | "type": "object", 37 | "description": "A map of additional information.", 38 | "additionalProperties": { 39 | "type": "array", 40 | "description": "A string which maps to an array of values.", 41 | "items": { 42 | "$ref": "Property" 43 | } 44 | } 45 | } 46 | } 47 | }, 48 | "GetMapResponse": { 49 | "id": "GetMapResponse", 50 | "type": "object", 51 | "description": "Response of getting a map.", 52 | "additionalProperties": { 53 | "type": "string" 54 | } 55 | } 56 | }, 57 | "resources": { 58 | "atlas": { 59 | "methods": { 60 | "getMap": { 61 | "id": "mapofstrings.getMap", 62 | "path": "map", 63 | "httpMethod": "GET", 64 | "description": "Get a map.", 65 | "response": { 66 | "$ref": "GetMapResponse" 67 | } 68 | } 69 | } 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /resource/resource.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 CoreOS, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package resource 18 | 19 | // ResourceTuple groups together CPU, memory and disk space. This could be 20 | // total, available or consumed. It could also be used by job resource requirements. 21 | type ResourceTuple struct { 22 | // in hundreds, ie 100=1core, 50=0.5core, 200=2cores, etc 23 | Cores int 24 | // in MB 25 | Memory int 26 | // in MB 27 | Disk int 28 | } 29 | 30 | // Empty returns true if all components of the ResourceTuple are zero. 31 | func (rt ResourceTuple) Empty() bool { 32 | return rt.Cores == 0 && rt.Memory == 0 && rt.Disk == 0 33 | } 34 | 35 | const ( 36 | // TODO(jonboulle): make these configurable 37 | HostCores = 100 38 | HostMemory = 256 39 | HostDisk = 0 40 | ) 41 | 42 | // HostResources represents a set of resources that fleet considers reserved 43 | // for the host, i.e. outside of any units it is running 44 | var HostResources = ResourceTuple{ 45 | HostCores, 46 | HostMemory, 47 | HostDisk, 48 | } 49 | 50 | // Sum aggregates a number of ResourceTuples into a single entity 51 | func Sum(resources ...ResourceTuple) (res ResourceTuple) { 52 | for _, r := range resources { 53 | res.Cores += r.Cores 54 | res.Memory += r.Memory 55 | res.Disk += r.Disk 56 | } 57 | return 58 | } 59 | 60 | // Sub returns a ResourceTuple representing the difference between two 61 | // ResourceTuples 62 | func Sub(r1, r2 ResourceTuple) (res ResourceTuple) { 63 | res.Cores = r1.Cores - r2.Cores 64 | res.Memory = r1.Memory - r2.Memory 65 | res.Disk = r1.Disk - r2.Disk 66 | return 67 | } 68 | -------------------------------------------------------------------------------- /functional/README.md: -------------------------------------------------------------------------------- 1 | ## fleet functional tests 2 | 3 | This functional test suite deploys a fleet cluster using nspawn containers, and asserts fleet is functioning properly. 4 | 5 | It shares an instance of etcd deployed on the host machine with each of the nspawn containers. 6 | 7 | It's recommended to run this in a virtual machine environment on CoreOS (e.g. using coreos-vagrant). The only dependency for the tests not provided on the CoreOS image is `go`. 8 | 9 | The caller must do three things before running the tests: 10 | 11 | 1. Ensure an ssh-agent is running and the functional-testing identity is loaded. The `SSH_AUTH_SOCK` environment variable must be set. 12 | 13 | ``` 14 | $ ssh-agent 15 | $ ssh-add fleet/functional/fixtures/id_rsa 16 | $ echo $SSH_AUTH_SOCK 17 | /tmp/ssh-kwmtTOsL7978/agent.7978 18 | ``` 19 | 2. Ensure the `FLEETD_BIN` and `FLEETCTL_BIN` environment variables point to the respective fleetd and fleetctl binaries that should be used to drive the actual tests. 20 | 21 | ``` 22 | $ export FLEETD_BIN=/path/to/fleetd 23 | $ export FLEETCTL_BIN=/path/to/fleetctl 24 | ``` 25 | 26 | 3. Make sure etcd is running on the host system. 27 | 28 | ``` 29 | $ systemctl start etcd 30 | ``` 31 | 32 | Then the tests can be run with: 33 | 34 | ``` 35 | # go test github.com/coreos/fleet/functional 36 | ``` 37 | 38 | Since the tests utilize `systemd-nspawn`, this needs to be invoked as sudo/root. 39 | 40 | An example test session using coreos-vagrant follows. This assumes that go is available in `/home/core/go` and the fleet repository in `/home/core/fleet` on the target machine (the easiest way to achieve this is to use shared folders). 41 | ``` 42 | vagrant ssh core-01 -- -A 43 | export GOROOT="$(pwd)/go" 44 | export PATH="${GOROOT}/bin:$PATH" 45 | cd fleet 46 | ssh-add functional/fixtures/id_rsa 47 | export GOPATH="$(pwd)/gopath" 48 | export FLEETD_BIN="$(pwd)/bin/fleet" 49 | export FLEETCTL_BIN="$(pwd)/bin/fleetctl" 50 | sudo -E env PATH=$PATH go test github.com/coreos/fleet/functional -v 51 | ``` 52 | 53 | If the tests are aborted partway through, it's currently possible for them to leave residual state as a result of the systemd-nspawn operations. This can be cleaned up using the `clean.sh` script. 54 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/google.golang.org/api/google-api-go-generator/gen_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "flag" 6 | "io/ioutil" 7 | "path/filepath" 8 | "testing" 9 | ) 10 | 11 | var updateGolden = flag.Bool("update_golden", false, "If true, causes TestAPIs to update golden files") 12 | 13 | func TestAPIs(t *testing.T) { 14 | names := []string{ 15 | "arrayofarray-1", 16 | "arrayofmapofobjects", 17 | "arrayofmapofstrings", 18 | "blogger-3", 19 | "getwithoutbody", 20 | "mapofany", 21 | "mapofarrayofobjects", 22 | "mapofobjects", 23 | "mapofstrings-1", 24 | "quotednum", 25 | "resource-named-service", // blogger/v3/blogger-api.json + s/BlogUserInfo/Service/ 26 | "variants", 27 | } 28 | for _, name := range names { 29 | api, err := apiFromFile(filepath.Join("testdata", name+".json")) 30 | if err != nil { 31 | t.Errorf("Error loading API testdata/%s.json: %v", name, err) 32 | continue 33 | } 34 | clean, err := api.GenerateCode() 35 | if err != nil { 36 | t.Errorf("Error generating code for %s: %v", name, err) 37 | continue 38 | } 39 | goldenFile := filepath.Join("testdata", name+".want") 40 | if *updateGolden { 41 | if err := ioutil.WriteFile(goldenFile, clean, 0644); err != nil { 42 | t.Fatal(err) 43 | } 44 | } 45 | want, err := ioutil.ReadFile(goldenFile) 46 | if err != nil { 47 | t.Error(err) 48 | continue 49 | } 50 | if !bytes.Equal(want, clean) { 51 | tf, _ := ioutil.TempFile("", "api-"+name+"-got-json.") 52 | tf.Write(clean) 53 | tf.Close() 54 | t.Errorf("Output for API %s differs: diff -u %s %s", name, goldenFile, tf.Name()) 55 | } 56 | } 57 | } 58 | 59 | func TestScope(t *testing.T) { 60 | tests := [][]string{ 61 | { 62 | "https://www.googleapis.com/auth/somescope", 63 | "SomescopeScope", 64 | }, 65 | { 66 | "https://mail.google.com/somescope", 67 | "MailGoogleComSomescopeScope", 68 | }, 69 | { 70 | "https://mail.google.com/", 71 | "MailGoogleComScope", 72 | }, 73 | } 74 | for _, test := range tests { 75 | if got := scopeIdentifierFromURL(test[0]); got != test[1] { 76 | t.Errorf("scopeIdentifierFromURL(%q) got %q, want %q", test[0], got, test[1]) 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /registry/event_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 CoreOS, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package registry 18 | 19 | import ( 20 | "reflect" 21 | "testing" 22 | 23 | "github.com/coreos/fleet/etcd" 24 | "github.com/coreos/fleet/pkg" 25 | ) 26 | 27 | func TestFilterEtcdEvents(t *testing.T) { 28 | tests := []struct { 29 | in string 30 | ev pkg.Event 31 | ok bool 32 | }{ 33 | { 34 | in: "", 35 | ok: false, 36 | }, 37 | { 38 | in: "/", 39 | ok: false, 40 | }, 41 | { 42 | in: "/fleet", 43 | ok: false, 44 | }, 45 | { 46 | in: "/fleet/job", 47 | ok: false, 48 | }, 49 | { 50 | in: "/fleet/job/foo/object", 51 | ok: false, 52 | }, 53 | { 54 | in: "/fleet/machine/asdf", 55 | ok: false, 56 | }, 57 | { 58 | in: "/fleet/state/asdf", 59 | ok: false, 60 | }, 61 | { 62 | in: "/fleet/job/foobarbaz/target-state", 63 | ev: JobTargetStateChangeEvent, 64 | ok: true, 65 | }, 66 | { 67 | in: "/fleet/job/asdf/target", 68 | ev: JobTargetChangeEvent, 69 | ok: true, 70 | }, 71 | } 72 | 73 | for i, tt := range tests { 74 | for _, action := range []string{"set", "update", "create", "delete"} { 75 | prefix := "/fleet" 76 | 77 | res := &etcd.Result{ 78 | Node: &etcd.Node{ 79 | Key: tt.in, 80 | }, 81 | Action: action, 82 | } 83 | ev, ok := parse(res, prefix) 84 | if ok != tt.ok { 85 | t.Errorf("case %d: expected ok=%t, got %t", i, tt.ok, ok) 86 | continue 87 | } 88 | 89 | if !reflect.DeepEqual(tt.ev, ev) { 90 | t.Errorf("case %d: received incorrect event\nexpected %#v\ngot %#v", i, tt.ev, ev) 91 | t.Logf("action: %v", action) 92 | } 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /heart/monitor.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 CoreOS, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package heart 18 | 19 | import ( 20 | "errors" 21 | "time" 22 | 23 | "github.com/coreos/fleet/log" 24 | ) 25 | 26 | func NewMonitor(ttl time.Duration) *Monitor { 27 | return &Monitor{ttl, ttl / 2} 28 | } 29 | 30 | type Monitor struct { 31 | TTL time.Duration 32 | ival time.Duration 33 | } 34 | 35 | // Monitor ensures a Heart is still beating until a channel is closed, returning 36 | // an error if the heartbeats fail. 37 | func (m *Monitor) Monitor(hrt Heart, stop chan bool) error { 38 | ticker := time.Tick(m.ival) 39 | for { 40 | select { 41 | case <-stop: 42 | log.V(1).Info("Monitor exiting due to stop signal") 43 | return nil 44 | case <-ticker: 45 | if _, err := m.check(hrt); err != nil { 46 | return err 47 | } 48 | } 49 | } 50 | } 51 | 52 | // check attempts to beat a Heart several times within a timeout, returning the 53 | // log index at which the beat succeeded or an error 54 | func (m *Monitor) check(hrt Heart) (idx uint64, err error) { 55 | // time out after a third of the machine presence TTL, attempting 56 | // the heartbeat up to four times 57 | timeout := m.TTL / 3 58 | interval := timeout / 4 59 | 60 | tchan := time.After(timeout) 61 | next := time.After(0) 62 | for idx == 0 { 63 | select { 64 | case <-tchan: 65 | err = errors.New("Monitor timed out before successful heartbeat") 66 | return 67 | case <-next: 68 | idx, err = hrt.Beat(m.TTL) 69 | if err != nil { 70 | log.V(1).Infof("Monitor heartbeat function returned err, retrying in %v: %v", interval, err) 71 | } 72 | 73 | next = time.After(interval) 74 | } 75 | } 76 | 77 | return 78 | } 79 | -------------------------------------------------------------------------------- /ssh/LICENSE: -------------------------------------------------------------------------------- 1 | Portions of fleet's ssh package (particularly related to known_hosts handling) 2 | are derived from the OpenSSH source, the copyright notices and licenses for 3 | which follow below. 4 | 5 | /* 6 | * Author: Tatu Ylonen 7 | * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland 8 | * All rights reserved 9 | * Simple pattern matching, with '*' and '?' as wildcards. 10 | * Functions for manipulating the known hosts files. 11 | * 12 | * As far as I am concerned, the code I have written for this software 13 | * can be used freely for any purpose. Any derived versions of this 14 | * software must be clearly marked as such, and if the derived work is 15 | * incompatible with the protocol description in the RFC file, it must be 16 | * called by a name other than "ssh" or "Secure Shell". 17 | */ 18 | 19 | /* 20 | * Copyright (c) 2000 Markus Friedl. All rights reserved. 21 | * Copyright (c) 1999 Niels Provos. All rights reserved. 22 | * 23 | * Redistribution and use in source and binary forms, with or without 24 | * modification, are permitted provided that the following conditions 25 | * are met: 26 | * 1. Redistributions of source code must retain the above copyright 27 | * notice, this list of conditions and the following disclaimer. 28 | * 2. Redistributions in binary form must reproduce the above copyright 29 | * notice, this list of conditions and the following disclaimer in the 30 | * documentation and/or other materials provided with the distribution. 31 | * 32 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 33 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 34 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 35 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 36 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 37 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 38 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 39 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 40 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 41 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 42 | */ 43 | -------------------------------------------------------------------------------- /registry/unit.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 CoreOS, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package registry 18 | 19 | import ( 20 | "path" 21 | 22 | "github.com/coreos/fleet/etcd" 23 | "github.com/coreos/fleet/log" 24 | "github.com/coreos/fleet/unit" 25 | ) 26 | 27 | const ( 28 | unitPrefix = "/unit/" 29 | ) 30 | 31 | func (r *EtcdRegistry) storeOrGetUnitFile(u unit.UnitFile) (err error) { 32 | um := unitModel{ 33 | Raw: u.String(), 34 | } 35 | 36 | json, err := marshal(um) 37 | if err != nil { 38 | return err 39 | } 40 | 41 | req := etcd.Create{ 42 | Key: r.hashedUnitPath(u.Hash()), 43 | Value: json, 44 | } 45 | _, err = r.etcd.Do(&req) 46 | // unit is already stored 47 | if err != nil && isNodeExist(err) { 48 | // TODO(jonboulle): verify more here? 49 | err = nil 50 | } 51 | return 52 | } 53 | 54 | // getUnitByHash retrieves from the Registry the Unit associated with the given Hash 55 | func (r *EtcdRegistry) getUnitByHash(hash unit.Hash) *unit.UnitFile { 56 | req := etcd.Get{ 57 | Key: r.hashedUnitPath(hash), 58 | Recursive: true, 59 | } 60 | resp, err := r.etcd.Do(&req) 61 | if err != nil { 62 | if isKeyNotFound(err) { 63 | err = nil 64 | } 65 | return nil 66 | } 67 | var um unitModel 68 | if err := unmarshal(resp.Node.Value, &um); err != nil { 69 | log.Errorf("error unmarshaling Unit(%s): %v", hash, err) 70 | return nil 71 | } 72 | 73 | u, err := unit.NewUnitFile(um.Raw) 74 | if err != nil { 75 | log.Errorf("error parsing Unit(%s): %v", hash, err) 76 | return nil 77 | } 78 | 79 | return u 80 | } 81 | 82 | func (r *EtcdRegistry) hashedUnitPath(hash unit.Hash) string { 83 | return path.Join(r.keyPrefix, unitPrefix, hash.String()) 84 | } 85 | 86 | type unitModel struct { 87 | Raw string 88 | } 89 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/coreos/go-systemd/dbus/dbus_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2013 CoreOS Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package dbus 18 | 19 | import ( 20 | "testing" 21 | ) 22 | 23 | func TestNeedsEscape(t *testing.T) { 24 | // Anything not 0-9a-zA-Z should always be escaped 25 | for want, vals := range map[bool][]byte{ 26 | false: []byte{'a', 'b', 'z', 'A', 'Q', '1', '4', '9'}, 27 | true: []byte{'#', '%', '$', '!', '.', '_', '-', '%', '\\'}, 28 | } { 29 | for i := 1; i < 10; i++ { 30 | for _, b := range vals { 31 | got := needsEscape(i, b) 32 | if got != want { 33 | t.Errorf("needsEscape(%d, %c) returned %t, want %t", i, b, got, want) 34 | } 35 | } 36 | } 37 | } 38 | 39 | // 0-9 in position 0 should be escaped 40 | for want, vals := range map[bool][]byte{ 41 | false: []byte{'A', 'a', 'e', 'x', 'Q', 'Z'}, 42 | true: []byte{'0', '4', '5', '9'}, 43 | } { 44 | for _, b := range vals { 45 | got := needsEscape(0, b) 46 | if got != want { 47 | t.Errorf("needsEscape(0, %c) returned %t, want %t", b, got, want) 48 | } 49 | } 50 | } 51 | 52 | } 53 | 54 | func TestPathBusEscape(t *testing.T) { 55 | for in, want := range map[string]string{ 56 | "": "_", 57 | "foo.service": "foo_2eservice", 58 | "foobar": "foobar", 59 | "woof@woof.service": "woof_40woof_2eservice", 60 | "0123456": "_30123456", 61 | "account_db.service": "account_5fdb_2eservice", 62 | "got-dashes": "got_2ddashes", 63 | } { 64 | got := PathBusEscape(in) 65 | if got != want { 66 | t.Errorf("bad result for PathBusEscape(%s): got %q, want %q", in, got, want) 67 | } 68 | } 69 | 70 | } 71 | 72 | // TestNew ensures that New() works without errors. 73 | func TestNew(t *testing.T) { 74 | _, err := New() 75 | 76 | if err != nil { 77 | t.Fatal(err) 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /api/mux.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 CoreOS, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package api 18 | 19 | import ( 20 | "net/http" 21 | 22 | "github.com/coreos/fleet/client" 23 | "github.com/coreos/fleet/log" 24 | "github.com/coreos/fleet/registry" 25 | "github.com/coreos/fleet/version" 26 | ) 27 | 28 | func NewServeMux(reg registry.Registry) http.Handler { 29 | sm := http.NewServeMux() 30 | cAPI := &client.RegistryClient{Registry: reg} 31 | 32 | for _, prefix := range []string{"/v1-alpha", "/fleet/v1"} { 33 | wireUpDiscoveryResource(sm, prefix) 34 | wireUpMachinesResource(sm, prefix, cAPI) 35 | wireUpStateResource(sm, prefix, cAPI) 36 | wireUpUnitsResource(sm, prefix, cAPI) 37 | sm.HandleFunc(prefix, methodNotAllowedHandler) 38 | } 39 | 40 | sm.HandleFunc("/", baseHandler) 41 | 42 | hdlr := http.Handler(sm) 43 | hdlr = &loggingMiddleware{hdlr} 44 | hdlr = &serverInfoMiddleware{hdlr} 45 | 46 | return hdlr 47 | } 48 | 49 | type loggingMiddleware struct { 50 | next http.Handler 51 | } 52 | 53 | func (lm *loggingMiddleware) ServeHTTP(rw http.ResponseWriter, req *http.Request) { 54 | log.V(1).Infof("HTTP %s %v", req.Method, req.URL) 55 | lm.next.ServeHTTP(rw, req) 56 | } 57 | 58 | type serverInfoMiddleware struct { 59 | next http.Handler 60 | } 61 | 62 | func (si *serverInfoMiddleware) ServeHTTP(rw http.ResponseWriter, req *http.Request) { 63 | rw.Header().Set("Server", "fleetd/"+version.Version) 64 | si.next.ServeHTTP(rw, req) 65 | } 66 | 67 | func methodNotAllowedHandler(rw http.ResponseWriter, req *http.Request) { 68 | sendError(rw, http.StatusMethodNotAllowed, nil) 69 | } 70 | 71 | func baseHandler(rw http.ResponseWriter, req *http.Request) { 72 | var code int 73 | if req.URL.Path == "/" { 74 | code = http.StatusMethodNotAllowed 75 | } else { 76 | code = http.StatusNotFound 77 | } 78 | 79 | sendError(rw, code, nil) 80 | } 81 | -------------------------------------------------------------------------------- /fleetctl/list_machines_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 CoreOS, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "testing" 21 | 22 | "github.com/coreos/fleet/machine" 23 | "github.com/coreos/fleet/registry" 24 | ) 25 | 26 | func newTestRegistryForListMachines() registry.Registry { 27 | m := []machine.MachineState{ 28 | machine.MachineState{ID: "mnopqr"}, 29 | machine.MachineState{ID: "abcdef"}, 30 | machine.MachineState{ID: "ghijkl"}, 31 | } 32 | 33 | reg := registry.NewFakeRegistry() 34 | reg.SetMachines(m) 35 | 36 | return reg 37 | } 38 | 39 | func TestListMachinesFieldsToStrings(t *testing.T) { 40 | id := "4d389537d9d14bdabe8be54a9c29f68d" 41 | ip := "192.0.2.1" 42 | metadata := map[string]string{ 43 | "foo": "bar", 44 | "ping": "pong", 45 | } 46 | ver := "v9.9.9" 47 | 48 | ms := &machine.MachineState{ 49 | ID: id, 50 | PublicIP: ip, 51 | Metadata: metadata, 52 | Version: ver, 53 | } 54 | 55 | val := listMachinesFields["machine"](ms, false) 56 | assertEqual(t, "machine", "4d389537...", val) 57 | 58 | val = listMachinesFields["machine"](ms, true) 59 | assertEqual(t, "machine", "4d389537d9d14bdabe8be54a9c29f68d", val) 60 | 61 | val = listMachinesFields["ip"](ms, false) 62 | assertEqual(t, "ip", "192.0.2.1", val) 63 | 64 | val = listMachinesFields["metadata"](ms, false) 65 | assertEqual(t, "metadata", "foo=bar,ping=pong", val) 66 | } 67 | 68 | func TestListMachinesFieldsEmpty(t *testing.T) { 69 | id := "4d389537d9d14bdabe8be54a9c29f68d" 70 | ip := "" 71 | metadata := map[string]string{} 72 | ver := "v9.9.9" 73 | 74 | ms := &machine.MachineState{ 75 | ID: id, 76 | PublicIP: ip, 77 | Metadata: metadata, 78 | Version: ver, 79 | } 80 | 81 | for _, tt := range []string{"ip", "metadata"} { 82 | f := listMachinesFields[tt](ms, false) 83 | assertEqual(t, tt, "-", f) 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /unit/fake.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 CoreOS, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package unit 18 | 19 | import ( 20 | "sync" 21 | 22 | "github.com/coreos/fleet/pkg" 23 | ) 24 | 25 | func NewFakeUnitManager() *FakeUnitManager { 26 | return &FakeUnitManager{u: map[string]bool{}} 27 | } 28 | 29 | type FakeUnitManager struct { 30 | sync.RWMutex 31 | u map[string]bool 32 | } 33 | 34 | func (fum *FakeUnitManager) Load(name string, u UnitFile) error { 35 | fum.Lock() 36 | defer fum.Unlock() 37 | 38 | fum.u[name] = false 39 | return nil 40 | } 41 | 42 | func (fum *FakeUnitManager) Unload(name string) { 43 | fum.Lock() 44 | defer fum.Unlock() 45 | 46 | delete(fum.u, name) 47 | } 48 | 49 | func (fum *FakeUnitManager) TriggerStart(string) {} 50 | func (fum *FakeUnitManager) TriggerStop(string) {} 51 | 52 | func (fum *FakeUnitManager) Units() ([]string, error) { 53 | fum.RLock() 54 | defer fum.RUnlock() 55 | 56 | lst := make([]string, 0, len(fum.u)) 57 | for name, _ := range fum.u { 58 | lst = append(lst, name) 59 | } 60 | return lst, nil 61 | } 62 | 63 | func (fum *FakeUnitManager) GetUnitState(name string) (us *UnitState, err error) { 64 | fum.RLock() 65 | defer fum.RUnlock() 66 | 67 | if _, ok := fum.u[name]; ok { 68 | us = &UnitState{ 69 | LoadState: "loaded", 70 | ActiveState: "active", 71 | SubState: "running", 72 | } 73 | } 74 | return 75 | } 76 | 77 | func (fum *FakeUnitManager) GetUnitStates(filter pkg.Set) (map[string]*UnitState, error) { 78 | fum.RLock() 79 | defer fum.RUnlock() 80 | 81 | states := make(map[string]*UnitState) 82 | for _, name := range filter.Values() { 83 | if _, ok := fum.u[name]; ok { 84 | states[name] = &UnitState{"loaded", "active", "running", "", "", name} 85 | } 86 | } 87 | 88 | return states, nil 89 | } 90 | 91 | func (fum *FakeUnitManager) MarshalJSON() ([]byte, error) { 92 | return nil, nil 93 | } 94 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/coreos/go-systemd/activation/listeners_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 CoreOS Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package activation 18 | 19 | import ( 20 | "io" 21 | "net" 22 | "os" 23 | "os/exec" 24 | "testing" 25 | ) 26 | 27 | // correctStringWritten fails the text if the correct string wasn't written 28 | // to the other side of the pipe. 29 | func correctStringWrittenNet(t *testing.T, r net.Conn, expected string) bool { 30 | bytes := make([]byte, len(expected)) 31 | io.ReadAtLeast(r, bytes, len(expected)) 32 | 33 | if string(bytes) != expected { 34 | t.Fatalf("Unexpected string %s", string(bytes)) 35 | } 36 | 37 | return true 38 | } 39 | 40 | // TestActivation forks out a copy of activation.go example and reads back two 41 | // strings from the pipes that are passed in. 42 | func TestListeners(t *testing.T) { 43 | cmd := exec.Command("go", "run", "../examples/activation/listen.go") 44 | 45 | l1, err := net.Listen("tcp", ":9999") 46 | if err != nil { 47 | t.Fatalf(err.Error()) 48 | } 49 | l2, err := net.Listen("tcp", ":1234") 50 | if err != nil { 51 | t.Fatalf(err.Error()) 52 | } 53 | 54 | t1 := l1.(*net.TCPListener) 55 | t2 := l2.(*net.TCPListener) 56 | 57 | f1, _ := t1.File() 58 | f2, _ := t2.File() 59 | 60 | cmd.ExtraFiles = []*os.File{ 61 | f1, 62 | f2, 63 | } 64 | 65 | r1, err := net.Dial("tcp", "127.0.0.1:9999") 66 | if err != nil { 67 | t.Fatalf(err.Error()) 68 | } 69 | r1.Write([]byte("Hi")) 70 | 71 | r2, err := net.Dial("tcp", "127.0.0.1:1234") 72 | if err != nil { 73 | t.Fatalf(err.Error()) 74 | } 75 | r2.Write([]byte("Hi")) 76 | 77 | cmd.Env = os.Environ() 78 | cmd.Env = append(cmd.Env, "LISTEN_FDS=2", "FIX_LISTEN_PID=1") 79 | 80 | out, err := cmd.Output() 81 | if err != nil { 82 | println(string(out)) 83 | t.Fatalf(err.Error()) 84 | } 85 | 86 | correctStringWrittenNet(t, r1, "Hello world") 87 | correctStringWrittenNet(t, r2, "Goodbye world") 88 | } 89 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/golang.org/x/crypto/ssh/testdata_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // IMPLEMENTOR NOTE: To avoid a package loop, this file is in three places: 6 | // ssh/, ssh/agent, and ssh/test/. It should be kept in sync across all three 7 | // instances. 8 | 9 | package ssh 10 | 11 | import ( 12 | "crypto/rand" 13 | "fmt" 14 | 15 | "github.com/coreos/fleet/Godeps/_workspace/src/golang.org/x/crypto/ssh/testdata" 16 | ) 17 | 18 | var ( 19 | testPrivateKeys map[string]interface{} 20 | testSigners map[string]Signer 21 | testPublicKeys map[string]PublicKey 22 | ) 23 | 24 | func init() { 25 | var err error 26 | 27 | n := len(testdata.PEMBytes) 28 | testPrivateKeys = make(map[string]interface{}, n) 29 | testSigners = make(map[string]Signer, n) 30 | testPublicKeys = make(map[string]PublicKey, n) 31 | for t, k := range testdata.PEMBytes { 32 | testPrivateKeys[t], err = ParseRawPrivateKey(k) 33 | if err != nil { 34 | panic(fmt.Sprintf("Unable to parse test key %s: %v", t, err)) 35 | } 36 | testSigners[t], err = NewSignerFromKey(testPrivateKeys[t]) 37 | if err != nil { 38 | panic(fmt.Sprintf("Unable to create signer for test key %s: %v", t, err)) 39 | } 40 | testPublicKeys[t] = testSigners[t].PublicKey() 41 | } 42 | 43 | // Create a cert and sign it for use in tests. 44 | testCert := &Certificate{ 45 | Nonce: []byte{}, // To pass reflect.DeepEqual after marshal & parse, this must be non-nil 46 | ValidPrincipals: []string{"gopher1", "gopher2"}, // increases test coverage 47 | ValidAfter: 0, // unix epoch 48 | ValidBefore: CertTimeInfinity, // The end of currently representable time. 49 | Reserved: []byte{}, // To pass reflect.DeepEqual after marshal & parse, this must be non-nil 50 | Key: testPublicKeys["ecdsa"], 51 | SignatureKey: testPublicKeys["rsa"], 52 | Permissions: Permissions{ 53 | CriticalOptions: map[string]string{}, 54 | Extensions: map[string]string{}, 55 | }, 56 | } 57 | testCert.SignCert(rand.Reader, testSigners["rsa"]) 58 | testPrivateKeys["cert"] = testPrivateKeys["ecdsa"] 59 | testSigners["cert"], err = NewCertSigner(testCert, testSigners["ecdsa"]) 60 | if err != nil { 61 | panic(fmt.Sprintf("Unable to create certificate signer: %v", err)) 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /fleetctl/unload.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 CoreOS, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "os" 21 | 22 | "github.com/coreos/fleet/job" 23 | "github.com/coreos/fleet/log" 24 | ) 25 | 26 | var ( 27 | cmdUnloadUnit = &Command{ 28 | Name: "unload", 29 | Summary: "Unschedule one or more units in the cluster.", 30 | Usage: "UNIT...", 31 | Run: runUnloadUnit, 32 | } 33 | ) 34 | 35 | func init() { 36 | cmdUnloadUnit.Flags.IntVar(&sharedFlags.BlockAttempts, "block-attempts", 0, "Wait until the units are inactive, performing up to N attempts before giving up. A value of 0 indicates no limit.") 37 | cmdUnloadUnit.Flags.BoolVar(&sharedFlags.NoBlock, "no-block", false, "Do not wait until the units have become inactive before exiting.") 38 | } 39 | 40 | func runUnloadUnit(args []string) (exit int) { 41 | units, err := findUnits(args) 42 | if err != nil { 43 | stderr("%v", err) 44 | return 1 45 | } 46 | 47 | wait := make([]string, 0) 48 | for _, s := range units { 49 | if !suToGlobal(s) { 50 | if job.JobState(s.CurrentState) == job.JobStateInactive { 51 | log.V(1).Infof("Target state of Unit(%s) already %s, skipping.", s.Name, job.JobStateInactive) 52 | continue 53 | } 54 | } 55 | 56 | log.V(1).Infof("Setting target state of Unit(%s) to %s", s.Name, job.JobStateInactive) 57 | cAPI.SetUnitTargetState(s.Name, string(job.JobStateInactive)) 58 | if suToGlobal(s) { 59 | stdout("Triggered global unit %s unload", s.Name) 60 | } else { 61 | wait = append(wait, s.Name) 62 | } 63 | } 64 | 65 | if !sharedFlags.NoBlock { 66 | errchan := waitForUnitStates(wait, job.JobStateInactive, sharedFlags.BlockAttempts, os.Stdout) 67 | for err := range errchan { 68 | stderr("Error waiting for units: %v", err) 69 | exit = 1 70 | } 71 | } else { 72 | for _, name := range wait { 73 | stdout("Triggered unit %s unload", name) 74 | } 75 | } 76 | 77 | return 78 | } 79 | -------------------------------------------------------------------------------- /registry/fake_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 CoreOS, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package registry 18 | 19 | import ( 20 | "reflect" 21 | "testing" 22 | 23 | "github.com/coreos/fleet/job" 24 | "github.com/coreos/fleet/unit" 25 | ) 26 | 27 | func TestFakeRegistryUnitLifecycle(t *testing.T) { 28 | reg := NewFakeRegistry() 29 | 30 | units, err := reg.Units() 31 | if err != nil { 32 | t.Fatalf("Received error while calling Jobs: %v", err) 33 | } 34 | if !reflect.DeepEqual([]job.Unit{}, units) { 35 | t.Fatalf("Expected no units, got %v", units) 36 | } 37 | 38 | uf, _ := unit.NewUnitFile("") 39 | u1 := job.Unit{Name: "u1.service", Unit: *uf, TargetState: job.JobStateLoaded} 40 | err = reg.CreateUnit(&u1) 41 | if err != nil { 42 | t.Fatalf("Received error while calling CreateUnit: %v", err) 43 | } 44 | 45 | units, err = reg.Units() 46 | if err != nil { 47 | t.Fatalf("Received error while calling Units: %v", err) 48 | } 49 | if len(units) != 1 { 50 | t.Fatalf("Expected 1 Unit, got %v", units) 51 | } 52 | if !reflect.DeepEqual(u1, units[0]) { 53 | t.Fatalf("Expected unit %v, got %v", u1, units[0]) 54 | } 55 | 56 | err = reg.ScheduleUnit("u1.service", "XXX") 57 | if err != nil { 58 | t.Fatalf("Received error while calling ScheduleUnit: %v", err) 59 | } 60 | 61 | su, err := reg.ScheduledUnit("u1.service") 62 | if err != nil { 63 | t.Fatalf("Received error while calling ScheduledUnit: %v", err) 64 | } 65 | if su.TargetMachineID != "XXX" { 66 | t.Fatalf("Unit should be scheduled to XXX, got %v", su.TargetMachineID) 67 | } 68 | 69 | err = reg.DestroyUnit("u1.service") 70 | if err != nil { 71 | t.Fatalf("Received error while calling DestroyUnit: %v", err) 72 | } 73 | 74 | units, err = reg.Units() 75 | if err != nil { 76 | t.Fatalf("Received error while calling Units: %v", err) 77 | } 78 | if !reflect.DeepEqual([]job.Unit{}, units) { 79 | t.Fatalf("Expected no units, got %v", units) 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /engine/scheduler.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 CoreOS, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package engine 18 | 19 | import ( 20 | "fmt" 21 | "sort" 22 | 23 | "github.com/coreos/fleet/agent" 24 | "github.com/coreos/fleet/job" 25 | ) 26 | 27 | type decision struct { 28 | machineID string 29 | } 30 | 31 | type Scheduler interface { 32 | Decide(*clusterState, *job.Job) (*decision, error) 33 | } 34 | 35 | type leastLoadedScheduler struct{} 36 | 37 | func (lls *leastLoadedScheduler) Decide(clust *clusterState, j *job.Job) (*decision, error) { 38 | agents := lls.sortedAgents(clust) 39 | 40 | if len(agents) == 0 { 41 | return nil, fmt.Errorf("zero agents available") 42 | } 43 | 44 | var target *agent.AgentState 45 | for _, as := range agents { 46 | if able, _ := as.AbleToRun(j); !able { 47 | continue 48 | } 49 | 50 | as := as 51 | target = as 52 | break 53 | } 54 | 55 | if target == nil { 56 | return nil, fmt.Errorf("no agents able to run job") 57 | } 58 | 59 | dec := decision{ 60 | machineID: target.MState.ID, 61 | } 62 | 63 | return &dec, nil 64 | } 65 | 66 | // sortedAgents returns a list of AgentState objects sorted ascending 67 | // by the number of scheduled units 68 | func (lls *leastLoadedScheduler) sortedAgents(clust *clusterState) []*agent.AgentState { 69 | agents := clust.agents() 70 | 71 | sas := make(sortableAgentStates, 0) 72 | for _, as := range agents { 73 | sas = append(sas, as) 74 | } 75 | sort.Sort(sas) 76 | 77 | return []*agent.AgentState(sas) 78 | } 79 | 80 | type sortableAgentStates []*agent.AgentState 81 | 82 | func (sas sortableAgentStates) Len() int { return len(sas) } 83 | func (sas sortableAgentStates) Swap(i, j int) { sas[i], sas[j] = sas[j], sas[i] } 84 | 85 | func (sas sortableAgentStates) Less(i, j int) bool { 86 | niUnits := len(sas[i].Units) 87 | njUnits := len(sas[j].Units) 88 | return niUnits < njUnits || (niUnits == njUnits && sas[i].MState.ID < sas[j].MState.ID) 89 | } 90 | -------------------------------------------------------------------------------- /functional/fleetctl_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 CoreOS, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package functional 18 | 19 | import ( 20 | "fmt" 21 | "strings" 22 | "testing" 23 | 24 | "github.com/coreos/fleet/functional/util" 25 | "github.com/coreos/fleet/version" 26 | ) 27 | 28 | func TestClientVersionFlag(t *testing.T) { 29 | stdout, _, err := util.RunFleetctl("--version") 30 | if err != nil { 31 | t.Fatalf("Unexpected error while executing fleetctl: %v", err) 32 | } 33 | 34 | if strings.TrimSpace(stdout) != fmt.Sprintf("fleetctl version %s", version.Version) { 35 | t.Fatalf("Received unexpected output for `fleetctl --version`: '%s'", stdout) 36 | } 37 | } 38 | 39 | func TestClientVersionHelpOutput(t *testing.T) { 40 | stdout, _, err := util.RunFleetctl() 41 | if err != nil { 42 | t.Fatalf("Unexpected error while executing fleetctl: %v", err) 43 | } 44 | 45 | if !strings.Contains(stdout, fmt.Sprintf("%s", version.Version)) { 46 | t.Fatalf("Could not find expected version string (%s) in help output:\n%s", version.Version, stdout) 47 | } 48 | } 49 | 50 | func TestClientHelpFlag(t *testing.T) { 51 | var err error 52 | var fixture, stdout, stderr string 53 | for i, tt := range []string{"--help", "-h", "help", ""} { 54 | if tt == "" { 55 | stdout, stderr, err = util.RunFleetctl() 56 | } else { 57 | stdout, stderr, err = util.RunFleetctl(tt) 58 | } 59 | 60 | if err != nil { 61 | t.Fatalf("case %d: failed getting %s output: %v\n\nstdout: %s\n\nstderr: %s", i, tt, err, stdout, stderr) 62 | } 63 | 64 | // use the output of the first test case as the point 65 | // of comparison for all future cases 66 | if i == 0 { 67 | if len(stdout) == 0 { 68 | t.Fatalf("case 0: initial case has no help output") 69 | } 70 | fixture = stdout 71 | continue 72 | } 73 | 74 | if stdout != fixture { 75 | t.Errorf("case %d: stdout:\n%s\n\ndiffers from stdout of case 0:\n%s", i, stdout, fixture) 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /Documentation/examples/api.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file provides an example of a very simple client library written in Python. 3 | # The client builds an interface for interacting with the fleet API, then retrieves 4 | # a list of Units currently loaded into fleet. 5 | # 6 | # Warning: the code below is a significally simplified version of a typical client 7 | # library. It is an incomplete implementation that is provided to demonstrate 8 | # some aspects of building a client library. It is not production-ready code. 9 | # 10 | # This example assumes that fleet is configured to listen on localhost:8080 11 | # 12 | # Requirements: 13 | # httplib2 - https://github.com/jcgregorio/httplib2 14 | # uritemplate - https://github.com/uri-templates/uritemplate-py 15 | # 16 | import httplib2 17 | import json 18 | import uritemplate 19 | import urllib 20 | import urlparse 21 | import pprint 22 | 23 | # Step 1: Fetch Discovery document. 24 | ROOT_URL = "http://localhost:8080/" 25 | DISCOVERY_URI = ROOT_URL + "fleet/v1/discovery" 26 | h = httplib2.Http() 27 | resp, content = h.request(DISCOVERY_URI) 28 | discovery = json.loads(content) 29 | 30 | # Step 2.a: Construct base URI 31 | BASE_URI = ROOT_URL + discovery['servicePath'] 32 | 33 | class Collection(object): pass 34 | 35 | def createNewMethod(name, method): 36 | # Step 2.b Compose request 37 | def newMethod(**kwargs): 38 | body = kwargs.pop('body', None) 39 | url = urlparse.urljoin(BASE_URI, uritemplate.expand(method['path'], kwargs)) 40 | for pname, pconfig in method.get('parameters', {}).iteritems(): 41 | if pconfig['location'] == 'path' and pname in kwargs: 42 | del kwargs[pname] 43 | if kwargs: 44 | url = url + '?' + urllib.urlencode(kwargs) 45 | return h.request(url, method=method['httpMethod'], body=body, 46 | headers={'content-type': 'application/json'}) 47 | 48 | return newMethod 49 | 50 | # Step 3.a: Build client surface 51 | def build(discovery, collection): 52 | for name, resource in discovery.get('resources', {}).iteritems(): 53 | setattr(collection, name, build(resource, Collection())) 54 | for name, method in discovery.get('methods', {}).iteritems(): 55 | setattr(collection, name, createNewMethod(name, method)) 56 | return collection 57 | 58 | service = build(discovery, Collection()) 59 | 60 | # Step 3.b: Use the client 61 | response = service.Machines.List() 62 | 63 | # output metadata (status, content-length, etc...) 64 | pprint.pprint(response[0]) 65 | 66 | # output body 67 | pprint.pprint(json.loads(response[1])) 68 | 69 | --------------------------------------------------------------------------------