1
// Copyright 2016 Canonical Ltd.
2
// Licensed under the AGPLv3, see LICENCE file for details.
7
"github.com/juju/errors"
8
"github.com/juju/utils"
10
"github.com/juju/juju/core/migration"
11
"github.com/juju/juju/watcher"
12
"github.com/juju/juju/worker/catacomb"
15
// ErrChanged indicates that a Worker has stopped because its
16
// Check result is no longer valid.
17
var ErrChanged = errors.New("migration flag value changed")
19
// Facade exposes controller functionality required by a Worker.
20
type Facade interface {
21
Watch(uuid string) (watcher.NotifyWatcher, error)
22
Phase(uuid string) (migration.Phase, error)
25
// Predicate defines a predicate.
26
type Predicate func(migration.Phase) bool
28
// IsTerminal returns true when the given phase means a migration has
29
// finished (successfully or otherwise).
30
func IsTerminal(phase migration.Phase) bool {
31
return phase.IsTerminal()
34
// Config holds the dependencies and configuration for a Worker.
41
// Validate returns an error if the config cannot be expected to
42
// drive a functional Worker.
43
func (config Config) Validate() error {
44
if config.Facade == nil {
45
return errors.NotValidf("nil Facade")
47
if !utils.IsValidUUIDString(config.Model) {
48
return errors.NotValidf("Model %q", config.Model)
50
if config.Check == nil {
51
return errors.NotValidf("nil Check")
56
// New returns a Worker that tracks the result of the configured
57
// Check on the Model's migration phase, as exposed by the Facade.
58
func New(config Config) (*Worker, error) {
59
if err := config.Validate(); err != nil {
60
return nil, errors.Trace(err)
62
phase, err := config.Facade.Phase(config.Model)
64
return nil, errors.Trace(err)
71
err = catacomb.Invoke(catacomb.Plan{
76
return nil, errors.Trace(err)
81
// Worker implements worker.Worker and util.Flag, and exits
82
// with ErrChanged whenever the result of its configured Check of
83
// the Model's migration phase changes.
85
catacomb catacomb.Catacomb
90
// Kill is part of the worker.Worker interface.
91
func (w *Worker) Kill() {
95
// Wait is part of the worker.Worker interface.
96
func (w *Worker) Wait() error {
97
return w.catacomb.Wait()
100
// Check is part of the util.Flag interface.
101
func (w *Worker) Check() bool {
102
return w.config.Check(w.phase)
105
func (w *Worker) loop() error {
106
model := w.config.Model
107
facade := w.config.Facade
108
watcher, err := facade.Watch(model)
110
return errors.Trace(err)
112
if err := w.catacomb.Add(watcher); err != nil {
113
return errors.Trace(err)
117
case <-w.catacomb.Dying():
118
return w.catacomb.ErrDying()
119
case <-watcher.Changes():
120
phase, err := facade.Phase(model)
122
return errors.Trace(err)
124
if w.Check() != w.config.Check(phase) {