54
47
providers[name] = p
57
// Provider returns the previously registered provider with the given type.
58
func Provider(typ string) (EnvironProvider, error) {
59
p, ok := providers[typ]
61
return nil, fmt.Errorf("no registered provider for %q", typ)
66
50
// ReadEnvironsBytes parses the contents of an environments.yaml file
67
51
// and returns its representation. An environment with an unknown type
68
52
// will only generate an error when New is called for that environment.
69
53
// Attributes for environments with known types are checked.
70
54
func ReadEnvironsBytes(data []byte) (*Environs, error) {
73
Environments map[string]map[string]interface{}
56
Default string "default"
57
Environments map[string]interface{} "environments"
59
raw.Environments = make(map[string]interface{}) // TODO fix bug in goyaml - it should make this automatically.
75
60
err := goyaml.Unmarshal(data, &raw)
94
79
environs := make(map[string]environ)
95
for name, attrs := range raw.Environments {
80
for name, x := range raw.Environments {
81
attrs, ok := x.(map[interface{}]interface{})
83
return nil, fmt.Errorf("environment %q does not have attributes", name)
96
85
kind, _ := attrs["type"].(string)
98
environs[name] = environ{
99
err: fmt.Errorf("environment %q has no type", name),
87
return nil, fmt.Errorf("environment %q has no type", name)
103
90
p := providers[kind]
92
// unknown provider type - skip entry but leave error message
93
// in case the environment is used later.
105
94
environs[name] = environ{
106
err: fmt.Errorf("environment %q has an unknown provider type %q", name, kind),
96
err: fmt.Errorf("environment %q has an unknown provider type: %q", name, kind),
110
// store the name of the this environment in the config itself
111
// so that providers can see it.
113
cfg, err := config.New(attrs)
100
cfg, err := p.ConfigChecker().Coerce(attrs, nil)
115
environs[name] = environ{
116
err: fmt.Errorf("error parsing environment %q: %v", name, err),
120
environs[name] = environ{config: cfg}
102
return nil, fmt.Errorf("error parsing environment %q: %v", name, err)
104
environs[name] = environ{
122
109
return &Environs{raw.Default, environs}, nil
125
func environsPath(path string) string {
127
path = config.JujuHomePath("environments.yaml")
132
112
// ReadEnvirons reads the juju environments.yaml file
133
113
// and returns the result of running ParseEnvironments
134
114
// on the file's contents.
135
// If path is empty, $HOME/.juju/environments.yaml is used.
136
func ReadEnvirons(path string) (*Environs, error) {
137
environsFilepath := environsPath(path)
138
data, err := ioutil.ReadFile(environsFilepath)
115
// If environsFile is empty, $HOME/.juju/environments.yaml
117
func ReadEnvirons(environsFile string) (*Environs, error) {
118
if environsFile == "" {
119
home := os.Getenv("HOME")
121
return nil, errors.New("$HOME not set")
123
environsFile = filepath.Join(home, ".juju/environments.yaml")
125
data, err := ioutil.ReadFile(environsFile)
142
129
e, err := ReadEnvironsBytes(data)
144
return nil, fmt.Errorf("cannot parse %q: %v", environsFilepath, err)
131
return nil, fmt.Errorf("cannot parse %q: %v", environsFile, err)
149
// WriteEnvirons creates a new juju environments.yaml file with the specified contents.
150
func WriteEnvirons(path string, fileContents string) (string, error) {
151
environsFilepath := environsPath(path)
152
environsDir := filepath.Dir(environsFilepath)
155
if info, err = os.Lstat(environsDir); os.IsNotExist(err) {
156
if err = os.MkdirAll(environsDir, 0700); err != nil {
159
} else if err != nil {
161
} else if info.Mode().Perm() != 0700 {
162
logger.Warningf("permission of %q is %q", environsDir, info.Mode().Perm())
164
if err := ioutil.WriteFile(environsFilepath, []byte(fileContents), 0600); err != nil {
167
// WriteFile does not change permissions of existing files.
168
if err := os.Chmod(environsFilepath, 0600); err != nil {
171
return environsFilepath, nil
174
// BootstrapConfig returns a copy of the supplied configuration with
175
// secret attributes removed. If the resulting config is not suitable
176
// for bootstrapping an environment, an error is returned.
177
func BootstrapConfig(cfg *config.Config) (*config.Config, error) {
178
p, err := Provider(cfg.Type())
182
secrets, err := p.SecretAttrs(cfg)
187
for k := range secrets {
191
// We never want to push admin-secret or the root CA private key to the cloud.
192
delete(m, "admin-secret")
193
m["ca-private-key"] = ""
194
if cfg, err = config.New(m); err != nil {
197
if _, ok := cfg.AgentVersion(); !ok {
198
return nil, fmt.Errorf("environment configuration has no agent-version")