github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/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 cfg := env.Config() 77 server, rootdrive, arch, err := client.newInstance(args, img, userData, cfg.AuthorizedKeys()) 78 if err != nil { 79 return nil, errors.Errorf("failed start instance: %v", err) 80 } 81 82 inst := &sigmaInstance{server: server} 83 84 // prepare hardware characteristics 85 hwch, err := inst.hardware(arch, rootdrive.Size()) 86 if err != nil { 87 return nil, err 88 } 89 90 logger.Debugf("hardware: %v", hwch) 91 return &environs.StartInstanceResult{ 92 Instance: inst, 93 Hardware: hwch, 94 }, nil 95 } 96 97 // AllInstances returns all instances currently known to the broker. 98 func (env *environ) AllInstances() ([]instance.Instance, error) { 99 // Please note that this must *not* return instances that have not been 100 // allocated as part of this environment -- if it does, juju will see they 101 // are not tracked in state, assume they're stale/rogue, and shut them down. 102 103 logger.Tracef("environ.AllInstances...") 104 105 servers, err := env.client.instances() 106 if err != nil { 107 logger.Tracef("environ.AllInstances failed: %v", err) 108 return nil, err 109 } 110 111 instances := make([]instance.Instance, 0, len(servers)) 112 for _, server := range servers { 113 instance := sigmaInstance{server: server} 114 instances = append(instances, instance) 115 } 116 117 if logger.LogLevel() <= loggo.TRACE { 118 logger.Tracef("All instances, len = %d:", len(instances)) 119 for _, instance := range instances { 120 logger.Tracef("... id: %q, status: %q", instance.Id(), instance.Status()) 121 } 122 } 123 124 return instances, nil 125 } 126 127 // Instances returns a slice of instances corresponding to the 128 // given instance ids. If no instances were found, but there 129 // was no other error, it will return ErrNoInstances. If 130 // some but not all the instances were found, the returned slice 131 // will have some nil slots, and an ErrPartialInstances error 132 // will be returned. 133 func (env *environ) Instances(ids []instance.Id) ([]instance.Instance, error) { 134 logger.Tracef("environ.Instances %#v", ids) 135 // Please note that this must *not* return instances that have not been 136 // allocated as part of this environment -- if it does, juju will see they 137 // are not tracked in state, assume they're stale/rogue, and shut them down. 138 // This advice applies even if an instance id passed in corresponds to a 139 // real instance that's not part of the environment -- the Environ should 140 // treat that no differently to a request for one that does not exist. 141 142 m, err := env.client.instanceMap() 143 if err != nil { 144 return nil, errors.Annotate(err, "environ.Instances failed") 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, errors.Trace(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 }