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  }