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