Skip to content

Commit

Permalink
Use node's arch during image scan (#200)
Browse files Browse the repository at this point in the history
* set image arch from node it run on

* get image from remote using arch and os

* update
  • Loading branch information
zdarovich authored Dec 6, 2023
1 parent f227c65 commit acec50f
Show file tree
Hide file tree
Showing 10 changed files with 83 additions and 40 deletions.
12 changes: 8 additions & 4 deletions cmd/imgcollector/collector/collector.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,16 @@ import (
"strings"
"time"

"github.com/castai/image-analyzer/image"
"github.com/castai/image-analyzer/image/hostfs"
fanalyzer "github.com/aquasecurity/trivy/pkg/fanal/analyzer"
"github.com/cenkalti/backoff/v4"
"github.com/google/go-containerregistry/pkg/name"
"github.com/samber/lo"
"github.com/sirupsen/logrus"
"gopkg.in/yaml.v3"

fanalyzer "github.com/aquasecurity/trivy/pkg/fanal/analyzer"
analyzer "github.com/castai/image-analyzer"
"github.com/castai/image-analyzer/image"
"github.com/castai/image-analyzer/image/hostfs"
"github.com/castai/kvisor/castai"
"github.com/castai/kvisor/cmd/imgcollector/config"
)
Expand Down Expand Up @@ -86,7 +86,7 @@ func (c *Collector) Collect(ctx context.Context) error {
metadata := &castai.ImageMetadata{
ImageName: c.cfg.ImageName,
ImageID: c.cfg.ImageID,
Architecture: arRef.ArtifactInfo.Architecture,
Architecture: c.cfg.ImageArchitecture,
ImageDigest: digest.String(),
ResourceIDs: strings.Split(c.cfg.ResourceIDs, ","),
BlobsInfo: arRef.BlobsInfo,
Expand Down Expand Up @@ -147,6 +147,10 @@ func (c *Collector) getImage(ctx context.Context) (image.ImageWithIndex, func(),
return nil, nil, fmt.Errorf("unmarshaling docker options file: %w", err)
}
}
if c.cfg.ImageArchitecture != "" && c.cfg.ImageOS != "" {
opts.Architecture = c.cfg.ImageArchitecture
opts.OS = c.cfg.ImageOS
}
img, err := image.NewFromRemote(ctx, c.cfg.ImageName, opts)
return img, func() {}, err
}
Expand Down
18 changes: 10 additions & 8 deletions cmd/imgcollector/collector/collector_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ import (
"testing"
"time"

"github.com/castai/image-analyzer/image"
"github.com/castai/image-analyzer/image/hostfs"
"github.com/google/go-containerregistry/pkg/name"
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/sirupsen/logrus"
"github.com/stretchr/testify/require"

"github.com/castai/image-analyzer/image"
"github.com/castai/image-analyzer/image/hostfs"
mock_blobcache "github.com/castai/kvisor/blobscache/mock"
"github.com/castai/kvisor/castai"
"github.com/castai/kvisor/cmd/imgcollector/config"
Expand Down Expand Up @@ -50,12 +50,13 @@ func TestCollector(t *testing.T) {
p := path.Join(cwd, "testdata/amd64-linux/io.containerd.content.v1.content")

c := New(log, config.Config{
ApiURL: srv.URL,
ImageID: imgID,
ImageName: imgName,
Timeout: 5 * time.Minute,
Mode: config.ModeHostFS,
Runtime: config.RuntimeContainerd,
ApiURL: srv.URL,
ImageID: imgID,
ImageName: imgName,
Timeout: 5 * time.Minute,
Mode: config.ModeHostFS,
Runtime: config.RuntimeContainerd,
ImageArchitecture: "amd64",
}, mockCache, &hostfs.ContainerdHostFSConfig{
Platform: v1.Platform{
Architecture: "amd64",
Expand All @@ -71,6 +72,7 @@ func TestCollector(t *testing.T) {
b, err := os.ReadFile("./testdata/expected_image_scan_meta1.json")
r.NoError(err)
r.NoError(json.Unmarshal(b, &expected))
expected.Architecture = "amd64"

var receivedMeta castai.ImageMetadata
r.NoError(json.Unmarshal(receivedMetaBytes, &receivedMeta))
Expand Down
24 changes: 13 additions & 11 deletions cmd/imgcollector/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,19 @@ const (
)

type Config struct {
ApiURL string `envconfig:"KVISOR_SERVER_API_URL" required:"true"`
ImageID string `envconfig:"COLLECTOR_IMAGE_ID" required:"true"`
ImageName string `envconfig:"COLLECTOR_IMAGE_NAME" required:"true"`
ImagePullSecret string `envconfig:"COLLECTOR_PULL_SECRET" default:""`
Timeout time.Duration `envconfig:"COLLECTOR_TIMEOUT" default:"5m"`
Mode Mode `envconfig:"COLLECTOR_MODE"`
Runtime Runtime `envconfig:"COLLECTOR_RUNTIME" required:"true"`
ResourceIDs string `envconfig:"COLLECTOR_RESOURCE_IDS" required:"true"`
DockerOptionPath string `envconfig:"COLLECTOR_DOCKER_OPTION_PATH" default:""`
PprofAddr string `envconfig:"COLLECTOR_PPROF_ADDR" default:""`
SlowMode bool `envconfig:"SLOW_MODE" default:"true"`
ApiURL string `envconfig:"KVISOR_SERVER_API_URL" required:"true"`
ImageID string `envconfig:"COLLECTOR_IMAGE_ID" required:"true"`
ImageName string `envconfig:"COLLECTOR_IMAGE_NAME" required:"true"`
ImageArchitecture string `envconfig:"COLLECTOR_IMAGE_ARCHITECTURE" required:"true"`
ImageOS string `envconfig:"COLLECTOR_IMAGE_OS" required:"true"`
ImagePullSecret string `envconfig:"COLLECTOR_PULL_SECRET" default:""`
Timeout time.Duration `envconfig:"COLLECTOR_TIMEOUT" default:"5m"`
Mode Mode `envconfig:"COLLECTOR_MODE"`
Runtime Runtime `envconfig:"COLLECTOR_RUNTIME" required:"true"`
ResourceIDs string `envconfig:"COLLECTOR_RESOURCE_IDS" required:"true"`
DockerOptionPath string `envconfig:"COLLECTOR_DOCKER_OPTION_PATH" default:""`
PprofAddr string `envconfig:"COLLECTOR_PPROF_ADDR" default:""`
SlowMode bool `envconfig:"SLOW_MODE" default:"true"`
// ImageLocalTarPath is used only with ModeTarArchive for local dev.
ImageLocalTarPath string
}
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ require (
github.com/aws/aws-sdk-go-v2/service/eks v1.22.1
github.com/aws/smithy-go v1.13.4
github.com/bombsimon/logrusr/v4 v4.0.0
github.com/castai/image-analyzer v0.1.0
github.com/castai/image-analyzer v0.2.0
github.com/cenkalti/backoff/v4 v4.1.3
github.com/containerd/containerd v1.7.8
github.com/davecgh/go-spew v1.1.1
Expand Down
8 changes: 2 additions & 6 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -238,8 +238,8 @@ github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0 h1:nvj0OLI3YqYXe
github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE=
github.com/caarlos0/env/v6 v6.10.1 h1:t1mPSxNpei6M5yAeu1qtRdPAK29Nbcf/n3G7x+b3/II=
github.com/caarlos0/env/v6 v6.10.1/go.mod h1:hvp/ryKXKipEkcuYjs9mI4bBCg+UI0Yhgm5Zu0ddvwc=
github.com/castai/image-analyzer v0.1.0 h1:S4HaztzLacwICJv/EYSu6NjhBGNcL8tP/mLAo/iKHW0=
github.com/castai/image-analyzer v0.1.0/go.mod h1:HJ+p9mvz92DDC/eqrTrscnV7w7NdBZd9a/PQZZ03PdM=
github.com/castai/image-analyzer v0.2.0 h1:rAazxM063PDaxGA2y5IsDEI7Yt2B6xETYh9To9k+ICU=
github.com/castai/image-analyzer v0.2.0/go.mod h1:HJ+p9mvz92DDC/eqrTrscnV7w7NdBZd9a/PQZZ03PdM=
github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
github.com/cenkalti/backoff/v4 v4.1.3 h1:cFAlzYUlVYDysBEH2T5hyJZMh3+5+WCBvSnK6Q8UtC4=
github.com/cenkalti/backoff/v4 v4.1.3/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
Expand Down Expand Up @@ -1786,8 +1786,6 @@ honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
k8s.io/api v0.24.1/go.mod h1:JhoOvNiLXKTPQ60zh2g0ewpA+bnEYf5q44Flhquh4vQ=
k8s.io/api v0.26.1 h1:f+SWYiPd/GsiWwVRz+NbFyCgvv75Pk9NK6dlkZgpCRQ=
k8s.io/api v0.26.1/go.mod h1:xd/GBNgR0f707+ATNyPmQ1oyKSgndzXij81FzWGsejg=
k8s.io/api v0.26.11 h1:hLhTZRdYc3vBBOY4wbEyTLWgMyieOAk2Ws9NG57QqO4=
k8s.io/api v0.26.11/go.mod h1:bSr/A0TKRt5W2OMDdexkM/ER1NxOxiQqNNFXW2nMZrM=
k8s.io/apiextensions-apiserver v0.26.1 h1:cB8h1SRk6e/+i3NOrQgSFij1B2S0Y0wDoNl66bn8RMI=
Expand All @@ -1802,8 +1800,6 @@ k8s.io/apiserver v0.26.1/go.mod h1:wr75z634Cv+sifswE9HlAo5FQ7UoUauIICRlOE+5dCg=
k8s.io/cli-runtime v0.25.3 h1:Zs7P7l7db/5J+KDePOVtDlArAa9pZXaDinGWGZl0aM8=
k8s.io/cli-runtime v0.25.3/go.mod h1:InHHsjkyW5hQsILJGpGjeruiDZT/R0OkROQgD6GzxO4=
k8s.io/client-go v0.24.1/go.mod h1:f1kIDqcEYmwXS/vTbbhopMUbhKp2JhOeVTfxgaCIlF8=
k8s.io/client-go v0.26.1 h1:87CXzYJnAMGaa/IDDfRdhTzxk/wzGZ+/HUQpqgVSZXU=
k8s.io/client-go v0.26.1/go.mod h1:IWNSglg+rQ3OcvDkhY6+QLeasV4OYHDjdqeWkDQZwGE=
k8s.io/client-go v0.26.11 h1:RjfZr5+vQjjTRmk4oCqHyC0cgrZXPjw+X+ge35sk4GI=
k8s.io/client-go v0.26.11/go.mod h1:+emNszw9va/uRJIM5ALTBtFnlZMTjwBrNjRfEh0iuw8=
k8s.io/code-generator v0.19.7/go.mod h1:lwEq3YnLYb/7uVXLorOJfxg+cUu2oihFhHZ0n9NIla0=
Expand Down
2 changes: 2 additions & 0 deletions imagescan/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,8 @@ func (s *Controller) scanImage(ctx context.Context, img *image) (rerr error) {
DeleteFinishedJob: true,
WaitForCompletion: true,
WaitDurationAfterCompletion: 30 * time.Second,
Architecture: img.architecture,
Os: img.os,
})
}

Expand Down
2 changes: 2 additions & 0 deletions imagescan/controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,8 @@ func TestSubscriber(t *testing.T) {
DeleteFinishedJob: true,
WaitForCompletion: true,
WaitDurationAfterCompletion: 30 * time.Second,
Architecture: defaultImageArch,
Os: defaultImageOs,
}, ngnxImage)
r.Len(client.getImagesResourcesChanges(), 1)
r.Len(client.getImagesResourcesChanges()[0].Images, 3)
Expand Down
32 changes: 24 additions & 8 deletions imagescan/delta.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ var (
errNoCandidates = errors.New("no candidates")
)

const defaultImageOs = "linux"
const defaultImageArch = "amd64"

type podOwnerGetter interface {
Expand Down Expand Up @@ -101,6 +102,7 @@ func (d *deltaState) updateNodeUsage(v *corev1.Node) {
n = &node{
name: v.GetName(),
architecture: v.Status.NodeInfo.Architecture,
os: v.Status.NodeInfo.OperatingSystem,
allocatableMem: &inf.Dec{},
allocatableCPU: &inf.Dec{},
pods: make(map[types.UID]*pod),
Expand Down Expand Up @@ -168,14 +170,15 @@ func (d *deltaState) upsertImages(pod *corev1.Pod) {
}

nodeName := pod.Spec.NodeName
arch := d.getPodArch(pod)
key := cs.ImageID + arch + cont.Image
platform := d.getPodPlatform(pod)
key := cs.ImageID + platform.architecture + cont.Image
img, found := d.images[key]
if !found {
img = newImage()
img.name = cont.Image
img.key = key
img.architecture = arch
img.architecture = platform.architecture
img.os = platform.os
}
img.id = cs.ImageID
img.containerRuntime = getContainerRuntime(cs.ContainerID)
Expand Down Expand Up @@ -209,7 +212,7 @@ func (d *deltaState) upsertImages(pod *corev1.Pod) {
func (d *deltaState) handlePodDelete(pod *corev1.Pod) {
now := time.Now().UTC()
for imgKey, img := range d.images {
if img.architecture != d.getPodArch(pod) {
if img.architecture != d.getPodPlatform(pod).architecture {
continue
}

Expand Down Expand Up @@ -320,12 +323,23 @@ func (d *deltaState) setImageScanned(scannedImg castai.ScannedImage) {
}
}

func (d *deltaState) getPodArch(pod *corev1.Pod) string {
type platform struct {
architecture string
os string
}

func (d *deltaState) getPodPlatform(pod *corev1.Pod) platform {
n, ok := d.nodes[pod.Spec.NodeName]
if ok && n.architecture != "" {
return n.architecture
if ok && n.architecture != "" && n.os != "" {
return platform{
architecture: n.architecture,
os: n.os,
}
}
return platform{
architecture: defaultImageArch,
os: defaultImageOs,
}
return defaultImageArch
}

func getContainerRuntime(containerID string) imgcollectorconfig.Runtime {
Expand All @@ -352,6 +366,7 @@ type pod struct {
type node struct {
name string
architecture string
os string
allocatableMem *inf.Dec
allocatableCPU *inf.Dec
pods map[types.UID]*pod
Expand Down Expand Up @@ -426,6 +441,7 @@ type image struct {
name string

architecture string
os string
containerRuntime imgcollectorconfig.Runtime

// owners map key points to higher level k8s resource for that image. (Image Affected resource in CAST AI console).
Expand Down
13 changes: 11 additions & 2 deletions imagescan/scanner.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,12 @@ import (
"time"

"github.com/samber/lo"
"k8s.io/apimachinery/pkg/labels"

batchv1 "k8s.io/api/batch/v1"
corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/client-go/kubernetes"
batchv1typed "k8s.io/client-go/kubernetes/typed/batch/v1"
Expand Down Expand Up @@ -65,6 +64,8 @@ type ScanImageParams struct {
DeleteFinishedJob bool
WaitForCompletion bool
WaitDurationAfterCompletion time.Duration
Architecture string
Os string
}

func (s *Scanner) ScanImage(ctx context.Context, params ScanImageParams) (rerr error) {
Expand Down Expand Up @@ -202,6 +203,14 @@ func (s *Scanner) ScanImage(ctx context.Context, params ScanImageParams) (rerr e
Name: "KVISOR_SERVER_API_URL",
Value: s.cfg.ImageScan.APIUrl,
},
{
Name: "COLLECTOR_IMAGE_ARCHITECTURE",
Value: params.Architecture,
},
{
Name: "COLLECTOR_IMAGE_OS",
Value: params.Os,
},
}

if s.cfg.ImageScan.PullSecret != "" {
Expand Down
10 changes: 10 additions & 0 deletions imagescan/scanner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ func TestScanner(t *testing.T) {
Mode: "hostfs",
NodeName: "n1",
ResourceIDs: []string{"p1", "p2"},
Architecture: "amd64",
Os: "linux",
})
r.NoError(err)

Expand Down Expand Up @@ -162,6 +164,14 @@ func TestScanner(t *testing.T) {
Name: "KVISOR_SERVER_API_URL",
Value: "http://kvisor:6060",
},
{
Name: "COLLECTOR_IMAGE_ARCHITECTURE",
Value: "amd64",
},
{
Name: "COLLECTOR_IMAGE_OS",
Value: "linux",
},
{
Name: "COLLECTOR_PPROF_ADDR",
Value: ":6060",
Expand Down

0 comments on commit acec50f

Please sign in to comment.