/
provider.go
165 lines (139 loc) · 5.62 KB
/
provider.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
// Copyright 2015 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.
// Juju provider for CloudSigma
package cloudsigma
import (
"fmt"
"github.com/juju/errors"
"github.com/juju/loggo"
"github.com/juju/utils"
"github.com/juju/juju/environs"
"github.com/juju/juju/environs/config"
"github.com/juju/juju/environs/simplestreams"
"github.com/juju/juju/storage/provider/registry"
)
var logger = loggo.GetLogger("juju.provider.cloudsigma")
const (
providerType = "cloudsigma"
)
func getImageSource(env environs.Environ) (simplestreams.DataSource, error) {
e, ok := env.(*environ)
if !ok {
return nil, errors.NotSupportedf("non-cloudsigma environment")
}
return simplestreams.NewURLDataSource("cloud images", fmt.Sprintf(CloudsigmaCloudImagesURLTemplate, e.ecfg.region()), utils.VerifySSLHostnames), nil
}
type environProvider struct{}
var providerInstance = environProvider{}
// check the provider implements environs.EnvironProvider interface
var _ environs.EnvironProvider = (*environProvider)(nil)
func init() {
// This will only happen in binaries that actually import this provider
// somewhere. To enable a provider, import it in the "providers/all"
// package; please do *not* import individual providers anywhere else,
// except in direct tests for that provider.
environs.RegisterProvider("cloudsigma", providerInstance)
environs.RegisterImageDataSourceFunc("Image source", getImageSource)
registry.RegisterEnvironStorageProviders(providerType)
}
// Boilerplate returns a default configuration for the environment in yaml format.
// The text should be a key followed by some number of attributes:
// `environName:
// type: environTypeName
// attr1: val1
// `
// The text is used as a template (see the template package) with one extra template
// function available, rand, which expands to a random hexadecimal string when invoked.
func (environProvider) BoilerplateConfig() string {
return boilerplateConfig
}
// Open opens the environment and returns it.
// The configuration must have come from a previously
// prepared environment.
func (environProvider) Open(cfg *config.Config) (environs.Environ, error) {
logger.Infof("opening environment %q", cfg.Name())
cfg, err := prepareConfig(cfg)
if err != nil {
return nil, err
}
env := &environ{name: cfg.Name()}
if err := env.SetConfig(cfg); err != nil {
return nil, err
}
return env, nil
}
// RestrictedConfigAttributes are provider specific attributes stored in
// the config that really cannot or should not be changed across
// environments running inside a single juju server.
func (environProvider) RestrictedConfigAttributes() []string {
return []string{"region"}
}
// PrepareForCreateEnvironment prepares an environment for creation. Any
// additional configuration attributes are added to the config passed in
// and returned. This allows providers to add additional required config
// for new environments that may be created in an existing juju server.
func (environProvider) PrepareForCreateEnvironment(cfg *config.Config) (*config.Config, error) {
// Not even sure if this will ever make sense.
return nil, errors.NotImplementedf("PrepareForCreateEnvironment")
}
// Prepare prepares an environment for use. Any additional
// configuration attributes in the returned environment should
// be saved to be used later. If the environment is already
// prepared, this call is equivalent to Open.
func (environProvider) PrepareForBootstrap(ctx environs.BootstrapContext, cfg *config.Config) (environs.Environ, error) {
logger.Infof("preparing environment %q", cfg.Name())
return providerInstance.Open(cfg)
}
// Validate ensures that config is a valid configuration for this
// provider, applying changes to it if necessary, and returns the
// validated configuration.
// If old is not nil, it holds the previous environment configuration
// for consideration when validating changes.
func (environProvider) Validate(cfg, old *config.Config) (*config.Config, error) {
logger.Infof("validating environment %q", cfg.Name())
// You should almost certainly not change this method; if you need to change
// how configs are validated, you should edit validateConfig itself, to ensure
// that your checks are always applied.
newEcfg, err := validateConfig(cfg, nil)
if err != nil {
return nil, errors.Errorf("invalid config: %v", err)
}
if old != nil {
oldEcfg, err := validateConfig(old, nil)
if err != nil {
return nil, errors.Errorf("invalid base config: %v", err)
}
if newEcfg, err = validateConfig(cfg, oldEcfg); err != nil {
return nil, errors.Errorf("invalid config change: %v", err)
}
}
return newEcfg.Config, nil
}
// SecretAttrs filters the supplied configuration returning only values
// which are considered sensitive. All of the values of these secret
// attributes need to be strings.
func (environProvider) SecretAttrs(cfg *config.Config) (map[string]string, error) {
logger.Infof("filtering secret attributes for environment %q", cfg.Name())
// If you keep configSecretFields up to date, this method should Just Work.
ecfg, err := validateConfig(cfg, nil)
if err != nil {
return nil, err
}
secretAttrs := map[string]string{}
for _, field := range configSecretFields {
if value, ok := ecfg.attrs[field]; ok {
if stringValue, ok := value.(string); ok {
secretAttrs[field] = stringValue
} else {
// All your secret attributes must be strings at the moment. Sorry.
// It's an expedient and hopefully temporary measure that helps us
// plug a security hole in the API.
return nil, errors.Errorf(
"secret %q field must have a string value; got %v",
field, value,
)
}
}
}
return secretAttrs, nil
}