github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/apiserver/machinemanager/machinemanager.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package machinemanager
     5  
     6  import (
     7  	"fmt"
     8  
     9  	"github.com/juju/errors"
    10  
    11  	"github.com/juju/juju/apiserver/common"
    12  	"github.com/juju/juju/apiserver/params"
    13  	"github.com/juju/juju/environs/config"
    14  	"github.com/juju/juju/instance"
    15  	"github.com/juju/juju/state"
    16  )
    17  
    18  func init() {
    19  	common.RegisterStandardFacade("MachineManager", 2, NewMachineManagerAPI)
    20  }
    21  
    22  // MachineManagerAPI provides access to the MachineManager API facade.
    23  type MachineManagerAPI struct {
    24  	st         stateInterface
    25  	authorizer common.Authorizer
    26  	check      *common.BlockChecker
    27  }
    28  
    29  var getState = func(st *state.State) stateInterface {
    30  	return stateShim{st}
    31  }
    32  
    33  // NewMachineManagerAPI creates a new server-side MachineManager API facade.
    34  func NewMachineManagerAPI(
    35  	st *state.State,
    36  	resources *common.Resources,
    37  	authorizer common.Authorizer,
    38  ) (*MachineManagerAPI, error) {
    39  
    40  	if !authorizer.AuthClient() {
    41  		return nil, common.ErrPerm
    42  	}
    43  
    44  	s := getState(st)
    45  	return &MachineManagerAPI{
    46  		st:         s,
    47  		authorizer: authorizer,
    48  		check:      common.NewBlockChecker(s),
    49  	}, nil
    50  }
    51  
    52  // AddMachines adds new machines with the supplied parameters.
    53  func (mm *MachineManagerAPI) AddMachines(args params.AddMachines) (params.AddMachinesResults, error) {
    54  	results := params.AddMachinesResults{
    55  		Machines: make([]params.AddMachinesResult, len(args.MachineParams)),
    56  	}
    57  	if err := mm.check.ChangeAllowed(); err != nil {
    58  		return results, errors.Trace(err)
    59  	}
    60  	for i, p := range args.MachineParams {
    61  		m, err := mm.addOneMachine(p)
    62  		results.Machines[i].Error = common.ServerError(err)
    63  		if err == nil {
    64  			results.Machines[i].Machine = m.Id()
    65  		}
    66  	}
    67  	return results, nil
    68  }
    69  
    70  func (mm *MachineManagerAPI) addOneMachine(p params.AddMachineParams) (*state.Machine, error) {
    71  	if p.ParentId != "" && p.ContainerType == "" {
    72  		return nil, fmt.Errorf("parent machine specified without container type")
    73  	}
    74  	if p.ContainerType != "" && p.Placement != nil {
    75  		return nil, fmt.Errorf("container type and placement are mutually exclusive")
    76  	}
    77  	if p.Placement != nil {
    78  		// Extract container type and parent from container placement directives.
    79  		containerType, err := instance.ParseContainerType(p.Placement.Scope)
    80  		if err == nil {
    81  			p.ContainerType = containerType
    82  			p.ParentId = p.Placement.Directive
    83  			p.Placement = nil
    84  		}
    85  	}
    86  
    87  	if p.ContainerType != "" || p.Placement != nil {
    88  		// Guard against dubious client by making sure that
    89  		// the following attributes can only be set when we're
    90  		// not using placement.
    91  		p.InstanceId = ""
    92  		p.Nonce = ""
    93  		p.HardwareCharacteristics = instance.HardwareCharacteristics{}
    94  		p.Addrs = nil
    95  	}
    96  
    97  	if p.Series == "" {
    98  		conf, err := mm.st.ModelConfig()
    99  		if err != nil {
   100  			return nil, err
   101  		}
   102  		p.Series = config.PreferredSeries(conf)
   103  	}
   104  
   105  	var placementDirective string
   106  	if p.Placement != nil {
   107  		env, err := mm.st.Model()
   108  		if err != nil {
   109  			return nil, err
   110  		}
   111  		// For 1.21 we should support both UUID and name, and with 1.22
   112  		// just support UUID
   113  		if p.Placement.Scope != env.Name() && p.Placement.Scope != env.UUID() {
   114  			return nil, fmt.Errorf("invalid model name %q", p.Placement.Scope)
   115  		}
   116  		placementDirective = p.Placement.Directive
   117  	}
   118  
   119  	volumes := make([]state.MachineVolumeParams, 0, len(p.Disks))
   120  	for _, cons := range p.Disks {
   121  		if cons.Count == 0 {
   122  			return nil, errors.Errorf("invalid volume params: count not specified")
   123  		}
   124  		// Pool and Size are validated by AddMachineX.
   125  		volumeParams := state.VolumeParams{
   126  			Pool: cons.Pool,
   127  			Size: cons.Size,
   128  		}
   129  		volumeAttachmentParams := state.VolumeAttachmentParams{}
   130  		for i := uint64(0); i < cons.Count; i++ {
   131  			volumes = append(volumes, state.MachineVolumeParams{
   132  				volumeParams, volumeAttachmentParams,
   133  			})
   134  		}
   135  	}
   136  
   137  	jobs, err := common.StateJobs(p.Jobs)
   138  	if err != nil {
   139  		return nil, err
   140  	}
   141  	template := state.MachineTemplate{
   142  		Series:      p.Series,
   143  		Constraints: p.Constraints,
   144  		Volumes:     volumes,
   145  		InstanceId:  p.InstanceId,
   146  		Jobs:        jobs,
   147  		Nonce:       p.Nonce,
   148  		HardwareCharacteristics: p.HardwareCharacteristics,
   149  		Addresses:               params.NetworkAddresses(p.Addrs),
   150  		Placement:               placementDirective,
   151  	}
   152  	if p.ContainerType == "" {
   153  		return mm.st.AddOneMachine(template)
   154  	}
   155  	if p.ParentId != "" {
   156  		return mm.st.AddMachineInsideMachine(template, p.ParentId, p.ContainerType)
   157  	}
   158  	return mm.st.AddMachineInsideNewMachine(template, template, p.ContainerType)
   159  }