Skip to content

Commit

Permalink
adding a new updateImage method to enable partners to re-run prefligh…
Browse files Browse the repository at this point in the history
…t if there are pyxis errors during our checks

Signed-off-by: Adam D. Cornett <adc@redhat.com>
  • Loading branch information
acornett21 authored and bcrochet committed Sep 23, 2022
1 parent a32ad27 commit 82aca79
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 0 deletions.
45 changes: 45 additions & 0 deletions certification/pyxis/pyxis.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,51 @@ func (p *pyxisClient) getImage(ctx context.Context, dockerImageDigest string) (*
return &data.Data[0], nil
}

// updateImage updates a given certification image based on how the image is built in the `submit` flow
func (p *pyxisClient) updateImage(ctx context.Context, certImage *CertImage) (*CertImage, error) {
// instantiating a patchCertImage struct, so we only send the minimum fields required to pyxis
patchCertImage := &CertImage{
ID: certImage.ID,
Architecture: certImage.Architecture,
Certified: certImage.Certified,
}

b, err := json.Marshal(patchCertImage)
if err != nil {
return nil, fmt.Errorf("could not marshal certImage: %w", err)
}
req, err := p.newRequestWithAPIToken(ctx, http.MethodPatch, p.getPyxisURL(fmt.Sprintf("images/id/%s", patchCertImage.ID)), bytes.NewReader(b))
if err != nil {
return nil, err
}

resp, err := p.Client.Do(req)
if err != nil {
return nil, fmt.Errorf("cannot update image in pyxis: %w", err)
}

defer resp.Body.Close()

body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("could not read response body: %w", err)
}

if ok := checkStatus(resp.StatusCode); !ok {
return nil, fmt.Errorf(
"status code: %d: body: %s",
resp.StatusCode,
string(body))
}

var updatedCertImage CertImage
if err := json.Unmarshal(body, &updatedCertImage); err != nil {
return nil, fmt.Errorf("could not unmarshal body: %s: %w", string(body), err)
}

return &updatedCertImage, nil
}

// FindImagesByDigest uses an unauthenticated call to find_images() graphql function, and will
// return a slice of CertImages. It accepts a slice of image digests. The query return is then
// packed into the slice of CertImages.
Expand Down
11 changes: 11 additions & 0 deletions certification/pyxis/pyxis_suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"io"
"net/http"
"net/http/httptest"
"strings"
"testing"

