166
166
return st, errors.Annotate(err, "cannot open state")
169
type machineModel struct {
170
machine *state.Machine
169
174
// updateAllMachines finds all machines and resets the stored state address
170
175
// in each of them. The address does not include the port.
171
176
// It is too late to go back and errors in a couple of agents have
172
177
// better chance of being fixed by the user, if we were to fail
173
178
// we risk an inconsistent controller because of one unresponsive
174
179
// agent, we should nevertheless return the err info to the user.
175
func updateAllMachines(privateAddress string, machines []*state.Machine) error {
180
func updateAllMachines(privateAddress, publicAddress string, machines []machineModel) error {
176
181
var machineUpdating sync.WaitGroup
177
for key := range machines {
178
// key is used to have machine be scope bound to the loop iteration.
179
machine := machines[key]
182
for _, item := range machines {
183
machine := item.machine
180
184
// A newly resumed controller requires no updating, and more
181
185
// than one controller is not yet supported by this code.
182
186
if machine.IsManager() || machine.Life() == state.Dead {
185
189
machineUpdating.Add(1)
190
go func(machine *state.Machine, model *state.Model) {
187
191
defer machineUpdating.Done()
188
err := runMachineUpdate(machine, setAgentAddressScript(privateAddress))
189
logger.Errorf("failed updating machine: %v", err)
192
logger.Debugf("updating addresses for machine %s in model %s/%s", machine.Tag().Id(), model.Owner().Canonical(), model.Name())
193
// TODO: thumper 2016-09-20
194
// runMachineUpdate only handles linux machines, what about windows?
195
err := runMachineUpdate(machine, setAgentAddressScript(privateAddress, publicAddress))
197
logger.Errorf("failed updating machine: %v", err)
199
}(machine, item.model)
192
201
machineUpdating.Wait()
203
212
cd /var/lib/juju/agents
206
status jujud-$agent| grep -q "^jujud-$agent start" > /dev/null
207
if [ $? -eq 0 ]; then
208
initctl stop jujud-$agent
215
service jujud-$agent stop > /dev/null
217
# The below statement will work in cases where there
218
# is a private address for the api server only
219
# or where there are a private and a public, which are
220
# the two common cases.
210
221
sed -i.old -r "/^(stateaddresses|apiaddresses):/{
212
223
s/- .*(:[0-9]+)/- {{.Address}}\1/
225
s/- .*(:[0-9]+)/- {{.PubAddress}}\1/
213
226
}" $agent/agent.conf
215
228
# If we're processing a unit agent's directly
222
235
find $agent/state/relations -type f -exec sed -i -r 's/change-version: [0-9]+$/change-version: 0/' {} \;
224
# Just in case is a stale unit
225
status jujud-$agent| grep -q "^jujud-$agent stop" > /dev/null
226
if [ $? -eq 0 ]; then
227
initctl start jujud-$agent
228
systemctl stop jujud-$agent
229
systemctl start jujud-$agent
237
service jujud-$agent start > /dev/null
234
241
// setAgentAddressScript generates an ssh script argument to update state addresses.
235
func setAgentAddressScript(stateAddr string) string {
242
func setAgentAddressScript(stateAddr, statePubAddr string) string {
236
243
var buf bytes.Buffer
237
244
err := agentAddressAndRelationsTemplate.Execute(&buf, struct {
247
}{stateAddr, statePubAddr})
241
249
panic(errors.Annotate(err, "template error"))
265
273
sshOptions := ssh.Options{}
266
274
sshOptions.SetIdentities("/var/lib/juju/system-identity")
267
275
userCmd := sshCommand(userAddr, []string{"sudo", "-n", "bash", "-c " + utils.ShQuote(script)}, &sshOptions)
276
var stdoutBuf bytes.Buffer
268
277
var stderrBuf bytes.Buffer
278
userCmd.Stdout = &stdoutBuf
269
279
userCmd.Stderr = &stderrBuf
280
logger.Debugf("updating %s, script:\n%s", addr, script)
270
281
if err := userCmd.Run(); err != nil {
271
282
return errors.Annotatef(err, "ssh command failed: %q", stderrBuf.String())
284
logger.Debugf("result %s\nstdout: \n%s\nstderr: %s", addr, stdoutBuf.String(), stderrBuf.String())