@@ -2,12 +2,12 @@ package v1
22
33import (
44 "context"
5- "errors"
65 "fmt"
76 "io"
87 "strings"
98
109 "github.com/alecthomas/units"
10+ "github.com/brevdev/cloud/internal/errors"
1111 v1 "github.com/brevdev/cloud/v1"
1212 openapi "github.com/brevdev/cloud/v1/providers/shadeform/gen/shadeform"
1313 "github.com/google/uuid"
@@ -24,9 +24,11 @@ const (
2424func (c * ShadeformClient ) CreateInstance (ctx context.Context , attrs v1.CreateInstanceAttrs ) (* v1.Instance , error ) { //nolint:gocyclo,funlen // ok
2525 authCtx := c .makeAuthContext (ctx )
2626
27+ c .logger .Debug (ctx , "Creating instance" , v1 .LogField ("instanceAttrs" , attrs ))
2728 // Check if the instance type is allowed by configuration
28- if ! c .isInstanceTypeAllowed (attrs .InstanceType ) {
29- return nil , fmt .Errorf ("instance type: %v is not deployable" , attrs .InstanceType )
29+ allowed , _ := c .isInstanceTypeAllowed (attrs .InstanceType )
30+ if ! allowed {
31+ return nil , errors .WrapAndTrace (fmt .Errorf ("instance type: %v is not deployable" , attrs .InstanceType ))
3032 }
3133
3234 sshKeyID := ""
@@ -38,52 +40,53 @@ func (c *ShadeformClient) CreateInstance(ctx context.Context, attrs v1.CreateIns
3840
3941 if keyPairName == "" {
4042 keyPairName = uuid .New ().String ()
43+ c .logger .Debug (ctx , "No key pair name provided, generating new one" , v1 .LogField ("keyPairName" , keyPairName ))
4144 }
4245
4346 if attrs .PublicKey != "" {
4447 var err error
4548 sshKeyID , err = c .addSSHKey (ctx , keyPairName , attrs .PublicKey )
4649 if err != nil && ! strings .Contains (err .Error (), "name must be unique" ) {
47- return nil , fmt .Errorf ("failed to add SSH key: %w" , err )
50+ return nil , errors . WrapAndTrace ( fmt .Errorf ("failed to add SSH key: %w" , err ) )
4851 }
4952 }
5053
5154 region := attrs .Location
5255 cloud , shadeInstanceType , err := c .getShadeformCloudAndInstanceType (attrs .InstanceType )
5356 if err != nil {
54- return nil , err
57+ return nil , errors . WrapAndTrace ( err )
5558 }
5659
5760 cloudEnum , err := openapi .NewCloudFromValue (cloud )
5861 if err != nil {
59- return nil , err
62+ return nil , errors . WrapAndTrace ( err )
6063 }
6164
6265 // Add refID tag
6366 refIDTag , err := c .createTag (refIDTagName , attrs .RefID )
6467 if err != nil {
65- return nil , err
68+ return nil , errors . WrapAndTrace ( err )
6669 }
6770
6871 // Add cloudRefID tag
6972 cloudCredRefIDTag , err := c .createTag (cloudCredRefIDTagName , c .GetReferenceID ())
7073 if err != nil {
71- return nil , err
74+ return nil , errors . WrapAndTrace ( err )
7275 }
7376
7477 tags := []string {refIDTag , cloudCredRefIDTag }
7578 // Add all other tags
7679 for key , value := range attrs .Tags {
7780 createdTag , err := c .createTag (key , value )
7881 if err != nil {
79- return nil , err
82+ return nil , errors . WrapAndTrace ( err )
8083 }
8184 tags = append (tags , createdTag )
8285 }
8386
8487 base64Script , err := c .GenerateFirewallScript (attrs .FirewallRules )
8588 if err != nil {
86- return nil , err
89+ return nil , errors . WrapAndTrace ( err )
8790 }
8891
8992 req := openapi.CreateRequest {
@@ -108,18 +111,18 @@ func (c *ShadeformClient) CreateInstance(ctx context.Context, attrs v1.CreateIns
108111 }
109112 if err != nil {
110113 httpMessage , _ := io .ReadAll (httpResp .Body )
111- return nil , fmt .Errorf ("failed to create instance: %w, %s" , err , string (httpMessage ))
114+ return nil , errors . WrapAndTrace ( fmt .Errorf ("failed to create instance: %w, %s" , err , string (httpMessage ) ))
112115 }
113116
114117 if resp == nil {
115- return nil , fmt .Errorf ("no instance returned from create request" )
118+ return nil , errors . WrapAndTrace ( fmt .Errorf ("no instance returned from create request" ) )
116119 }
117120
118121 // Since Shadeform doesn't return the full instance that's created, we need to make a second API call to get
119122 // the created instance after we call create
120123 createdInstance , err := c .GetInstance (authCtx , v1 .CloudProviderInstanceID (resp .Id ))
121124 if err != nil {
122- return nil , err
125+ return nil , errors . WrapAndTrace ( err )
123126 }
124127
125128 return createdInstance , nil
@@ -152,11 +155,11 @@ func (c *ShadeformClient) addSSHKey(ctx context.Context, keyPairName string, pub
152155 }
153156 if err != nil {
154157 httpMessage , _ := io .ReadAll (httpResp .Body )
155- return "" , fmt .Errorf ("failed to add SSH Key: %w, %s" , err , string (httpMessage ))
158+ return "" , errors . WrapAndTrace ( fmt .Errorf ("failed to add SSH Key: %w, %s" , err , string (httpMessage ) ))
156159 }
157160
158161 if resp == nil {
159- return "" , fmt .Errorf ("no instance returned from post request" )
162+ return "" , errors . WrapAndTrace ( fmt .Errorf ("no instance returned from post request" ) )
160163 }
161164
162165 return resp .Id , nil
@@ -170,16 +173,16 @@ func (c *ShadeformClient) GetInstance(ctx context.Context, instanceID v1.CloudPr
170173 defer func () { _ = httpResp .Body .Close () }()
171174 }
172175 if err != nil {
173- return nil , fmt .Errorf ("failed to get instance: %w" , err )
176+ return nil , errors . WrapAndTrace ( fmt .Errorf ("failed to get instance: %w" , err ) )
174177 }
175178
176179 if resp == nil {
177- return nil , fmt .Errorf ("no instance returned from get request" )
180+ return nil , errors . WrapAndTrace ( fmt .Errorf ("no instance returned from get request" ) )
178181 }
179182
180- instance , err := c .convertInstanceInfoResponseToV1Instance (* resp )
183+ instance , err := c .convertInstanceInfoResponseToV1Instance (ctx , * resp )
181184 if err != nil {
182- return nil , err
185+ return nil , errors . WrapAndTrace ( err )
183186 }
184187
185188 return instance , nil
@@ -193,7 +196,7 @@ func (c *ShadeformClient) TerminateInstance(ctx context.Context, instanceID v1.C
193196 defer func () { _ = httpResp .Body .Close () }()
194197 }
195198 if err != nil {
196- return fmt .Errorf ("failed to terminate instance: %w" , err )
199+ return errors . WrapAndTrace ( fmt .Errorf ("failed to terminate instance: %w" , err ) )
197200 }
198201
199202 return nil
@@ -207,14 +210,14 @@ func (c *ShadeformClient) ListInstances(ctx context.Context, _ v1.ListInstancesA
207210 defer func () { _ = httpResp .Body .Close () }()
208211 }
209212 if err != nil {
210- return nil , fmt .Errorf ("failed to list instances: %w" , err )
213+ return nil , errors . WrapAndTrace ( fmt .Errorf ("failed to list instances: %w" , err ) )
211214 }
212215
213216 var instances []v1.Instance
214217 for _ , instance := range resp .Instances {
215- singleInstance , err := c .convertShadeformInstanceToV1Instance (instance )
218+ singleInstance , err := c .convertShadeformInstanceToV1Instance (ctx , instance )
216219 if err != nil {
217- return nil , err
220+ return nil , errors . WrapAndTrace ( err )
218221 }
219222 instances = append (instances , * singleInstance )
220223 }
@@ -254,27 +257,33 @@ func (c *ShadeformClient) getLifecycleStatus(status string) v1.LifecycleStatus {
254257}
255258
256259// convertInstanceInfoResponseToV1Instance - converts Instance Info to v1 instance
257- func (c * ShadeformClient ) convertInstanceInfoResponseToV1Instance (instanceInfo openapi.InstanceInfoResponse ) (* v1.Instance , error ) {
260+ func (c * ShadeformClient ) convertInstanceInfoResponseToV1Instance (ctx context.Context , instanceInfo openapi.InstanceInfoResponse ) (* v1.Instance , error ) {
261+ c .logger .Debug (ctx , "converting instance info response to v1 instance" , v1 .LogField ("instanceInfo" , instanceInfo ))
258262 instanceType := c .getInstanceType (string (instanceInfo .Cloud ), instanceInfo .ShadeInstanceType )
259263 lifeCycleStatus := c .getLifecycleStatus (string (instanceInfo .Status ))
260264
261265 tags , err := c .convertShadeformTagToV1Tag (instanceInfo .Tags )
262266 if err != nil {
263- return nil , err
267+ return nil , errors . WrapAndTrace ( err )
264268 }
265269
266270 refID , found := tags [refIDTagName ]
267271 if ! found {
268- return nil , errors .New ("could not find refID tag" )
272+ return nil , errors .WrapAndTrace ( errors . New ("could not find refID tag" ) )
269273 }
274+ c .logger .Debug (ctx , "refID found, deleting from tags" , v1 .LogField ("refID" , refID ))
270275 delete (tags , refIDTagName )
271276
272- cloudCredRefID := tags [cloudCredRefIDTagName ]
273- if err != nil {
274- return nil , errors .New ("could not find cloudCredRefID tag" )
277+ cloudCredRefID , found := tags [cloudCredRefIDTagName ]
278+ if ! found {
279+ return nil , errors .WrapAndTrace ( errors . New ("could not find cloudCredRefID tag" ) )
275280 }
281+ c .logger .Debug (ctx , "cloudCredRefID found, deleting from tags" , v1 .LogField ("cloudCredRefID" , cloudCredRefID ))
276282 delete (tags , cloudCredRefIDTagName )
277283
284+ diskSize := units .Base2Bytes (instanceInfo .Configuration .StorageInGb ) * units .GiB
285+ c .logger .Debug (ctx , "calculated diskSize" , v1 .LogField ("diskSize" , diskSize ), v1 .LogField ("storageInGb" , instanceInfo .Configuration .StorageInGb ))
286+
278287 instance := & v1.Instance {
279288 Name : c .getProvidedInstanceName (instanceInfo .Name ),
280289 CreatedAt : instanceInfo .CreatedAt ,
@@ -285,7 +294,7 @@ func (c *ShadeformClient) convertInstanceInfoResponseToV1Instance(instanceInfo o
285294 ImageID : instanceInfo .Configuration .Os ,
286295 InstanceType : instanceType ,
287296 InstanceTypeID : v1 .InstanceTypeID (c .getInstanceTypeID (instanceType , instanceInfo .Region )),
288- DiskSize : units . Base2Bytes ( instanceInfo . Configuration . StorageInGb ) * units . GiB ,
297+ DiskSize : diskSize ,
289298 SSHUser : instanceInfo .SshUser ,
290299 SSHPort : int (instanceInfo .SshPort ),
291300 Status : v1.Status {
@@ -304,27 +313,33 @@ func (c *ShadeformClient) convertInstanceInfoResponseToV1Instance(instanceInfo o
304313
305314// convertInstanceInfoResponseToV1Instance - converts /instances response to v1 instance; the api struct is slightly
306315// different from instance info response and expected to diverge so keeping it as a separate function for now
307- func (c * ShadeformClient ) convertShadeformInstanceToV1Instance (shadeformInstance openapi.Instance ) (* v1.Instance , error ) {
316+ func (c * ShadeformClient ) convertShadeformInstanceToV1Instance (ctx context.Context , shadeformInstance openapi.Instance ) (* v1.Instance , error ) {
317+ c .logger .Debug (ctx , "converting shadeform instance to v1 instance" , v1 .LogField ("shadeformInstance" , shadeformInstance ))
308318 instanceType := c .getInstanceType (string (shadeformInstance .Cloud ), shadeformInstance .ShadeInstanceType )
309319 lifeCycleStatus := c .getLifecycleStatus (string (shadeformInstance .Status ))
310320
311321 tags , err := c .convertShadeformTagToV1Tag (shadeformInstance .Tags )
312322 if err != nil {
313- return nil , err
323+ return nil , errors . WrapAndTrace ( err )
314324 }
315325
316326 refID , found := tags [refIDTagName ]
317327 if ! found {
318- return nil , errors .New ("could not find refID tag" )
328+ return nil , errors .WrapAndTrace ( errors . New ("could not find refID tag" ) )
319329 }
330+ c .logger .Debug (ctx , "refID found, deleting from tags" , v1 .LogField ("refID" , refID ))
320331 delete (tags , refIDTagName )
321332
322- cloudCredRefID := tags [cloudCredRefIDTagName ]
323- if err != nil {
324- return nil , errors .New ("could not find cloudCredRefID tag" )
333+ cloudCredRefID , found := tags [cloudCredRefIDTagName ]
334+ if ! found {
335+ return nil , errors .WrapAndTrace ( errors . New ("could not find cloudCredRefID tag" ) )
325336 }
337+ c .logger .Debug (ctx , "cloudCredRefID found, deleting from tags" , v1 .LogField ("cloudCredRefID" , cloudCredRefID ))
326338 delete (tags , cloudCredRefIDTagName )
327339
340+ diskSize := units .Base2Bytes (shadeformInstance .Configuration .StorageInGb ) * units .GiB
341+ c .logger .Debug (ctx , "calculated diskSize" , v1 .LogField ("diskSize" , diskSize ), v1 .LogField ("storageInGb" , shadeformInstance .Configuration .StorageInGb ))
342+
328343 instance := & v1.Instance {
329344 Name : shadeformInstance .Name ,
330345 CreatedAt : shadeformInstance .CreatedAt ,
@@ -334,7 +349,7 @@ func (c *ShadeformClient) convertShadeformInstanceToV1Instance(shadeformInstance
334349 Hostname : hostname ,
335350 ImageID : shadeformInstance .Configuration .Os ,
336351 InstanceType : instanceType ,
337- DiskSize : units . Base2Bytes ( shadeformInstance . Configuration . StorageInGb ) * units . GiB ,
352+ DiskSize : diskSize ,
338353 SSHUser : shadeformInstance .SshUser ,
339354 SSHPort : int (shadeformInstance .SshPort ),
340355 Status : v1.Status {
@@ -357,7 +372,7 @@ func (c *ShadeformClient) convertShadeformTagToV1Tag(shadeformTags []string) (v1
357372 for _ , tag := range shadeformTags {
358373 key , value , err := c .getTag (tag )
359374 if err != nil {
360- return nil , err
375+ return nil , errors . WrapAndTrace ( err )
361376 }
362377 tags [key ] = value
363378 }
@@ -366,7 +381,7 @@ func (c *ShadeformClient) convertShadeformTagToV1Tag(shadeformTags []string) (v1
366381
367382func (c * ShadeformClient ) createTag (key string , value string ) (string , error ) {
368383 if strings .Contains (key , "=" ) {
369- return "" , errors .New ("tags cannot contain the '=' character" )
384+ return "" , errors .WrapAndTrace ( errors . New ("tags cannot contain the '=' character" ) )
370385 }
371386
372387 return fmt .Sprintf ("%v=%v" , key , value ), nil
@@ -375,7 +390,7 @@ func (c *ShadeformClient) createTag(key string, value string) (string, error) {
375390func (c * ShadeformClient ) getTag (shadeformTag string ) (string , string , error ) {
376391 key , value , found := strings .Cut (shadeformTag , "=" )
377392 if ! found {
378- return "" , "" , fmt .Errorf ("tag %v does not conform to the key value tag format" , shadeformTag )
393+ return "" , "" , errors . WrapAndTrace ( fmt .Errorf ("tag %v does not conform to the key value tag format" , shadeformTag ) )
379394 }
380395 return key , value , nil
381396}
0 commit comments