keep layer order

Signed-off-by: Jess Frazelle <acidburn@microsoft.com>
This commit is contained in:
Jess Frazelle 2018-06-11 14:34:08 -04:00
parent 5f1abe4779
commit 07cc661cea
No known key found for this signature in database
GPG key ID: 18F3685C0022BFF3
6 changed files with 65 additions and 65 deletions

View file

@ -1,78 +1,58 @@
package clair
import (
"bytes"
"encoding/json"
"net/http"
"context"
"errors"
"github.com/coreos/clair/api/v3/clairpb"
)
// GetAncestry displays an ancestry and optionally all of its features and vulnerabilities.
func (c *Clair) GetAncestry(name string, features, vulnerabilities bool) (*clairpb.Ancestry, error) {
url := c.url("/v3/ancestry")
c.Logf("clair.ancestry.get url=%s name=%s", url, name)
c.Logf("clair.ancestry.get name=%s", name)
b, err := json.Marshal(clairpb.GetAncestryRequest{AncestryName: name, WithVulnerabilities: vulnerabilities, WithFeatures: features})
client := clairpb.NewAncestryServiceClient(c.grpcConn)
resp, err := client.GetAncestry(context.Background(), &clairpb.GetAncestryRequest{
AncestryName: name,
WithVulnerabilities: vulnerabilities,
WithFeatures: features,
})
if err != nil {
return nil, err
}
c.Logf("clair.ancestry.get req.Body=%s", string(b))
req, err := http.NewRequest("GET", url, bytes.NewReader(b))
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", "application/json")
resp, err := c.Client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
c.Logf("clair.ancestry.get resp.Status=%s", resp.Status)
var aResp clairpb.GetAncestryResponse
if err := json.NewDecoder(resp.Body).Decode(&aResp); err != nil {
return nil, err
if resp == nil {
return nil, errors.New("ancestry response was nil")
}
if aResp.GetStatus() != nil {
c.Logf("clair.ancestry.get ClairStatus=%#v", *aResp.GetStatus())
if resp.GetStatus() != nil {
c.Logf("clair.ancestry.get ClairStatus=%#v", *resp.GetStatus())
}
return aResp.GetAncestry(), nil
return resp.GetAncestry(), nil
}
// PostAncestry performs the analysis of all layers from the provided path.
func (c *Clair) PostAncestry(name string, layers []*clairpb.PostAncestryRequest_PostLayer) error {
url := c.url("/v3/ancestry")
c.Logf("clair.ancestry.post url=%s name=%s", url, name)
c.Logf("clair.ancestry.post name=%s", name)
b, err := json.Marshal(clairpb.PostAncestryRequest{AncestryName: name, Layers: layers})
client := clairpb.NewAncestryServiceClient(c.grpcConn)
resp, err := client.PostAncestry(context.Background(), &clairpb.PostAncestryRequest{
AncestryName: name,
Layers: layers,
})
if err != nil {
return err
}
c.Logf("clair.ancestry.post req.Body=%s", string(b))
resp, err := c.Client.Post(url, "application/json", bytes.NewReader(b))
if err != nil {
return err
}
defer resp.Body.Close()
c.Logf("clair.ancestry.post resp.Status=%s", resp.Status)
var aResp clairpb.PostAncestryResponse
if err := json.NewDecoder(resp.Body).Decode(&aResp); err != nil {
return err
if resp == nil {
return errors.New("ancestry response was nil")
}
if aResp.GetStatus() != nil {
c.Logf("clair.ancestry.post ClairStatus=%#v", *aResp.GetStatus())
if resp.GetStatus() != nil {
c.Logf("clair.ancestry.post ClairStatus=%#v", *resp.GetStatus())
}
return nil

View file

@ -7,13 +7,16 @@ import (
"log"
"net/http"
"time"
"google.golang.org/grpc"
)
// Clair defines the client for retriving information from the clair API.
type Clair struct {
URL string
Client *http.Client
Logf LogfCallback
URL string
Client *http.Client
Logf LogfCallback
grpcConn *grpc.ClientConn
}
// LogfCallback is the callback for formatting logs.
@ -38,12 +41,16 @@ type Opt struct {
func New(url string, opt Opt) (*Clair, error) {
transport := http.DefaultTransport
grpcOpt := []grpc.DialOption{}
if opt.Insecure {
transport = &http.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: true,
},
}
grpcOpt = append(grpcOpt, grpc.WithInsecure())
}
errorTransport := &ErrorTransport{
@ -56,13 +63,19 @@ func New(url string, opt Opt) (*Clair, error) {
logf = Log
}
conn, err := grpc.Dial(url, grpcOpt...)
if err != nil {
logf("grpc dial %s failed: %v", url, err)
}
registry := &Clair{
URL: url,
Client: &http.Client{
Timeout: opt.Timeout,
Transport: errorTransport,
},
Logf: logf,
Logf: logf,
grpcConn: conn,
}
return registry, nil

View file

@ -10,7 +10,7 @@ import (
)
// NewClairLayer will form a layer struct required for a clair scan.
func (c *Clair) NewClairLayer(r *registry.Registry, image string, fsLayers []distribution.Descriptor, index int) (*Layer, error) {
func (c *Clair) NewClairLayer(r *registry.Registry, image string, fsLayers map[int]distribution.Descriptor, index int) (*Layer, error) {
var parentName string
if index < len(fsLayers)-1 {
parentName = fsLayers[index+1].Digest.String()
@ -52,25 +52,25 @@ func (c *Clair) NewClairV3Layer(r *registry.Registry, image string, fsLayer dist
}, nil
}
func (c *Clair) getFilteredLayers(r *registry.Registry, repo, tag string) ([]distribution.Descriptor, error) {
func (c *Clair) getFilteredLayers(r *registry.Registry, repo, tag string) (map[int]distribution.Descriptor, error) {
ok := true
// Get the manifest to pass to clair.
mf, err := r.ManifestV2(repo, tag)
if err != nil {
ok = false
c.Logf("couldn't retrieve manifest v2, falling back to v1")
// return nil, fmt.Errorf("getting the v2 manifest for %s:%s failed: %v", repo, tag, err)
}
var filteredLayers []distribution.Descriptor
filteredLayers := map[int]distribution.Descriptor{}
// Filter out the empty layers.
if ok {
for _, layer := range mf.Layers {
if !IsEmptyLayer(layer.Digest) {
filteredLayers = append(filteredLayers, layer)
for i := 0; i < len(mf.Layers); i++ {
if !IsEmptyLayer(mf.Layers[i].Digest) {
filteredLayers[i] = mf.Layers[i]
}
}
return filteredLayers, nil
}
@ -79,13 +79,13 @@ func (c *Clair) getFilteredLayers(r *registry.Registry, repo, tag string) ([]dis
return nil, fmt.Errorf("getting the v1 manifest for %s:%s failed: %v", repo, tag, err)
}
for _, layer := range m.FSLayers {
if !IsEmptyLayer(layer.BlobSum) {
for i := 0; i < len(m.FSLayers); i++ {
if !IsEmptyLayer(m.FSLayers[i].BlobSum) {
newLayer := distribution.Descriptor{
Digest: layer.BlobSum,
Digest: m.FSLayers[i].BlobSum,
}
filteredLayers = append(filteredLayers, newLayer)
filteredLayers[i] = newLayer
}
}

View file

@ -1,6 +1,7 @@
package clair
import (
"errors"
"fmt"
"time"
@ -115,6 +116,10 @@ func (c *Clair) VulnerabilitiesV3(r *registry.Registry, repo, tag string) (Vulne
return report, err
}
if vl == nil {
return report, errors.New("ancestry response was nil")
}
// Get the vulns.
for _, f := range vl.Features {
for _, v := range f.Vulnerabilities {

View file

@ -130,8 +130,9 @@ func main() {
// create a clair instance if needed
if c.GlobalString("clair") != "" {
cl, err = clair.New(c.String("clair"), clair.Opt{
Debug: c.GlobalBool("debug"),
Timeout: timeout,
Insecure: c.GlobalBool("insecure"),
Debug: c.GlobalBool("debug"),
Timeout: timeout,
})
if err != nil {
logrus.Warnf("creation of clair failed: %v", err)

View file

@ -51,8 +51,9 @@ var vulnsCommand = cli.Command{
// Initialize clair client.
cr, err := clair.New(c.String("clair"), clair.Opt{
Debug: c.GlobalBool("debug"),
Timeout: timeout,
Debug: c.GlobalBool("debug"),
Timeout: timeout,
Insecure: c.GlobalBool("insecure"),
})
if err != nil {
return err