github.com/billybanfield/evergreen@v0.0.0-20170525200750-eeee692790f7/cloud/cloud.go (about) 1 package cloud 2 3 import ( 4 "time" 5 6 "github.com/evergreen-ci/evergreen" 7 "github.com/evergreen-ci/evergreen/model/distro" 8 "github.com/evergreen-ci/evergreen/model/host" 9 "github.com/evergreen-ci/evergreen/util" 10 ) 11 12 type CloudStatus int 13 14 const ( 15 //Catch-all for unrecognized status codes 16 StatusUnknown = CloudStatus(iota) 17 18 //StatusPending indicates that it is not yet clear if the instance 19 //has been successfully started or not (e.g., pending spot request) 20 StatusPending 21 22 //StatusInitializing means the instance request has been successfully 23 //fulfilled, but it's not yet done booting up 24 StatusInitializing 25 26 //StatusFailed indicates that an attempt to start the instance has failed; 27 //Could be due to billing, lack of capacity, etc. 28 StatusFailed 29 30 //StatusRunning means the machine is done booting, and active 31 StatusRunning 32 33 StatusStopped 34 StatusTerminated 35 ) 36 37 func (stat CloudStatus) String() string { 38 switch stat { 39 case StatusPending: 40 return "pending" 41 case StatusFailed: 42 return "failed" 43 case StatusInitializing: 44 return "initializing" 45 case StatusRunning: 46 return "running" 47 case StatusStopped: 48 return "stopped" 49 case StatusTerminated: 50 return "terminated" 51 default: 52 return "unknown" 53 } 54 } 55 56 // ProviderSettings exposes provider-specific configuration settings for a CloudManager. 57 type ProviderSettings interface { 58 Validate() error 59 } 60 61 //CloudManager is an interface which handles creating new hosts or modifying 62 //them via some third-party API. 63 type CloudManager interface { 64 // Returns a pointer to the manager's configuration settings struct 65 GetSettings() ProviderSettings 66 67 //Load credentials or other settings from the config file 68 Configure(*evergreen.Settings) error 69 70 // SpawnInstance attempts to create a new host by requesting one from the 71 // provider's API. 72 SpawnInstance(*distro.Distro, HostOptions) (*host.Host, error) 73 74 // CanSpawn indicates if this provider is capable of creating new instances 75 // with SpawnInstance(). If this provider doesn't support spawning new 76 // hosts, this will return false (and calls to SpawnInstance will 77 // return errors) 78 CanSpawn() (bool, error) 79 80 // get the status of an instance 81 GetInstanceStatus(*host.Host) (CloudStatus, error) 82 83 // TerminateInstances destroys the host in the underlying provider 84 TerminateInstance(*host.Host) error 85 86 //IsUp returns true if the underlying provider has not destroyed the 87 //host (in other words, if the host "should" be reachable. This does not 88 //necessarily mean that the host actually *is* reachable via SSH 89 IsUp(*host.Host) (bool, error) 90 91 //Called by the hostinit process when the host is actually up. Used 92 //to set additional provider-specific metadata 93 OnUp(*host.Host) error 94 95 //IsSSHReachable returns true if the host can successfully 96 //accept and run an ssh command. 97 IsSSHReachable(host *host.Host, keyPath string) (bool, error) 98 99 // GetDNSName returns the DNS name of a host. 100 GetDNSName(*host.Host) (string, error) 101 102 // GetSSHOptions generates the command line args to be passed to ssh to 103 // allow connection to the machine 104 GetSSHOptions(host *host.Host, keyName string) ([]string, error) 105 106 // TimeTilNextPayment returns how long there is until the next payment 107 // is due for a particular host 108 TimeTilNextPayment(host *host.Host) time.Duration 109 } 110 111 // CloudCostCalculator is an interface for cloud managers that can estimate an 112 // what a span of time on a given host costs. 113 type CloudCostCalculator interface { 114 CostForDuration(host *host.Host, start time.Time, end time.Time) (float64, error) 115 } 116 117 // HostOptions is a struct of options that are commonly passed around when creating a 118 // new cloud host. 119 type HostOptions struct { 120 ProvisionOptions *host.ProvisionOptions 121 ExpirationDuration *time.Duration 122 UserName string 123 UserData string 124 UserHost bool 125 } 126 127 // NewIntent creates an IntentHost using the given host settings. An IntentHost is a host that 128 // does not exist yet but is intended to be picked up by the hostinit package and started. This 129 // function takes distro information, the name of the instance, the provider of the instance and 130 // a HostOptions and returns an IntentHost. 131 func NewIntent(d distro.Distro, instanceName, provider string, options HostOptions) *host.Host { 132 133 creationTime := time.Now() 134 // proactively write all possible information pertaining 135 // to the host we want to create. this way, if we are unable 136 // to start it or record its instance id, we have a way of knowing 137 // something went wrong - and what 138 intentHost := &host.Host{ 139 Id: instanceName, 140 User: d.User, 141 Distro: d, 142 Tag: instanceName, 143 CreationTime: creationTime, 144 Status: evergreen.HostUninitialized, 145 TerminationTime: util.ZeroTime, 146 TaskDispatchTime: util.ZeroTime, 147 Provider: provider, 148 StartedBy: options.UserName, 149 UserHost: options.UserHost, 150 } 151 152 if options.ExpirationDuration != nil { 153 intentHost.ExpirationTime = creationTime.Add(*options.ExpirationDuration) 154 } 155 if options.ProvisionOptions != nil { 156 intentHost.ProvisionOptions = options.ProvisionOptions 157 } 158 if options.UserData != "" { 159 intentHost.UserData = options.UserData 160 } 161 162 return intentHost 163 164 } 165 166 //CloudHost is a provider-agnostic host object that delegates methods 167 //like status checks, ssh options, DNS name checks, termination, etc. to the 168 //underlying provider's implementation. 169 type CloudHost struct { 170 Host *host.Host 171 KeyPath string 172 CloudMgr CloudManager 173 } 174 175 func (cloudHost *CloudHost) IsSSHReachable() (bool, error) { 176 return cloudHost.CloudMgr.IsSSHReachable(cloudHost.Host, cloudHost.KeyPath) 177 } 178 179 func (cloudHost *CloudHost) IsUp() (bool, error) { 180 return cloudHost.CloudMgr.IsUp(cloudHost.Host) 181 } 182 183 func (cloudHost *CloudHost) TerminateInstance() error { 184 return cloudHost.CloudMgr.TerminateInstance(cloudHost.Host) 185 } 186 187 func (cloudHost *CloudHost) GetInstanceStatus() (CloudStatus, error) { 188 return cloudHost.CloudMgr.GetInstanceStatus(cloudHost.Host) 189 } 190 191 func (cloudHost *CloudHost) GetDNSName() (string, error) { 192 return cloudHost.CloudMgr.GetDNSName(cloudHost.Host) 193 } 194 195 func (cloudHost *CloudHost) GetSSHOptions() ([]string, error) { 196 return cloudHost.CloudMgr.GetSSHOptions(cloudHost.Host, cloudHost.KeyPath) 197 }