github.com/altoros/juju-vmware@v0.0.0-20150312064031-f19ae857ccca/upgrades/agentconfig.go (about) 1 // Copyright 2014 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package upgrades 5 6 import ( 7 "fmt" 8 "github.com/juju/errors" 9 "os" 10 "os/user" 11 "path/filepath" 12 "strconv" 13 14 "github.com/juju/utils/symlink" 15 16 "github.com/juju/juju/agent" 17 "github.com/juju/juju/environs/config" 18 "github.com/juju/juju/state/multiwatcher" 19 ) 20 21 var ( 22 rootLogDir = "/var/log" 23 rootSpoolDir = "/var/spool/rsyslog" 24 ) 25 26 var chownPath = func(path, username string) error { 27 user, err := user.Lookup(username) 28 if err != nil { 29 return fmt.Errorf("cannot lookup %q user id: %v", username, err) 30 } 31 uid, err := strconv.Atoi(user.Uid) 32 if err != nil { 33 return fmt.Errorf("invalid user id %q: %v", user.Uid, err) 34 } 35 gid, err := strconv.Atoi(user.Gid) 36 if err != nil { 37 return fmt.Errorf("invalid group id %q: %v", user.Gid, err) 38 } 39 return os.Chown(path, uid, gid) 40 } 41 42 var isLocalEnviron = func(envConfig *config.Config) bool { 43 return envConfig.Type() == "local" 44 } 45 46 func migrateLocalProviderAgentConfig(context Context) error { 47 st := context.State() 48 if st == nil { 49 logger.Debugf("no state connection, no migration required") 50 // We're running on a different node than the state server. 51 return nil 52 } 53 envConfig, err := st.EnvironConfig() 54 if err != nil { 55 return fmt.Errorf("failed to read current config: %v", err) 56 } 57 if !isLocalEnviron(envConfig) { 58 logger.Debugf("not a local environment, no migration required") 59 return nil 60 } 61 attrs := envConfig.AllAttrs() 62 rootDir, _ := attrs["root-dir"].(string) 63 sharedStorageDir := filepath.Join(rootDir, "shared-storage") 64 // In case these two are empty we need to set them and update the 65 // environment config. 66 namespace, _ := attrs["namespace"].(string) 67 container, _ := attrs["container"].(string) 68 69 if namespace == "" { 70 username := os.Getenv("USER") 71 if username == "root" { 72 // sudo was probably called, get the original user. 73 username = os.Getenv("SUDO_USER") 74 } 75 if username == "" { 76 return fmt.Errorf("cannot get current user from the environment: %v", os.Environ()) 77 } 78 namespace = username + "-" + envConfig.Name() 79 } 80 if container == "" { 81 container = "lxc" 82 } 83 84 dataDir := rootDir 85 localLogDir := filepath.Join(rootDir, "log") 86 // rsyslogd is restricted to write to /var/log 87 logDir := fmt.Sprintf("%s/juju-%s", rootLogDir, namespace) 88 jobs := []multiwatcher.MachineJob{multiwatcher.JobManageEnviron} 89 values := map[string]string{ 90 agent.Namespace: namespace, 91 // ContainerType is empty on the bootstrap node. 92 agent.ContainerType: "", 93 agent.AgentServiceName: "juju-agent-" + namespace, 94 } 95 deprecatedValues := []string{ 96 "SHARED_STORAGE_ADDR", 97 "SHARED_STORAGE_DIR", 98 } 99 100 // Remove shared-storage dir if there. 101 if err := os.RemoveAll(sharedStorageDir); err != nil { 102 return fmt.Errorf("cannot remove deprecated %q: %v", sharedStorageDir, err) 103 } 104 105 // We need to create the dirs if they don't exist. 106 if err := os.MkdirAll(dataDir, 0755); err != nil { 107 return fmt.Errorf("cannot create dataDir %q: %v", dataDir, err) 108 } 109 // We always recreate the logDir to make sure it's empty. 110 if err := os.RemoveAll(logDir); err != nil { 111 return fmt.Errorf("cannot remove logDir %q: %v", logDir, err) 112 } 113 if err := os.MkdirAll(logDir, 0755); err != nil { 114 return fmt.Errorf("cannot create logDir %q: %v", logDir, err) 115 } 116 // Reconfigure rsyslog as needed: 117 // 1. logDir must be owned by syslog:adm 118 // 2. Remove old rsyslog spool config 119 // 3. Relink logs to the new logDir 120 if err := chownPath(logDir, "syslog"); err != nil { 121 return err 122 } 123 spoolConfig := fmt.Sprintf("%s/machine-0-%s", rootSpoolDir, namespace) 124 if err := os.RemoveAll(spoolConfig); err != nil { 125 return fmt.Errorf("cannot remove %q: %v", spoolConfig, err) 126 } 127 allMachinesLog := filepath.Join(logDir, "all-machines.log") 128 if err := symlink.New(allMachinesLog, localLogDir+"/"); err != nil && !os.IsExist(err) { 129 return fmt.Errorf("cannot symlink %q to %q: %v", allMachinesLog, localLogDir, err) 130 } 131 machine0Log := filepath.Join(localLogDir, "machine-0.log") 132 if err := symlink.New(machine0Log, logDir+"/"); err != nil && !os.IsExist(err) { 133 return fmt.Errorf("cannot symlink %q to %q: %v", machine0Log, logDir, err) 134 } 135 136 newCfg := map[string]interface{}{ 137 "namespace": namespace, 138 "container": container, 139 } 140 if err := st.UpdateEnvironConfig(newCfg, nil, nil); err != nil { 141 return fmt.Errorf("cannot update environment config: %v", err) 142 } 143 144 return context.AgentConfig().Migrate(agent.MigrateParams{ 145 DataDir: dataDir, 146 LogDir: logDir, 147 Jobs: jobs, 148 Values: values, 149 DeleteValues: deprecatedValues, 150 }) 151 } 152 153 func addEnvironmentUUIDToAgentConfig(context Context) error { 154 if context.AgentConfig().Environment().Id() != "" { 155 logger.Infof("environment uuid already set in agent config") 156 return nil 157 } 158 159 environTag, err := context.APIState().EnvironTag() 160 if err != nil { 161 return errors.Annotate(err, "no environment uuid set on api") 162 } 163 164 return context.AgentConfig().Migrate(agent.MigrateParams{ 165 Environment: environTag, 166 }) 167 }