crossplane

Форк
0
263 строки · 7.7 Кб
1
/*
2
Copyright 2023 The Crossplane Authors.
3

4
Licensed under the Apache License, Version 2.0 (the "License");
5
you may not use this file except in compliance with the License.
6
You may obtain a copy of the License at
7

8
    http://www.apache.org/licenses/LICENSE-2.0
9

10
Unless required by applicable law or agreed to in writing, software
11
distributed under the License is distributed on an "AS IS" BASIS,
12
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
See the License for the specific language governing permissions and
14
limitations under the License.
15
*/
16

17
// Package config manages the Crossplane CLI configuration.
18
package config
19

20
import (
21
	"bytes"
22
	"encoding/json"
23
	"io"
24
	"os"
25
	"path/filepath"
26

27
	"github.com/crossplane/crossplane-runtime/pkg/errors"
28
)
29

30
// TODO(negz): If/when this config file stores anything apart from Upbound user
31
// profiles (i.e. for authenticating to xpkg.upbound.io) we should split out the
32
// generic Crossplane config from the xpkg.upbound.io stuff.
33

34
// Location of crossplane CLI config file.
35
const (
36
	ConfigDir  = ".crossplane"
37
	ConfigFile = "config.json"
38
)
39

40
const (
41
	errDefaultNotExist    = "profile specified as default does not exist"
42
	errNoDefaultSpecified = "no default profile specified"
43
	errInvalidProfile     = "profile is not valid"
44

45
	errProfileNotFoundFmt = "profile not found with identifier: %s"
46
	errNoProfilesFound    = "no profiles found"
47
)
48

49
// Config is format for the up configuration file.
50
type Config struct {
51
	Upbound Upbound `json:"upbound"`
52
}
53

54
// Extract performs extraction of configuration from the provided source.
55
func Extract(src Source) (*Config, error) {
56
	conf, err := src.GetConfig()
57
	if err != nil {
58
		return nil, err
59
	}
60
	return conf, nil
61
}
62

63
// GetDefaultPath returns the default config path or error.
64
func GetDefaultPath() (string, error) {
65
	h, err := os.UserHomeDir()
66
	if err != nil {
67
		return "", err
68
	}
69
	return filepath.Join(h, ConfigDir, ConfigFile), nil
70
}
71

72
// Upbound contains configuration information for Upbound.
73
type Upbound struct {
74
	// Default indicates the default profile.
75
	Default string `json:"default"`
76

77
	// Profiles contain sets of credentials for communicating with Upbound. Key
78
	// is name of the profile.
79
	Profiles map[string]Profile `json:"profiles,omitempty"`
80
}
81

82
// ProfileType is a type of Upbound profile.
83
type ProfileType string
84

85
// Types of profiles.
86
const (
87
	UserProfileType  ProfileType = "user"
88
	TokenProfileType ProfileType = "token"
89
)
90

91
// A Profile is a set of credentials
92
type Profile struct {
93
	// ID is either a username, email, or token.
94
	ID string `json:"id"`
95

96
	// Type is the type of the profile.
97
	Type ProfileType `json:"type"`
98

99
	// Session is a session token used to authenticate to Upbound.
100
	Session string `json:"session,omitempty"`
101

102
	// Account is the default account to use when this profile is selected.
103
	Account string `json:"account,omitempty"`
104

105
	// BaseConfig represent persisted settings for this profile.
106
	// For example:
107
	// * flags
108
	// * environment variables
109
	BaseConfig map[string]string `json:"base,omitempty"`
110
}
111

112
// RedactedProfile embeds a Upbound Profile for the sole purpose of redacting
113
// sensitive information.
114
type RedactedProfile struct {
115
	Profile
116
}
117

118
// MarshalJSON overrides the session field with `REDACTED` so as not to leak
119
// sensitive information. We're using an explicit copy here instead of updating
120
// the underlying Profile struct so as to not modifying the internal state of
121
// the struct by accident.
122
func (p RedactedProfile) MarshalJSON() ([]byte, error) {
123
	type profile RedactedProfile
124
	pc := profile(p)
125
	s := "NONE"
126
	if pc.Session != "" {
127
		s = "REDACTED"
128
	}
129
	pc.Session = s
130
	return json.Marshal(&pc)
131
}
132

133
// checkProfile ensures a profile does not violate constraints.
134
func checkProfile(p Profile) error {
135
	if p.ID == "" || p.Type == "" {
136
		return errors.New(errInvalidProfile)
137
	}
138
	return nil
139
}
140

