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 }