forked from rkt/rkt
/
discovery.go
112 lines (89 loc) · 2.13 KB
/
discovery.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
package discovery
import (
"io"
"strings"
"github.com/coreos/rocket/Godeps/_workspace/src/golang.org/x/net/html"
"github.com/coreos/rocket/Godeps/_workspace/src/golang.org/x/net/html/atom"
)
type acMeta struct {
name string
prefix string
uri string
}
type Endpoints struct {
Sig []string
ACI []string
Keys []string
}
func appendMeta(meta []acMeta, attrs []html.Attribute) []acMeta {
m := acMeta{}
for _, a := range attrs {
if a.Namespace != "" {
continue
}
switch a.Key {
case "name":
m.name = a.Val
case "content":
parts := strings.SplitN(strings.TrimSpace(a.Val), " ", 2)
if len(parts) < 2 {
break
}
m.prefix = parts[0]
m.uri = strings.TrimSpace(parts[1])
}
}
// TODO(eyakubovich): should prefix be optional?
if !strings.HasPrefix(m.name, "ac-") || m.prefix == "" || m.uri == "" {
return meta
}
return append(meta, m)
}
func extractACMeta(r io.Reader) []acMeta {
var meta []acMeta
z := html.NewTokenizer(r)
for {
switch z.Next() {
case html.ErrorToken:
return meta
case html.StartTagToken, html.SelfClosingTagToken:
tok := z.Token()
if tok.DataAtom == atom.Meta {
meta = appendMeta(meta, tok.Attr)
}
}
}
}
func renderTemplate(tpl string, kvs ...string) string {
for i := 0; i < len(kvs); i += 2 {
k := kvs[i]
v := kvs[i+1]
tpl = strings.Replace(tpl, k, v, -1)
}
return tpl
}
func DiscoverEndpoints(app App, insecure bool) (*Endpoints, error) {
_, body, err := httpsOrHTTP(app.Name.String(), insecure)
if err != nil {
return nil, err
}
defer body.Close()
meta := extractACMeta(body)
tplVars := []string{"{os}", app.Labels["os"], "{arch}", app.Labels["arch"],
"{name}", app.Name.String(), "{version}", app.Labels["version"]}
de := &Endpoints{}
for _, m := range meta {
if !strings.HasPrefix(app.Name.String(), m.prefix) {
continue
}
switch m.name {
case "ac-discovery":
m.uri = renderTemplate(m.uri, tplVars...)
de.Sig = append(de.Sig, renderTemplate(m.uri, "{ext}", "sig"))
de.ACI = append(de.ACI, renderTemplate(m.uri, "{ext}", "aci"))
case "ac-discovery-pubkeys":
de.Keys = append(de.Keys, m.uri)
}
}
return de, nil
}