Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(62)

Delta Between Two Patch Sets: worker/provisioner/container_initialisation.go

Issue 25040043: Refactor container provisioner (Closed)
Left Patch Set: - Created 10 years, 4 months ago
Right Patch Set: - Created 10 years, 4 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
LEFTRIGHT
1 // Copyright 2012, 2013 Canonical Ltd. 1 // Copyright 2012, 2013 Canonical Ltd.
2 // Licensed under the AGPLv3, see LICENCE file for details. 2 // Licensed under the AGPLv3, see LICENCE file for details.
3 3
4 package provisioner 4 package provisioner
5 5
6 import ( 6 import (
7 "fmt" 7 "fmt"
8 "sync/atomic"
9
8 "launchpad.net/juju-core/agent" 10 "launchpad.net/juju-core/agent"
9 "launchpad.net/juju-core/instance" 11 "launchpad.net/juju-core/instance"
10 apiprovisioner "launchpad.net/juju-core/state/api/provisioner" 12 apiprovisioner "launchpad.net/juju-core/state/api/provisioner"
11 "launchpad.net/juju-core/state/api/watcher" 13 "launchpad.net/juju-core/state/api/watcher"
12 "launchpad.net/juju-core/worker" 14 "launchpad.net/juju-core/worker"
13 ) 15 )
14 16
17 // ContainerSetup is a StringsWatchHandler that is notified when containers of
18 // the specified type are created on the given machine. It will set up the
19 // machine to be able to create containers and start a provisioner.
15 type ContainerSetup struct { 20 type ContainerSetup struct {
16 runner worker.Runner 21 runner worker.Runner
17 workerName string
18 containerType instance.ContainerType 22 containerType instance.ContainerType
19 provisioner *apiprovisioner.State 23 provisioner *apiprovisioner.State
20 machine *apiprovisioner.Machine 24 machine *apiprovisioner.Machine
21 config agent.Config 25 config agent.Config
26
27 // Save the workerName so the worker thread can be stopped.
28 workerName string
29 // setupDone is non zero if the container setup has been invoked.
30 setupDone int32
22 } 31 }
23 32
33 // NewContainerSetupHandler returns a StringsWatchHandler which is notified when
34 // containers are created on the given machine.
24 func NewContainerSetupHandler(runner worker.Runner, workerName string, container instance.ContainerType, 35 func NewContainerSetupHandler(runner worker.Runner, workerName string, container instance.ContainerType,
25 machine *apiprovisioner.Machine, provisioner *apiprovisioner.State, 36 machine *apiprovisioner.Machine, provisioner *apiprovisioner.State,
26 config agent.Config) worker.StringsWatchHandler { 37 config agent.Config) worker.StringsWatchHandler {
27 38
28 return &ContainerSetup{ 39 return &ContainerSetup{
29 runner: runner, 40 runner: runner,
30 » » workerName: workerName, 41 » » containerType: container,
31 machine: machine, 42 machine: machine,
32 containerType: container,
33 provisioner: provisioner, 43 provisioner: provisioner,
34 config: config, 44 config: config,
45 workerName: workerName,
35 } 46 }
36 } 47 }
37 48
38 func (cs *ContainerSetup) SetUp() (watcher.StringsWatcher, error) { 49 // SetUp is defined on the StringsWatchHandler interface.
39 » containerWatcher, err := cs.machine.WatchContainers(cs.containerType) 50 func (cs *ContainerSetup) SetUp() (watcher watcher.StringsWatcher, err error) {
40 » if err != nil { 51 » if watcher, err = cs.machine.WatchContainers(cs.containerType); err != n il {
41 return nil, err 52 return nil, err
42 } 53 }
43 » return containerWatcher, nil 54 » return watcher, nil
44 } 55 }
45 56
57 // Handle is called whenever containers change on the machine being watched.
58 // All machines start out with so containers so the first time Handle is called,
59 // it will be because a container has been added.
46 func (cs *ContainerSetup) Handle(containerIds []string) error { 60 func (cs *ContainerSetup) Handle(containerIds []string) error {
61 // Consume the initial watcher event.
62 if len(containerIds) == 0 {
63 return nil
64 }
65
66 // This callback must only be invoked once. Stopping the watcher
67 // below should be sufficient but I'm paranoid.
68 if atomic.LoadInt32(&cs.setupDone) != 0 {
69 return nil
70 }
71 atomic.StoreInt32(&cs.setupDone, 1)
72
47 logger.Tracef("initial container setup with ids: %v", containerIds) 73 logger.Tracef("initial container setup with ids: %v", containerIds)
48 » cs.runner.StopWorker(cs.workerName) 74 » // We only care about the initial container creation.
75 » // This worker has done its job so stop it.
76 » // We do not expect there will be an error, and there's not much we can do anyway.
77 » if err := cs.runner.StopWorker(cs.workerName); err != nil {
78 » » logger.Warningf("stopping machine agent container watcher: %v", err)
79 » }
49 if err := cs.ensureContainerDependencies(); err != nil { 80 if err := cs.ensureContainerDependencies(); err != nil {
william.reade 2013/11/18 15:30:58 I still think this is better done lazily inside th
50 return fmt.Errorf("setting up container dependnecies on host mac hine: %v", err) 81 return fmt.Errorf("setting up container dependnecies on host mac hine: %v", err)
51 } 82 }
52 return cs.startProvisioner()
53 }
54
55 func (cs *ContainerSetup) TearDown() error {
56 // Nothing to do here.
57 return nil
58 }
59
60 func (cs *ContainerSetup) ensureContainerDependencies() error {
61 // TODO
62 return nil
63 }
64
65 func (cs *ContainerSetup) startProvisioner() error {
66
67 // TODO - add check so that startProvisionerCallback is only ever called once, for each container type
68 workerName := fmt.Sprintf("%s-provisioner", cs.containerType)
69 var provisionerType ProvisionerType 83 var provisionerType ProvisionerType
70 switch cs.containerType { 84 switch cs.containerType {
71 case instance.LXC: 85 case instance.LXC:
72 provisionerType = LXC 86 provisionerType = LXC
73 case instance.KVM: 87 case instance.KVM:
74 provisionerType = KVM 88 provisionerType = KVM
75 default: 89 default:
76 return fmt.Errorf("invalid container type %q", cs.containerType) 90 return fmt.Errorf("invalid container type %q", cs.containerType)
77 } 91 }
92 return StartProvisioner(cs.runner, provisionerType, cs.provisioner, cs.c onfig)
93 }
78 94
79 » return cs.runner.StartWorker(workerName, func() (worker.Worker, error) { 95 // TearDown is defined on the StringsWatchHandler interface.
80 » » return NewProvisioner(provisionerType, cs.provisioner, cs.config ), nil 96 func (cs *ContainerSetup) TearDown() error {
97 » // Nothing to do here.
98 » return nil
99 }
100
101 func (cs *ContainerSetup) ensureContainerDependencies() error {
102 » // TODO(wallyworld) - install whatever dependencies are required to supp ort starting containers
103 » return nil
104 }
105
106 // Override for testing.
107 var StartProvisioner = startProvisionerWorker
108
109 // startProvisionerWorker kicks off a provisioner task responsible for creating containers
110 // of the specified type on the machine.
111 func startProvisionerWorker(runner worker.Runner, provisionerType ProvisionerTyp e,
112 » provisioner *apiprovisioner.State, config agent.Config) error {
113
114 » workerName := fmt.Sprintf("%s-provisioner", provisionerType)
115 » // The provisioner task is created after a container record has already been added to the machine.
116 » // It will see that the container does not have an instance yet and crea te one.
117 » return runner.StartWorker(workerName, func() (worker.Worker, error) {
118 » » return NewProvisioner(provisionerType, provisioner, config), nil
william.reade 2013/11/18 15:30:58 This is all still kinda messed up (nothing to do w
81 }) 119 })
82 } 120 }
LEFTRIGHT

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b