github.com/castai/kvisor@v1.7.1-0.20240516114728-b3572a2607b5/cmd/imagescan/imgscan.go (about)

     1  package main
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"log/slog"
     7  	"net/http"
     8  	"net/http/pprof"
     9  	"os"
    10  	"runtime"
    11  
    12  	"github.com/castai/image-analyzer/image/hostfs"
    13  	"github.com/castai/kvisor/cmd/imagescan/collector"
    14  	"github.com/castai/kvisor/cmd/imagescan/config"
    15  	"github.com/castai/kvisor/pkg/blobscache"
    16  	"github.com/castai/kvisor/pkg/castai"
    17  	v1 "github.com/google/go-containerregistry/pkg/v1"
    18  	"github.com/sirupsen/logrus"
    19  	"github.com/spf13/cobra"
    20  )
    21  
    22  func NewCommand(version string) *cobra.Command {
    23  	return &cobra.Command{
    24  		Use:   "scan",
    25  		Short: "Run kvisor image scanning",
    26  		Run: func(cmd *cobra.Command, args []string) {
    27  			if err := run(cmd.Context(), version); err != nil {
    28  				slog.Error(err.Error())
    29  				os.Exit(1)
    30  			}
    31  		},
    32  	}
    33  }
    34  
    35  func run(ctx context.Context, version string) error {
    36  	// TODO: Switch to pkg/logging.
    37  	log := logrus.New()
    38  	log.SetLevel(logrus.DebugLevel)
    39  	log.Infof("running image scan job, version=%s", version)
    40  
    41  	cfg, err := config.FromEnv()
    42  	if err != nil {
    43  		return err
    44  	}
    45  
    46  	blobsCache := blobscache.NewRemoteBlobsCacheClient(cfg.BlobsCacheURL)
    47  
    48  	ingestClient, err := castai.NewClient(fmt.Sprintf("kvisor-imagescan/%s", version), castai.Config{
    49  		ClusterID:   cfg.CastaiClusterID,
    50  		APIKey:      cfg.CastaiAPIKey,
    51  		APIGrpcAddr: cfg.CastaiAPIGrpcAddr,
    52  		Insecure:    cfg.CastaiGRPCInsecure,
    53  	})
    54  	if err != nil {
    55  		return err
    56  	}
    57  	defer ingestClient.Close()
    58  
    59  	var h *hostfs.ContainerdHostFSConfig
    60  	if cfg.Runtime == config.RuntimeContainerd && cfg.Mode == config.ModeHostFS {
    61  		h = &hostfs.ContainerdHostFSConfig{
    62  			Platform: v1.Platform{
    63  				Architecture: runtime.GOARCH,
    64  				OS:           runtime.GOOS,
    65  			},
    66  			ContentDir: config.ContainerdContentDir,
    67  		}
    68  	}
    69  	c := collector.New(log, cfg, ingestClient.GRPC, blobsCache, h)
    70  
    71  	ctx, cancel := context.WithTimeout(ctx, cfg.Timeout)
    72  	defer cancel()
    73  
    74  	if cfg.PprofAddr != "" {
    75  		mux := http.NewServeMux()
    76  		addPprofHandlers(mux)
    77  		go func() {
    78  			if err := http.ListenAndServe(cfg.PprofAddr, mux); err != nil { //nolint:gosec
    79  				log.Warnf("pprof http server failed: %v", err)
    80  			}
    81  		}()
    82  	}
    83  
    84  	log.Infof("collecting artifacts for image '%s(%s)', mode=%s", cfg.ImageName, cfg.ImageID, cfg.Mode)
    85  	err = c.Collect(ctx)
    86  	if err != nil {
    87  		return fmt.Errorf("image artifacts collection failed: %w", err)
    88  	}
    89  	log.Info("image artifacts collection finished")
    90  	return nil
    91  }
    92  
    93  func addPprofHandlers(mux *http.ServeMux) {
    94  	mux.HandleFunc("/debug/pprof/", pprof.Index)
    95  	mux.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
    96  	mux.HandleFunc("/debug/pprof/profile", pprof.Profile)
    97  	mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
    98  	mux.HandleFunc("/debug/pprof/trace", pprof.Trace)
    99  }