launchpad.net/~rogpeppe/juju-core/500-errgo-fix@v0.0.0-20140213181702-000000002356/agent/format-1.12.go (about) 1 // Copyright 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package agent 5 6 import ( 7 "fmt" 8 "io/ioutil" 9 "os" 10 "path" 11 12 "launchpad.net/goyaml" 13 14 "launchpad.net/juju-core/state" 15 "launchpad.net/juju-core/state/api" 16 "launchpad.net/juju-core/utils" 17 ) 18 19 const format_1_12 = "format 1.12" 20 21 // formatter_1_12 is the formatter for the 1.12 format. 22 type formatter_1_12 struct { 23 } 24 25 // format_1_12Serialization holds information stored in the agent.conf file. 26 type format_1_12Serialization struct { 27 // StateServerCert and StateServerKey hold the state server 28 // certificate and private key in PEM format. 29 StateServerCert []byte `yaml:",omitempty"` 30 StateServerKey []byte `yaml:",omitempty"` 31 32 StatePort int `yaml:",omitempty"` 33 APIPort int `yaml:",omitempty"` 34 35 // OldPassword specifies a password that should be 36 // used to connect to the state if StateInfo.Password 37 // is blank or invalid. 38 OldPassword string 39 40 // MachineNonce is set at provisioning/bootstrap time and used to 41 // ensure the agent is running on the correct instance. 42 MachineNonce string 43 44 // StateInfo specifies how the agent should connect to the 45 // state. The password may be empty if an old password is 46 // specified, or when bootstrapping. 47 StateInfo *state.Info `yaml:",omitempty"` 48 49 // OldAPIPassword specifies a password that should 50 // be used to connect to the API if APIInfo.Password 51 // is blank or invalid. 52 OldAPIPassword string 53 54 // APIInfo specifies how the agent should connect to the 55 // state through the API. 56 APIInfo *api.Info `yaml:",omitempty"` 57 } 58 59 // Ensure that the formatter_1_12 struct implements the formatter interface. 60 var _ formatter = (*formatter_1_12)(nil) 61 62 func (*formatter_1_12) configFile(dirName string) string { 63 return path.Join(dirName, "agent.conf") 64 } 65 66 func (formatter *formatter_1_12) read(dirName string) (*configInternal, error) { 67 data, err := ioutil.ReadFile(formatter.configFile(dirName)) 68 if err != nil { 69 return nil, err 70 } 71 var conf format_1_12Serialization 72 if err := goyaml.Unmarshal(data, &conf); err != nil { 73 return nil, err 74 } 75 76 var stateDetails *connectionDetails 77 var caCert []byte 78 var tag string 79 if conf.StateInfo != nil { 80 stateDetails = &connectionDetails{ 81 conf.StateInfo.Addrs, 82 conf.StateInfo.Password, 83 } 84 tag = conf.StateInfo.Tag 85 caCert = conf.StateInfo.CACert 86 } 87 var apiDetails *connectionDetails 88 if conf.APIInfo != nil { 89 apiDetails = &connectionDetails{ 90 conf.APIInfo.Addrs, 91 conf.APIInfo.Password, 92 } 93 tag = conf.APIInfo.Tag 94 caCert = conf.APIInfo.CACert 95 } 96 return &configInternal{ 97 tag: tag, 98 nonce: conf.MachineNonce, 99 caCert: caCert, 100 stateDetails: stateDetails, 101 apiDetails: apiDetails, 102 oldPassword: conf.OldPassword, 103 stateServerCert: conf.StateServerCert, 104 stateServerKey: conf.StateServerKey, 105 apiPort: conf.APIPort, 106 values: map[string]string{}, 107 }, nil 108 } 109 110 func (formatter *formatter_1_12) makeAgentConf(config *configInternal) *format_1_12Serialization { 111 format := &format_1_12Serialization{ 112 StateServerCert: config.stateServerCert, 113 StateServerKey: config.stateServerKey, 114 APIPort: config.apiPort, 115 OldPassword: config.oldPassword, 116 MachineNonce: config.nonce, 117 } 118 if config.stateDetails != nil { 119 // It is fine that we are copying the slices for the addresses. 120 format.StateInfo = &state.Info{ 121 Addrs: config.stateDetails.addresses, 122 Password: config.stateDetails.password, 123 Tag: config.tag, 124 CACert: config.caCert, 125 } 126 } 127 if config.apiDetails != nil { 128 format.APIInfo = &api.Info{ 129 Addrs: config.apiDetails.addresses, 130 Password: config.apiDetails.password, 131 Tag: config.tag, 132 CACert: config.caCert, 133 } 134 } 135 return format 136 } 137 138 func (formatter *formatter_1_12) write(config *configInternal) error { 139 dirName := config.Dir() 140 conf := formatter.makeAgentConf(config) 141 data, err := goyaml.Marshal(conf) 142 if err != nil { 143 return err 144 } 145 if err := os.MkdirAll(dirName, 0755); err != nil { 146 return err 147 } 148 newFile := path.Join(dirName, "agent.conf-new") 149 if err := ioutil.WriteFile(newFile, data, 0600); err != nil { 150 return err 151 } 152 if err := os.Rename(newFile, formatter.configFile(dirName)); err != nil { 153 return err 154 } 155 return nil 156 } 157 158 func (formatter *formatter_1_12) writeCommands(config *configInternal) ([]string, error) { 159 dirName := config.Dir() 160 conf := formatter.makeAgentConf(config) 161 data, err := goyaml.Marshal(conf) 162 if err != nil { 163 return nil, err 164 } 165 var commands []string 166 addCommand := func(f string, a ...interface{}) { 167 commands = append(commands, fmt.Sprintf(f, a...)) 168 } 169 filename := utils.ShQuote(formatter.configFile(dirName)) 170 addCommand("mkdir -p %s", utils.ShQuote(dirName)) 171 addCommand("install -m %o /dev/null %s", 0600, filename) 172 addCommand(`printf '%%s\n' %s > %s`, utils.ShQuote(string(data)), filename) 173 return commands, nil 174 } 175 176 func (*formatter_1_12) migrate(config *configInternal) { 177 }