~nskaggs/+junk/xenial-test

« back to all changes in this revision

Viewing changes to src/github.com/juju/juju/jujuclient/accounts.go

  • Committer: Nicholas Skaggs
  • Date: 2016-10-24 20:56:05 UTC
  • Revision ID: nicholas.skaggs@canonical.com-20161024205605-z8lta0uvuhtxwzwl
Initi with beta15

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright 2016 Canonical Ltd.
 
2
// Licensed under the AGPLv3, see LICENCE file for details.
 
3
 
 
4
package jujuclient
 
5
 
 
6
import (
 
7
        "io/ioutil"
 
8
        "os"
 
9
 
 
10
        "github.com/juju/errors"
 
11
        "github.com/juju/utils"
 
12
        "gopkg.in/yaml.v2"
 
13
 
 
14
        "github.com/juju/juju/juju/osenv"
 
15
)
 
16
 
 
17
// JujuAccountsPath is the location where accounts information is
 
18
// expected to be found.
 
19
func JujuAccountsPath() string {
 
20
        return osenv.JujuXDGDataHomePath("accounts.yaml")
 
21
}
 
22
 
 
23
// ReadAccountsFile loads all accounts defined in a given file.
 
24
// If the file is not found, it is not an error.
 
25
func ReadAccountsFile(file string) (map[string]AccountDetails, error) {
 
26
        data, err := ioutil.ReadFile(file)
 
27
        if err != nil {
 
28
                if os.IsNotExist(err) {
 
29
                        return nil, nil
 
30
                }
 
31
                return nil, err
 
32
        }
 
33
        if err := migrateLegacyAccounts(data); err != nil {
 
34
                return nil, err
 
35
        }
 
36
        accounts, err := ParseAccounts(data)
 
37
        if err != nil {
 
38
                return nil, err
 
39
        }
 
40
        return accounts, nil
 
41
}
 
42
 
 
43
// WriteAccountsFile marshals to YAML details of the given accounts
 
44
// and writes it to the accounts file.
 
45
func WriteAccountsFile(controllerAccounts map[string]AccountDetails) error {
 
46
        data, err := yaml.Marshal(accountsCollection{controllerAccounts})
 
47
        if err != nil {
 
48
                return errors.Annotate(err, "cannot marshal accounts")
 
49
        }
 
50
        return utils.AtomicWriteFile(JujuAccountsPath(), data, os.FileMode(0600))
 
51
}
 
52
 
 
53
// ParseAccounts parses the given YAML bytes into accounts metadata.
 
54
func ParseAccounts(data []byte) (map[string]AccountDetails, error) {
 
55
        var result accountsCollection
 
56
        if err := yaml.Unmarshal(data, &result); err != nil {
 
57
                return nil, errors.Annotate(err, "cannot unmarshal accounts")
 
58
        }
 
59
        return result.ControllerAccounts, nil
 
60
}
 
61
 
 
62
type accountsCollection struct {
 
63
        ControllerAccounts map[string]AccountDetails `yaml:"controllers"`
 
64
}
 
65
 
 
66
// TODO(axw) 2016-07-14 #1603841
 
67
// Drop this code once we get to 2.0.
 
68
func migrateLegacyAccounts(data []byte) error {
 
69
        type legacyControllerAccounts struct {
 
70
                Accounts       map[string]AccountDetails `yaml:"accounts"`
 
71
                CurrentAccount string                    `yaml:"current-account,omitempty"`
 
72
        }
 
73
        type legacyAccountsCollection struct {
 
74
                ControllerAccounts map[string]legacyControllerAccounts `yaml:"controllers"`
 
75
        }
 
76
        var legacy legacyAccountsCollection
 
77
        if err := yaml.Unmarshal(data, &legacy); err != nil {
 
78
                return errors.Annotate(err, "cannot unmarshal accounts")
 
79
        }
 
80
        result := make(map[string]AccountDetails)
 
81
        for controller, controllerAccounts := range legacy.ControllerAccounts {
 
82
                if controllerAccounts.CurrentAccount == "" {
 
83
                        continue
 
84
                }
 
85
                details, ok := controllerAccounts.Accounts[controllerAccounts.CurrentAccount]
 
86
                if !ok {
 
87
                        continue
 
88
                }
 
89
                result[controller] = details
 
90
        }
 
91
        if len(result) > 0 {
 
92
                // Only write if we found at least one,
 
93
                // which means the file was in legacy
 
94
                // format. Otherwise leave it alone.
 
95
                return WriteAccountsFile(result)
 
96
        }
 
97
        return nil
 
98
}