-
Notifications
You must be signed in to change notification settings - Fork 601
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
release: use locking around lazy intialized state #6306
release: use locking around lazy intialized state #6306
Conversation
Some state data in the release package, namely AppArmor level/summary & kernel/parser features as well as Seccomp feature set, is only initialized when needed. Since there is a chance, this information could be accessed in concurrently, we need to add some locking around the code that mutates the data. Signed-off-by: Maciej Borzecki <maciej.zenon.borzecki@canonical.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM but let's please just use one mutex for both AppArmor variables.
using sync.Once would be more idiomatic |
Refactor the AppArmor and Seccomp handling code to use sync.Once, in hope for making the code more idiomatic. Drop or update the necessary tests. Signed-off-by: Maciej Borzecki <maciej.zenon.borzecki@canonical.com>
@pedronis pushed the change to use sync.Once. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
some questions/comments
release/apparmor.go
Outdated
) | ||
|
||
func assessAppArmorOnce() { | ||
appArmorAssessOnce.Do(assessAppArmor) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
were the actual functions like assesAppArmor etc tested?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, they are tested in a couple of places:
Codecov Report
@@ Coverage Diff @@
## master #6306 +/- ##
==========================================
+ Coverage 78.95% 78.98% +0.02%
==========================================
Files 561 561
Lines 43650 43664 +14
==========================================
+ Hits 34463 34486 +23
+ Misses 6387 6378 -9
Partials 2800 2800
Continue to review full report at Codecov.
|
…n mocking Signed-off-by: Maciej Borzecki <maciej.zenon.borzecki@canonical.com>
release/apparmor.go
Outdated
// appArmorProbeParserOnce sync.Once | ||
// appArmorProbeKernelOnce sync.Once | ||
// appArmorAssessOnce sync.Once | ||
type appArmorOnceBattery struct { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not super fond of the name.
release/apparmor.go
Outdated
if appArmorLevel == UnknownAppArmor { | ||
assessAppArmor() | ||
} | ||
appArmorAssess() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we have a test that checks if the assessment is cached and actually done once? Since this extra if
goes away, it would be good to have a test, in case the implementation based on sync.Once
gets replaced in the future with new Go.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I looked into this, in the end I reorganized things quite a bit, mostly because the Mock* functions below are complicated/long but didn't help fully with testing this. I'm pushing the new code now, with it commenting the Once.Do bits always make some test fail.
…g them swapping full structures, add various tests increasing coverage and proving that the once-only logic is in place
appArmorKernelFeatures, appArmorKernelError = probeAppArmorKernelFeatures() | ||
} | ||
return appArmorKernelFeatures, appArmorKernelError | ||
return appArmorAssessment.KernelFeatures() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mostly curiuous - is there a reason we use slightly different pattern here and above? I mean explicit call to assess()
, rather than having Level()
and Summary()
methods that to sync.Once
internally?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These ones are used both internally and externally and also participate in the interface. Summary and Level are just exposed externally so having another layer of methods didn't seem interesting just for the symmetry.
appArmorLevel = NoAppArmor | ||
appArmorSummary = "apparmor not enabled" | ||
return | ||
return NoAppArmor, "apparmor not enabled" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is nice, after writing this I was thinking about changing the code around to avoid the risk of forgetting to return. This makes the problem moot.
appArmorLevel = NoAppArmor | ||
appArmorSummary = "apparmor not enabled" | ||
return | ||
return NoAppArmor, "apparmor not enabled" | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about other errors? I think with the change to the func AppArmorKernelFeatures() ([]string, error)
method we are no longer returning actual appArmorKernelError
from AppArmorKernelFeatures
, no?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
appArmorKernelError doesn't exist anymore as a global, it's stored in the kernelError field of the impl of appArmorProber, and returned in their KernelFeatures methods and then out of AppArmorKernelFeatures
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. But I don't think "Simple" label is true anymore ;)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice. Thank you!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@pedronis thanks for the cleanup!
Some state data in the release package, namely AppArmor level/summary &
kernel/parser features as well as Seccomp feature set, is only initialized when
needed. Since there is a chance, this information could be accessed in
concurrently, we need to add some locking around the code that mutates the data.