~fwereade/pyjuju/go-place-unit

« back to all changes in this revision

Viewing changes to cmd/jujud/provisioning.go

  • Committer: William Reade
  • Date: 2012-06-06 09:57:29 UTC
  • mfrom: (193.1.10 go)
  • Revision ID: fwereade@gmail.com-20120606095729-gvsqo1auqspzog9j
merge parent

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
package main
2
2
 
3
3
import (
4
 
        "fmt"
5
4
        "launchpad.net/gnuflag"
6
5
        "launchpad.net/juju/go/cmd"
 
6
        "launchpad.net/juju/go/environs"
 
7
        "launchpad.net/juju/go/log"
 
8
        "launchpad.net/juju/go/state"
 
9
        "launchpad.net/tomb"
 
10
 
 
11
        // register providers
 
12
        _ "launchpad.net/juju/go/environs/dummy"
 
13
        _ "launchpad.net/juju/go/environs/ec2"
7
14
)
8
15
 
9
16
// ProvisioningAgent is a cmd.Command responsible for running a provisioning agent.
27
34
 
28
35
// Run runs a provisioning agent.
29
36
func (a *ProvisioningAgent) Run(_ *cmd.Context) error {
30
 
        return fmt.Errorf("MachineAgent.Run not implemented")
31
 
}
 
37
        // TODO(dfc) place the logic in a loop with a suitable delay
 
38
        st, err := state.Open(&a.Conf.StateInfo)
 
39
        if err != nil {
 
40
                return err
 
41
        }
 
42
        p := NewProvisioner(st)
 
43
        return p.Wait()
 
44
}
 
45
 
 
46
type Provisioner struct {
 
47
        st      *state.State
 
48
        environ environs.Environ
 
49
        tomb    tomb.Tomb
 
50
 
 
51
        environWatcher  *state.ConfigWatcher
 
52
        machinesWatcher *state.MachinesWatcher
 
53
}
 
54
 
 
55
// NewProvisioner returns a Provisioner.
 
56
func NewProvisioner(st *state.State) *Provisioner {
 
57
        p := &Provisioner{
 
58
                st: st,
 
59
        }
 
60
        go p.loop()
 
61
        return p
 
62
}
 
63
 
 
64
func (p *Provisioner) loop() {
 
65
        defer p.tomb.Done()
 
66
 
 
67
        p.environWatcher = p.st.WatchEnvironConfig()
 
68
        // TODO(dfc) we need a method like state.IsConnected() here to exit cleanly if
 
69
        // there is a connection problem.
 
70
        for {
 
71
                select {
 
72
                case <-p.tomb.Dying():
 
73
                        return
 
74
                case config, ok := <-p.environWatcher.Changes():
 
75
                        if !ok {
 
76
                                err := p.environWatcher.Stop()
 
77
                                if err != nil {
 
78
                                        p.tomb.Kill(err)
 
79
                                }
 
80
                                return
 
81
                        }
 
82
                        var err error
 
83
                        p.environ, err = environs.NewEnviron(config.Map())
 
84
                        if err != nil {
 
85
                                log.Printf("provisioner loaded invalid environment configuration: %v", err)
 
86
                                continue
 
87
                        }
 
88
                        log.Printf("provisioner loaded new environment configuration")
 
89
                        p.innerLoop()
 
90
                }
 
91
        }
 
92
}
 
93
 
 
94
func (p *Provisioner) innerLoop() {
 
95
        p.machinesWatcher = p.st.WatchMachines()
 
96
        // TODO(dfc) we need a method like state.IsConnected() here to exit cleanly if
 
97
        // there is a connection problem.
 
98
        for {
 
99
                select {
 
100
                case <-p.tomb.Dying():
 
101
                        return
 
102
                case change, ok := <-p.environWatcher.Changes():
 
103
                        if !ok {
 
104
                                err := p.environWatcher.Stop()
 
105
                                if err != nil {
 
106
                                        p.tomb.Kill(err)
 
107
                                }
 
108
                                return
 
109
                        }
 
110
                        config, err := environs.NewConfig(change.Map())
 
111
                        if err != nil {
 
112
                                log.Printf("provisioner loaded invalid environment configuration: %v", err)
 
113
                                continue
 
114
                        }
 
115
                        p.environ.SetConfig(config)
 
116
                        log.Printf("provisioner loaded new environment configuration")
 
117
                case machines, ok := <-p.machinesWatcher.Changes():
 
118
                        if !ok {
 
119
                                err := p.machinesWatcher.Stop()
 
120
                                if err != nil {
 
121
                                        p.tomb.Kill(err)
 
122
                                }
 
123
                                return
 
124
                        }
 
125
                        p.processMachines(machines)
 
126
                }
 
127
        }
 
128
}
 
129
 
 
130
// Wait waits for the Provisioner to exit.
 
131
func (p *Provisioner) Wait() error {
 
132
        return p.tomb.Wait()
 
133
}
 
134
 
 
135
// Stop stops the Provisioner and returns any error encountered while
 
136
// provisioning.
 
137
func (p *Provisioner) Stop() error {
 
138
        p.tomb.Kill(nil)
 
139
        return p.tomb.Wait()
 
140
}
 
141
 
 
142
func (p *Provisioner) processMachines(changes *state.MachinesChange) {}