mirror of
https://github.com/genuinetools/reg.git
synced 2024-05-20 12:08:33 -04:00
keep layer order
Signed-off-by: Jess Frazelle <acidburn@microsoft.com>
This commit is contained in:
parent
5f1abe4779
commit
07cc661cea
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
|
|
5
vulns.go
5
vulns.go
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue