Skip to content

Commit

Permalink
feat: globbing support for -d
Browse files Browse the repository at this point in the history
  • Loading branch information
arcln committed Mar 30, 2023
1 parent 30b406e commit cbebdde
Show file tree
Hide file tree
Showing 2 changed files with 112 additions and 32 deletions.
86 changes: 54 additions & 32 deletions internal/exporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,9 +140,9 @@ func (exporter *Exporter) parseAllCertificates() ([]*certificateRef, []*certific
}

for _, file := range exporter.Files {
refs, err := exporter.collectMatchingCertificates(file, certificateFormatPEM)
refs, errs := exporter.collectMatchingPaths(file, certificateFormatPEM, false)

if err != nil {
for _, err := range errs {
raiseError(&certificateError{
err: fmt.Errorf("failed to parse \"%s\": %s", file, err.Error()),
})
Expand All @@ -152,9 +152,9 @@ func (exporter *Exporter) parseAllCertificates() ([]*certificateRef, []*certific
}

for _, file := range exporter.YAMLs {
refs, err := exporter.collectMatchingCertificates(file, certificateFormatYAML)
refs, errs := exporter.collectMatchingPaths(file, certificateFormatYAML, false)

if err != nil {
for _, err := range errs {
raiseError(&certificateError{
err: fmt.Errorf("failed to parse \"%s\": %s", file, err.Error()),
})
Expand All @@ -164,25 +164,15 @@ func (exporter *Exporter) parseAllCertificates() ([]*certificateRef, []*certific
}

for _, dir := range exporter.Directories {
files, err := os.ReadDir(dir)
if err != nil {
refs, errs := exporter.collectMatchingPaths(dir, certificateFormatYAML, true)

for _, err := range errs {
raiseError(&certificateError{
err: fmt.Errorf("failed to open directory \"%s\", %s", dir, err.Error()),
err: fmt.Errorf("failed to parse \"%s\": %s", dir, err.Error()),
})

continue
}

for _, file := range files {
if file.IsDir() {
continue
}

output = append(output, &certificateRef{
path: path.Clean(path.Join(dir, file.Name())),
format: certificateFormatPEM,
})
}
output = append(output, refs...)
}

if exporter.kubeClient != nil {
Expand Down Expand Up @@ -245,38 +235,70 @@ func (exporter *Exporter) parseAllCertificates() ([]*certificateRef, []*certific
return output, outputErrors
}

func (exporter *Exporter) collectMatchingCertificates(pattern string, format certificateFormat) ([]*certificateRef, error) {
func (exporter *Exporter) collectMatchingPaths(pattern string, format certificateFormat, directories bool) ([]*certificateRef, []error) {
output := []*certificateRef{}
outputErrors := []error{}
basepath, match := doublestar.SplitPattern(pattern)

walk := func(filepath string, entry fs.DirEntry) error {
output = append(output, &certificateRef{
path: path.Clean(path.Join(basepath, filepath)),
format: format,
yamlPaths: exporter.YAMLPaths,
})
if directories {
if !entry.IsDir() {
return nil
}

dir := path.Clean(path.Join(basepath, filepath))
files, err := os.ReadDir(dir)
if err != nil {
outputErrors = append(outputErrors, err)
return nil
}

for _, file := range files {
if file.IsDir() {
continue
}

output = append(output, &certificateRef{
path: path.Clean(path.Join(dir, file.Name())),
format: certificateFormatPEM,
})
}
} else {
output = append(output, &certificateRef{
path: path.Clean(path.Join(basepath, filepath)),
format: format,
yamlPaths: exporter.YAMLPaths,
})
}

return nil
}

options := []doublestar.GlobOption{
doublestar.WithFailOnIOErrors(),
doublestar.WithFailOnPatternNotExist(),
// doublestar.WithNoFollow(),
}

if !directories {
options = append(options, doublestar.WithFilesOnly())
}

err := doublestar.GlobWalk(
os.DirFS(basepath),
match,
walk,
doublestar.WithFilesOnly(),
doublestar.WithFailOnIOErrors(),
doublestar.WithFailOnPatternNotExist(),
// doublestar.WithNoFollow(),
options...,
)
if err != nil {
if errors.Is(err, doublestar.ErrPatternNotExist) {
return nil, errors.New("no files match \"" + pattern + "\"")
return nil, []error{errors.New("no files match \"" + pattern + "\"")}
}

return nil, err
return nil, []error{err}
}

return output, nil
return output, outputErrors
}

func (exporter *Exporter) compareCertificates(
Expand Down
58 changes: 58 additions & 0 deletions internal/exporter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -804,6 +804,64 @@ func TestYamlGlobbing(t *testing.T) {
})
}

func TestDirectoryGlobbing(t *testing.T) {
// single star match
testRequest(t, &Exporter{
Directories: []string{"../tes*"},
}, func(metrics []model.MetricFamily) {
foundMetrics := getMetricsForName(metrics, "x509_cert_expired")
assert.Len(t, foundMetrics, 4)
foundNbMetrics := getMetricsForName(metrics, "x509_cert_not_before")
assert.Len(t, foundNbMetrics, 4)
foundNaMetrics := getMetricsForName(metrics, "x509_cert_not_after")
assert.Len(t, foundNaMetrics, 4)
errMetric := getMetricsForName(metrics, "x509_read_errors")
assert.Equal(t, 19., errMetric[0].GetGauge().GetValue())
})

// double star match
testRequest(t, &Exporter{
Directories: []string{"../**/foo"},
}, func(metrics []model.MetricFamily) {
foundMetrics := getMetricsForName(metrics, "x509_cert_expired")
assert.Len(t, foundMetrics, 1)
foundNbMetrics := getMetricsForName(metrics, "x509_cert_not_before")
assert.Len(t, foundNbMetrics, 1)
foundNaMetrics := getMetricsForName(metrics, "x509_cert_not_after")
assert.Len(t, foundNaMetrics, 1)
errMetric := getMetricsForName(metrics, "x509_read_errors")
assert.Equal(t, 0., errMetric[0].GetGauge().GetValue())
})

// combined
testRequest(t, &Exporter{
Directories: []string{"../test/**/fo*"},
}, func(metrics []model.MetricFamily) {
foundMetrics := getMetricsForName(metrics, "x509_cert_expired")
assert.Len(t, foundMetrics, 1)
foundNbMetrics := getMetricsForName(metrics, "x509_cert_not_before")
assert.Len(t, foundNbMetrics, 1)
foundNaMetrics := getMetricsForName(metrics, "x509_cert_not_after")
assert.Len(t, foundNaMetrics, 1)
errMetric := getMetricsForName(metrics, "x509_read_errors")
assert.Equal(t, 0., errMetric[0].GetGauge().GetValue())
})

// file match
testRequest(t, &Exporter{
Directories: []string{"../test/**/basic.pem"},
}, func(metrics []model.MetricFamily) {
foundMetrics := getMetricsForName(metrics, "x509_cert_expired")
assert.Len(t, foundMetrics, 0)
foundNbMetrics := getMetricsForName(metrics, "x509_cert_not_before")
assert.Len(t, foundNbMetrics, 0)
foundNaMetrics := getMetricsForName(metrics, "x509_cert_not_after")
assert.Len(t, foundNaMetrics, 0)
errMetric := getMetricsForName(metrics, "x509_read_errors")
assert.Equal(t, 0., errMetric[0].GetGauge().GetValue())
})
}

func TestListenError(t *testing.T) {
exporter := &Exporter{ListenAddress: "127.0.0.1:4242"}
err := exporter.Listen()
Expand Down

0 comments on commit cbebdde

Please sign in to comment.