File: client.go

package info (click to toggle)
singularity-container 4.0.3%2Bds1-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 21,672 kB
  • sloc: asm: 3,857; sh: 2,125; ansic: 1,677; awk: 414; makefile: 110; python: 99
file content (172 lines) | stat: -rw-r--r-- 4,529 bytes parent folder | download | duplicates (2)
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
171
172
// Copyright (c) 2020-2023, Sylabs Inc. All rights reserved.
// Copyright (c) 2020, Control Command Inc. All rights reserved.
// This software is licensed under a 3-clause BSD license. Please consult the
// LICENSE.md file distributed with the sources of this project regarding your
// rights to use or distribute this software.

package endpoint

import (
	"fmt"
	"net/http"
	"strings"

	golog "github.com/go-log/log"
	keyclient "github.com/sylabs/scs-key-client/client"
	libclient "github.com/sylabs/scs-library-client/client"
	remoteutil "github.com/sylabs/singularity/v4/internal/pkg/remote/util"
	"github.com/sylabs/singularity/v4/pkg/sylog"
	useragent "github.com/sylabs/singularity/v4/pkg/util/user-agent"
)

func (ep *Config) KeyserverClientOpts(uri string, op KeyserverOp) ([]keyclient.Option, error) {
	// empty uri means to use the default endpoint
	isDefault := uri == ""

	if err := ep.UpdateKeyserversConfig(); err != nil {
		return nil, err
	}

	var primaryKeyserver *ServiceConfig

	for _, kc := range ep.Keyservers {
		if kc.Skip {
			continue
		}
		primaryKeyserver = kc
		break
	}

	// shouldn't happen
	if primaryKeyserver == nil {
		return nil, fmt.Errorf("no primary keyserver configured")
	}

	var keyservers []*ServiceConfig

	if isDefault {
		uri = primaryKeyserver.URI

		if op == KeyserverVerifyOp {
			// verify operation can query multiple keyserver, the token
			// is automatically set by the custom client
			keyservers = ep.Keyservers
		} else {
			// use the primary keyserver
			keyservers = []*ServiceConfig{
				primaryKeyserver,
			}
		}
	} else if ep.Exclusive {
		available := make([]string, 0)
		found := false
		for _, kc := range ep.Keyservers {
			if kc.Skip {
				continue
			}
			available = append(available, kc.URI)
			if remoteutil.SameKeyserver(uri, kc.URI) {
				found = true
				break
			}
		}
		if !found {
			list := strings.Join(available, ", ")
			return nil, fmt.Errorf(
				"endpoint is set as exclusive by the system administrator: only %q can be used",
				list,
			)
		}
	} else {
		keyservers = []*ServiceConfig{
			{
				URI:      uri,
				External: true,
			},
		}
	}

	co := []keyclient.Option{
		keyclient.OptBaseURL(uri),
		keyclient.OptUserAgent(useragent.Value()),
		keyclient.OptHTTPClient(newClient(keyservers, op)),
	}
	return co, nil
}

func (ep *Config) LibraryClientConfig(uri string) (*libclient.Config, error) {
	// empty uri means to use the default endpoint
	isDefault := uri == ""

	config := &libclient.Config{
		BaseURL:   uri,
		UserAgent: useragent.Value(),
		Logger:    (golog.Logger)(sylog.DebugLogger{}),
		// TODO - probably should establish an appropriate client timeout here.
		HTTPClient: &http.Client{},
	}

	if isDefault {
		libURI, err := ep.GetServiceURI(Library)
		if err != nil {
			return nil, fmt.Errorf("unable to get library service URI: %v", err)
		}
		config.AuthToken = ep.Token
		config.BaseURL = libURI
	} else if ep.Exclusive {
		libURI, err := ep.GetServiceURI(Library)
		if err != nil {
			return nil, fmt.Errorf("unable to get library service URI: %v", err)
		}
		if !remoteutil.SameURI(uri, libURI) {
			return nil, fmt.Errorf(
				"endpoint is set as exclusive by the system administrator: only %q can be used",
				libURI,
			)
		}
	}

	return config, nil
}

// BuilderClientConfig returns the baseURI and authToken associated with ep, in the context of uri.
func (ep *Config) BuilderClientConfig(uri string) (baseURI, authToken string, err error) {
	// empty uri means to use the default endpoint
	isDefault := uri == ""

	baseURI = uri

	if isDefault {
		buildURI, err := ep.GetServiceURI(Builder)
		if err != nil {
			return "", "", fmt.Errorf("unable to get builder service URI: %v", err)
		}
		authToken = ep.Token
		baseURI = buildURI
	} else if ep.Exclusive {
		buildURI, err := ep.GetServiceURI(Builder)
		if err != nil {
			return "", "", fmt.Errorf("unable to get builder service URI: %v", err)
		}
		if !remoteutil.SameURI(uri, buildURI) {
			return "", "", fmt.Errorf(
				"endpoint is set as exclusive by the system administrator: only %q can be used",
				buildURI,
			)
		}
	}

	return baseURI, authToken, nil
}

// RegistryURI returns the URI of the backing OCI registry for the library service, associated with ep.
func (ep *Config) RegistryURI() (string, error) {
	registryURI, err := ep.getServiceConfigVal(Library, RegistryURIConfigKey)
	if err != nil {
		return "", err
	}
	if registryURI == "" {
		return "", fmt.Errorf("library does not provide an OCI registry")
	}
	return registryURI, nil
}