Skip to content

Commit 4fbf287

Browse files
authored
Merge pull request #49 from brevdev/pratik/BREV-1938/loggingoption
feat(BREV-1938): add logging options for Shadeform Client
2 parents e905fd6 + 8074236 commit 4fbf287

File tree

3 files changed

+85
-55
lines changed

3 files changed

+85
-55
lines changed

v1/providers/shadeform/client.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,12 @@ func (c *ShadeformCredential) GetCapabilities(ctx context.Context) (v1.Capabilit
5858
}
5959

6060
// MakeClient creates a new Shadeform client from this credential
61-
func (c *ShadeformCredential) MakeClient(_ context.Context, _ string) (v1.CloudClient, error) {
62-
return NewShadeformClient(c.RefID, c.APIKey), nil
61+
func (c *ShadeformCredential) MakeClient(ctx context.Context, location string) (v1.CloudClient, error) {
62+
return c.MakeClientWithOptions(ctx, location)
63+
}
64+
65+
func (c *ShadeformCredential) MakeClientWithOptions(_ context.Context, _ string, opts ...ShadeformClientOption) (v1.CloudClient, error) {
66+
return NewShadeformClient(c.RefID, c.APIKey, opts...), nil
6367
}
6468

6569
// Shadeform implements the CloudClient interface for Shadeform

v1/providers/shadeform/instance.go

Lines changed: 55 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@ package v1
22

33
import (
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 (
2424
func (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

367382
func (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) {
375390
func (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

Comments
 (0)