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