141
// AddOrUpdateUpboundProfile adds or updates an Upbound profile to the Config.
142
func (c *Config) AddOrUpdateUpboundProfile(name string, new Profile) error {
143
	if err := checkProfile(new); err != nil {
144
		return err
145
	}
146
	if c.Upbound.Profiles == nil {
147
		c.Upbound.Profiles = map[string]Profile{}
148
	}
149
	c.Upbound.Profiles[name] = new
150
	return nil
151
}
152

153
// GetDefaultUpboundProfile gets the default Upbound profile or returns an error if
154
// default is not set or default profile does not exist.
155
func (c *Config) GetDefaultUpboundProfile() (string, Profile, error) {
156
	if c.Upbound.Default == "" {
157
		return "", Profile{}, errors.New(errNoDefaultSpecified)
158
	}
159
	p, ok := c.Upbound.Profiles[c.Upbound.Default]
160
	if !ok {
161
		return "", Profile{}, errors.New(errDefaultNotExist)
162
	}
163
	return c.Upbound.Default, p, nil
164
}
165

166
// GetUpboundProfile gets a profile with a given identifier. If a profile does not
167
// exist for the given identifier an error will be returned. Multiple profiles
168
// should never exist for the same identifier, but in the case that they do, the
169
// first will be returned.
170
func (c *Config) GetUpboundProfile(name string) (Profile, error) {
171
	p, ok := c.Upbound.Profiles[name]
172
	if !ok {
173
		return Profile{}, errors.Errorf(errProfileNotFoundFmt, name)
174
	}
175
	return p, nil
176
}
177

178
// GetUpboundProfiles returns the list of existing profiles. If no profiles
179
// exist, then an error will be returned.
180
func (c *Config) GetUpboundProfiles() (map[string]Profile, error) {
181
	if c.Upbound.Profiles == nil {
182
		return nil, errors.New(errNoProfilesFound)
183
	}
184

185
	return c.Upbound.Profiles, nil
186
}
187

188
// SetDefaultUpboundProfile sets the default profile for communicating with
189
// Upbound. Setting a default profile that does not exist will return an
190
// error.
191
func (c *Config) SetDefaultUpboundProfile(name string) error {
192
	if _, ok := c.Upbound.Profiles[name]; !ok {
193
		return errors.Errorf(errProfileNotFoundFmt, name)
194
	}
195
	c.Upbound.Default = name
196
	return nil
197
}
198

199
// GetBaseConfig returns the persisted base configuration associated with the
200
// provided Profile. If the supplied name does not match an existing Profile
201
// an error is returned.
202
func (c *Config) GetBaseConfig(name string) (map[string]string, error) {
203
	profile, ok := c.Upbound.Profiles[name]
204
	if !ok {
205
		return nil, errors.Errorf(errProfileNotFoundFmt, name)
206
	}
207
	return profile.BaseConfig, nil
208
}
209

210
// AddToBaseConfig adds the supplied key, value pair to the base config map of
211
// the profile that corresponds to the given name. If the supplied name does
212
// not match an existing Profile an error is returned. If the overrides map
213
// does not currently exist on the corresponding profile, a map is initialized.
214
func (c *Config) AddToBaseConfig(name, key, value string) error {
215
	profile, ok := c.Upbound.Profiles[name]
216
	if !ok {
217
		return errors.Errorf(errProfileNotFoundFmt, name)
218
	}
219

220
	if profile.BaseConfig == nil {
221
		profile.BaseConfig = make(map[string]string)
222
	}
223

224
	profile.BaseConfig[key] = value
225
	c.Upbound.Profiles[name] = profile
226
	return nil
227
}
228

229
// RemoveFromBaseConfig removes the supplied key from the base config map of
230
// the Profile that corresponds to the given name. If the supplied name does
231
// not match an existing Profile an error is returned. If the base config map
232
// does not currently exist on the corresponding profile, a no-op occurs.
233
func (c *Config) RemoveFromBaseConfig(name, key string) error {
234
	profile, ok := c.Upbound.Profiles[name]
235
	if !ok {
236
		return errors.Errorf(errProfileNotFoundFmt, name)
237
	}
238

239
	if profile.BaseConfig == nil {
240
		return nil
241
	}
242

243
	delete(profile.BaseConfig, key)
244
	c.Upbound.Profiles[name] = profile
245
	return nil
246
}
247

248
// BaseToJSON converts the base config of the given Profile to JSON. If the
249
// config couldn't be converted or if the supplied name does not correspond
250
// to an existing Profile, an error is returned.
251
func (c *Config) BaseToJSON(name string) (io.Reader, error) {
252
	profile, err := c.GetBaseConfig(name)
253
	if err != nil {
254
		return nil, err
255
	}
256

257
	var buf bytes.Buffer
258
	if err := json.NewEncoder(&buf).Encode(profile); err != nil {
259
		return nil, err
260
	}
261

262
	return &buf, nil
263
}
264

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.