Ejemplo n.º 1
0
func (s *InstanceSuite) TestParseContainerType(c *gc.C) {
	ctype, err := instance.ParseContainerType("lxc")
	c.Assert(err, gc.IsNil)
	c.Assert(ctype, gc.Equals, instance.LXC)

	ctype, err = instance.ParseContainerType("kvm")
	c.Assert(err, gc.IsNil)
	c.Assert(ctype, gc.Equals, instance.KVM)

	ctype, err = instance.ParseContainerType("none")
	c.Assert(err, gc.ErrorMatches, `invalid container type "none"`)

	ctype, err = instance.ParseContainerType("omg")
	c.Assert(err, gc.ErrorMatches, `invalid container type "omg"`)
}
Ejemplo n.º 2
0
func (c *Client) addOneMachine(p params.AddMachineParams) (*state.Machine, error) {
	if p.ParentId != "" && p.ContainerType == "" {
		return nil, fmt.Errorf("parent machine specified without container type")
	}
	if p.ContainerType != "" && p.Placement != nil {
		return nil, fmt.Errorf("container type and placement are mutually exclusive")
	}
	if p.Placement != nil {
		// Extract container type and parent from container placement directives.
		containerType, err := instance.ParseContainerType(p.Placement.Scope)
		if err == nil {
			p.ContainerType = containerType
			p.ParentId = p.Placement.Directive
			p.Placement = nil
		}
	}

	if p.ContainerType != "" || p.Placement != nil {
		// Guard against dubious client by making sure that
		// the following attributes can only be set when we're
		// not using placement.
		p.InstanceId = ""
		p.Nonce = ""
		p.HardwareCharacteristics = instance.HardwareCharacteristics{}
		p.Addrs = nil
	}

	if p.Series == "" {
		conf, err := c.api.state.EnvironConfig()
		if err != nil {
			return nil, err
		}
		p.Series = config.PreferredSeries(conf)
	}

	var placementDirective string
	if p.Placement != nil {
		env, err := c.api.state.Environment()
		if err != nil {
			return nil, err
		}
		if p.Placement.Scope != env.Name() {
			return nil, fmt.Errorf("invalid environment name %q", p.Placement.Scope)
		}
		placementDirective = p.Placement.Directive
	}

	jobs, err := stateJobs(p.Jobs)
	if err != nil {
		return nil, err
	}
	template := state.MachineTemplate{
		Series:      p.Series,
		Constraints: p.Constraints,
		InstanceId:  p.InstanceId,
		Jobs:        jobs,
		Nonce:       p.Nonce,
		HardwareCharacteristics: p.HardwareCharacteristics,
		Addresses:               p.Addrs,
		Placement:               placementDirective,
	}
	if p.ContainerType == "" {
		return c.api.state.AddOneMachine(template)
	}
	if p.ParentId != "" {
		return c.api.state.AddMachineInsideMachine(template, p.ParentId, p.ContainerType)
	}
	return c.api.state.AddMachineInsideNewMachine(template, template, p.ContainerType)
}
Ejemplo n.º 3
0
// AddUnits starts n units of the given service and allocates machines
// to them as necessary.
func AddUnits(st *state.State, svc *state.Service, n int, machineIdSpec string) ([]*state.Unit, error) {
	units := make([]*state.Unit, n)
	// Hard code for now till we implement a different approach.
	policy := state.AssignCleanEmpty
	// All units should have the same networks as the service.
	includeNetworks, excludeNetworks, err := svc.Networks()
	if err != nil {
		return nil, fmt.Errorf("cannot get service %q networks: %v", svc.Name(), err)
	}
	// TODO what do we do if we fail half-way through this process?
	for i := 0; i < n; i++ {
		unit, err := svc.AddUnit()
		if err != nil {
			return nil, fmt.Errorf("cannot add unit %d/%d to service %q: %v", i+1, n, svc.Name(), err)
		}
		if machineIdSpec != "" {
			if n != 1 {
				return nil, fmt.Errorf("cannot add multiple units of service %q to a single machine", svc.Name())
			}
			// machineIdSpec may be an existing machine or container, eg 3/lxc/2
			// or a new container on a machine, eg lxc:3
			mid := machineIdSpec
			var containerType instance.ContainerType
			specParts := strings.SplitN(machineIdSpec, ":", 2)
			if len(specParts) > 1 {
				firstPart := specParts[0]
				var err error
				if containerType, err = instance.ParseContainerType(firstPart); err == nil {
					mid = specParts[1]
				} else {
					mid = machineIdSpec
				}
			}
			if !names.IsMachine(mid) {
				return nil, fmt.Errorf("invalid force machine id %q", mid)
			}

			var err error
			var m *state.Machine
			// If a container is to be used, create it.
			if containerType != "" {
				// Create the new machine marked as dirty so that
				// nothing else will grab it before we assign the unit to it.
				template := state.MachineTemplate{
					Series:          unit.Series(),
					Jobs:            []state.MachineJob{state.JobHostUnits},
					Dirty:           true,
					IncludeNetworks: includeNetworks,
					ExcludeNetworks: excludeNetworks,
				}
				m, err = st.AddMachineInsideMachine(template, mid, containerType)
			} else {
				m, err = st.Machine(mid)
			}
			if err != nil {
				return nil, fmt.Errorf("cannot assign unit %q to machine: %v", unit.Name(), err)
			}
			err = unit.AssignToMachine(m)

			if err != nil {
				return nil, err
			}
		} else if err := st.AssignUnit(unit, policy); err != nil {
			return nil, err
		}
		units[i] = unit
	}
	return units, nil
}
Ejemplo n.º 4
0
func (c *AddMachineCommand) Run(ctx *cmd.Context) error {
	if c.Placement != nil && c.Placement.Scope == "ssh" {
		args := manual.ProvisionMachineArgs{
			Host:    c.Placement.Directive,
			EnvName: c.EnvName,
			Stdin:   ctx.Stdin,
			Stdout:  ctx.Stdout,
			Stderr:  ctx.Stderr,
		}
		_, err := manual.ProvisionMachine(args)
		return err
	}

	client, err := juju.NewAPIClientFromName(c.EnvName)
	if err != nil {
		return err
	}
	defer client.Close()

	if c.Placement != nil && c.Placement.Scope == instance.MachineScope {
		// It does not make sense to add-machine <id>.
		return fmt.Errorf("machine-id cannot be specified when adding machines")
	}

	machineParams := params.AddMachineParams{
		Placement:   c.Placement,
		Series:      c.Series,
		Constraints: c.Constraints,
		Jobs:        []params.MachineJob{params.JobHostUnits},
	}
	results, err := client.AddMachines([]params.AddMachineParams{machineParams})
	if params.IsCodeNotImplemented(err) {
		if c.Placement != nil {
			containerType, parseErr := instance.ParseContainerType(c.Placement.Scope)
			if parseErr != nil {
				// The user specified a non-container placement directive:
				// return original API not implemented error.
				return err
			}
			machineParams.ContainerType = containerType
			machineParams.ParentId = c.Placement.Directive
			machineParams.Placement = nil
		}
		logger.Infof(
			"AddMachinesWithPlacement not supported by the API server, " +
				"falling back to 1.18 compatibility mode",
		)
		results, err = client.AddMachines1dot18([]params.AddMachineParams{machineParams})
	}
	if err != nil {
		return err
	}

	// Currently, only one machine is added, but in future there may be several added in one call.
	machineInfo := results[0]
	if machineInfo.Error != nil {
		return machineInfo.Error
	}
	machineId := machineInfo.Machine

	if names.IsContainerMachine(machineId) {
		ctx.Infof("created container %v", machineId)
	} else {
		ctx.Infof("created machine %v", machineId)
	}
	return nil
}