-
Notifications
You must be signed in to change notification settings - Fork 13
ROX-13770: Introduce local Node Scanner #1164
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
Changes from all commits
6476e7a
51358ef
2c7f746
0bae277
a200daa
e83d067
44b4e4f
8a9af9a
2e4511d
1b12dd0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,6 @@ | ||
# IDE | ||
.idea | ||
.vscode | ||
|
||
# Mac OS hidden file | ||
.DS_Store | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
* | ||
!.gitignore |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
ARG BASE_REGISTRY=registry.access.redhat.com | ||
ARG BASE_IMAGE=ubi9-minimal | ||
ARG BASE_TAG=9.1 | ||
|
||
FROM ${BASE_REGISTRY}/${BASE_IMAGE}:${BASE_TAG} AS base | ||
|
||
COPY ./bin/local-nodescanner /local-nodescanner | ||
|
||
ENTRYPOINT [ "/local-nodescanner" ] |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
# Local Nodescanner | ||
The local nodescanner is a tool to run the code related to Node Scanning locally without having to run the full Docker image or server. | ||
Function-wise, it uses the very same calls and therefore is generating the same results a node scan running in the Node Scanner image would. | ||
|
||
## Building | ||
A `makefile` target named `local-nodescanner` is available in the main makefile. | ||
It will create binaries in the projects' `bin` folder. | ||
For ease of use, a Docker image is also available as target `local-nodescanner-image`. | ||
|
||
## Running the Docker image | ||
As the default for `fspath` is set to `/host`, one can run the image without changes when mounting the target fs to the right path: | ||
`docker run -it -v /path/to/rhcos/fs:/host local-nodescanner:$(make tag)` | ||
Additional flags for the local nodescanner binary can be provided as args to the Docker image. | ||
For example, to enable verbose output: | ||
`docker run -it -v /path/to/rhcos/fs:/host local-nodescanner:$(make tag) --verbose` | ||
|
||
## Requirements | ||
The scanning code requires an `rpmdb` binary to be available in the executing systems `PATH`. | ||
Be warned that RPM installed via `brew` on OSX *will not work correctly*, as it will produce an empty RPM database. | ||
|
||
The only required flag is the path to a filesystem. | ||
This can be a RO-mount of a running system (e.g. `/host` in the Compliance or Node-Scanner images), | ||
or an unpacked filesystem, e.g. from a Docker image or ISO. | ||
Refer to `testdata/NodeScanning/rhcos4.12-minimal.tar.gz` for an archive containing a minimal example. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was hoping that we get a bit more instructions how to handle that 17MB file - could we maybe get a command where we extract it to some tmp location and then do There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have added a complete working example that should get anyone up and running. See L25-L31 in the README |
||
This archive can be used in conjunction with the Docker image. | ||
**NOTE**: If you are running on OSX, mounting anyting in `/tmp` as Docker volume might not work. Resort to using a different folder, e.g. in your homefolder in that case. | ||
```shell | ||
TMPDIR=$(mktemp -d) | ||
tar xzf testdata/NodeScanning/rhcos4.12-minimal.tar.gz -C "$TMPDIR" | ||
make local-nodescanner-image | ||
docker run -it -v "$TMPDIR"/rhcos-412:/host local-nodescanner:$(make tag) | ||
``` | ||
You should see a successful scan, indicated by the scanner noting that it found 503 installed RPM packages and 4 Content Sets. | ||
|
||
The minimal folder/file structure needed for a scan to succeed is: | ||
- `/etc/redhat-release` & `/etc/os-release` with contents denoting an RHCOS OS | ||
- `/usr/share/rpm` containing the RPM database | ||
- `/usr/share/buildinfo/content_manifest.json` containing the content sets |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
package main | ||
|
||
import ( | ||
"context" | ||
"flag" | ||
"os" | ||
"path/filepath" | ||
|
||
log "github.com/sirupsen/logrus" | ||
"github.com/stackrox/scanner/pkg/analyzer/nodes" | ||
) | ||
|
||
func main() { | ||
flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ExitOnError) | ||
fPath := flag.String("fspath", "/host", "Path to the root folder of a filesystem") | ||
fRHCOSrequired := flag.Bool("rhcos-required", true, "Fails scan if path does not contain a filesystem generated by RHCOS. Node Scanning only works on RHCOS.") | ||
fUncertifiedRHEL := flag.Bool("uncertified-rhel", false, "Set true for CentOS and false for RHEL.") | ||
fVerbose := flag.Bool("verbose", false, "Print verbose output if set") | ||
flag.Parse() | ||
|
||
setupLog(*fVerbose) | ||
|
||
fspath, err := filepath.Abs(*fPath) | ||
if err != nil { | ||
log.Fatalf("Encountered error while formatting path: %v", err) | ||
} | ||
|
||
log.Infof("Analyzing rootfs in %v", fspath) | ||
if err := checkTargetDir(fspath); err != nil { | ||
log.Fatalf("Target directory is empty or non-existing: %v", err) | ||
} | ||
|
||
components, err := nodes.Analyze(context.Background(), "nodename", fspath, nodes.AnalyzeOpts{UncertifiedRHEL: *fUncertifiedRHEL, IsRHCOSRequired: *fRHCOSrequired}) | ||
if err != nil { | ||
log.Errorf("Encountered error while scanning: %v", err) | ||
} | ||
|
||
printResults(components) | ||
} | ||
|
||
func setupLog(verbose bool) { | ||
log.SetFormatter(&log.TextFormatter{ | ||
DisableLevelTruncation: true, | ||
PadLevelText: true, | ||
FullTimestamp: true, | ||
TimestampFormat: "2006-01-02 15:04:05", | ||
}) | ||
|
||
if verbose { | ||
log.SetLevel(log.DebugLevel) | ||
} | ||
} | ||
|
||
func checkTargetDir(path string) error { | ||
dir, err := os.Open(path) | ||
if err != nil { | ||
return err | ||
} | ||
_, err = dir.Readdirnames(10) | ||
if err != nil { | ||
return err | ||
} | ||
return nil | ||
} | ||
|
||
func printResults(components *nodes.Components) { | ||
if components == nil || components.CertifiedRHELComponents == nil { | ||
log.Info("No Components discovered") | ||
return | ||
} | ||
log.Infof("Determined OS: %v", components.CertifiedRHELComponents.Dist) | ||
if components.CertifiedRHELComponents.Packages != nil { | ||
log.Infof("Number of installed RPM packages: %v", len(components.CertifiedRHELComponents.Packages)) | ||
for _, c := range components.CertifiedRHELComponents.Packages { | ||
log.Debugf("Component: %v", c) | ||
} | ||
} | ||
|
||
if components.CertifiedRHELComponents.ContentSets != nil { | ||
log.Infof("Number of discovered content sets: %v", len(components.CertifiedRHELComponents.ContentSets)) | ||
for _, cs := range components.CertifiedRHELComponents.ContentSets { | ||
log.Debugf("Content set: %v", cs) | ||
} | ||
} | ||
|
||
} |
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.
is the idea that this should only be used inside a container? Otherwise, Mac users won't be able to use the binary directly :(
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.
The idea is to have maximum flexibility. I have added a UBI 9 container target in this PR to make it runnable anywhere, but we could add more, e.g. UBI 8 or even Fedora latest for a bleeding edge RPM version.
The binary can either be used for tests and/or CI, or as a debug entry point for local debugging. That local debugging would not work on bare metal OSX w.r.t. RPM packages, but still might be useful, or could be done in the container.