github.com/mattyw/juju@v0.0.0-20140610034352-732aecd63861/provider/manual/provider.go (about)

     1  // Copyright 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package manual
     5  
     6  import (
     7  	"errors"
     8  	"fmt"
     9  
    10  	"github.com/juju/utils"
    11  
    12  	"github.com/juju/juju/environs"
    13  	"github.com/juju/juju/environs/config"
    14  	"github.com/juju/juju/environs/manual"
    15  )
    16  
    17  type manualProvider struct{}
    18  
    19  func init() {
    20  	p := manualProvider{}
    21  	environs.RegisterProvider("manual", p, "null")
    22  }
    23  
    24  var errNoBootstrapHost = errors.New("bootstrap-host must be specified")
    25  
    26  var initUbuntuUser = manual.InitUbuntuUser
    27  
    28  func ensureBootstrapUbuntuUser(ctx environs.BootstrapContext, cfg *environConfig) error {
    29  	err := initUbuntuUser(cfg.bootstrapHost(), cfg.bootstrapUser(), cfg.AuthorizedKeys(), ctx.GetStdin(), ctx.GetStdout())
    30  	if err != nil {
    31  		logger.Errorf("initializing ubuntu user: %v", err)
    32  		return err
    33  	}
    34  	logger.Infof("initialized ubuntu user")
    35  	return nil
    36  }
    37  
    38  func (p manualProvider) Prepare(ctx environs.BootstrapContext, cfg *config.Config) (environs.Environ, error) {
    39  	if _, ok := cfg.UnknownAttrs()["storage-auth-key"]; !ok {
    40  		uuid, err := utils.NewUUID()
    41  		if err != nil {
    42  			return nil, err
    43  		}
    44  		cfg, err = cfg.Apply(map[string]interface{}{
    45  			"storage-auth-key": uuid.String(),
    46  		})
    47  		if err != nil {
    48  			return nil, err
    49  		}
    50  	}
    51  	if use, ok := cfg.UnknownAttrs()["use-sshstorage"].(bool); ok && !use {
    52  		return nil, fmt.Errorf("use-sshstorage must not be specified")
    53  	}
    54  	envConfig, err := p.validate(cfg, nil)
    55  	if err != nil {
    56  		return nil, err
    57  	}
    58  	if err := ensureBootstrapUbuntuUser(ctx, envConfig); err != nil {
    59  		return nil, err
    60  	}
    61  	return p.open(envConfig)
    62  }
    63  
    64  func (p manualProvider) Open(cfg *config.Config) (environs.Environ, error) {
    65  	envConfig, err := p.validate(cfg, nil)
    66  	if err != nil {
    67  		return nil, err
    68  	}
    69  	return p.open(envConfig)
    70  }
    71  
    72  func (p manualProvider) open(cfg *environConfig) (environs.Environ, error) {
    73  	env := &manualEnviron{cfg: cfg}
    74  	// Need to call SetConfig to initialise storage.
    75  	if err := env.SetConfig(cfg.Config); err != nil {
    76  		return nil, err
    77  	}
    78  	return env, nil
    79  }
    80  
    81  func checkImmutableString(cfg, old *environConfig, key string) error {
    82  	if old.attrs[key] != cfg.attrs[key] {
    83  		return fmt.Errorf("cannot change %s from %q to %q", key, old.attrs[key], cfg.attrs[key])
    84  	}
    85  	return nil
    86  }
    87  
    88  func (p manualProvider) validate(cfg, old *config.Config) (*environConfig, error) {
    89  	// Check for valid changes for the base config values.
    90  	if err := config.Validate(cfg, old); err != nil {
    91  		return nil, err
    92  	}
    93  	validated, err := cfg.ValidateUnknownAttrs(configFields, configDefaults)
    94  	if err != nil {
    95  		return nil, err
    96  	}
    97  	envConfig := newEnvironConfig(cfg, validated)
    98  	if envConfig.bootstrapHost() == "" {
    99  		return nil, errNoBootstrapHost
   100  	}
   101  	// Check various immutable attributes.
   102  	if old != nil {
   103  		oldEnvConfig, err := p.validate(old, nil)
   104  		if err != nil {
   105  			return nil, err
   106  		}
   107  		for _, key := range [...]string{
   108  			"bootstrap-user",
   109  			"bootstrap-host",
   110  			"storage-listen-ip",
   111  		} {
   112  			if err = checkImmutableString(envConfig, oldEnvConfig, key); err != nil {
   113  				return nil, err
   114  			}
   115  		}
   116  		oldPort, newPort := oldEnvConfig.storagePort(), envConfig.storagePort()
   117  		if oldPort != newPort {
   118  			return nil, fmt.Errorf("cannot change storage-port from %q to %q", oldPort, newPort)
   119  		}
   120  		oldUseSSHStorage, newUseSSHStorage := oldEnvConfig.useSSHStorage(), envConfig.useSSHStorage()
   121  		if oldUseSSHStorage != newUseSSHStorage && newUseSSHStorage == true {
   122  			return nil, fmt.Errorf("cannot change use-sshstorage from %v to %v", oldUseSSHStorage, newUseSSHStorage)
   123  		}
   124  	}
   125  	return envConfig, nil
   126  }
   127  
   128  func (p manualProvider) Validate(cfg, old *config.Config) (valid *config.Config, err error) {
   129  	envConfig, err := p.validate(cfg, old)
   130  	if err != nil {
   131  		return nil, err
   132  	}
   133  	return cfg.Apply(envConfig.attrs)
   134  }
   135  
   136  func (_ manualProvider) BoilerplateConfig() string {
   137  	return `
   138  manual:
   139      type: manual
   140      # bootstrap-host holds the host name of the machine where the
   141      # bootstrap machine agent will be started.
   142      bootstrap-host: somehost.example.com
   143      
   144      # bootstrap-user specifies the user to authenticate as when
   145      # connecting to the bootstrap machine. It defaults to
   146      # the current user.
   147      # bootstrap-user: joebloggs
   148      
   149      # storage-listen-ip specifies the IP address that the
   150      # bootstrap machine's Juju storage server will listen
   151      # on. By default, storage will be served on all
   152      # network interfaces.
   153      # storage-listen-ip:
   154      
   155      # storage-port specifes the TCP port that the
   156      # bootstrap machine's Juju storage server will listen
   157      # on. It defaults to ` + fmt.Sprint(defaultStoragePort) + `
   158      # storage-port: ` + fmt.Sprint(defaultStoragePort) + `
   159  
   160  
   161  `[1:]
   162  }
   163  
   164  func (p manualProvider) SecretAttrs(cfg *config.Config) (map[string]string, error) {
   165  	envConfig, err := p.validate(cfg, nil)
   166  	if err != nil {
   167  		return nil, err
   168  	}
   169  	attrs := make(map[string]string)
   170  	attrs["storage-auth-key"] = envConfig.storageAuthKey()
   171  	return attrs, nil
   172  }