generated from broadinstitute/golang-project-template
-
Notifications
You must be signed in to change notification settings - Fork 1
/
sherlock.go
112 lines (93 loc) · 3.49 KB
/
sherlock.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 sherlock
import (
"github.com/broadinstitute/thelma/internal/thelma/app/credentials"
"net/url"
"strings"
"github.com/broadinstitute/sherlock/sherlock-go-client/client"
"github.com/broadinstitute/sherlock/sherlock-go-client/client/misc"
"github.com/broadinstitute/thelma/internal/thelma/app/config"
httptransport "github.com/go-openapi/runtime/client"
"github.com/go-openapi/strfmt"
)
const configKey = "sherlock"
// Client is an interface representing the ability to both read and
// create/update thelma's internal state using a sherlock client. We have this
// interface largely so we can generate a mock for it.
type Client interface {
StateLoader
StateWriter
ChartVersionUpdater
ChartReleaseStatusUpdater
GetStatus() error
}
type Options struct {
Addr string
ConfigSource config.Config
IapTokenProvider credentials.TokenProvider
GhaOidcTokenProvider credentials.TokenProvider
}
type Option func(*Options)
type sherlockConfig struct {
Addr string `default:"https://sherlock.dsp-devops-prod.broadinstitute.org"`
}
// NewClient creates a Sherlock client, but you probably don't want to call it. You want to hit
// clients.Clients.Sherlock() instead, which still accepts options but fills the all-important
// authentication ones for you. Calling this directly is still useful for testing, though.
func NewClient(options ...Option) (Client, error) {
opts := &Options{}
for _, option := range options {
option(opts)
}
if opts.ConfigSource != nil {
var cfg sherlockConfig
if err := opts.ConfigSource.Unmarshal(configKey, &cfg); err != nil {
return nil, err
}
if opts.Addr == "" {
opts.Addr = cfg.Addr
}
}
hostname, scheme, err := extractSchemeAndHost(opts.Addr)
if err != nil {
return nil, err
}
// setup runtime for openapi client
transport := httptransport.New(hostname, "", []string{scheme})
transport.DefaultAuthentication = makeClientAuthWriter(opts.IapTokenProvider, opts.GhaOidcTokenProvider)
return &clientImpl{
client: client.New(transport, strfmt.Default),
ghaOidcTokenProviderIsHappy: credentials.IsTokenProviderHappy(opts.GhaOidcTokenProvider),
}, nil
}
// clientImpl contains an API client for a remote sherlock server. It implements Client.
type clientImpl struct {
client *client.Sherlock
// ghaOidcTokenProviderIsHappy helps control whether GHA-only behavior should short-circuit
// (currently ChartReleaseStatusUpdater) should short-circuit or not. We store this as state
// on the clientImpl so the same Client will be consistent about whether it short-circuits or
// not.
ghaOidcTokenProviderIsHappy bool
}
// sherlock client lib expects host and scheme as separate input values but
// specifying a fqdn in config makes more sense so this helper exists to extract the
// component parts
func extractSchemeAndHost(addr string) (string, string, error) {
sherlockURL, err := url.Parse(addr)
if err != nil {
return "", "", err
}
var sherlockHost string
sherlockHost = sherlockURL.Hostname()
// account for mock servers via httptest which are assigned a random port on localhost
if sherlockURL.Port() != "" {
sherlockHost = strings.Join([]string{sherlockHost, sherlockURL.Port()}, ":")
}
return sherlockHost, sherlockURL.Scheme, nil
}
// GetStatus is used in tests to verify that an initialized Client
// can successfully issue a request against a remote sherlock backend
func (c *clientImpl) GetStatus() error {
params := misc.NewGetStatusParams()
_, err := c.client.Misc.GetStatus(params)
return err
}