Skip to content

Commit 1064243

Browse files
feat: Expose if plugin was downloaded or cached (#341)
* feat: Expose if plugin was downloaded or cached * Implement my own review comments. * Implement review comments. * Fix some outdated naming. --------- Co-authored-by: Mariano Gappa <[email protected]>
1 parent a8a3850 commit 1064243

File tree

4 files changed

+92
-31
lines changed

4 files changed

+92
-31
lines changed

managedplugin/download.go

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -131,12 +131,15 @@ type DownloaderOptions struct {
131131
NoProgress bool
132132
}
133133

134-
func DownloadPluginFromHub(ctx context.Context, c *cloudquery_api.ClientWithResponses, ops HubDownloadOptions, dops DownloaderOptions) error {
135-
downloadDir := filepath.Dir(ops.LocalPath)
134+
func DownloadPluginFromHub(ctx context.Context, c *cloudquery_api.ClientWithResponses, ops HubDownloadOptions, dops DownloaderOptions) (AssetSource, error) {
136135
if _, err := os.Stat(ops.LocalPath); err == nil {
137-
return nil
136+
return AssetSourceCached, nil
138137
}
138+
return AssetSourceRemote, doDownloadPluginFromHub(ctx, c, ops, dops)
139+
}
139140

141+
func doDownloadPluginFromHub(ctx context.Context, c *cloudquery_api.ClientWithResponses, ops HubDownloadOptions, dops DownloaderOptions) error {
142+
downloadDir := filepath.Dir(ops.LocalPath)
140143
if err := os.MkdirAll(downloadDir, 0755); err != nil {
141144
return fmt.Errorf("failed to create plugin directory %s: %w", downloadDir, err)
142145
}
@@ -239,13 +242,16 @@ func downloadPluginAssetFromHub(ctx context.Context, c *cloudquery_api.ClientWit
239242
}
240243
}
241244

242-
func DownloadPluginFromGithub(ctx context.Context, logger zerolog.Logger, localPath string, org string, name string, version string, typ PluginType, dops DownloaderOptions) error {
243-
downloadDir := filepath.Dir(localPath)
244-
pluginZipPath := localPath + ".zip"
245-
245+
func DownloadPluginFromGithub(ctx context.Context, logger zerolog.Logger, localPath string, org string, name string, version string, typ PluginType, dops DownloaderOptions) (AssetSource, error) {
246246
if _, err := os.Stat(localPath); err == nil {
247-
return nil
247+
return AssetSourceCached, nil
248248
}
249+
return AssetSourceRemote, doDownloadPluginFromGithub(ctx, logger, localPath, org, name, version, typ, dops)
250+
}
251+
252+
func doDownloadPluginFromGithub(ctx context.Context, logger zerolog.Logger, localPath string, org string, name string, version string, typ PluginType, dops DownloaderOptions) error {
253+
downloadDir := filepath.Dir(localPath)
254+
pluginZipPath := localPath + ".zip"
249255

250256
if err := os.MkdirAll(downloadDir, 0755); err != nil {
251257
return fmt.Errorf("failed to create plugin directory %s: %w", downloadDir, err)

managedplugin/download_test.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,10 @@ func TestDownloadPluginFromGithubIntegration(t *testing.T) {
2929
logger := zerolog.Logger{}
3030
for _, tc := range cases {
3131
t.Run(tc.name, func(t *testing.T) {
32-
err := DownloadPluginFromGithub(context.Background(), logger, path.Join(tmp, tc.name), tc.org, tc.plugin, tc.version, tc.typ, DownloaderOptions{})
32+
assetSource, err := DownloadPluginFromGithub(context.Background(), logger, path.Join(tmp, tc.name), tc.org, tc.plugin, tc.version, tc.typ, DownloaderOptions{})
33+
if assetSource != AssetSourceRemote {
34+
t.Errorf("DownloadPluginFromGithub() got = %v, want %v", assetSource, AssetSourceRemote)
35+
}
3336
if (err != nil) != tc.wantErr {
3437
t.Errorf("DownloadPluginFromGithub() error = %v, wantErr %v", err, tc.wantErr)
3538
return
@@ -56,7 +59,7 @@ func TestDownloadPluginFromCloudQueryHub(t *testing.T) {
5659
}
5760
for _, tc := range cases {
5861
t.Run(tc.testName, func(t *testing.T) {
59-
err := DownloadPluginFromHub(context.Background(), c, HubDownloadOptions{
62+
assetSource, err := DownloadPluginFromHub(context.Background(), c, HubDownloadOptions{
6063
LocalPath: path.Join(tmp, tc.testName),
6164
AuthToken: "",
6265
TeamName: "",
@@ -67,6 +70,9 @@ func TestDownloadPluginFromCloudQueryHub(t *testing.T) {
6770
},
6871
DownloaderOptions{},
6972
)
73+
if assetSource != AssetSourceRemote {
74+
t.Errorf("TestDownloadPluginFromCloudQueryIntegration() got = %v, want %v", assetSource, AssetSourceRemote)
75+
}
7076
if (err != nil) != tc.wantErr {
7177
t.Errorf("TestDownloadPluginFromCloudQueryIntegration() error = %v, wantErr %v", err, tc.wantErr)
7278
return

managedplugin/metrics.go

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,53 @@
11
package managedplugin
22

3-
import "sync/atomic"
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"sync/atomic"
7+
)
8+
9+
type AssetSource int
10+
11+
const (
12+
AssetSourceUnknown AssetSource = iota
13+
AssetSourceCached
14+
AssetSourceRemote
15+
)
16+
17+
func (r AssetSource) String() string {
18+
return [...]string{"unknown", "cached", "remote"}[r]
19+
}
20+
21+
func (r AssetSource) MarshalJSON() ([]byte, error) {
22+
return []byte(fmt.Sprintf(`"%s"`, r.String())), nil
23+
}
24+
25+
func (r *AssetSource) UnmarshalJSON(data []byte) (err error) {
26+
var mode string
27+
if err := json.Unmarshal(data, &mode); err != nil {
28+
return err
29+
}
30+
if *r, err = AssetSourceFromString(mode); err != nil {
31+
return err
32+
}
33+
return nil
34+
}
35+
36+
func AssetSourceFromString(s string) (AssetSource, error) {
37+
switch s {
38+
case "cached":
39+
return AssetSourceCached, nil
40+
case "remote":
41+
return AssetSourceRemote, nil
42+
default:
43+
return AssetSourceUnknown, fmt.Errorf("unknown mode %s", s)
44+
}
45+
}
446

547
type Metrics struct {
6-
Errors uint64
7-
Warnings uint64
48+
Errors uint64
49+
Warnings uint64
50+
AssetSource AssetSource
851
}
952

1053
func (m *Metrics) incrementErrors() {

managedplugin/plugin.go

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -151,9 +151,13 @@ func NewClient(ctx context.Context, typ PluginType, config Config, opts ...Optio
151151
for _, opt := range opts {
152152
opt(c)
153153
}
154-
if err := c.downloadPlugin(ctx, typ); err != nil {
154+
assetSource, err := c.downloadPlugin(ctx, typ)
155+
if err != nil {
155156
return nil, err
156157
}
158+
if assetSource != AssetSourceUnknown {
159+
c.metrics.AssetSource = assetSource
160+
}
157161
if !c.noExec {
158162
if err := c.execPlugin(ctx); err != nil {
159163
return nil, err
@@ -163,35 +167,36 @@ func NewClient(ctx context.Context, typ PluginType, config Config, opts ...Optio
163167
return c, nil
164168
}
165169

166-
func (c *Client) downloadPlugin(ctx context.Context, typ PluginType) error {
170+
func (c *Client) downloadPlugin(ctx context.Context, typ PluginType) (AssetSource, error) {
167171
dops := DownloaderOptions{
168172
NoProgress: c.noProgress,
169173
}
170174
switch c.config.Registry {
171175
case RegistryGrpc:
172-
return nil // GRPC plugins are not downloaded
176+
return AssetSourceUnknown, nil // GRPC plugins are not downloaded
173177
case RegistryLocal:
174-
return validateLocalExecPath(c.config.Path)
178+
return AssetSourceUnknown, validateLocalExecPath(c.config.Path)
175179
case RegistryGithub:
176180
pathSplit := strings.Split(c.config.Path, "/")
177181
if len(pathSplit) != 2 {
178-
return fmt.Errorf("invalid github plugin path: %s. format should be owner/repo", c.config.Path)
182+
return AssetSourceUnknown, fmt.Errorf("invalid github plugin path: %s. format should be owner/repo", c.config.Path)
179183
}
180184
org, name := pathSplit[0], pathSplit[1]
181185
c.LocalPath = filepath.Join(c.directory, "plugins", typ.String(), org, name, c.config.Version, "plugin")
182186
c.LocalPath = WithBinarySuffix(c.LocalPath)
183-
return DownloadPluginFromGithub(ctx, c.logger, c.LocalPath, org, name, c.config.Version, typ, dops)
187+
assetSource, err := DownloadPluginFromGithub(ctx, c.logger, c.LocalPath, org, name, c.config.Version, typ, dops)
188+
return assetSource, err
184189
case RegistryDocker:
185190
if imageAvailable, err := isDockerImageAvailable(ctx, c.config.Path); err != nil {
186-
return err
191+
return AssetSourceUnknown, err
187192
} else if !imageAvailable {
188-
return pullDockerImage(ctx, c.config.Path, c.authToken, c.teamName, c.dockerAuth, dops)
193+
return AssetSourceRemote, pullDockerImage(ctx, c.config.Path, c.authToken, c.teamName, c.dockerAuth, dops)
189194
}
190-
return nil
195+
return AssetSourceCached, nil
191196
case RegistryCloudQuery:
192197
pathSplit := strings.Split(c.config.Path, "/")
193198
if len(pathSplit) != 2 {
194-
return fmt.Errorf("invalid cloudquery plugin path: %s. format should be team/name", c.config.Path)
199+
return AssetSourceUnknown, fmt.Errorf("invalid cloudquery plugin path: %s. format should be team/name", c.config.Path)
195200
}
196201
org, name := pathSplit[0], pathSplit[1]
197202
c.LocalPath = filepath.Join(c.directory, "plugins", typ.String(), org, name, c.config.Version, "plugin")
@@ -208,26 +213,26 @@ func (c *Client) downloadPlugin(ctx context.Context, typ PluginType) error {
208213
}
209214
hubClient, err := getHubClient(c.logger, ops)
210215
if err != nil {
211-
return err
216+
return AssetSourceUnknown, err
212217
}
213218
isDocker, err := isDockerPlugin(ctx, hubClient, ops)
214219
if err != nil {
215-
return err
220+
return AssetSourceUnknown, err
216221
}
217222
if isDocker {
218223
path := fmt.Sprintf(c.cqDockerHost+"/%s/%s-%s:%s", ops.PluginTeam, ops.PluginKind, ops.PluginName, ops.PluginVersion)
219224
c.config.Registry = RegistryDocker // will be used by exec step
220225
c.config.Path = path
221226
if imageAvailable, err := isDockerImageAvailable(ctx, path); err != nil {
222-
return err
227+
return AssetSourceUnknown, err
223228
} else if !imageAvailable {
224-
return pullDockerImage(ctx, path, c.authToken, c.teamName, "", dops)
229+
return AssetSourceRemote, pullDockerImage(ctx, path, c.authToken, c.teamName, "", dops)
225230
}
226-
return nil
231+
return AssetSourceCached, nil
227232
}
228233
return DownloadPluginFromHub(ctx, hubClient, ops, dops)
229234
default:
230-
return fmt.Errorf("unknown registry %s", c.config.Registry.String())
235+
return AssetSourceUnknown, fmt.Errorf("unknown registry %s", c.config.Registry.String())
231236
}
232237
}
233238

@@ -265,8 +270,9 @@ func (c *Client) ConnectionString() string {
265270

266271
func (c *Client) Metrics() Metrics {
267272
return Metrics{
268-
Errors: atomic.LoadUint64(&c.metrics.Errors),
269-
Warnings: atomic.LoadUint64(&c.metrics.Warnings),
273+
Errors: atomic.LoadUint64(&c.metrics.Errors),
274+
Warnings: atomic.LoadUint64(&c.metrics.Warnings),
275+
AssetSource: c.metrics.AssetSource,
270276
}
271277
}
272278

0 commit comments

Comments
 (0)