github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/provider/cloudsigma/environinstance.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package cloudsigma 5 6 import ( 7 "github.com/juju/errors" 8 "github.com/juju/loggo" 9 10 "github.com/juju/juju/cloudconfig/instancecfg" 11 "github.com/juju/juju/cloudconfig/providerinit" 12 "github.com/juju/juju/environs" 13 "github.com/juju/juju/environs/imagemetadata" 14 "github.com/juju/juju/instance" 15 "github.com/juju/juju/tools" 16 ) 17 18 // 19 // Imlementation of InstanceBroker: methods for starting and stopping instances. 20 // 21 22 var findInstanceImage = func( 23 matchingImages []*imagemetadata.ImageMetadata, 24 ) (*imagemetadata.ImageMetadata, error) { 25 if len(matchingImages) == 0 { 26 return nil, errors.New("no matching image meta data") 27 } 28 return matchingImages[0], nil 29 } 30 31 // MaintainInstance is specified in the InstanceBroker interface. 32 func (*environ) MaintainInstance(args environs.StartInstanceParams) error { 33 return nil 34 } 35 36 // StartInstance asks for a new instance to be created, associated with 37 // the provided config in machineConfig. The given config describes the juju 38 // state for the new instance to connect to. The config MachineNonce, which must be 39 // unique within an environment, is used by juju to protect against the 40 // consequences of multiple instances being started with the same machine id. 41 func (env *environ) StartInstance(args environs.StartInstanceParams) (*environs.StartInstanceResult, error) { 42 logger.Infof("sigmaEnviron.StartInstance...") 43 44 if args.InstanceConfig == nil { 45 return nil, errors.New("instance configuration is nil") 46 } 47 48 if len(args.Tools) == 0 { 49 return nil, errors.New("tools not found") 50 } 51 52 img, err := findInstanceImage(args.ImageMetadata) 53 if err != nil { 54 return nil, err 55 } 56 57 tools, err := args.Tools.Match(tools.Filter{Arch: img.Arch}) 58 if err != nil { 59 return nil, errors.Errorf("chosen architecture %v not present in %v", img.Arch, args.Tools.Arches()) 60 } 61 62 if err := args.InstanceConfig.SetTools(tools); err != nil { 63 return nil, errors.Trace(err) 64 } 65 if err := instancecfg.FinishInstanceConfig(args.InstanceConfig, env.Config()); err != nil { 66 return nil, err 67 } 68 userData, err := providerinit.ComposeUserData(args.InstanceConfig, nil, CloudSigmaRenderer{}) 69 if err != nil { 70 return nil, errors.Annotate(err, "cannot make user data") 71 } 72 73 logger.Debugf("cloudsigma user data; %d bytes", len(userData)) 74 75 client := env.client 76 server, rootdrive, arch, err := client.newInstance(args, img, userData) 77 if err != nil { 78 return nil, errors.Errorf("failed start instance: %v", err) 79 } 80 81 inst := &sigmaInstance{server: server} 82 83 // prepare hardware characteristics 84 hwch, err := inst.hardware(arch, rootdrive.Size()) 85 if err != nil { 86 return nil, err 87 } 88 89 logger.Debugf("hardware: %v", hwch) 90 return &environs.StartInstanceResult{ 91 Instance: inst, 92 Hardware: hwch, 93 }, nil 94 } 95 96 // AllInstances returns all instances currently known to the broker. 97 func (env *environ) AllInstances() ([]instance.Instance, error) { 98 // Please note that this must *not* return instances that have not been 99 // allocated as part of this environment -- if it does, juju will see they 100 // are not tracked in state, assume they're stale/rogue, and shut them down. 101 102 logger.Tracef("environ.AllInstances...") 103 104 servers, err := env.client.instances() 105 if err != nil { 106 logger.Tracef("environ.AllInstances failed: %v", err) 107 return nil, err 108 } 109 110 instances := make([]instance.Instance, 0, len(servers)) 111 for _, server := range servers { 112 instance := sigmaInstance{server: server} 113 instances = append(instances, instance) 114 } 115 116 if logger.LogLevel() <= loggo.TRACE { 117 logger.Tracef("All instances, len = %d:", len(instances)) 118 for _, instance := range instances { 119 logger.Tracef("... id: %q, status: %q", instance.Id(), instance.Status()) 120 } 121 } 122 123 return instances, nil 124 } 125 126 // Instances returns a slice of instances corresponding to the 127 // given instance ids. If no instances were found, but there 128 // was no other error, it will return ErrNoInstances. If 129 // some but not all the instances were found, the returned slice 130 // will have some nil slots, and an ErrPartialInstances error 131 // will be returned. 132 func (env *environ) Instances(ids []instance.Id) ([]instance.Instance, error) { 133 logger.Tracef("environ.Instances %#v", ids) 134 // Please note that this must *not* return instances that have not been 135 // allocated as part of this environment -- if it does, juju will see they 136 // are not tracked in state, assume they're stale/rogue, and shut them down. 137 // This advice applies even if an instance id passed in corresponds to a 138 // real instance that's not part of the environment -- the Environ should 139 // treat that no differently to a request for one that does not exist. 140 141 m, err := env.client.instanceMap() 142 if err != nil { 143 logger.Warningf("environ.Instances failed: %v", err) 144 return nil, err 145 } 146 147 var found int 148 r := make([]instance.Instance, len(ids)) 149 for i, id := range ids { 150 if s, ok := m[string(id)]; ok { 151 r[i] = sigmaInstance{server: s} 152 found++ 153 } 154 } 155 156 if found == 0 { 157 err = environs.ErrNoInstances 158 } else if found != len(ids) { 159 err = environs.ErrPartialInstances 160 } 161 162 return r, err 163 } 164 165 // StopInstances shuts down the given instances. 166 func (env *environ) StopInstances(instances ...instance.Id) error { 167 logger.Debugf("stop instances %+v", instances) 168 169 var err error 170 171 for _, instance := range instances { 172 if e := env.client.stopInstance(instance); e != nil { 173 err = e 174 } 175 } 176 177 return err 178 }