-
Notifications
You must be signed in to change notification settings - Fork 1.2k
/
Copy pathindexer.go
150 lines (135 loc) · 4.25 KB
/
indexer.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
package client
import (
"bytes"
"context"
"encoding/json"
"fmt"
"net/http"
"path"
"github.com/quay/claircore"
clairerror "github.com/quay/clair/v4/clair-error"
"github.com/quay/clair/v4/httptransport"
"github.com/quay/clair/v4/indexer"
)
var _ indexer.Service = (*HTTP)(nil)
func (s *HTTP) AffectedManifests(ctx context.Context, v []claircore.Vulnerability) (*claircore.AffectedManifests, error) {
var affected claircore.AffectedManifests
buf := bytes.NewBuffer([]byte{})
err := json.NewEncoder(buf).Encode(struct {
V []claircore.Vulnerability `json:"vulnerabilities"`
}{
v,
})
if err != nil {
return nil, &clairerror.ErrBadVulnerabilities{err}
}
u, err := s.addr.Parse(httptransport.AffectedManifestAPIPath)
if err != nil {
return nil, fmt.Errorf("failed to parse api address: %v", err)
}
req, err := http.NewRequestWithContext(ctx, "POST", u.String(), buf)
if err != nil {
return nil, fmt.Errorf("failed to create request: %v", err)
}
resp, err := s.c.Do(req)
if resp != nil {
defer resp.Body.Close()
}
if err != nil {
return nil, &clairerror.ErrRequestFail{Code: resp.StatusCode, Status: resp.Status}
}
err = json.NewDecoder(resp.Body).Decode(&affected)
if err != nil {
return nil, &clairerror.ErrBadAffectedManifests{err}
}
return &affected, nil
}
// Index receives a Manifest and returns a IndexReport providing the indexed
// items in the resulting image.
//
// Index blocks until completion. An error is returned if the index operation
// could not start. If an error occurs during the index operation the error will
// be preset on the IndexReport.Err field of the returned IndexReport.
func (s *HTTP) Index(ctx context.Context, manifest *claircore.Manifest) (*claircore.IndexReport, error) {
buf := bytes.NewBuffer([]byte{})
err := json.NewEncoder(buf).Encode(manifest)
if err != nil {
return nil, &clairerror.ErrBadManifest{err}
}
u, err := s.addr.Parse(httptransport.IndexAPIPath)
if err != nil {
return nil, fmt.Errorf("failed to create request: %v", err)
}
req, err := http.NewRequestWithContext(ctx, "POST", u.String(), buf)
if err != nil {
return nil, fmt.Errorf("failed to create request: %v", err)
}
resp, err := s.c.Do(req)
if resp != nil {
defer resp.Body.Close()
}
if err != nil {
return nil, fmt.Errorf("failed to do request: %v", err)
}
if resp.StatusCode != http.StatusOK {
return nil, &clairerror.ErrRequestFail{Code: resp.StatusCode, Status: resp.Status}
}
var sr *claircore.IndexReport
err = json.NewDecoder(resp.Body).Decode(sr)
if err != nil {
return nil, &clairerror.ErrBadIndexReport{err}
}
return sr, nil
}
// IndexReport retrieves a IndexReport given a manifest hash string
func (s *HTTP) IndexReport(ctx context.Context, manifest claircore.Digest) (*claircore.IndexReport, bool, error) {
u, err := s.addr.Parse(path.Join(httptransport.IndexReportAPIPath, manifest.String()))
if err != nil {
return nil, false, fmt.Errorf("failed to create request: %v", err)
}
req, err := http.NewRequestWithContext(ctx, "GET", u.String(), nil)
if err != nil {
return nil, false, fmt.Errorf("failed to create request: %v", err)
}
resp, err := s.c.Do(req)
if resp != nil {
defer resp.Body.Close()
}
if err != nil {
return nil, false, fmt.Errorf("failed to do request: %v", err)
}
if resp.StatusCode == http.StatusNotFound {
return nil, false, nil
}
if resp.StatusCode != http.StatusOK {
return nil, false, &clairerror.ErrIndexReportRetrieval{&clairerror.ErrRequestFail{Code: resp.StatusCode, Status: resp.Status}}
}
ir := &claircore.IndexReport{}
err = json.NewDecoder(resp.Body).Decode(ir)
if err != nil {
return nil, false, &clairerror.ErrBadIndexReport{err}
}
return ir, true, nil
}
func (s *HTTP) State(ctx context.Context) (string, error) {
u, err := s.addr.Parse(httptransport.IndexStateAPIPath)
if err != nil {
return "", fmt.Errorf("failed to create request: %v", err)
}
req, err := http.NewRequestWithContext(ctx, "GET", u.String(), nil)
if err != nil {
return "", fmt.Errorf("failed to create request: %v", err)
}
resp, err := s.c.Do(req)
if resp != nil {
defer resp.Body.Close()
}
if err != nil {
return "", fmt.Errorf("failed to do request: %v", err)
}
buf := &bytes.Buffer{}
if _, err := buf.ReadFrom(resp.Body); err != nil {
return "", err
}
return buf.String(), nil
}