. "github.com/onsi/ginkgo/v2/dsl/core"
Expand Down Expand Up @@ -90,6 +91,14 @@ func (p *pyxisImageHandler) ServeHTTP(response http.ResponseWriter, request *htt
responseString := `{"_id":"blah","certified":false,"deleted":false,"image_id":"123456789abc"}`
log.Tracef("Method: %s", request.Method)
switch {
case request.Method == http.MethodPost && strings.Contains(request.Header["X-Api-Key"][0], "my-update-image"):
response.WriteHeader(http.StatusConflict)
case request.Method == http.MethodGet && strings.Contains(request.Header["X-Api-Key"][0], "my-update-image"):
mustWrite(response, `{"data":[{"_id":"updateImage","certified":false,"deleted":false,"image_id":"123456789abc"}]}`)
case request.Method == http.MethodPatch && request.Header["X-Api-Key"][0] == "my-update-image-success-api-token":
mustWrite(response, `{"_id":"updateImage","certified":true,"deleted":false,"image_id":"123456789abc"}`)
case request.Method == http.MethodPatch && request.Header["X-Api-Key"][0] == "my-update-image-failure-api-token":
response.WriteHeader(http.StatusInternalServerError)
case request.Method == http.MethodPost && request.Header["X-Api-Key"][0] == "my-image-409-api-token":
response.WriteHeader(http.StatusConflict)
case request.Method == http.MethodPost && request.Header["X-Api-Key"][0] == "my-bad-401-image-api-token":
Expand Down Expand Up @@ -128,6 +137,8 @@ func (p *pyxisRPMManifestHandler) ServeHTTP(response http.ResponseWriter, reques
response.WriteHeader(http.StatusUnauthorized)
case request.Header["X-Api-Key"][0] == "my-bad-rpmmanifest-api-token":
response.WriteHeader(http.StatusUnauthorized)
case request.Method == http.MethodPost && request.Header["X-Api-Key"][0] == "my-update-image-success-api-token":
mustWrite(response, `{"_id":"updateImage"}`)
default:
mustWrite(response, `{"_id":"blah"}`)
}
Expand Down
16 changes: 16 additions & 0 deletions certification/pyxis/submit.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ func (p *pyxisClient) SubmitResults(ctx context.Context, certInput *Certificatio
// in the event that it exists. createImage will wipe it otherwise.
originalImageDigest := certImage.DockerImageDigest

// store the certification status for this execution, in case a previous execution failed and we need to patch the image
certified := certInput.CertImage.Certified

// normalizing index.docker.io to docker.io for the certImage
certImage.Repositories[0].Registry = normalizeDockerRegistry(certImage.Repositories[0].Registry)

Expand All @@ -68,6 +71,19 @@ func (p *pyxisClient) SubmitResults(ctx context.Context, certInput *Certificatio
if err != nil {
return nil, fmt.Errorf("could not get image: %v", err)
}

// checking to see if the original value is certified and the previous value is not certified,
// this would indicate that a partner is running preflight again, and during the first run there was a timeout/error
// in a check that interacts with pyxis and we need to correct the certified value for the image
if certified && !certImage.Certified {
// change the certified value to `true`
certImage.Certified = certified

certImage, err = p.updateImage(ctx, certImage)
if err != nil {
return nil, fmt.Errorf("could not update image: %v", err)
}
}
}

// Create the RPM manifest, or get it if it already exists.
Expand Down
40 changes: 40 additions & 0 deletions certification/pyxis/submit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ var _ = Describe("Pyxis Submit", func() {
mux.Handle("/api/v1/projects/certification/id/my-awesome-project-id/test-results", &pyxisTestResultsHandler{})
mux.Handle("/api/v1/projects/certification/id/my-image-project-id/images", &pyxisImageHandler{})
mux.Handle("/api/v1/projects/certification/id/", &pyxisProjectHandler{})
mux.Handle("/api/v1/images/id/updateImage", &pyxisImageHandler{})
mux.Handle("/api/v1/images/id/blah/", &pyxisRPMManifestHandler{})
mux.Handle("/api/v1/images/id/updateImage/", &pyxisImageHandler{})
mux.Handle("/api/v1/images", &pyxisImageHandler{})

BeforeEach(func() {
Expand Down Expand Up @@ -170,6 +172,44 @@ var _ = Describe("Pyxis Submit", func() {
})
})

Context("createImage 409 Conflict, getImage 200, and updateImage 200", func() {
BeforeEach(func() {
pyxisClient.APIToken = "my-update-image-success-api-token"
pyxisClient.ProjectID = "my-image-project-id"
certInput.CertImage.Certified = true
})
Context("when a project is submitted", func() {
Context("and an update token is sent to getImage and createImage is in conflict", func() {
It("should call updateImage and certified flag should be updated", func() {
certResults, err := pyxisClient.SubmitResults(ctx, &certInput)
Expect(err).ToNot(HaveOccurred())
Expect(certResults).ToNot(BeNil())
Expect(certResults.CertProject).ToNot(BeNil())
Expect(certResults.CertImage).ToNot(BeNil())
Expect(certResults.CertImage.Certified).To(Equal(true))
Expect(certResults.TestResults).ToNot(BeNil())
})
})
})
})

Context("createImage 409 Conflict, getImage 200, and updateImage 500", func() {
BeforeEach(func() {
pyxisClient.APIToken = "my-update-image-failure-api-token"
pyxisClient.ProjectID = "my-image-project-id"
certInput.CertImage.Certified = true
})
Context("when a project is submitted", func() {
Context("and an update token is sent to getImage and createImage is in conflict", func() {
It("should call updateImage and error", func() {
certResults, err := pyxisClient.SubmitResults(ctx, &certInput)
Expect(err).To(HaveOccurred())
Expect(certResults).To(BeNil())
})
})
})
})

Context("createImage 500 InternalServerError", func() {
BeforeEach(func() {
pyxisClient.APIToken = "my-bad-500-image-api-token"
Expand Down

0 comments on commit 82aca79

Please sign in to comment.