1
// Copyright 2014 Canonical Ltd.
2
// Copyright 2014 Cloudbase Solutions SRL
3
// Licensed under the AGPLv3, see LICENCE file for details.
10
"github.com/juju/errors"
12
"gopkg.in/mgo.v2/bson"
16
var _ RebootFlagSetter = (*Machine)(nil)
17
var _ RebootActionGetter = (*Machine)(nil)
19
// RebootAction defines the action a machine should
20
// take when a hook needs to reboot
21
type RebootAction string
24
// ShouldDoNothing instructs a machine agent that no action
25
// is required on its part
26
ShouldDoNothing RebootAction = "noop"
27
// ShouldReboot instructs a machine to reboot
28
// this happens when a hook running on a machine, requests
30
ShouldReboot RebootAction = "reboot"
31
// ShouldShutdown instructs a machine to shut down. This usually
32
// happens when running inside a container, and a hook on the parent
33
// machine requests a reboot
34
ShouldShutdown RebootAction = "shutdown"
37
// rebootDoc will hold the reboot flag for a machine.
38
type rebootDoc struct {
39
DocID string `bson:"_id"`
40
Id string `bson:"machineid"`
41
ModelUUID string `bson:"model-uuid"`
44
func (m *Machine) setFlag() error {
46
return mgo.ErrNotFound
49
assertModelActiveOp(m.st.ModelUUID()),
57
Insert: &rebootDoc{Id: m.Id()},
60
err := m.st.runTransaction(ops)
61
if err == txn.ErrAborted {
62
if err := checkModelActive(m.st); err != nil {
63
return errors.Trace(err)
65
return mgo.ErrNotFound
66
} else if err != nil {
67
return errors.Errorf("failed to set reboot flag: %v", err)
72
func removeRebootDocOp(st *State, machineId string) txn.Op {
75
Id: st.docID(machineId),
81
func (m *Machine) clearFlag() error {
82
reboot, closer := m.st.getCollection(rebootC)
86
count, err := reboot.FindId(docID).Count()
90
ops := []txn.Op{removeRebootDocOp(m.st, m.Id())}
91
err = m.st.runTransaction(ops)
93
return errors.Errorf("failed to clear reboot flag: %v", err)
98
// SetRebootFlag sets the reboot flag of a machine to a boolean value. It will also
99
// do a lazy create of a reboot document if needed; i.e. If a document
100
// does not exist yet for this machine, it will create it.
101
func (m *Machine) SetRebootFlag(flag bool) error {
108
// GetRebootFlag returns the reboot flag for this machine.
109
func (m *Machine) GetRebootFlag() (bool, error) {
110
rebootCol, closer := m.st.getCollection(rebootC)
113
count, err := rebootCol.FindId(m.doc.DocID).Count()
115
return false, fmt.Errorf("failed to get reboot flag: %v", err)
123
func (m *Machine) machinesToCareAboutRebootsFor() []string {
124
var possibleIds []string
125
for currentId := m.Id(); currentId != ""; {
126
possibleIds = append(possibleIds, currentId)
127
currentId = ParentId(currentId)
132
// ShouldRebootOrShutdown check if the current node should reboot or shutdown
133
// If we are a container, and our parent needs to reboot, this should return:
135
func (m *Machine) ShouldRebootOrShutdown() (RebootAction, error) {
136
rebootCol, closer := m.st.getCollection(rebootC)
139
machines := m.machinesToCareAboutRebootsFor()
141
docs := []rebootDoc{}
142
sel := bson.D{{"machineid", bson.D{{"$in", machines}}}}
143
if err := rebootCol.Find(sel).All(&docs); err != nil {
144
return ShouldDoNothing, errors.Trace(err)
148
for _, val := range docs {
149
if val.Id != m.doc.Id {
150
return ShouldShutdown, nil
155
return ShouldReboot, nil
157
return ShouldDoNothing, nil
160
type RebootFlagSetter interface {
161
SetRebootFlag(flag bool) error
164
type RebootActionGetter interface {
165
ShouldRebootOrShutdown() (RebootAction, error)