-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
68dd7d7
commit d95581c
Showing
10 changed files
with
275 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
// Copyright The OpenTelemetry Authors | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package templateprovider // import "go.opentelemetry.io/collector/confmap/provider/templateprovider" | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"html/template" | ||
"os" | ||
"path/filepath" | ||
"strings" | ||
|
||
"go.opentelemetry.io/collector/confmap" | ||
"go.opentelemetry.io/collector/confmap/provider/internal" | ||
) | ||
|
||
const ( | ||
schemeName = "template" | ||
templateKey = "template" | ||
typeKey = "type" | ||
|
||
// The template provider will always return the following structure: | ||
// { | ||
// "templates": { | ||
// "the_type_of_template": "the_template" | ||
// }, | ||
// } | ||
// This allows multiple templates to be aggreated under the same global key. | ||
allTemplatesKey = "templates" | ||
) | ||
|
||
type provider struct{} | ||
|
||
// New returns a new confmap.Provider that reads the template from a file. | ||
// | ||
// This Provider supports "file" scheme, and can be called with a "uri" that follows: | ||
// | ||
// file-uri = "template:" local-path | ||
// local-path = [ drive-letter ] file-path | ||
// drive-letter = ALPHA ":" | ||
// | ||
// The "file-path" can be relative or absolute, and it can be any OS supported format. | ||
// | ||
// Examples: | ||
// `template:path/to/template` - relative path (unix, windows) | ||
// `template:/path/to/template` - absolute path (unix, windows) | ||
// `template:c:/path/to/template` - absolute path including drive-letter (windows) | ||
// `template:c:\path\to\template` - absolute path including drive-letter (windows) | ||
func New() confmap.Provider { | ||
return &provider{} | ||
} | ||
|
||
func (fmp *provider) Retrieve(_ context.Context, uri string, _ confmap.WatcherFunc) (*confmap.Retrieved, error) { | ||
if !strings.HasPrefix(uri, schemeName+":") { | ||
return nil, fmt.Errorf("%q uri is not supported by %q provider", uri, schemeName) | ||
} | ||
|
||
// Clean the path before using it. | ||
content, err := os.ReadFile(filepath.Clean(uri[len(schemeName)+1:])) | ||
if err != nil { | ||
return nil, fmt.Errorf("unable to read the file %v: %w", uri, err) | ||
} | ||
|
||
retrieved, err := internal.NewRetrievedFromYAML(content) | ||
if err != nil { | ||
return nil, fmt.Errorf("read template %v: %w", uri, err) | ||
} | ||
|
||
templateConf, err := retrieved.AsConf() | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
if !templateConf.IsSet("type") { | ||
return nil, fmt.Errorf("template %v: must have a 'type'", uri) | ||
} | ||
templateType, ok := templateConf.Get("type").(string) | ||
if !ok { | ||
return nil, fmt.Errorf("template %v: 'type' must be a string", uri) | ||
} | ||
|
||
if !templateConf.IsSet("template") { | ||
return nil, fmt.Errorf("template %v: must have a 'template'", uri) | ||
} | ||
|
||
rawTemplate, ok := templateConf.Get("template").(string) | ||
if !ok { | ||
return nil, fmt.Errorf("template %v: 'template' must be a string", uri) | ||
} | ||
|
||
if _, err = template.New(templateType).Parse(rawTemplate); err != nil { | ||
return nil, fmt.Errorf("template %v: parse as text/template: %w", uri, err) | ||
} | ||
|
||
return confmap.NewRetrieved(map[string]any{ | ||
allTemplatesKey: map[string]any{ | ||
templateType: rawTemplate, | ||
}, | ||
}) | ||
} | ||
|
||
func (*provider) Scheme() string { | ||
return schemeName | ||
} | ||
|
||
func (*provider) Shutdown(context.Context) error { | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
// Copyright The OpenTelemetry Authors | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package templateprovider | ||
|
||
import ( | ||
"context" | ||
"os" | ||
"path/filepath" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/require" | ||
|
||
"go.opentelemetry.io/collector/confmap" | ||
"go.opentelemetry.io/collector/confmap/confmaptest" | ||
) | ||
|
||
const templateSchemePrefix = schemeName + ":" | ||
|
||
func TestValidateProviderScheme(t *testing.T) { | ||
assert.NoError(t, confmaptest.ValidateProviderScheme(New())) | ||
} | ||
|
||
func TestEmptyName(t *testing.T) { | ||
fp := New() | ||
_, err := fp.Retrieve(context.Background(), "", nil) | ||
require.Error(t, err) | ||
require.NoError(t, fp.Shutdown(context.Background())) | ||
} | ||
|
||
func TestUnsupportedScheme(t *testing.T) { | ||
fp := New() | ||
_, err := fp.Retrieve(context.Background(), "https://", nil) | ||
assert.Error(t, err) | ||
assert.NoError(t, fp.Shutdown(context.Background())) | ||
} | ||
|
||
func TestNonExistent(t *testing.T) { | ||
fp := New() | ||
_, err := fp.Retrieve(context.Background(), templateSchemePrefix+filepath.Join("testdata", "non-existent.yaml"), nil) | ||
assert.Error(t, err) | ||
_, err = fp.Retrieve(context.Background(), templateSchemePrefix+absolutePath(t, filepath.Join("testdata", "non-existent.yaml")), nil) | ||
assert.Error(t, err) | ||
require.NoError(t, fp.Shutdown(context.Background())) | ||
} | ||
|
||
func TestInvalidYAML(t *testing.T) { | ||
fp := New() | ||
_, err := fp.Retrieve(context.Background(), templateSchemePrefix+filepath.Join("testdata", "invalid-yaml.yaml"), nil) | ||
assert.Error(t, err) | ||
_, err = fp.Retrieve(context.Background(), templateSchemePrefix+absolutePath(t, filepath.Join("testdata", "invalid-yaml.yaml")), nil) | ||
assert.Error(t, err) | ||
require.NoError(t, fp.Shutdown(context.Background())) | ||
} | ||
|
||
func TestNonMapContent(t *testing.T) { | ||
fp := New() | ||
_, err := fp.Retrieve(context.Background(), templateSchemePrefix+filepath.Join("testdata", "nonmap.yaml"), nil) | ||
assert.ErrorContains(t, err, "cannot be used as a Conf") | ||
_, err = fp.Retrieve(context.Background(), templateSchemePrefix+absolutePath(t, filepath.Join("testdata", "nonmap.yaml")), nil) | ||
assert.ErrorContains(t, err, "cannot be used as a Conf") | ||
require.NoError(t, fp.Shutdown(context.Background())) | ||
} | ||
|
||
func TestMissingType(t *testing.T) { | ||
fp := New() | ||
_, err := fp.Retrieve(context.Background(), templateSchemePrefix+filepath.Join("testdata", "missing-type.yaml"), nil) | ||
assert.ErrorContains(t, err, "must have a 'type'") | ||
_, err = fp.Retrieve(context.Background(), templateSchemePrefix+absolutePath(t, filepath.Join("testdata", "missing-type.yaml")), nil) | ||
assert.ErrorContains(t, err, "must have a 'type'") | ||
require.NoError(t, fp.Shutdown(context.Background())) | ||
} | ||
|
||
func TestNonStringType(t *testing.T) { | ||
fp := New() | ||
_, err := fp.Retrieve(context.Background(), templateSchemePrefix+filepath.Join("testdata", "nonstring-type.yaml"), nil) | ||
assert.ErrorContains(t, err, "type' must be a string") | ||
_, err = fp.Retrieve(context.Background(), templateSchemePrefix+absolutePath(t, filepath.Join("testdata", "nonstring-type.yaml")), nil) | ||
assert.ErrorContains(t, err, "type' must be a string") | ||
require.NoError(t, fp.Shutdown(context.Background())) | ||
} | ||
|
||
func TestMissingTemplate(t *testing.T) { | ||
fp := New() | ||
_, err := fp.Retrieve(context.Background(), templateSchemePrefix+filepath.Join("testdata", "missing-template.yaml"), nil) | ||
assert.ErrorContains(t, err, "must have a 'template'") | ||
_, err = fp.Retrieve(context.Background(), templateSchemePrefix+absolutePath(t, filepath.Join("testdata", "missing-template.yaml")), nil) | ||
assert.ErrorContains(t, err, "must have a 'template'") | ||
require.NoError(t, fp.Shutdown(context.Background())) | ||
} | ||
|
||
func TestNonStringTemplate(t *testing.T) { | ||
fp := New() | ||
_, err := fp.Retrieve(context.Background(), templateSchemePrefix+filepath.Join("testdata", "nonstring-template.yaml"), nil) | ||
assert.ErrorContains(t, err, "template' must be a string") | ||
_, err = fp.Retrieve(context.Background(), templateSchemePrefix+absolutePath(t, filepath.Join("testdata", "nonstring-template.yaml")), nil) | ||
assert.ErrorContains(t, err, "template' must be a string") | ||
require.NoError(t, fp.Shutdown(context.Background())) | ||
} | ||
|
||
func TestInvalidTemplate(t *testing.T) { | ||
fp := New() | ||
_, err := fp.Retrieve(context.Background(), templateSchemePrefix+filepath.Join("testdata", "invalid-template.yaml"), nil) | ||
assert.ErrorContains(t, err, "parse as text/template") | ||
_, err = fp.Retrieve(context.Background(), templateSchemePrefix+absolutePath(t, filepath.Join("testdata", "invalid-template.yaml")), nil) | ||
assert.ErrorContains(t, err, "parse as text/template") | ||
require.NoError(t, fp.Shutdown(context.Background())) | ||
} | ||
|
||
func TestRelativePath(t *testing.T) { | ||
fp := New() | ||
ret, err := fp.Retrieve(context.Background(), templateSchemePrefix+filepath.Join("testdata", "default-config.yaml"), nil) | ||
require.NoError(t, err) | ||
retMap, err := ret.AsConf() | ||
assert.NoError(t, err) | ||
expectedMap := confmap.NewFromStringMap(map[string]any{ | ||
allTemplatesKey: map[string]any{ | ||
"my_filelog_template": "filelog:\n include: {{ .my_file }}\n", | ||
}, | ||
}) | ||
assert.Equal(t, expectedMap, retMap) | ||
assert.NoError(t, fp.Shutdown(context.Background())) | ||
} | ||
|
||
func TestAbsolutePath(t *testing.T) { | ||
fp := New() | ||
ret, err := fp.Retrieve(context.Background(), templateSchemePrefix+absolutePath(t, filepath.Join("testdata", "default-config.yaml")), nil) | ||
require.NoError(t, err) | ||
retMap, err := ret.AsConf() | ||
assert.NoError(t, err) | ||
expectedMap := confmap.NewFromStringMap(map[string]any{ | ||
allTemplatesKey: map[string]any{ | ||
"my_filelog_template": "filelog:\n include: {{ .my_file }}\n", | ||
}, | ||
}) | ||
assert.Equal(t, expectedMap, retMap) | ||
assert.NoError(t, fp.Shutdown(context.Background())) | ||
} | ||
|
||
func absolutePath(t *testing.T, relativePath string) string { | ||
dir, err := os.Getwd() | ||
require.NoError(t, err) | ||
return filepath.Join(dir, relativePath) | ||
} |
4 changes: 4 additions & 0 deletions
4
confmap/provider/templateprovider/testdata/default-config.yaml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
type: my_filelog_template | ||
template: | | ||
filelog: | ||
include: {{ .my_file }} |
4 changes: 4 additions & 0 deletions
4
confmap/provider/templateprovider/testdata/invalid-template.yaml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
type: my_filelog_template | ||
template: | | ||
filelog: | ||
include: {{ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
[invalid, |
1 change: 1 addition & 0 deletions
1
confmap/provider/templateprovider/testdata/missing-template.yaml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
type: my_filelog_template |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
template: | | ||
filelog: | ||
include: {{ .my_file }} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
- 123 | ||
- 456 |
2 changes: 2 additions & 0 deletions
2
confmap/provider/templateprovider/testdata/nonstring-template.yaml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
type: my_filelog_template | ||
template: [123,456] |
4 changes: 4 additions & 0 deletions
4
confmap/provider/templateprovider/testdata/nonstring-type.yaml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
type: [123,456] | ||
template: | | ||
filelog: | ||
include: {{ .my_file }} |