Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
ad9cf66
Fix: Ensure that consecutive calls to nodeScanHandlerImpl.Start don't…
vikin91 Nov 14, 2022
c441c41
Optimize nodeScanHandlerImpl.sendScan
vikin91 Nov 14, 2022
41dd60f
Remove stoppedC, fix race condition in test
vikin91 Nov 15, 2022
4df0e64
Minor: Tune a comment and reduce a line
vikin91 Nov 15, 2022
70b80bb
Make the nodeScanHandlerImpl restartable
vikin91 Nov 16, 2022
da01dfe
Rename mutex var
vikin91 Nov 21, 2022
053b710
Rename var runFinishedC to stoppedC
vikin91 Nov 21, 2022
375a03e
Undo restartability: allow the component to Start() once
vikin91 Nov 21, 2022
c5052a7
Extend comment for the test where producer stops the component after …
vikin91 Nov 21, 2022
17932b4
Change error message when starting NodeScanHandler for the N>1 time
vikin91 Nov 21, 2022
32ba377
Make deferred statement evaluate properly
vikin91 Nov 23, 2022
7e85378
Do not initialize toCentral chan twice
vikin91 Nov 23, 2022
943deee
Correct comment
vikin91 Nov 23, 2022
889e083
Address race in TestHandlerStoppedError by accepting both values
vikin91 Nov 23, 2022
142289d
Delete SetupTest and make sure that the Suite implements the interface
vikin91 Nov 25, 2022
b8a647d
Add waiting for Stopped() in TestStopHandler
vikin91 Nov 25, 2022
38c94fe
Rephrase comment in TestStopHandler
vikin91 Nov 25, 2022
86dae6e
Add more assertions to TestHandlerRegularRoutine
vikin91 Nov 25, 2022
c008157
Ensure all test cases do h.Stopped().Wait()
vikin91 Nov 25, 2022
283a43e
WIP: Rework tests
vikin91 Nov 25, 2022
98a2509
Reword comment
vikin91 Nov 28, 2022
d9fcadc
Fix race in TestStopHandler between handler Stop and receiver receivi…
vikin91 Nov 28, 2022
83f8613
Stop(nil) and skip stopAll in TestHandlerRegularRoutine
vikin91 Nov 28, 2022
706d1aa
Skip stopAll in TestHandlerStoppedError
vikin91 Nov 28, 2022
cc6fd29
Cleanup generateTestInputNoClose
vikin91 Nov 28, 2022
ae283da
Improve TestRestartHandler
vikin91 Nov 28, 2022
d948528
Improve TestDoubleStartHandler and TestDoubleStopHandler
vikin91 Nov 28, 2022
13befb8
Temporarily revert "Fix race in TestStopHandler between handler Stop …
vikin91 Nov 28, 2022
dc50b12
Remove the test context
vikin91 Nov 28, 2022
a4f7112
Do not defer assertNoGoroutineLeaks
vikin91 Nov 28, 2022
8369b91
Correct stopAll code in TestStopHandler
vikin91 Nov 28, 2022
ad836f8
Remove redundant waiting in TestRestartHandler
vikin91 Nov 28, 2022
06bc997
Remove stopAll and fix race in TestStopHandler
vikin91 Nov 28, 2022
a4c6c54
Fix hidden race in TestMultipleStartHandler
vikin91 Nov 28, 2022
e22e35b
Remove redundant TestRestartHandler
vikin91 Nov 28, 2022
ed00521
Remove assertions NotPanics
vikin91 Nov 28, 2022
e385c20
Add coverage with test TestInputChannelClosed
vikin91 Nov 28, 2022
5246c62
Fine details: comments and order of cleanup
vikin91 Nov 28, 2022
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
11 changes: 6 additions & 5 deletions sensor/common/compliance/nodescan_handler.go
Original file line number Diff line number Diff line change
@@ -1,24 +1,25 @@
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/pkg/sync"
"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
Stopped() concurrency.ReadOnlyErrorSignal
}

