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 }