/
machiner.go
132 lines (117 loc) · 3.69 KB
/
machiner.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
// Copyright 2012, 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.
package machiner
import (
"fmt"
"net"
"github.com/juju/loggo"
"github.com/juju/names"
"github.com/juju/juju/agent"
"github.com/juju/juju/api/watcher"
"github.com/juju/juju/apiserver/params"
"github.com/juju/juju/network"
"github.com/juju/juju/worker"
)
var logger = loggo.GetLogger("juju.worker.machiner")
// Machiner is responsible for a machine agent's lifecycle.
type Machiner struct {
st MachineAccessor
tag names.MachineTag
machine Machine
}
// NewMachiner returns a Worker that will wait for the identified machine
// to become Dying and make it Dead; or until the machine becomes Dead by
// other means.
func NewMachiner(st MachineAccessor, agentConfig agent.Config) worker.Worker {
mr := &Machiner{st: st, tag: agentConfig.Tag().(names.MachineTag)}
return worker.NewNotifyWorker(mr)
}
func (mr *Machiner) SetUp() (watcher.NotifyWatcher, error) {
// Find which machine we're responsible for.
m, err := mr.st.Machine(mr.tag)
if params.IsCodeNotFoundOrCodeUnauthorized(err) {
return nil, worker.ErrTerminateAgent
} else if err != nil {
return nil, err
}
mr.machine = m
// Set the addresses in state to the host's addresses.
if err := setMachineAddresses(mr.tag, m); err != nil {
return nil, err
}
// Mark the machine as started and log it.
if err := m.SetStatus(params.StatusStarted, "", nil); err != nil {
return nil, fmt.Errorf("%s failed to set status started: %v", mr.tag, err)
}
logger.Infof("%q started", mr.tag)
return m.Watch()
}
var interfaceAddrs = net.InterfaceAddrs
// setMachineAddresses sets the addresses for this machine to all of the
// host's non-loopback interface IP addresses.
func setMachineAddresses(tag names.MachineTag, m Machine) error {
addrs, err := interfaceAddrs()
if err != nil {
return err
}
var hostAddresses []network.Address
for _, addr := range addrs {
var ip net.IP
switch addr := addr.(type) {
case *net.IPAddr:
ip = addr.IP
case *net.IPNet:
ip = addr.IP
default:
continue
}
address := network.NewAddress(ip.String())
// Filter out link-local addresses as we cannot reliably use them.
if address.Scope == network.ScopeLinkLocal {
continue
}
hostAddresses = append(hostAddresses, address)
}
if len(hostAddresses) == 0 {
return nil
}
// Filter out any LXC bridge addresses.
hostAddresses = network.FilterLXCAddresses(hostAddresses)
logger.Infof("setting addresses for %v to %q", tag, hostAddresses)
return m.SetMachineAddresses(hostAddresses)
}
func (mr *Machiner) Handle(_ <-chan struct{}) error {
if err := mr.machine.Refresh(); params.IsCodeNotFoundOrCodeUnauthorized(err) {
return worker.ErrTerminateAgent
} else if err != nil {
return err
}
life := mr.machine.Life()
if life == params.Alive {
return nil
}
logger.Debugf("%q is now %s", mr.tag, life)
if err := mr.machine.SetStatus(params.StatusStopped, "", nil); err != nil {
return fmt.Errorf("%s failed to set status stopped: %v", mr.tag, err)
}
// Attempt to mark the machine Dead. If the machine still has units
// assigned, or storage attached, this will fail with
// CodeHasAssignedUnits or CodeMachineHasAttachedStorage respectively.
// Once units or storage are removed, the watcher will trigger again
// and we'll reattempt.
if err := mr.machine.EnsureDead(); err != nil {
if params.IsCodeHasAssignedUnits(err) {
return nil
}
if params.IsCodeMachineHasAttachedStorage(err) {
logger.Tracef("machine still has storage attached")
return nil
}
return fmt.Errorf("%s failed to set machine to dead: %v", mr.tag, err)
}
return worker.ErrTerminateAgent
}
func (mr *Machiner) TearDown() error {
// Nothing to do here.
return nil
}