Skip to content

Commit 570e578

Browse files
fix(cli): avoid panic while updating progress (#1597)
* fix(cli): avoid panic while updating progress Signed-off-by: Lacework <[email protected]> * style(lwcomponent): do not obsure named returns Signed-off-by: Lacework <[email protected]> --------- Signed-off-by: Lacework <[email protected]> Co-authored-by: Lacework <[email protected]>
1 parent fc36cc2 commit 570e578

File tree

8 files changed

+120
-89
lines changed

8 files changed

+120
-89
lines changed

Makefile

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,10 @@ help:
6161
prepare: git-env install-tools go-vendor ## Initialize the go environment
6262

6363
.PHONY: test
64-
test: prepare ## Run all go-sdk tests
64+
test: prepare test-only ## Run all go-sdk tests
65+
66+
.PHONY: test-only
67+
test-only: ## Run all go-sdk tests only (without prepare)
6568
$(eval PACKAGES := $(shell go list ./... | grep -v integration))
6669
gotestsum -f testname --rerun-fails=3 --packages="$(PACKAGES)" \
6770
-- -v -cover -run=$(regex) -coverprofile=$(COVERAGEOUT) $(PACKAGES)

cli/cmd/component.go

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -432,6 +432,15 @@ func installComponent(args []string) (err error) {
432432
return
433433
}
434434

435+
installedVersion := component.InstalledVersion()
436+
if installedVersion != nil {
437+
return errors.Errorf(
438+
"component %s is already installed. To upgrade run '%s'",
439+
color.HiYellowString(componentName),
440+
color.HiGreenString("lacework component upgrade %s", componentName),
441+
)
442+
}
443+
435444
cli.OutputChecklist(successIcon, fmt.Sprintf("Component %s found\n", component.Name))
436445

437446
cli.StartProgress(fmt.Sprintf("Staging component %s...", componentName))
@@ -1139,7 +1148,7 @@ func downloadProgress(complete chan int8, path string, sizeB int64) {
11391148
spinnerSuffix string = ""
11401149
)
11411150

1142-
if !cli.nonInteractive {
1151+
if cli.spinner != nil {
11431152
spinnerSuffix = cli.spinner.Suffix
11441153
}
11451154

@@ -1163,24 +1172,18 @@ func downloadProgress(complete chan int8, path string, sizeB int64) {
11631172
mb := float64(size) / (1 << 20)
11641173

11651174
if mb > previous {
1166-
if !cli.nonInteractive {
1167-
cli.spinner.Suffix = fmt.Sprintf("%s Downloaded: %.0fmb", spinnerSuffix, mb)
1168-
} else {
1169-
cli.OutputHuman("..Downloaded: %.0fmb\n", mb)
1170-
}
1171-
1175+
sizeString := fmt.Sprintf("%.0fmb", mb)
1176+
cli.Log.Infow("downloading component", "size", sizeString)
1177+
cli.StartProgress(fmt.Sprintf("%s (%s downloaded)", spinnerSuffix, sizeString))
11721178
previous = mb
11731179
}
11741180
} else {
11751181
percent := float64(size) / float64(sizeB) * 100
11761182

11771183
if percent > previous {
1178-
if !cli.nonInteractive {
1179-
cli.spinner.Suffix = fmt.Sprintf("%s Downloaded: %.0f%s", spinnerSuffix, percent, "%")
1180-
} else {
1181-
cli.OutputHuman("..Downloaded: %.0f%s\n", percent, "%")
1182-
}
1183-
1184+
percentString := fmt.Sprintf("%.0f%%", percent)
1185+
cli.Log.Infow("downloading component", "percent", percentString)
1186+
cli.StartProgress(fmt.Sprintf("%s (%s downloaded)", spinnerSuffix, percentString))
11841187
previous = percent
11851188
}
11861189
}

integration/component_test.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,11 @@ func TestCDKComponentInstall(t *testing.T) {
109109
out = run(t, dir, "component-example")
110110
assert.Contains(t, out, "component")
111111

112+
outBytes, errBytes, exitcode := LaceworkCLIWithHome(dir, "component", "install", "component-example")
113+
assert.NotContains(t, outBytes.String(), "Installation completed.", "STDOUT should be empty")
114+
assert.Contains(t, errBytes.String(), "already installed")
115+
assert.Equal(t, 1, exitcode, "EXITCODE is not the expected one")
116+
112117
cleanup(dir)
113118
}
114119

lwcomponent/catalog.go

Lines changed: 18 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -73,15 +73,13 @@ func (c *Catalog) GetComponent(name string) (*CDKComponent, error) {
7373
return &component, nil
7474
}
7575

76-
func (c *Catalog) ListComponentVersions(component *CDKComponent) (versions []*semver.Version, err error) {
76+
func (c *Catalog) ListComponentVersions(component *CDKComponent) ([]*semver.Version, error) {
7777
if component.ApiInfo == nil {
78-
err = errors.Errorf("component '%s' api info not available", component.Name)
79-
return
78+
return nil, errors.Errorf("component '%s' api info not available", component.Name)
8079
}
8180

82-
versions = component.ApiInfo.AllVersions
83-
if versions != nil {
84-
return
81+
if component.ApiInfo.AllVersions != nil {
82+
return component.ApiInfo.AllVersions, nil
8583
}
8684

8785
return listComponentVersions(c.client, component.ApiInfo.Id)
@@ -180,7 +178,7 @@ func (c *Catalog) Stage(
180178
return
181179
}
182180

183-
func (c *Catalog) Verify(component *CDKComponent) (err error) {
181+
func (c *Catalog) Verify(component *CDKComponent) error {
184182
path := filepath.Join(component.stage.Directory(), component.Name)
185183

186184
if operatingSystem == "windows" {
@@ -189,12 +187,12 @@ func (c *Catalog) Verify(component *CDKComponent) (err error) {
189187

190188
data, err := os.ReadFile(path)
191189
if err != nil {
192-
return
190+
return err
193191
}
194192

195193
sig, err := component.stage.Signature()
196194
if err != nil {
197-
return
195+
return err
198196
}
199197

200198
rootPublicKey := minisign.PublicKey{}
@@ -205,29 +203,29 @@ func (c *Catalog) Verify(component *CDKComponent) (err error) {
205203
return verifySignature(rootPublicKey, data, sig)
206204
}
207205

208-
func (c *Catalog) Install(component *CDKComponent) (err error) {
206+
func (c *Catalog) Install(component *CDKComponent) error {
209207
if component.stage == nil {
210208
return errors.Errorf("component '%s' not staged", component.Name)
211209
}
212210

213211
componentDir, err := componentDirectory(component.Name)
214212
if err != nil {
215-
return
213+
return err
216214
}
217215

218216
err = os.MkdirAll(componentDir, os.ModePerm)
219217
if err != nil {
220-
return
218+
return err
221219
}
222220

223221
err = component.stage.Commit(componentDir)
224222
if err != nil {
225-
return
223+
return err
226224
}
227225

228226
component.HostInfo, err = NewHostInfo(componentDir, component.Description, component.Type)
229227
if err != nil {
230-
return
228+
return err
231229
}
232230

233231
path := filepath.Join(componentDir, component.Name)
@@ -243,27 +241,25 @@ func (c *Catalog) Install(component *CDKComponent) (err error) {
243241
}
244242
}
245243

246-
return
244+
return nil
247245
}
248246

249247
// Delete a CDKComponent
250248
//
251249
// Remove the Component install directory and all sub-directory. This function will not return an
252250
// error if the Component is not installed.
253-
func (c *Catalog) Delete(component *CDKComponent) (err error) {
251+
func (c *Catalog) Delete(component *CDKComponent) error {
254252
componentDir, err := componentDirectory(component.Name)
255253
if err != nil {
256-
return
254+
return err
257255
}
258256

259257
_, err = os.Stat(componentDir)
260258
if err != nil {
261259
return errors.Errorf("component not installed. Try running 'lacework component install %s'", component.Name)
262260
}
263261

264-
os.RemoveAll(componentDir)
265-
266-
return
262+
return os.RemoveAll(componentDir)
267263
}
268264

269265
func NewCatalog(
@@ -412,7 +408,7 @@ func LoadLocalComponents() (components map[string]CDKComponent, err error) {
412408
return
413409
}
414410

415-
func listComponentVersions(client *api.Client, componentId int32) (versions []*semver.Version, err error) {
411+
func listComponentVersions(client *api.Client, componentId int32) ([]*semver.Version, error) {
416412
response, err := client.V2.Components.ListComponentVersions(componentId, operatingSystem, architecture)
417413
if err != nil {
418414
return nil, err
@@ -424,7 +420,7 @@ func listComponentVersions(client *api.Client, componentId int32) (versions []*s
424420
rawVersions = response.Data[0].Versions
425421
}
426422

427-
versions = make([]*semver.Version, len(rawVersions))
423+
versions := make([]*semver.Version, len(rawVersions))
428424

429425
for idx, v := range rawVersions {
430426
ver, err := semver.NewVersion(v)

lwcomponent/cdk_component.go

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -124,34 +124,32 @@ func (c *CDKComponent) EnterDevMode() error {
124124
return nil
125125
}
126126

127-
func (c *CDKComponent) InstalledVersion() (version *semver.Version) {
128-
var err error
129-
127+
func (c *CDKComponent) InstalledVersion() *semver.Version {
130128
if c.HostInfo != nil {
131-
version, err = c.HostInfo.Version()
129+
version, err := c.HostInfo.Version()
132130
if err == nil {
133-
return
131+
return version
134132
}
135133

136134
if componentDir, err := c.Dir(); err == nil {
137135
if devInfo, err := newDevInfo(componentDir); err == nil {
138136
version, err = semver.NewVersion(devInfo.Version)
139137
if err == nil {
140-
return
138+
return version
141139
}
142140
}
143141
}
144142
}
145143

146-
return
144+
return nil
147145
}
148146

149-
func (c *CDKComponent) LatestVersion() (version *semver.Version) {
147+
func (c *CDKComponent) LatestVersion() *semver.Version {
150148
if c.ApiInfo != nil {
151-
version = c.ApiInfo.Version
149+
return c.ApiInfo.Version
152150
}
153151

154-
return
152+
return nil
155153
}
156154

157155
func (c *CDKComponent) PrintSummary() []string {

lwcomponent/http.go

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
package lwcomponent
2020

2121
import (
22-
"fmt"
2322
"os"
2423
"strconv"
2524
"time"
@@ -32,12 +31,12 @@ const (
3231
DefaultMaxRetry = 3
3332
)
3433

35-
var log = lwlogger.New("INFO")
34+
var log = lwlogger.New("INFO").Sugar()
3635

3736
// Retry 3 times (4 requests total)
3837
// Resty default RetryWaitTime is 100ms
3938
// Exponential backoff to a maximum of RetryWaitTime of 2s
40-
func DownloadFile(path string, url string) (err error) {
39+
func DownloadFile(path string, url string) error {
4140
client := resty.New()
4241

4342
download_timeout := os.Getenv("CDK_DOWNLOAD_TIMEOUT_MINUTES")
@@ -52,14 +51,31 @@ func DownloadFile(path string, url string) (err error) {
5251
client.SetRetryCount(DefaultMaxRetry)
5352

5453
client.OnError(func(req *resty.Request, err error) {
54+
fields := []interface{}{
55+
"raw_error", err,
56+
}
57+
5558
if v, ok := err.(*resty.ResponseError); ok {
56-
log.Warn(fmt.Sprintf("Failed to download component: %s: %s", v.Response.Body(), v.Err))
59+
60+
fields = append(fields, "response_body", string(v.Response.Body()))
61+
62+
if v.Response.Request != nil {
63+
trace := v.Response.Request.TraceInfo()
64+
fields = append(fields, "trace_info", trace)
65+
}
66+
67+
if v.Err != nil {
68+
fields = append(fields, "response_error", v.Err.Error())
69+
}
5770
}
5871

59-
log.Warn(fmt.Sprintf("Failed to download component: %s", err.Error()))
72+
log.Warnw("Failed to download component", fields...)
6073
})
6174

62-
_, err = client.R().SetOutput(path).Get(url)
75+
_, err := client.R().
76+
EnableTrace().
77+
SetOutput(path).
78+
Get(url)
6379

64-
return
80+
return err
6581
}

lwcomponent/http_test.go

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package lwcomponent_test
1+
package lwcomponent
22

33
import (
44
"fmt"
@@ -7,8 +7,10 @@ import (
77
"os"
88
"testing"
99

10-
"github.com/lacework/go-sdk/lwcomponent"
1110
"github.com/stretchr/testify/assert"
11+
12+
capturer "github.com/lacework/go-sdk/internal/capturer"
13+
"github.com/lacework/go-sdk/lwlogger"
1214
)
1315

1416
func TestDownloadFile(t *testing.T) {
@@ -33,7 +35,7 @@ func TestDownloadFile(t *testing.T) {
3335
})
3436

3537
t.Run("happy path", func(t *testing.T) {
36-
err = lwcomponent.DownloadFile(file.Name(), fmt.Sprintf("%s%s", server.URL, urlPath))
38+
err = DownloadFile(file.Name(), fmt.Sprintf("%s%s", server.URL, urlPath))
3739
assert.Nil(t, err)
3840

3941
buf, err := os.ReadFile(file.Name())
@@ -53,14 +55,33 @@ func TestDownloadFile(t *testing.T) {
5355
}
5456
})
5557

56-
err = lwcomponent.DownloadFile(file.Name(), fmt.Sprintf("%s%s", server.URL, "/err"))
58+
logsCaptured := capturer.CaptureOutput(func() {
59+
log = lwlogger.New("INFO").Sugar()
60+
err = DownloadFile(file.Name(), fmt.Sprintf("%s%s", server.URL, "/err"))
61+
})
5762
assert.NotNil(t, err)
58-
assert.Equal(t, lwcomponent.DefaultMaxRetry+1, count)
63+
assert.Equal(t, DefaultMaxRetry+1, count)
64+
65+
assert.Contains(t, logsCaptured, "WARN RESTY Get")
66+
assert.Contains(t, logsCaptured, "/err\": EOF")
67+
assert.Contains(t, logsCaptured, "Attempt 4") // the fifth attempt will error
68+
assert.Contains(t, logsCaptured, "ERROR RESTY Get")
69+
assert.Contains(t, logsCaptured, "Failed to download component")
70+
assert.Contains(t, logsCaptured, "trace_info")
5971
})
6072

6173
t.Run("url error", func(t *testing.T) {
62-
err = lwcomponent.DownloadFile(file.Name(), "")
74+
logsCaptured := capturer.CaptureOutput(func() {
75+
log = lwlogger.New("INFO").Sugar()
76+
err = DownloadFile(file.Name(), "")
77+
})
6378
assert.NotNil(t, err)
6479
assert.False(t, os.IsTimeout(err))
80+
81+
assert.Contains(t, logsCaptured, "WARN RESTY Get")
82+
assert.Contains(t, logsCaptured, "Attempt 4") // the fifth attempt will error
83+
assert.Contains(t, logsCaptured, "ERROR RESTY Get")
84+
assert.Contains(t, logsCaptured, "Failed to download component")
85+
assert.Contains(t, logsCaptured, "trace_info")
6586
})
6687
}

0 commit comments

Comments
 (0)