~cloud-green/juju-core/charmstore-sdist

« back to all changes in this revision

Viewing changes to launchpad.net/juju-core/worker/machineenvironmentworker/machineenvironmentworker.go

  • Committer: Casey Marshall
  • Date: 2014-03-27 15:59:46 UTC
  • Revision ID: cmars@cmarstech.com-20140327155946-8huorf37g0zwar43
Source distribution of launchpad.net/juju-core created 20140327105939

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright 2014 Canonical Ltd.
 
2
// Licensed under the AGPLv3, see LICENCE file for details.
 
3
 
 
4
package machineenvironmentworker
 
5
 
 
6
import (
 
7
        "fmt"
 
8
        "io/ioutil"
 
9
        "path"
 
10
 
 
11
        "github.com/juju/loggo"
 
12
 
 
13
        "launchpad.net/juju-core/agent"
 
14
        "launchpad.net/juju-core/juju/osenv"
 
15
        "launchpad.net/juju-core/names"
 
16
        "launchpad.net/juju-core/provider"
 
17
        "launchpad.net/juju-core/state/api/environment"
 
18
        "launchpad.net/juju-core/state/api/watcher"
 
19
        "launchpad.net/juju-core/utils"
 
20
        "launchpad.net/juju-core/utils/exec"
 
21
        "launchpad.net/juju-core/worker"
 
22
)
 
23
 
 
24
var (
 
25
        logger = loggo.GetLogger("juju.worker.machineenvironment")
 
26
 
 
27
        // ProxyDirectory is the directory containing the proxy file that contains
 
28
        // the environment settings for the proxies based on the environment
 
29
        // config values.
 
30
        ProxyDirectory = "/home/ubuntu"
 
31
 
 
32
        // ProxyFile is the name of the file to be stored in the ProxyDirectory.
 
33
        ProxyFile = ".juju-proxy"
 
34
 
 
35
        // Started is a function that is called when the worker has started.
 
36
        Started = func() {}
 
37
)
 
38
 
 
39
// MachineEnvironmentWorker is responsible for monitoring the juju environment
 
40
// configuration and making changes on the physical (or virtual) machine as
 
41
// necessary to match the environment changes.  Examples of these types of
 
42
// changes are apt proxy configuration and the juju proxies stored in the juju
 
43
// proxy file.
 
44
type MachineEnvironmentWorker struct {
 
45
        api      *environment.Facade
 
46
        aptProxy osenv.ProxySettings
 
47
        proxy    osenv.ProxySettings
 
48
 
 
49
        writeSystemFiles bool
 
50
        // The whole point of the first value is to make sure that the the files
 
51
        // are written out the first time through, even if they are the same as
 
52
        // "last" time, as the initial value for last time is the zeroed struct.
 
53
        // There is the possibility that the files exist on disk with old
 
54
        // settings, and the environment has been updated to now not have them. We
 
55
        // need to make sure that the disk reflects the environment, so the first
 
56
        // time through, even if the proxies are empty, we write the files to
 
57
        // disk.
 
58
        first bool
 
59
}
 
60
 
 
61
var _ worker.NotifyWatchHandler = (*MachineEnvironmentWorker)(nil)
 
62
 
 
63
// NewMachineEnvironmentWorker returns a worker.Worker that uses the notify
 
64
// watcher returned from the setup.
 
65
func NewMachineEnvironmentWorker(api *environment.Facade, agentConfig agent.Config) worker.Worker {
 
66
        // We don't write out system files for the local provider on machine zero
 
67
        // as that is the host machine.
 
68
        writeSystemFiles := (agentConfig.Tag() != names.MachineTag("0") ||
 
69
                agentConfig.Value(agent.ProviderType) != provider.Local)
 
70
        logger.Debugf("write system files: %v", writeSystemFiles)
 
71
        envWorker := &MachineEnvironmentWorker{
 
72
                api:              api,
 
73
                writeSystemFiles: writeSystemFiles,
 
74
                first:            true,
 
75
        }
 
76
        return worker.NewNotifyWorker(envWorker)
 
77
}
 