// 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(),
toCentral: nil,
stopC: concurrency.NewErrorSignal(),
lock: &sync.Mutex{},
stoppedC: concurrency.NewErrorSignal(),
}
}
97 changes: 62 additions & 35 deletions sensor/common/compliance/nodescan_handler_impl.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,31 +6,52 @@ import (
"github.com/stackrox/rox/generated/storage"
"github.com/stackrox/rox/pkg/centralsensor"
"github.com/stackrox/rox/pkg/concurrency"
"github.com/stackrox/rox/pkg/sync"
)

var (
errInputChanClosed = errors.New("channel receiving node scans v2 is closed")
errStartMoreThanOnce = errors.New("unable to start the component more than once")
)

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

stopC concurrency.ErrorSignal
// lock prevents the race condition between Start() [writer] and ResponsesC() [reader]
lock *sync.Mutex
// stopC is a command that tells this component to stop
stopC concurrency.ErrorSignal
// stoppedC is signaled when the goroutine inside of run() finishes
stoppedC concurrency.ErrorSignal
}

func (c *nodeScanHandlerImpl) Stopped() concurrency.ReadOnlyErrorSignal {
return &c.stoppedC
}

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

// ResponsesC returns a channel with messages to Central. It must be called after Start() for the channel to be not nil
func (c *nodeScanHandlerImpl) ResponsesC() <-chan *central.MsgFromSensor {
c.lock.Lock()
defer c.lock.Unlock()
if c.toCentral == nil {
log.Panic("Start must be called before ResponsesC")
}
return c.toCentral
}

func (c *nodeScanHandlerImpl) Start() error {
// 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
c.lock.Lock()
defer c.lock.Unlock()
if c.toCentral != nil {
return errStartMoreThanOnce
}
return errors.New("stopped handlers cannot be restarted")
c.toCentral = c.run()
return nil
}

func (c *nodeScanHandlerImpl) Stop(err error) {
Expand All @@ -43,40 +64,46 @@ func (c *nodeScanHandlerImpl) ProcessMessage(_ *central.MsgToSensor) error {
return nil
}

func (c *nodeScanHandlerImpl) run() {
defer c.stoppedC.SignalWithError(c.stopC.Err())
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"))
// run handles the messages from Compliance and forwards them to Central
// This is the only goroutine that writes into the toCentral channel, thus it is responsible for creating and closing that chan
func (c *nodeScanHandlerImpl) run() <-chan *central.MsgFromSensor {
toC := make(chan *central.MsgFromSensor)
go func() {
defer func() {
c.stoppedC.SignalWithError(c.stopC.Err())
}()
defer close(toC)
for !c.stopC.IsDone() {
select {
case <-c.stopC.Done():
return
case scan, ok := <-c.nodeScans:
if !ok {
c.stopC.SignalWithError(errInputChanClosed)
return
}
// TODO(ROX-12943): Do something with the scan, e.g., attach NodeID
c.sendScan(toC, scan)
}
// TODO(ROX-12943): Do something with the scan, e.g., attach NodeID
c.sendScan(scan)
}
}
}()
return toC
}

func (c *nodeScanHandlerImpl) sendScan(scan *storage.NodeScanV2) {
if scan != nil {
select {
case <-c.stopC.Done():
return
case c.toCentral <- &central.MsgFromSensor{
Msg: &central.MsgFromSensor_Event{
Event: &central.SensorEvent{
Resource: &central.SensorEvent_NodeScanV2{
NodeScanV2: scan,
},
func (c *nodeScanHandlerImpl) sendScan(toC chan *central.MsgFromSensor, scan *storage.NodeScanV2) {
if scan == nil {
return
}
select {
case <-c.stopC.Done():
case toC <- &central.MsgFromSensor{
Msg: &central.MsgFromSensor_Event{
Event: &central.SensorEvent{
Resource: &central.SensorEvent_NodeScanV2{
NodeScanV2: scan,
},
},
}:
return
}
},
}:
}
}
Loading