@@ -16,6 +16,7 @@ import (
1616 "github.com/google/go-containerregistry/pkg/v1/remote/transport"
1717 "github.com/quay/claircore"
1818 "github.com/quay/zlog"
19+ spdxtools "github.com/spdx/tools-golang/spdx/v2/v2_3"
1920 "github.com/tomnomnom/linkheader"
2021
2122 "github.com/quay/clair/v4/cmd"
@@ -105,7 +106,28 @@ var (
105106 errNovelManifest = errors .New ("manifest unknown to the system" )
106107)
107108
108- func (c * Client ) IndexReport (ctx context.Context , id claircore.Digest , m * claircore.Manifest ) error {
109+ func (c * Client ) SPDXReport (ctx context.Context , id claircore.Digest , m * claircore.Manifest ) (* spdxtools.Document , error ) {
110+ var report = spdxtools.Document {}
111+ err := c .GetIndexReport (ctx , id , m , & report , "application/spdx+json" )
112+ if err != nil {
113+ return nil , err
114+ }
115+ return & report , nil
116+ }
117+
118+ func (c * Client ) IndexReport (ctx context.Context , id claircore.Digest , m * claircore.Manifest ) (* claircore.IndexReport , error ) {
119+ var report = claircore.IndexReport {}
120+ err := c .GetIndexReport (ctx , id , m , & report , "application/json" )
121+ if err != nil {
122+ return nil , err
123+ }
124+ if ! report .Success && report .Err != "" {
125+ return nil , errors .New ("indexer error: " + report .Err )
126+ }
127+ return & report , nil
128+ }
129+
130+ func (c * Client ) GetIndexReport (ctx context.Context , id claircore.Digest , m * claircore.Manifest , dest interface {}, mediaType string ) error {
109131 var (
110132 req * http.Request
111133 res * http.Response
@@ -121,6 +143,7 @@ func (c *Client) IndexReport(ctx context.Context, id claircore.Digest, m *clairc
121143 if err != nil {
122144 return err
123145 }
146+ req .Header .Add ("Accept" , mediaType )
124147 res , err = c .client .Do (req )
125148 if err != nil {
126149 zlog .Debug (ctx ).
@@ -130,97 +153,90 @@ func (c *Client) IndexReport(ctx context.Context, id claircore.Digest, m *clairc
130153 return err
131154 }
132155 defer res .Body .Close ()
133- ev := zlog .Debug (ctx ).
156+ zlog .Debug (ctx ).
134157 Str ("method" , res .Request .Method ).
135158 Str ("path" , res .Request .URL .Path ).
136159 Str ("status" , res .Status )
137- if ev .Enabled () && res .ContentLength > 0 && res .ContentLength <= 256 {
138- var buf bytes.Buffer
139- buf .ReadFrom (io .LimitReader (res .Body , 256 ))
140- ev .Stringer ("body" , & buf )
141- }
142- ev .Send ()
143- switch res .StatusCode {
144- case http .StatusNotFound , http .StatusOK :
145- case http .StatusNotModified :
146- return nil
147- default :
148- return fmt .Errorf ("unexpected return status: %d" , res .StatusCode )
149- }
150160
151- if m == nil {
152- ev := zlog .Debug (ctx ).
153- Stringer ("manifest" , id )
154- if res .StatusCode == http .StatusNotFound {
155- ev .Msg ("don't have needed manifest" )
156- return errNovelManifest
161+ var rd io.Reader
162+ switch res .StatusCode {
163+ case http .StatusOK , http .StatusNotModified :
164+ rd = res .Body
165+ case http .StatusNotFound :
166+ if m == nil {
167+ ev := zlog .Debug (ctx ).
168+ Stringer ("manifest" , id )
169+ if res .StatusCode == http .StatusNotFound {
170+ ev .Msg ("don't have needed manifest" )
171+ return errNovelManifest
172+ }
173+ ev .Msg ("manifest may be out-of-date" )
174+ return errNeedManifest
175+ }
176+ ru , err := c .host .Parse (path .Join (c .host .RequestURI (), httptransport .IndexAPIPath ))
177+ if err != nil {
178+ zlog .Debug (ctx ).
179+ Err (err ).
180+ Msg ("unable to construct index_report url" )
181+ return err
157182 }
158- ev .Msg ("manifest may be out-of-date" )
159- return errNeedManifest
160- }
161- ru , err := c .host .Parse (path .Join (c .host .RequestURI (), httptransport .IndexAPIPath ))
162- if err != nil {
163- zlog .Debug (ctx ).
164- Err (err ).
165- Msg ("unable to construct index_report url" )
166- return err
167- }
168183
169- req , err = c .request (ctx , ru , http .MethodPost )
170- if err != nil {
171- return err
172- }
173- req .Body = codec .JSONReader (m )
174- res , err = c .client .Do (req )
175- if err != nil {
184+ req , err = c .request (ctx , ru , http .MethodPost )
185+ if err != nil {
186+ return err
187+ }
188+ req .Header .Add ("Accept" , mediaType )
189+ req .Body = codec .JSONReader (m )
190+ res , err = c .client .Do (req )
191+ if err != nil {
192+ zlog .Debug (ctx ).
193+ Err (err ).
194+ Stringer ("url" , req .URL ).
195+ Msg ("request failed" )
196+ return err
197+ }
198+ defer res .Body .Close ()
176199 zlog .Debug (ctx ).
177- Err (err ).
178- Stringer ("url" , req .URL ).
179- Msg ("request failed" )
180- return err
181- }
182- defer res .Body .Close ()
183- zlog .Debug (ctx ).
184- Str ("method" , res .Request .Method ).
185- Str ("path" , res .Request .URL .Path ).
186- Str ("status" , res .Status ).
187- Send ()
188- switch res .StatusCode {
189- case http .StatusOK :
190- case http .StatusCreated :
191- //
200+ Str ("method" , res .Request .Method ).
201+ Str ("path" , res .Request .URL .Path ).
202+ Str ("status" , res .Status ).
203+ Send ()
204+ switch res .StatusCode {
205+ case http .StatusOK :
206+ case http .StatusCreated :
207+ //
208+ default :
209+ return fmt .Errorf ("unexpected return status: %d" , res .StatusCode )
210+ }
211+ switch {
212+ case res .ContentLength > 0 && res .ContentLength < 32 + 9 :
213+ // Less than the size of the digest representation, something's up.
214+ var buf bytes.Buffer
215+ // Ignore error, because what would we do with it here?
216+ ct , _ := buf .ReadFrom (res .Body )
217+ zlog .Info (ctx ).
218+ Int64 ("size" , ct ).
219+ Stringer ("response" , & buf ).
220+ Msg ("body seems short" )
221+ return fmt .Errorf ("body seems short: %d bytes" , ct )
222+ case res .ContentLength < 0 : // Streaming
223+ fallthrough
224+ default :
225+ rd = res .Body
226+ }
192227 default :
193228 return fmt .Errorf ("unexpected return status: %d" , res .StatusCode )
194229 }
195- var rd io.Reader
196- switch {
197- case res .ContentLength > 0 && res .ContentLength < 32 + 9 :
198- // Less than the size of the digest representation, something's up.
199- var buf bytes.Buffer
200- // Ignore error, because what would we do with it here?
201- ct , _ := buf .ReadFrom (res .Body )
202- zlog .Info (ctx ).
203- Int64 ("size" , ct ).
204- Stringer ("response" , & buf ).
205- Msg ("body seems short" )
206- rd = & buf
207- case res .ContentLength < 0 : // Streaming
208- fallthrough
209- default :
210- rd = res .Body
211- }
212- var report claircore.IndexReport
230+
213231 dec := codec .GetDecoder (rd )
214232 defer codec .PutDecoder (dec )
215- if err := dec .Decode (& report ); err != nil {
233+ if err := dec .Decode (& dest ); err != nil {
216234 zlog .Debug (ctx ).
217235 Err (err ).
218236 Msg ("unable to decode json payload" )
219237 return err
220238 }
221- if ! report .Success && report .Err != "" {
222- return errors .New ("indexer error: " + report .Err )
223- }
239+
224240 if v := res .Header .Get ("etag" ); v != "" {
225241 ls := linkheader .ParseMultiple (res .Header [http .CanonicalHeaderKey ("link" )]).
226242 FilterByRel ("https://projectquay.io/clair/v1/index_report" )
@@ -232,6 +248,7 @@ func (c *Client) IndexReport(ctx context.Context, id claircore.Digest, m *clairc
232248 c .setValidator (ctx , u .Path , v )
233249 }
234250 }
251+
235252 return nil
236253}
237254
0 commit comments