Exemple #1
0
func (c *UpgradeJujuCommand) Init(args []string) error {
	if c.vers != "" {
		vers, err := version.Parse(c.vers)
		if err != nil {
			return err
		}
		if vers.Major != version.Current.Major {
			return fmt.Errorf("cannot upgrade to version incompatible with CLI")
		}
		if c.UploadTools && vers.Build != 0 {
			// TODO(fwereade): when we start taking versions from actual built
			// code, we should disable --version when used with --upload-tools.
			// For now, it's the only way to experiment with version upgrade
			// behaviour live, so the only restriction is that Build cannot
			// be used (because its value needs to be chosen internally so as
			// not to collide with existing tools).
			return fmt.Errorf("cannot specify build number when uploading tools")
		}
		c.Version = vers
	}
	if len(c.Series) > 0 && !c.UploadTools {
		return fmt.Errorf("--series requires --upload-tools")
	}
	return cmd.CheckEmpty(args)
}
Exemple #2
0
func (suite) TestComparison(c *C) {
	for i, test := range cmpTests {
		c.Logf("test %d", i)
		v1, err := version.Parse(test.v1)
		c.Assert(err, IsNil)
		v2, err := version.Parse(test.v2)
		c.Assert(err, IsNil)
		less := v1.Less(v2)
		gt := v2.Less(v1)
		c.Check(less, Equals, test.less)
		if test.eq {
			c.Check(gt, Equals, false)
		} else {
			c.Check(gt, Equals, !test.less)
		}
	}
}
Exemple #3
0
// Validate ensures that config is a valid configuration.  If old is not nil,
// it holds the previous environment configuration for consideration when
// validating changes.
func Validate(cfg, old *Config) error {

	// Check if there are any required fields that are empty.
	for _, attr := range []string{"name", "type", "default-series", "authorized-keys"} {
		if cfg.asString(attr) == "" {
			return fmt.Errorf("empty %s in environment configuration", attr)
		}
	}

	if strings.ContainsAny(cfg.asString("name"), "/\\") {
		return fmt.Errorf("environment name contains unsafe characters")
	}

	// Check that the agent version parses ok if set explicitly; otherwise leave
	// it alone.
	if v, ok := cfg.m["agent-version"].(string); ok {
		if _, err := version.Parse(v); err != nil {
			return fmt.Errorf("invalid agent version in environment configuration: %q", v)
		}
	}

	// Check firewall mode.
	firewallMode := cfg.FirewallMode()
	switch firewallMode {
	case FwDefault, FwInstance, FwGlobal:
		// Valid mode.
	default:
		return fmt.Errorf("invalid firewall mode in environment configuration: %q", firewallMode)
	}

	// Check the immutable config values.  These can't change
	if old != nil {
		for _, attr := range []string{"type", "name", "firewall-mode"} {
			oldValue := old.asString(attr)
			newValue := cfg.asString(attr)
			if oldValue != newValue {
				return fmt.Errorf("cannot change %s from %q to %q", attr, oldValue, newValue)
			}
		}
		oldStatePort := old.StatePort()
		newStatePort := cfg.StatePort()
		if oldStatePort != newStatePort {
			return fmt.Errorf("cannot change state-port from %d to %d", oldStatePort, newStatePort)
		}
		oldAPIPort := old.APIPort()
		newAPIPort := cfg.APIPort()
		if oldAPIPort != newAPIPort {
			return fmt.Errorf("cannot change api-port from %d to %d", oldAPIPort, newAPIPort)
		}
		if _, oldFound := old.AgentVersion(); oldFound {
			if _, newFound := cfg.AgentVersion(); !newFound {
				return fmt.Errorf("cannot clear agent-version")
			}
		}
	}

	return nil
}
Exemple #4
0
// AgentVersion returns the proposed version number for the agent tools,
// and whether it has been set. Once an environment is bootstrapped, this
// must always be valid.
func (c *Config) AgentVersion() (version.Number, bool) {
	if v, ok := c.m["agent-version"].(string); ok {
		n, err := version.Parse(v)
		if err != nil {
			panic(err) // We should have checked it earlier.
		}
		return n, true
	}
	return version.Zero, false
}
Exemple #5
0
// AgentVersion returns the proposed version number for the agent tools.
// It returns the zero version if unset.
func (c *Config) AgentVersion() version.Number {
	v, ok := c.m["agent-version"].(string)
	if !ok {
		return version.Number{}
	}
	n, err := version.Parse(v)
	if err != nil {
		panic(err) // We should have checked it earlier.
	}
	return n
}
Exemple #6
0
func (suite) TestParse(c *C) {
	for i, test := range parseTests {
		c.Logf("test %d", i)
		got, err := version.Parse(test.v)
		if test.err != "" {
			c.Assert(err, ErrorMatches, test.err)
		} else {
			c.Assert(err, IsNil)
			c.Assert(got, Equals, test.expect)
			c.Check(got.IsDev(), Equals, test.dev)
			c.Check(got.String(), Equals, test.v)
		}
	}
}
Exemple #7
0
func (c *UpgradeJujuCommand) Init(f *gnuflag.FlagSet, args []string) error {
	addEnvironFlags(&c.EnvName, f)
	var vers string
	f.BoolVar(&c.UploadTools, "upload-tools", false, "upload local version of tools")
	f.StringVar(&vers, "version", "", "version to upgrade to (defaults to highest available version with the current major version number)")
	f.BoolVar(&c.BumpVersion, "bump-version", false, "upload the tools with a higher build number if necessary, and use that version (overrides --version)")
	f.BoolVar(&c.Development, "dev", false, "allow development versions to be chosen")

	if err := f.Parse(true, args); err != nil {
		return err
	}
	if vers != "" {
		var err error
		c.Version, err = version.Parse(vers)
		if err != nil {
			return err
		}
		if c.Version == (version.Number{}) {
			return fmt.Errorf("cannot upgrade to version 0.0.0")
		}
	}

	return cmd.CheckEmpty(f.Args())
}
Exemple #8
0
// New returns a new configuration.  Fields that are common to all
// environment providers are verified.  The "authorized-keys-path" key
// is translated into "authorized-keys" by loading the content from
// respective file.  Similarly, "ca-cert-path" and "ca-private-key-path"
// are translated into the "ca-cert" and "ca-private-key" values.  If
// not specified, authorized SSH keys and CA details will be read from:
//
//	~/.ssh/id_dsa.pub
//	~/.ssh/id_rsa.pub
//	~/.ssh/identity.pub
//	~/.juju/<name>-cert.pem
//	~/.juju/<name>-private-key.pem
//
// The required keys (after any files have been read) are "name",
// "type" and "authorized-keys", all of type string.  Additional keys
// recognised are "agent-version" and "development", of types string
// and bool respectively.
func New(attrs map[string]interface{}) (*Config, error) {
	m, err := checker.Coerce(attrs, nil)
	if err != nil {
		return nil, err
	}
	c := &Config{
		m: m.(map[string]interface{}),
		t: make(map[string]interface{}),
	}

	name := c.m["name"].(string)
	if name == "" {
		return nil, fmt.Errorf("empty name in environment configuration")
	}
	if strings.ContainsAny(name, "/\\") {
		return nil, fmt.Errorf("environment name contains unsafe characters")
	}

	if c.m["default-series"].(string) == "" {
		c.m["default-series"] = version.Current.Series
	}

	// Load authorized-keys-path into authorized-keys if necessary.
	path := c.m["authorized-keys-path"].(string)
	keys := c.m["authorized-keys"].(string)
	if path != "" || keys == "" {
		c.m["authorized-keys"], err = readAuthorizedKeys(path)
		if err != nil {
			return nil, err
		}
	}
	delete(c.m, "authorized-keys-path")

	caCert, err := maybeReadFile(c.m, "ca-cert", name+"-cert.pem")
	if err != nil {
		return nil, err
	}
	caKey, err := maybeReadFile(c.m, "ca-private-key", name+"-private-key.pem")
	if err != nil {
		return nil, err
	}
	if caCert != nil || caKey != nil {
		if err := verifyKeyPair(caCert, caKey); err != nil {
			return nil, fmt.Errorf("bad CA certificate/key in configuration: %v", err)
		}
	}

	// Check if there are any required fields that are empty.
	for _, attr := range []string{"type", "default-series", "authorized-keys"} {
		if s, _ := c.m[attr].(string); s == "" {
			return nil, fmt.Errorf("empty %s in environment configuration", attr)
		}
	}

	// Check that the agent version parses ok if set.
	if v, ok := c.m["agent-version"].(string); ok {
		if _, err := version.Parse(v); err != nil {
			return nil, fmt.Errorf("invalid agent version in environment configuration: %q", v)
		}
	}

	// Check firewall mode.
	firewallMode := FirewallMode(c.m["firewall-mode"].(string))
	switch firewallMode {
	case FwDefault, FwInstance, FwGlobal:
		// Valid mode.
	default:
		return nil, fmt.Errorf("invalid firewall mode in environment configuration: %q", firewallMode)
	}

	// Copy unknown attributes onto the type-specific map.
	for k, v := range attrs {
		if _, ok := fields[k]; !ok {
			c.t[k] = v
		}
	}
	return c, nil
}
Exemple #9
0
func (test configTest) check(c *C, h fakeHome) {
	cfg, err := config.New(test.attrs)
	if test.err != "" {
		c.Check(cfg, IsNil)
		c.Assert(err, ErrorMatches, test.err)
		return
	}
	c.Assert(err, IsNil)

	typ, _ := test.attrs["type"].(string)
	name, _ := test.attrs["name"].(string)
	c.Assert(cfg.Type(), Equals, typ)
	c.Assert(cfg.Name(), Equals, name)
	if s := test.attrs["agent-version"]; s != nil {
		vers, err := version.Parse(s.(string))
		c.Assert(err, IsNil)
		c.Assert(cfg.AgentVersion(), Equals, vers)
	} else {
		c.Assert(cfg.AgentVersion(), Equals, version.Number{})
	}

	dev, _ := test.attrs["development"].(bool)
	c.Assert(cfg.Development(), Equals, dev)

	if series, _ := test.attrs["default-series"].(string); series != "" {
		c.Assert(cfg.DefaultSeries(), Equals, series)
	} else {
		c.Assert(cfg.DefaultSeries(), Equals, version.Current.Series)
	}

	if m, _ := test.attrs["firewall-mode"].(string); m != "" {
		c.Assert(cfg.FirewallMode(), Equals, config.FirewallMode(m))
	}

	if secret, _ := test.attrs["admin-secret"].(string); secret != "" {
		c.Assert(cfg.AdminSecret(), Equals, secret)
	}

	if path, _ := test.attrs["authorized-keys-path"].(string); path != "" {
		c.Assert(cfg.AuthorizedKeys(), Equals, h.fileContents(c, path))
		c.Assert(cfg.AllAttrs()["authorized-keys-path"], Equals, nil)
	} else if keys, _ := test.attrs["authorized-keys"].(string); keys != "" {
		c.Assert(cfg.AuthorizedKeys(), Equals, keys)
	} else {
		// Content of all the files that are read by default.
		want := "dsa\nrsa\nidentity\n"
		c.Assert(cfg.AuthorizedKeys(), Equals, want)
	}

	cert, certPresent := cfg.CACert()
	if path, _ := test.attrs["ca-cert-path"].(string); path != "" {
		c.Assert(certPresent, Equals, true)
		c.Assert(string(cert), Equals, h.fileContents(c, path))
	} else if v, ok := test.attrs["ca-cert"].(string); v != "" {
		c.Assert(certPresent, Equals, true)
		c.Assert(string(cert), Equals, v)
	} else if ok {
		c.Check(cert, HasLen, 0)
		c.Assert(certPresent, Equals, false)
	} else if h.fileExists(".juju/my-name-cert.pem") {
		c.Assert(certPresent, Equals, true)
		c.Assert(string(cert), Equals, h.fileContents(c, "my-name-cert.pem"))
	} else {
		c.Check(cert, HasLen, 0)
		c.Assert(certPresent, Equals, false)
	}

	key, keyPresent := cfg.CAPrivateKey()
	if path, _ := test.attrs["ca-private-key-path"].(string); path != "" {
		c.Assert(keyPresent, Equals, true)
		c.Assert(string(key), Equals, h.fileContents(c, path))
	} else if v, ok := test.attrs["ca-private-key"].(string); v != "" {
		c.Assert(keyPresent, Equals, true)
		c.Assert(string(key), Equals, v)
	} else if ok {
		c.Check(key, HasLen, 0)
		c.Assert(keyPresent, Equals, false)
	} else if h.fileExists(".juju/my-name-private-key.pem") {
		c.Assert(keyPresent, Equals, true)
		c.Assert(string(key), Equals, h.fileContents(c, "my-name-private-key.pem"))
	} else {
		c.Check(key, HasLen, 0)
		c.Assert(keyPresent, Equals, false)
	}

	if v, ok := test.attrs["ssl-hostname-verification"]; ok {
		c.Assert(cfg.SSLHostnameVerification(), Equals, v)
	}
}