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