Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion central/sensor/service/pipeline/all/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"github.com/stackrox/rox/central/sensor/service/pipeline/networkflowupdate"
"github.com/stackrox/rox/central/sensor/service/pipeline/networkpolicies"
"github.com/stackrox/rox/central/sensor/service/pipeline/nodes"
"github.com/stackrox/rox/central/sensor/service/pipeline/nodescansv2"
"github.com/stackrox/rox/central/sensor/service/pipeline/podevents"
"github.com/stackrox/rox/central/sensor/service/pipeline/processindicators"
"github.com/stackrox/rox/central/sensor/service/pipeline/reprocessing"
Expand All @@ -37,7 +38,7 @@ func NewFactory() pipeline.Factory {

type factoryImpl struct{}

// sendMessages grabs items from the queue, processes them, and sends them back to sensor.
// PipelineForCluster grabs items from the queue, processes them, and potentially sends them back to sensor.
func (s *factoryImpl) PipelineForCluster(ctx context.Context, clusterID string) (pipeline.ClusterPipeline, error) {
flowUpdateFragment, err := networkflowupdate.Singleton().GetFragment(ctx, clusterID)
if err != nil {
Expand All @@ -64,6 +65,9 @@ func (s *factoryImpl) PipelineForCluster(ctx context.Context, clusterID string)
alerts.GetPipeline(),
auditlogstateupdate.GetPipeline(),
}
if features.RHCOSNodeScanning.Enabled() {
pipelines = append(pipelines, nodescansv2.GetPipeline())
}
if features.ComplianceOperatorCheckResults.Enabled() {
pipelines = append(pipelines,
complianceoperatorresults.GetPipeline(),
Expand Down
57 changes: 57 additions & 0 deletions central/sensor/service/pipeline/nodescansv2/pipeline.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package nodescansv2

import (
"context"

"github.com/pkg/errors"
countMetrics "github.com/stackrox/rox/central/metrics"
"github.com/stackrox/rox/central/sensor/service/common"
"github.com/stackrox/rox/central/sensor/service/pipeline"
"github.com/stackrox/rox/central/sensor/service/pipeline/reconciliation"
"github.com/stackrox/rox/generated/internalapi/central"
"github.com/stackrox/rox/pkg/logging"
"github.com/stackrox/rox/pkg/metrics"
)

var (
log = logging.LoggerForModule()
)

// GetPipeline returns an instantiation of this particular pipeline
func GetPipeline() pipeline.Fragment {
return NewPipeline()
}

// NewPipeline returns a new instance of Pipeline.
func NewPipeline() pipeline.Fragment {
return &pipelineImpl{}
}

type pipelineImpl struct {
}

func (p *pipelineImpl) Reconcile(ctx context.Context, clusterID string, storeMap *reconciliation.StoreMap) error {
return nil
}

func (p *pipelineImpl) Match(msg *central.MsgFromSensor) bool {
return msg.GetEvent().GetNodeScanV2() != nil
}

// Run runs the pipeline template on the input and returns the output.
func (p *pipelineImpl) Run(ctx context.Context, clusterID string, msg *central.MsgFromSensor, _ common.MessageInjector) error {
defer countMetrics.IncrementResourceProcessedCounter(pipeline.ActionToOperation(msg.GetEvent().GetAction()), metrics.NodeScanV2)

event := msg.GetEvent()
nodeScan := event.GetNodeScanV2()
if nodeScan == nil {
return errors.Errorf("unexpected resource type %T for node scan v2", event.GetResource())
}

// TODO(ROX-12240, ROX-13053): Do something meaningful with the nodeScan
log.Infof("Central received NodeScanV2: %+v", nodeScan)

return nil
}

func (p *pipelineImpl) OnFinish(_ string) {}
317 changes: 206 additions & 111 deletions generated/internalapi/central/sensor_events.pb.go

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ require (
github.com/vbauerster/mpb/v4 v4.12.2
go.etcd.io/bbolt v1.3.6
go.uber.org/atomic v1.10.0
go.uber.org/goleak v1.2.0
go.uber.org/zap v1.23.0
golang.org/x/crypto v0.1.0
golang.org/x/exp v0.0.0-20220823124025-807a23277127
Expand Down
1 change: 1 addition & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -2043,6 +2043,7 @@ go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk=
go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
Expand Down
3 changes: 3 additions & 0 deletions pkg/centralsensor/caps_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,7 @@ const (

// ScopedImageIntegrations identifies the capability to have image integrations with sources from image pull secrets
ScopedImageIntegrations SensorCapability = "ScopedImageIntegrations"

// NodeScanningCap identifies the capability to scan nodes and provide node components for vulnerability analysis.
NodeScanningCap SensorCapability = "NodeScanning"
)
33 changes: 17 additions & 16 deletions pkg/metrics/resource_string.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions pkg/metrics/resources.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package metrics

// Resource represents the resource that we want to time.
//
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is a go1.19 thing. Since we are updating the file anyway, might as well keep it, but I have also had the displeasure of dealing with this when trying to style this repo

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I saw that and reverted to go 1.18

//go:generate stringer -type=Resource
type Resource int

Expand All @@ -14,6 +15,7 @@ const (
Namespace
NetworkPolicy
Node
NodeScanV2
ProviderMetadata
ComplianceReturn
ImageIntegration
Expand Down
3 changes: 2 additions & 1 deletion proto/internalapi/central/sensor_events.proto
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ message Timing {
int64 nanos = 3;
}

// Next tag: 24.
// Next tag: 26.
message SensorEvent {
// These fields may be duplicated in the individual events, but avoid the need to branch all the time
string id = 1;
Expand All @@ -68,6 +68,7 @@ message SensorEvent {
storage.NamespaceMetadata namespace = 6;
storage.Secret secret = 7;
storage.Node node = 9;
storage.NodeScanV2 node_scan_v2 = 25;
storage.ServiceAccount service_account = 14;
storage.K8sRole role = 15;
storage.K8sRoleBinding binding = 16;
Expand Down
2 changes: 2 additions & 0 deletions sensor/common/compliance/auditlog_manager_impl.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,8 @@ func (a *auditLogCollectionManagerImpl) runUpdater() {

for !a.stopSig.IsDone() {
select {
case <-a.stopSig.Done():
return
case <-a.forceUpdateSig.Done():
a.sendUpdate()
a.forceUpdateSig.Reset()
Expand Down
4 changes: 4 additions & 0 deletions sensor/common/compliance/auditlog_manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ type AuditLogCollectionManagerTestSuite struct {
suite.Suite
}

func (s *AuditLogCollectionManagerTestSuite) TearDownTest() {
defer assertNoGoroutineLeaks(s.T())
}

func (s *AuditLogCollectionManagerTestSuite) getFakeServersAndStates() (map[string]sensor.ComplianceService_CommunicateServer, map[string]*storage.AuditLogFileState) {
servers := map[string]sensor.ComplianceService_CommunicateServer{
"node-a": &mockServer{
Expand Down
24 changes: 24 additions & 0 deletions sensor/common/compliance/nodescan_handler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package compliance

import (
"github.com/stackrox/rox/generated/internalapi/central"
"github.com/stackrox/rox/generated/storage"
"github.com/stackrox/rox/pkg/concurrency"
"github.com/stackrox/rox/sensor/common"
)

// NodeScanHandler is responsible for handling the arriving NodeScanV2 messages, processing then, and sending them to central
type NodeScanHandler interface {
common.SensorComponent
}

// NewNodeScanHandler returns a new instance of a NodeScanHandler
func NewNodeScanHandler(ch <-chan *storage.NodeScanV2) NodeScanHandler {
return &nodeScanHandlerImpl{
nodeScans: ch,
toCentral: make(chan *central.MsgFromSensor),

stopC: concurrency.NewErrorSignal(),
stoppedC: concurrency.NewErrorSignal(),
}
}
82 changes: 82 additions & 0 deletions sensor/common/compliance/nodescan_handler_impl.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package compliance

import (
"github.com/pkg/errors"
"github.com/stackrox/rox/generated/internalapi/central"
"github.com/stackrox/rox/generated/storage"
"github.com/stackrox/rox/pkg/centralsensor"
"github.com/stackrox/rox/pkg/concurrency"
)

type nodeScanHandlerImpl struct {
nodeScans <-chan *storage.NodeScanV2
toCentral chan *central.MsgFromSensor

stopC concurrency.ErrorSignal
stoppedC concurrency.ErrorSignal
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is this used for?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems to be a leftover.

}

func (c *nodeScanHandlerImpl) Capabilities() []centralsensor.SensorCapability {
return []centralsensor.SensorCapability{centralsensor.NodeScanningCap}
}

func (c *nodeScanHandlerImpl) ResponsesC() <-chan *central.MsgFromSensor {
return c.toCentral
}

func (c *nodeScanHandlerImpl) Start() error {
Copy link
Copy Markdown
Contributor

@RTann RTann Nov 11, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to allow multiple Start calls to happen?

For example, this seems possible:

Start()
Start()
Start()
...
Stop()

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I investigated and this will cause a panic due to closing a channel twice (only when the feature-flag is enabled). I will provide a fix and a test for this.

// c.run closes chan toCentral on exit, so we do not want to close twice in case of a restart
if !c.stopC.IsDone() {
go c.run()
return nil
}
return errors.New("stopped handlers cannot be restarted")
}

func (c *nodeScanHandlerImpl) Stop(err error) {
c.stopC.SignalWithError(err)
}

func (c *nodeScanHandlerImpl) ProcessMessage(_ *central.MsgToSensor) error {
// This component doesn't actually process or handle any messages sent from Central to Sensor (yet).
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this imply there is a plan to add this (I'm imagining Central requesting a scan periodically as part of reprocessing or user forcing it)?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is added to implement the handler interface. It does not meant that we will support anything arriving from central, but we do have such possibility of we want to :)

// It uses the sensor component so that the lifecycle (start, stop) can be handled when Sensor starts up.
return nil
}

func (c *nodeScanHandlerImpl) run() {
defer c.stoppedC.SignalWithError(c.stopC.Err())
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems to me, that Start() can only be called once. At the moment when run() completes either due to Stop() or due to error, c.stopC will be set. Any subsequent attempts to Start() will not fail (maybe they should?) and will lead to run() quickly exiting.

In such situation, I think it makes sense to defer close c.toCentral so that we properly close channel and eliminate one forwarding goroutine (see central_sender_impl.go).
Please take into account that select/case will choose a random branch if multiple are satisfied, therefore it makes sense to additionally guard for { loop with a check. E.g. for !c.stopC.IsDone() {.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it covered!

I am only not fully sure which goroutine is meant with "eliminate one forwarding goroutine" 🤔

defer close(c.toCentral)

for !c.stopC.IsDone() {
select {
case <-c.stopC.Done():
return
case scan, ok := <-c.nodeScans:
if !ok {
c.stopC.SignalWithError(errors.New("channel receiving node scans v2 is closed"))
return
}
// TODO(ROX-12943): Do something with the scan, e.g., attach NodeID
c.sendScan(scan)
}
}
}

func (c *nodeScanHandlerImpl) sendScan(scan *storage.NodeScanV2) {
if scan != nil {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

up to you, but maybe we can do something like the following to remove all the indentation:

if scan == nil {
        return
}
...

select {
case <-c.stopC.Done():
return
case c.toCentral <- &central.MsgFromSensor{
Msg: &central.MsgFromSensor_Event{
Event: &central.SensorEvent{
Resource: &central.SensorEvent_NodeScanV2{
NodeScanV2: scan,
},
},
},
}:
return
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need the return here and for the other case?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, no need for them. I will remove them.

}
}
}
Loading