1
// Copyright 2014 Canonical Ltd.
2
// Licensed under the AGPLv3, see LICENCE file for details.
13
"launchpad.net/juju-core/agent"
14
"launchpad.net/juju-core/environs/config"
15
"launchpad.net/juju-core/state/api/params"
19
rootLogDir = "/var/log"
20
rootSpoolDir = "/var/spool/rsyslog"
23
var chownPath = func(path, username string) error {
24
user, err := user.Lookup(username)
26
return fmt.Errorf("cannot lookup %q user id: %v", username, err)
28
uid, err := strconv.Atoi(user.Uid)
30
return fmt.Errorf("invalid user id %q: %v", user.Uid, err)
32
gid, err := strconv.Atoi(user.Gid)
34
return fmt.Errorf("invalid group id %q: %v", user.Gid, err)
36
return os.Chown(path, uid, gid)
39
var isLocalEnviron = func(envConfig *config.Config) bool {
40
return envConfig.Type() == "local"
43
func migrateLocalProviderAgentConfig(context Context) error {
46
logger.Debugf("no state connection, no migration required")
47
// We're running on a different node than the state server.
50
envConfig, err := st.EnvironConfig()
52
return fmt.Errorf("failed to read current config: %v", err)
54
if !isLocalEnviron(envConfig) {
55
logger.Debugf("not a local environment, no migration required")
58
attrs := envConfig.AllAttrs()
59
rootDir, _ := attrs["root-dir"].(string)
60
sharedStorageDir := filepath.Join(rootDir, "shared-storage")
61
// In case these two are empty we need to set them and update the
62
// environment config.
63
namespace, _ := attrs["namespace"].(string)
64
container, _ := attrs["container"].(string)
67
username := os.Getenv("USER")
68
if username == "root" {
69
// sudo was probably called, get the original user.
70
username = os.Getenv("SUDO_USER")
73
return fmt.Errorf("cannot get current user from the environment: %v", os.Environ())
75
namespace = username + "-" + envConfig.Name()
82
localLogDir := filepath.Join(rootDir, "log")
83
// rsyslogd is restricted to write to /var/log
84
logDir := fmt.Sprintf("%s/juju-%s", rootLogDir, namespace)
85
jobs := []params.MachineJob{params.JobManageEnviron}
86
values := map[string]string{
87
agent.Namespace: namespace,
88
// ContainerType is empty on the bootstrap node.
89
agent.ContainerType: "",
90
agent.AgentServiceName: "juju-agent-" + namespace,
91
agent.MongoServiceName: "juju-db-" + namespace,
93
deprecatedValues := []string{
94
"SHARED_STORAGE_ADDR",
98
// Remove shared-storage dir if there.
99
if err := os.RemoveAll(sharedStorageDir); err != nil {
100
return fmt.Errorf("cannot remove deprecated %q: %v", sharedStorageDir, err)
103
// We need to create the dirs if they don't exist.
104
if err := os.MkdirAll(dataDir, 0755); err != nil {
105
return fmt.Errorf("cannot create dataDir %q: %v", dataDir, err)
107
// We always recreate the logDir to make sure it's empty.
108
if err := os.RemoveAll(logDir); err != nil {
109
return fmt.Errorf("cannot remove logDir %q: %v", logDir, err)
111
if err := os.MkdirAll(logDir, 0755); err != nil {
112
return fmt.Errorf("cannot create logDir %q: %v", logDir, err)
114
// Reconfigure rsyslog as needed:
115
// 1. logDir must be owned by syslog:adm
116
// 2. Remove old rsyslog spool config
117
// 3. Relink logs to the new logDir
118
if err := chownPath(logDir, "syslog"); err != nil {
121
spoolConfig := fmt.Sprintf("%s/machine-0-%s", rootSpoolDir, namespace)
122
if err := os.RemoveAll(spoolConfig); err != nil {
123
return fmt.Errorf("cannot remove %q: %v", spoolConfig, err)
125
allMachinesLog := filepath.Join(logDir, "all-machines.log")
126
if err := os.Symlink(allMachinesLog, localLogDir+"/"); err != nil && !os.IsExist(err) {
127
return fmt.Errorf("cannot symlink %q to %q: %v", allMachinesLog, localLogDir, err)
129
machine0Log := filepath.Join(localLogDir, "machine-0.log")
130
if err := os.Symlink(machine0Log, logDir+"/"); err != nil && !os.IsExist(err) {
131
return fmt.Errorf("cannot symlink %q to %q: %v", machine0Log, logDir, err)
134
newCfg := map[string]interface{}{
135
"namespace": namespace,
136
"container": container,
138
if err := st.UpdateEnvironConfig(newCfg, nil, nil); err != nil {
139
return fmt.Errorf("cannot update environment config: %v", err)
142
migrateParams := agent.MigrateConfigParams{
147
DeleteValues: deprecatedValues,
149
return agent.MigrateConfig(context.AgentConfig(), migrateParams)