78
 
 
79
func (w *MachineEnvironmentWorker) writeEnvironmentFile() error {
 
80
        // Writing the environment file is handled by executing the script for two
 
81
        // primary reasons:
 
82
        //
 
83
        // 1: In order to have the local provider specify the environment settings
 
84
        // for the machine agent running on the host, this worker needs to run,
 
85
        // but it shouldn't be touching any files on the disk.  If however there is
 
86
        // an ubuntu user, it will. This shouldn't be a problem.
 
87
        //
 
88
        // 2: On cloud-instance ubuntu images, the ubuntu user is uid 1000, but in
 
89
        // the situation where the ubuntu user has been created as a part of the
 
90
        // manual provisioning process, the user will exist, and will not have the
 
91
        // same uid/gid as the default cloud image.
 
92
        //
 
93
        // It is easier to shell out to check both these things, and is also the
 
94
        // same way that the file is written in the cloud-init process, so
 
95
        // consistency FTW.
 
96
        filePath := path.Join(ProxyDirectory, ProxyFile)
 
97
        result, err := exec.RunCommands(exec.RunParams{
 
98
                Commands: fmt.Sprintf(
 
99
                        `[ -e %s ] && (printf '%%s\n' %s > %s && chown ubuntu:ubuntu %s)`,
 
100
                        ProxyDirectory,
 
101
                        utils.ShQuote(w.proxy.AsScriptEnvironment()),
 
102
                        filePath, filePath),
 
103
                WorkingDir: ProxyDirectory,
 
104
        })
 
105
        if err != nil {
 
106
                return err
 
107
        }
 
108
        if result.Code != 0 {
 
109
                logger.Errorf("failed writing new proxy values: \n%s\n%s", result.Stdout, result.Stderr)
 
110
        }
 
111
        return nil
 
112
}
 
113
 
 
114
func (w *MachineEnvironmentWorker) handleProxyValues(proxySettings osenv.ProxySettings) {
 
115
        if proxySettings != w.proxy || w.first {
 
116
                logger.Debugf("new proxy settings %#v", proxySettings)
 
117
                w.proxy = proxySettings
 
118
                w.proxy.SetEnvironmentValues()
 
119
                if w.writeSystemFiles {
 
120
                        if err := w.writeEnvironmentFile(); err != nil {
 
121
                                // It isn't really fatal, but we should record it.
 
122
                                logger.Errorf("error writing proxy environment file: %v", err)
 
123
                        }
 
124
                }
 
125
        }
 
126
}
 
127
 
 
128
func (w *MachineEnvironmentWorker) handleAptProxyValues(aptSettings osenv.ProxySettings) {
 
129
        if w.writeSystemFiles && (aptSettings != w.aptProxy || w.first) {
 
130
                logger.Debugf("new apt proxy settings %#v", aptSettings)
 
131
                w.aptProxy = aptSettings
 
132
                // Always finish with a new line.
 
133
                content := utils.AptProxyContent(w.aptProxy) + "\n"
 
134
                err := ioutil.WriteFile(utils.AptConfFile, []byte(content), 0644)
 
135
                if err != nil {
 
136
                        // It isn't really fatal, but we should record it.
 
137
                        logger.Errorf("error writing apt proxy config file: %v", err)
 
138
                }
 
139
        }
 
140
}
 
141
 
 
142
func (w *MachineEnvironmentWorker) onChange() error {
 
143
        env, err := w.api.EnvironConfig()
 
144
        if err != nil {
 
145
                return err
 
146
        }
 
147
        w.handleProxyValues(env.ProxySettings())
 
148
        w.handleAptProxyValues(env.AptProxySettings())
 
149
        return nil
 
150
}
 
151
 
 
152
// SetUp is defined on the worker.NotifyWatchHandler interface.
 
153
func (w *MachineEnvironmentWorker) SetUp() (watcher.NotifyWatcher, error) {
 
154
        // We need to set this up initially as the NotifyWorker sucks up the first
 
155
        // event.
 
156
        err := w.onChange()
 
157
        if err != nil {
 
158
                return nil, err
 
159
        }
 
160
        w.first = false
 
161
        Started()
 
162
        return w.api.WatchForEnvironConfigChanges()
 
163
}
 
164
 
 
165
// Handle is defined on the worker.NotifyWatchHandler interface.
 
166
func (w *MachineEnvironmentWorker) Handle() error {
 
167
        return w.onChange()
 
168
}
 
169
 
 
170
// TearDown is defined on the worker.NotifyWatchHandler interface.
 
171
func (w *MachineEnvironmentWorker) TearDown() error {
 
172
        // Nothing to cleanup, only state is the watcher
 
173
        return nil
 
174
}