This repository has been archived by the owner on Aug 21, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathnamespaces.go
170 lines (151 loc) · 4.57 KB
/
namespaces.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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
package stashcp
import (
"bytes"
_ "embed"
"encoding/json"
"errors"
"fmt"
log "github.com/sirupsen/logrus"
"io"
"net/http"
"os"
"strings"
)
// I don't think we actually want stashcp to download the namespace every build
// Doesn't make for reproducible builds
// //go:generate curl -s https://topology-itb.opensciencegrid.org/stashcache/namespaces.json -o resources/namespaces.json
//go:embed resources/namespaces.json
var namespacesJson []byte
// defaultCaches is list of caches to use if no caches are specified in the namespace
var defaultCaches = []Cache{}
// namespaces is a global list of namespaces
var namespaces []Namespace
// Cache
type Cache struct {
AuthEndpoint string `json:"auth_endpoint"`
Endpoint string `json:"endpoint"`
Resource string `json:"resource"`
}
// Namespace holds the structure of stash namespaces
type Namespace struct {
Caches []Cache `json:"caches"`
Path string `json:"path"`
ReadHTTPS bool `json:"readhttps"`
UseTokenOnRead bool `json:"usetokenonread"`
WriteBackHost string `json:"writebackhost"`
DirListHost string `json:"dirlisthost"`
}
// GetCaches returns the list of caches for the namespace
func (ns *Namespace) GetCaches() []Cache {
if ns.Caches == nil || len(ns.Caches) == 0 {
return defaultCaches
}
return ns.Caches
}
func (ns *Namespace) GetCacheHosts() []string {
var caches []string
for _, cache := range ns.GetCaches() {
host := strings.Split(cache.Endpoint, ":")[0]
caches = append(caches, host)
}
return caches
}
// MatchCaches compares the caches passed in (presumably from an ordered list of caches)
// to the caches for the namespace, and returns the intersection of the two
func (ns *Namespace) MatchCaches(caches []string) []Cache {
// Get the caches for the namespace
nsCaches := ns.GetCacheHosts()
// Find the intersection of the two
intersectedCaches := intersect(caches, nsCaches)
// map the intersectedCaches back to the endpoints (with ports)
var intersectedCachesWithEndpoints []Cache
// For each of the caches in the intersection
for _, cache := range intersectedCaches {
// Match to the caches in the namespace
for _, nsCache := range ns.GetCaches() {
host := strings.Split(nsCache.Endpoint, ":")[0]
if host == cache {
intersectedCachesWithEndpoints = append(intersectedCachesWithEndpoints, nsCache)
}
}
}
return intersectedCachesWithEndpoints
}
// intersect returns the intersection of two slices
// in the order of a
func intersect(a, b []string) []string {
m := make(map[string]bool)
var intersect []string
for _, x := range b {
m[x] = true
}
for _, x := range a {
if _, ok := m[x]; ok {
intersect = append(intersect, x)
}
}
return intersect
}
type NamespaceFull struct {
Caches []Cache `json:"caches"`
Namespaces []Namespace `json:"namespaces"`
}
// GetNamespaces returns the list of namespaces
func GetNamespaces() ([]Namespace, error) {
// Allocate the namespaces
var nsfull NamespaceFull
// Try downloading the namespaces, if it fails, use the embedded namespaces
namespacesFromUrl, err := downloadNamespace()
if err != nil {
log.Debugf("Failed to download namespaces: %s, continueing using built-in namespace configuration", err)
} else {
namespacesJson = namespacesFromUrl
}
log.Debugln("Parsing namespaces: ", string(namespacesJson))
err = json.Unmarshal(namespacesJson, &nsfull)
if err != nil {
fmt.Println(err)
return nil, err
}
defaultCaches = nsfull.Caches
return nsfull.Namespaces, nil
}
// downloadNamespace downloads the namespace information with timeouts
func downloadNamespace() ([]byte, error) {
// Get the namespace url from the environment
namespaceUrl, gotNamespaceUrl := os.LookupEnv("STASH_NAMESPACE_URL")
if !gotNamespaceUrl {
namespaceUrl = "https://topology.opensciencegrid.org/stashcache/namespaces"
}
resp, err := http.Get(namespaceUrl)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
log.Errorf("Failed to download namespaces: %s", resp.Status)
return nil, errors.New("Failed to download namespaces: " + resp.Status)
}
var out bytes.Buffer
_, err = io.Copy(&out, resp.Body)
if err != nil {
return nil, err
}
return out.Bytes(), nil
}
// MatchNamespace matches the namespace passed in to the namespaces in the list
func MatchNamespace(path string) (Namespace, error) {
var err error
if namespaces == nil {
namespaces, err = GetNamespaces()
if err != nil {
return Namespace{}, err
}
}
for _, namespace := range namespaces {
if strings.HasPrefix(path, namespace.Path) {
return namespace, nil
}
}
return Namespace{}, nil
}