Skip to content

Commit fe9d168

Browse files
authored
feat: support to print the progress when oci download (#544)
Co-authored-by: rick <[email protected]>
1 parent af36027 commit fe9d168

File tree

10 files changed

+114
-22
lines changed

10 files changed

+114
-22
lines changed

atest-store-git

19.5 MB
Binary file not shown.

console/atest-ui/src/views/StoreManager.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ Magic.Keys(addStore, ['Alt+KeyN'])
112112
const rules = reactive<FormRules<Store>>({
113113
name: [{ required: true, message: 'Name is required', trigger: 'blur' }],
114114
url: [{ required: true, message: 'URL is required', trigger: 'blur' }],
115-
"kind.name": [{ required: true, message: 'Plugin is required', trigger: 'blur' }]
115+
pluginName: [{ required: true, message: 'Plugin is required', trigger: 'blur' }]
116116
})
117117
const submitForm = async (formEl: FormInstance | undefined) => {
118118
if (!formEl) return
@@ -185,7 +185,7 @@ function storeVerify(formEl: FormInstance | undefined) {
185185
ElMessage.error(e.message)
186186
}
187187
}, (e) => {
188-
ElMessage.error('Oops, ' + e)
188+
ElMessage.error(e.message)
189189
})
190190
}
191191

console/atest-ui/src/views/net-vue.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,8 @@ function CreateOrUpdateStore(payload: any, create: boolean,
4747
})
4848
}
4949

