diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index d649605..70aabf1 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -12,32 +12,28 @@ }, { "ImportPath": "github.com/appc/spec/aci", - "Comment": "v0.2.0-44-g2fee340e9314", - "Rev": "2fee340e9314b9f0f53cbf0e929d158a09930a5f" + "Comment": "v0.3.0-2-g4c3cbeae4798", + "Rev": "4c3cbeae47980d073828dd263a8c982667855f06" }, { "ImportPath": "github.com/appc/spec/actool", - "Comment": "v0.2.0-44-g2fee340e9314", - "Rev": "2fee340e9314b9f0f53cbf0e929d158a09930a5f" + "Comment": "v0.3.0-2-g4c3cbeae4798", + "Rev": "4c3cbeae47980d073828dd263a8c982667855f06" }, { "ImportPath": "github.com/appc/spec/discovery", - "Comment": "v0.2.0-44-g2fee340e9314", - "Rev": "2fee340e9314b9f0f53cbf0e929d158a09930a5f" + "Comment": "v0.3.0-2-g4c3cbeae4798", + "Rev": "4c3cbeae47980d073828dd263a8c982667855f06" }, { "ImportPath": "github.com/appc/spec/pkg/tarheader", - "Comment": "v0.2.0-44-g2fee340e9314", - "Rev": "2fee340e9314b9f0f53cbf0e929d158a09930a5f" + "Comment": "v0.3.0-2-g4c3cbeae4798", + "Rev": "4c3cbeae47980d073828dd263a8c982667855f06" }, { "ImportPath": "github.com/appc/spec/schema", - "Comment": "v0.2.0-44-g2fee340e9314", - "Rev": "2fee340e9314b9f0f53cbf0e929d158a09930a5f" - }, - { - "ImportPath": "github.com/coreos/go-iptables/iptables", - "Rev": "6c2d35e85727473f4d6a479c39650b548aa35f16" + "Comment": "v0.3.0-2-g4c3cbeae4798", + "Rev": "4c3cbeae47980d073828dd263a8c982667855f06" }, { "ImportPath": "github.com/coreos/go-semver/semver", diff --git a/Godeps/_workspace/src/github.com/appc/spec/aci/file_test.go b/Godeps/_workspace/src/github.com/appc/spec/aci/file_test.go index 1886625..8e3fd38 100644 --- a/Godeps/_workspace/src/github.com/appc/spec/aci/file_test.go +++ b/Godeps/_workspace/src/github.com/appc/spec/aci/file_test.go @@ -14,7 +14,7 @@ func newTestACI() (*os.File, error) { return nil, err } - manifestBody := `{"acKind":"ImageManifest","acVersion":"0.2.0","name":"example.com/app"}` + manifestBody := `{"acKind":"ImageManifest","acVersion":"0.3.0","name":"example.com/app"}` gw := gzip.NewWriter(tf) tw := tar.NewWriter(gw) diff --git a/Godeps/_workspace/src/github.com/appc/spec/actool/discover.go b/Godeps/_workspace/src/github.com/appc/spec/actool/discover.go index dc47836..0c03bf0 100644 --- a/Godeps/_workspace/src/github.com/appc/spec/actool/discover.go +++ b/Godeps/_workspace/src/github.com/appc/spec/actool/discover.go @@ -33,13 +33,16 @@ func runDiscover(args []string) (exit int) { stderr("%s: %s", name, err) return 1 } - eps, err := discovery.DiscoverEndpoints(*app, transportFlags.Insecure) + eps, attempts, err := discovery.DiscoverEndpoints(*app, transportFlags.Insecure) if err != nil { stderr("error fetching %s: %s", name, err) return 1 } + for _, a := range attempts { + fmt.Printf("discover walk: prefix: %s error: %v\n", a.Prefix, a.Error) + } for _, aciEndpoint := range eps.ACIEndpoints { - fmt.Println("ACI: %s, Sig: %s\n", aciEndpoint.ACI, aciEndpoint.Sig) + fmt.Printf("ACI: %s, Sig: %s\n", aciEndpoint.ACI, aciEndpoint.Sig) } if len(eps.Keys) > 0 { fmt.Println("Keys: " + strings.Join(eps.Keys, ",")) diff --git a/Godeps/_workspace/src/github.com/appc/spec/discovery/discovery.go b/Godeps/_workspace/src/github.com/appc/spec/discovery/discovery.go index adecbfb..4702dcb 100644 --- a/Godeps/_workspace/src/github.com/appc/spec/discovery/discovery.go +++ b/Godeps/_workspace/src/github.com/appc/spec/discovery/discovery.go @@ -1,6 +1,7 @@ package discovery import ( + "errors" "fmt" "io" "regexp" @@ -26,12 +27,18 @@ type Endpoints struct { Keys []string } +func (e *Endpoints) Append(ep Endpoints) { + e.ACIEndpoints = append(e.ACIEndpoints, ep.ACIEndpoints...) + e.Keys = append(e.Keys, ep.Keys...) +} + const ( defaultVersion = "latest" ) var ( templateExpression = regexp.MustCompile(`{.*?}`) + errEnough = errors.New("enough discovery information found") ) func appendMeta(meta []acMeta, attrs []html.Attribute) []acMeta { @@ -102,7 +109,7 @@ func createTemplateVars(app App) []string { return tplVars } -func doDiscover(app App, pre string, insecure bool) (*Endpoints, error) { +func doDiscover(pre string, app App, insecure bool) (*Endpoints, error) { if app.Labels["version"] == "" { app.Labels["version"] = defaultVersion } @@ -143,26 +150,92 @@ func doDiscover(app App, pre string, insecure bool) (*Endpoints, error) { } } - if len(de.ACIEndpoints) == 0 { - return nil, fmt.Errorf("found no ACI meta tags") - } - return de, nil } -// DiscoverEndpoints will make HTTPS requests to find the ac-discovery meta -// tags and optionally will use HTTP if insecure is set. Based on the app -// passed the discovery templates will be filled out and returned in eps. -func DiscoverEndpoints(app App, insecure bool) (eps *Endpoints, err error) { +// DiscoverWalk will make HTTPS requests to find discovery meta tags and +// optionally will use HTTP if insecure is set. Based on the response of the +// discoverFn it will continue to recurse up the tree. +func DiscoverWalk(app App, insecure bool, discoverFn DiscoverWalkFunc) (err error) { + var ( + eps *Endpoints + ) + parts := strings.Split(string(app.Name), "/") for i := range parts { end := len(parts) - i pre := strings.Join(parts[:end], "/") - eps, err = doDiscover(app, pre, insecure) - if err == nil { - break + + eps, err = doDiscover(pre, app, insecure) + derr := discoverFn(pre, eps, err) + if derr != nil { + return err } } return } + +// DiscoverWalkFunc can stop a DiscoverWalk by returning non-nil error. +type DiscoverWalkFunc func(prefix string, eps *Endpoints, err error) error + +// FailedAttempt represents a failed discovery attempt. This is for debugging +// and user feedback. +type FailedAttempt struct { + Prefix string + Error error +} + +func walker(out *Endpoints, attempts *[]FailedAttempt, testFn DiscoverWalkFunc) DiscoverWalkFunc { + return func(pre string, eps *Endpoints, err error) error { + if err != nil { + *attempts = append(*attempts, FailedAttempt{pre, err}) + return nil + } + out.Append(*eps) + if err := testFn(pre, eps, err); err != nil { + return err + } + return nil + } +} + +// DiscoverEndpoints will make HTTPS requests to find the ac-discovery meta +// tags and optionally will use HTTP if insecure is set. It will not give up +// until it has exhausted the path or found an image discovery. +func DiscoverEndpoints(app App, insecure bool) (out *Endpoints, attempts []FailedAttempt, err error) { + out = &Endpoints{} + testFn := func(pre string, eps *Endpoints, err error) error { + if len(out.ACIEndpoints) != 0 { + return errEnough + } + return nil + } + + err = DiscoverWalk(app, insecure, walker(out, &attempts, testFn)) + if err != nil && err != errEnough { + return nil, attempts, err + } + + return out, attempts, nil +} + +// DiscoverPublicKey will make HTTPS requests to find the ac-public-keys meta +// tags and optionally will use HTTP if insecure is set. It will not give up +// until it has exhausted the path or found an public key. +func DiscoverPublicKeys(app App, insecure bool) (out *Endpoints, attempts []FailedAttempt, err error) { + out = &Endpoints{} + testFn := func(pre string, eps *Endpoints, err error) error { + if len(out.Keys) != 0 { + return errEnough + } + return nil + } + + err = DiscoverWalk(app, insecure, walker(out, &attempts, testFn)) + if err != nil && err != errEnough { + return nil, attempts, err + } + + return out, attempts, nil +} diff --git a/Godeps/_workspace/src/github.com/appc/spec/discovery/discovery_test.go b/Godeps/_workspace/src/github.com/appc/spec/discovery/discovery_test.go index f0c4350..d268f42 100644 --- a/Godeps/_workspace/src/github.com/appc/spec/discovery/discovery_test.go +++ b/Godeps/_workspace/src/github.com/appc/spec/discovery/discovery_test.go @@ -180,7 +180,7 @@ func TestDiscoverEndpoints(t *testing.T) { for i, tt := range tests { httpGet = tt.get - de, err := DiscoverEndpoints(tt.app, true) + de, _, err := DiscoverEndpoints(tt.app, true) if err != nil && !tt.expectDiscoverySuccess { continue } diff --git a/Godeps/_workspace/src/github.com/appc/spec/schema/image_test.go b/Godeps/_workspace/src/github.com/appc/spec/schema/image_test.go index 77cbabe..74eb273 100644 --- a/Godeps/_workspace/src/github.com/appc/spec/schema/image_test.go +++ b/Godeps/_workspace/src/github.com/appc/spec/schema/image_test.go @@ -6,7 +6,7 @@ func TestEmptyApp(t *testing.T) { imj := ` { "acKind": "ImageManifest", - "acVersion": "0.2.0", + "acVersion": "0.3.0", "name": "example.com/test" } ` diff --git a/Godeps/_workspace/src/github.com/appc/spec/schema/version.go b/Godeps/_workspace/src/github.com/appc/spec/schema/version.go index 902e636..80b22de 100644 --- a/Godeps/_workspace/src/github.com/appc/spec/schema/version.go +++ b/Godeps/_workspace/src/github.com/appc/spec/schema/version.go @@ -8,7 +8,7 @@ const ( // version represents the canonical version of the appc spec and tooling. // For now, the schema and tooling is coupled with the spec itself, so // this must be kept in sync with the VERSION file in the root of the repo. - version string = "0.2.0+git" + version string = "0.3.0+git" ) var ( diff --git a/Godeps/_workspace/src/github.com/coreos/go-iptables/iptables/iptables.go b/Godeps/_workspace/src/github.com/coreos/go-iptables/iptables/iptables.go deleted file mode 100644 index 9d930eb..0000000 --- a/Godeps/_workspace/src/github.com/coreos/go-iptables/iptables/iptables.go +++ /dev/null @@ -1,251 +0,0 @@ -// Copyright 2015 CoreOS, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package iptables - -import ( - "bytes" - "fmt" - "log" - "os/exec" - "regexp" - "strconv" - "strings" - "syscall" -) - -// Adds the output of stderr to exec.ExitError -type Error struct { - exec.ExitError - msg string -} - -func (e *Error) ExitStatus() int { - return e.Sys().(syscall.WaitStatus).ExitStatus() -} - -func (e *Error) Error() string { - return fmt.Sprintf("exit status %v: %v", e.ExitStatus(), e.msg) -} - -type IPTables struct { - path string -} - -func New() (*IPTables, error) { - path, err := exec.LookPath("iptables") - if err != nil { - return nil, err - } - - return &IPTables{path}, nil -} - -// Exists checks if given rulespec in specified table/chain exists -func (ipt *IPTables) Exists(table, chain string, rulespec...string) (bool, error) { - checkPresent, err := getIptablesHasCheckCommand() - if err != nil { - log.Printf("Error checking iptables version, assuming version at least 1.4.11: %v", err) - checkPresent = true - } - - if !checkPresent { - cmd := append([]string{"-A", chain}, rulespec...) - return existsForOldIpTables(table, strings.Join(cmd, " ")) - } else { - cmd := append([]string{"-t", table, "-C", chain}, rulespec...) - err := ipt.run(cmd...) - - switch { - case err == nil: - return true, nil - case err.(*Error).ExitStatus() == 1: - return false, nil - default: - return false, err - } - } -} - -// Insert inserts rulespec to specified table/chain (in specified pos) -func (ipt *IPTables) Insert(table, chain string, pos int, rulespec ...string) error { - cmd := append([]string{"-t", table, "-I", chain, strconv.Itoa(pos)}, rulespec...) - return ipt.run(cmd...) -} - -// Append appends rulespec to specified table/chain -func (ipt *IPTables) Append(table, chain string, rulespec ...string) error { - cmd := append([]string{"-t", table, "-A", chain}, rulespec...) - return ipt.run(cmd...) -} - -// AppendUnique acts like Append except that it won't add a duplicate -func (ipt *IPTables) AppendUnique(table, chain string, rulespec ...string) error { - exists, err := ipt.Exists(table, chain, rulespec...) - if err != nil { - return err - } - - if !exists { - return ipt.Append(table, chain, rulespec...) - } - - return nil -} - -// Delete removes rulespec in specified table/chain -func (ipt *IPTables) Delete(table, chain string, rulespec ...string) error { - cmd := append([]string{"-t", table, "-D", chain}, rulespec...) - return ipt.run(cmd...) -} - -// List rules in specified table/chain -func (ipt *IPTables) List(table, chain string) ([]string, error) { - var stdout, stderr bytes.Buffer - cmd := exec.Cmd{ - Path: ipt.path, - Args: []string{ipt.path, "-t", table, "-S", chain}, - Stdout: &stdout, - Stderr: &stderr, - } - - if err := cmd.Run(); err != nil { - return nil, &Error{*(err.(*exec.ExitError)), stderr.String()} - } - - rules := strings.Split(stdout.String(), "\n") - if len(rules) > 0 && rules[len(rules)-1] == "" { - rules = rules[:len(rules)-1] - } - - return rules, nil -} - -// ClearChain flushed (deletes all rules) in the specifed table/chain. -// If the chain does not exist, new one will be created -func (ipt *IPTables) ClearChain(table, chain string) error { - err := ipt.run("-t", table, "-N", chain) - - switch { - case err == nil: - return nil - case err.(*Error).ExitStatus() == 1: - // chain already exists. Flush (clear) it. - return ipt.run("-t", table, "-F", chain) - default: - return err - } -} - -// DeleteChain deletes the chain in the specified table. -// The chain must be empty -func (ipt *IPTables) DeleteChain(table, chain string) error { - return ipt.run("-t", table, "-X", chain) -} - -func (ipt *IPTables) run(args... string) error { - var stderr bytes.Buffer - cmd := exec.Cmd{ - Path: ipt.path, - Args: append([]string{ipt.path}, args...), - Stderr: &stderr, - } - - if err := cmd.Run(); err != nil { - return &Error{*(err.(*exec.ExitError)), stderr.String()} - } - - return nil -} - -// Checks if iptables has the "-C" flag -func getIptablesHasCheckCommand() (bool, error) { - vstring, err := getIptablesVersionString() - if err != nil { - return false, err - } - - v1, v2, v3, err := extractIptablesVersion(vstring) - if err != nil { - return false, err - } - - return iptablesHasCheckCommand(v1, v2, v3), nil -} - -// getIptablesVersion returns the first three components of the iptables version. -// e.g. "iptables v1.3.66" would return (1, 3, 66, nil) -func extractIptablesVersion(str string) (int, int, int, error) { - versionMatcher := regexp.MustCompile("v([0-9]+)\\.([0-9]+)\\.([0-9]+)") - result := versionMatcher.FindStringSubmatch(str) - if result == nil { - return 0, 0, 0, fmt.Errorf("no iptables version found in string: %s", str) - } - - v1, err := strconv.Atoi(result[1]) - if err != nil { - return 0, 0, 0, err - } - - v2, err := strconv.Atoi(result[2]) - if err != nil { - return 0, 0, 0, err - } - - v3, err := strconv.Atoi(result[3]) - if err != nil { - return 0, 0, 0, err - } - - return v1, v2, v3, nil -} - -// Runs "iptables --version" to get the version string -func getIptablesVersionString() (string, error) { - cmd := exec.Command("iptables", "--version") - var out bytes.Buffer - cmd.Stdout = &out - err := cmd.Run() - if err != nil { - return "", err - } - return out.String(), nil -} - -// Checks if an iptables version is after 1.4.11, when --check was added -func iptablesHasCheckCommand(v1 int, v2 int, v3 int) bool { - if v1 > 1 { - return true - } - if v1 == 1 && v2 > 4 { - return true - } - if v1 == 1 && v2 == 4 && v3 >= 11 { - return true - } - return false -} - -// Checks if a rule specification exists for a table -func existsForOldIpTables(table string, ruleSpec string) (bool, error) { - cmd := exec.Command("iptables", "-t", table, "-S") - var out bytes.Buffer - cmd.Stdout = &out - err := cmd.Run() - if err != nil { - return false, err - } - rules := out.String() - return strings.Contains(rules, ruleSpec), nil -} diff --git a/Godeps/_workspace/src/github.com/coreos/go-iptables/iptables/iptables_test.go b/Godeps/_workspace/src/github.com/coreos/go-iptables/iptables/iptables_test.go deleted file mode 100644 index e4f3b17..0000000 --- a/Godeps/_workspace/src/github.com/coreos/go-iptables/iptables/iptables_test.go +++ /dev/null @@ -1,136 +0,0 @@ -// Copyright 2015 CoreOS, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package iptables - -import ( - "crypto/rand" - "math/big" - "reflect" - "testing" -) - -func randChain(t *testing.T) string { - n, err := rand.Int(rand.Reader, big.NewInt(1000000)) - if err != nil { - t.Fatalf("Failed to generate random chain name: %v", err) - } - - return "TEST-" + n.String() -} - -func TestChain(t *testing.T) { - chain := randChain(t) - - ipt, err := New() - if err != nil { - t.Fatalf("New failed: %v", err) - } - - // chain shouldn't exist, this will create new - err = ipt.ClearChain("filter", chain) - if err != nil { - t.Fatalf("ClearChain (of missing) failed: %v", err) - } - - // chain now exists - err = ipt.ClearChain("filter", chain) - if err != nil { - t.Fatalf("ClearChain (of empty) failed: %v", err) - } - - // put a simple rule in - err = ipt.Append("filter", chain, "-s", "0.0.0.0/0", "-j", "ACCEPT") - if err != nil { - t.Fatalf("Append failed: %v", err) - } - - // can't delete non-empty chain - err = ipt.DeleteChain("filter", chain) - if err == nil { - t.Fatalf("DeleteChain of non-empty chain did not fail") - } - - err = ipt.ClearChain("filter", chain) - if err != nil { - t.Fatalf("ClearChain (of non-empty) failed: %v", err) - } - - // chain empty, should be ok - err = ipt.DeleteChain("filter", chain) - if err != nil { - t.Fatalf("DeleteChain of empty chain failed: %v", err) - } -} - -func TestRules(t *testing.T) { - chain := randChain(t) - - ipt, err := New() - if err != nil { - t.Fatalf("New failed: %v", err) - } - - // chain shouldn't exist, this will create new - err = ipt.ClearChain("filter", chain) - if err != nil { - t.Fatalf("ClearChain (of missing) failed: %v", err) - } - - err = ipt.Append("filter", chain, "-s", "10.1.0.0/16", "-d", "8.8.8.8/32", "-j", "ACCEPT") - if err != nil { - t.Fatalf("Append failed: %v", err) - } - - err = ipt.AppendUnique("filter", chain, "-s", "10.1.0.0/16", "-d", "8.8.8.8/32", "-j", "ACCEPT") - if err != nil { - t.Fatalf("AppendUnique failed: %v", err) - } - - err = ipt.Append("filter", chain, "-s", "10.2.0.0/16", "-d", "8.8.8.8/32", "-j", "ACCEPT") - if err != nil { - t.Fatalf("Append failed: %v", err) - } - - err = ipt.Insert("filter", chain, 2, "-s", "10.2.0.0/16", "-d", "9.9.9.9/32", "-j", "ACCEPT") - if err != nil { - t.Fatalf("Insert failed: %v", err) - } - - err = ipt.Insert("filter", chain, 1, "-s", "10.1.0.0/16", "-d", "9.9.9.9/32", "-j", "ACCEPT") - if err != nil { - t.Fatalf("Insert failed: %v", err) - } - - err = ipt.Delete("filter", chain, "-s", "10.1.0.0/16", "-d", "9.9.9.9/32", "-j", "ACCEPT") - if err != nil { - t.Fatalf("Insert failed: %v", err) - } - - rules, err := ipt.List("filter", chain) - if err != nil { - t.Fatalf("List failed: %v", err) - } - - expected := []string{ - "-N " + chain, - "-A " + chain + " -s 10.1.0.0/16 -d 8.8.8.8/32 -j ACCEPT", - "-A " + chain + " -s 10.2.0.0/16 -d 9.9.9.9/32 -j ACCEPT", - "-A " + chain + " -s 10.2.0.0/16 -d 8.8.8.8/32 -j ACCEPT", - } - - if !reflect.DeepEqual(rules, expected) { - t.Fatalf("List mismatch: \ngot %#v \nneed %#v", rules, expected) - } -}