50-
function ErrorTip(e: {
51-
statusText:''
52-
}) {
53-
ElMessage.error('Oops, ' + e.statusText)
50+
const ErrorTip = (e: any) => {
51+
ElMessage.error(e.message)
5452
}
5553

5654
export const UIAPI = {

pkg/downloader/oci.go

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727
"time"
2828

2929
"github.com/blang/semver/v4"
30+
"github.com/linuxsuren/api-testing/pkg/util"
3031
)
3132

3233
type OCIDownloader interface {
@@ -95,7 +96,7 @@ func (d *defaultOCIDownloader) Download(image, tag, file string) (reader io.Read
9596
return
9697
}
9798

98-
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", authStr))
99+
req.Header.Set(util.Authorization, fmt.Sprintf("Bearer %s", authStr))
99100
req.Header.Set("Accept", "application/vnd.oci.image.manifest.v1+json")
100101

101102
var resp *http.Response
@@ -106,8 +107,12 @@ func (d *defaultOCIDownloader) Download(image, tag, file string) (reader io.Read
106107
err = fmt.Errorf("failed to get manifest from %q, status code: %d", api, resp.StatusCode)
107108
return
108109
} else {
110+
progressReader := NewProgressReader(resp.Body)
111+
progressReader.SetLength(resp.ContentLength)
112+
progressReader.SetTitle("Fetching manifest:")
113+
109114
var data []byte
110-
data, err = io.ReadAll(resp.Body)
115+
data, err = io.ReadAll(progressReader)
111116
if err != nil {
112117
return
113118
}
@@ -161,7 +166,7 @@ func (d *defaultOCIDownloader) getLatestTag(image, authToken string) (tag string
161166
return
162167
}
163168

164-
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", authToken))
169+
req.Header.Set(util.Authorization, fmt.Sprintf("Bearer %s", authToken))
165170
var resp *http.Response
166171
if resp, err = d.getHTTPClient().Do(req); err != nil {
167172
err = fmt.Errorf("failed to get image tags from %q, error: %v", req.URL, err)
@@ -170,8 +175,12 @@ func (d *defaultOCIDownloader) getLatestTag(image, authToken string) (tag string
170175
} else {
171176
defer resp.Body.Close()
172177

178+
progressReader := NewProgressReader(resp.Body)
179+
progressReader.SetLength(resp.ContentLength)
180+
progressReader.SetTitle("Fetching tags:")
181+
173182
var data []byte
174-
if data, err = io.ReadAll(resp.Body); err != nil {
183+
if data, err = io.ReadAll(progressReader); err != nil {
175184
return
176185
}
177186

@@ -214,13 +223,17 @@ func (d *defaultOCIDownloader) downloadLayer(image, digest, authToken string) (r
214223
return
215224
}
216225

217-
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", authToken))
226+
req.Header.Set(util.Authorization, fmt.Sprintf("Bearer %s", authToken))
218227
var resp *http.Response
219228
if resp, err = d.getHTTPClient().Do(req); err != nil {
220229
err = fmt.Errorf("failed to get layer from %q, error: %v", req.URL.String(), err)
221230
} else {
231+
progressReader := NewProgressReader(resp.Body)
232+
progressReader.SetLength(resp.ContentLength)
233+
progressReader.SetTitle("Fetching Layer:")
234+
222235
var data []byte
223-
if data, err = io.ReadAll(resp.Body); err != nil {
236+
if data, err = io.ReadAll(progressReader); err != nil {
224237
return
225238
}
226239

pkg/downloader/progress.go

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/*
2+
Copyright 2024 API Testing Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package downloader
18+
19+
import (
20+
"fmt"
21+
"io"
22+
"os"
23+
)
24+
25+
type ProgressReader interface {
26+
io.Reader
27+
Withoutput(io.Writer)
28+
SetLength(int64)
29+
SetTitle(string)
30+
}
31+
32+
type defaultProgressReader struct {
33+
reader io.Reader
34+
w io.Writer
35+
total int64
36+
current int
37+
lastPercent int64
38+
title string
39+
}
40+
41+
var _ io.Reader = (*defaultProgressReader)(nil)
42+
43+
func NewProgressReader(r io.Reader) ProgressReader {
44+
return &defaultProgressReader{
45+
reader: r,
46+
w: os.Stdout,
47+
}
48+
}
49+
50+
func (r *defaultProgressReader) SetTitle(title string) {
51+
r.title = title
52+
}
53+
54+
func (r *defaultProgressReader) Read(p []byte) (count int, err error) {
55+
count, err = r.reader.Read(p)
56+
if r.total > 0 {
57+
if count > 0 {
58+
r.current += count
59+
newPercent := int64(r.current*100) / r.total
60+
if newPercent != int64(r.lastPercent) {
61+
r.lastPercent = newPercent
62+
fmt.Fprintf(r.w, "%s\t%d%%\n", r.title, newPercent)
63+
}
64+
}
65+
} else {
66+
fmt.Fprintf(r.w, "%d\n", count)
67+
}
68+
return
69+
}
70+
71+
func (r *defaultProgressReader) Withoutput(w io.Writer) {
72+
r.w = w
73+
}
74+
75+
func (r *defaultProgressReader) SetLength(len int64) {
76+
r.total = len
77+
}

pkg/runner/kubernetes/client.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ func (r *defualtReader) request(api string) (result map[string]interface{}, err
5151
client := GetClient()
5252
var req *http.Request
5353
if req, err = http.NewRequest(http.MethodGet, api, nil); err == nil {
54-
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", r.token))
54+
req.Header.Add(util.Authorization, fmt.Sprintf("Bearer %s", r.token))
5555
var resp *http.Response
5656
if resp, err = client.Do(req); err == nil && resp.StatusCode == http.StatusOK {
5757
var data []byte

pkg/runner/kubernetes/verify_test.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -100,39 +100,39 @@ func TestKubernetesValidatorFunc(t *testing.T) {
100100
func preparePod() {
101101
gock.New(urlFoo).
102102
Get("/api/v1/namespaces/ns/pods/foo").
103-
MatchHeader("Authorization", defaultToken).
103+
MatchHeader(util.Authorization, defaultToken).
104104
Reply(http.StatusOK).
105105
JSON(`{"kind":"pod"}`)
106106
}
107107

108108
func prepareDeploy() {
109109
gock.New(urlFoo).
110110
Get("/apis/apps/v1/namespaces/ns/deployments/foo").
111-
MatchHeader("Authorization", defaultToken).
111+
MatchHeader(util.Authorization, defaultToken).
112112
Reply(http.StatusOK).
113113
JSON(`{"kind":"deploy"}`)
114114
}
115115

116116
func prepareStatefulset() {
117117
gock.New(urlFoo).
118118
Get("/apis/apps/v1/namespaces/ns/statefulsets/foo").
119-
MatchHeader("Authorization", defaultToken).
119+
MatchHeader(util.Authorization, defaultToken).
120120
Reply(http.StatusOK).
121121
JSON(`{"kind":"statefulset"}`)
122122
}
123123

124124
func prepareDaemonset() {
125125
gock.New(urlFoo).
126126
Get("/apis/apps/v1/namespaces/ns/daemonsets/foo").
127-
MatchHeader("Authorization", defaultToken).
127+
MatchHeader(util.Authorization, defaultToken).
128128
Reply(http.StatusOK).
129129
JSON(`{"kind":"daemonset","items":[]}`)
130130
}
131131

132132
func prepareCRDVM() {
133133
gock.New(urlFoo).
134134
Get("/apis/bar/v2/namespaces/ns/vms/foo").
135-
MatchHeader("Authorization", defaultToken).
135+
MatchHeader(util.Authorization, defaultToken).
136136
Reply(http.StatusOK).
137137
JSON(`{"kind":"vm"}`)
138138
}

pkg/runner/writer_github_pr_comment.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ func (w *githubPRCommentWriter) sendRequest(req *http.Request) (resp *http.Respo
180180
}
181181

182182
func (w *githubPRCommentWriter) setHeader(req *http.Request) {
183-
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", w.Token))
183+
req.Header.Set(util.Authorization, fmt.Sprintf("Bearer %s", w.Token))
184184
req.Header.Set("Accept", "application/vnd.github+json")
185185
req.Header.Set("X-GitHub-Api-Version", "2022-11-28")
186186
}

pkg/server/remote_server_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ func TestFindParentTestCases(t *testing.T) {
188188
testcase: &atest.TestCase{
189189
Request: atest.Request{
190190
Header: map[string]string{
191-
"Authorization": BearerToken,
191+
util.Authorization: BearerToken,
192192
},
193193
},
194194
},
@@ -252,7 +252,7 @@ func TestFindParentTestCases(t *testing.T) {
252252
Request: atest.Request{
253253
API: "/users/{{(index .users 0).name}}{{randomKubernetesName}}",
254254
Header: map[string]string{
255-
"Authorization": BearerToken,
255+
util.Authorization: BearerToken,
256256
},
257257
},
258258
},
@@ -269,7 +269,7 @@ func TestFindParentTestCases(t *testing.T) {
269269
Request: atest.Request{
270270
API: "/users/{{(index .users 0).name}}",
271271
Header: map[string]string{
272-
"Authorization": BearerToken,
272+
util.Authorization: BearerToken,
273273
},
274274
},
275275
}},

pkg/server/store_ext_manager.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package server
1818
import (
1919
"context"
2020
"errors"
21+
"fmt"
2122
"io"
2223
"net/http"
2324
"os"
@@ -98,6 +99,7 @@ func (s *storeExtManager) Start(name, socket string) (err error) {
9899
} else {
99100
binaryPath, err = s.execer.LookPath(name)
100101
if err != nil {
102+
err = fmt.Errorf("not found extension, try to download it.")
101103
go func() {
102104
reader, dErr := s.ociDownloader.Download(name, "", "")
103105
if dErr != nil {
@@ -125,6 +127,8 @@ func (s *storeExtManager) Start(name, socket string) (err error) {
125127

126128
func (s *storeExtManager) startPlugin(socketURL, plugin, pluginName string) (err error) {
127129
socketFile := strings.TrimPrefix(socketURL, s.socketPrefix)
130+
_ = os.RemoveAll(socketFile) // always deleting the socket file to avoid start failing
131+
128132
s.filesNeedToBeRemoved = append(s.filesNeedToBeRemoved, socketFile)
129133
s.extStatusMap[pluginName] = true
130134
if err = s.execer.RunCommandWithIO(plugin, "", os.Stdout, os.Stderr, s.processChan, "--socket", socketFile); err != nil {

0 commit comments

Comments
 (0)