Skip to content

Commit 11c3d15

Browse files
committed
feat: Warn when referencing an unknown environment or group in a config
1 parent b19958e commit 11c3d15

File tree

5 files changed

+150
-12
lines changed

5 files changed

+150
-12
lines changed

pkg/config/errors/loader_errors.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package errors
1818

1919
import (
2020
"fmt"
21+
2122
"github.com/dynatrace/dynatrace-configuration-as-code/v2/pkg/config/coordinate"
2223
)
2324

pkg/config/loader/config_entry_loader.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525

2626
"github.com/spf13/afero"
2727

28+
"github.com/dynatrace/dynatrace-configuration-as-code/v2/internal/log"
2829
"github.com/dynatrace/dynatrace-configuration-as-code/v2/pkg/api"
2930
"github.com/dynatrace/dynatrace-configuration-as-code/v2/pkg/config"
3031
"github.com/dynatrace/dynatrace-configuration-as-code/v2/pkg/config/coordinate"
@@ -55,7 +56,19 @@ func parseConfigEntry(
5556
return nil, []error{newDefinitionParserError(configId, singleConfigContext, err.Error())}
5657
}
5758

59+
for _, group := range definition.GroupOverrides {
60+
if _, exists := loaderContext.KnownGroups[group.Group]; !exists {
61+
log.Warn("unknown group '%s'", group.Group)
62+
}
63+
}
64+
5865
groupOverrideMap := toGroupOverrideMap(definition.GroupOverrides)
66+
67+
for _, env := range definition.EnvironmentOverrides {
68+
if _, exists := loaderContext.KnownEnvironments[env.Environment]; !exists {
69+
log.Warn("unknown environment '%s'", env.Environment)
70+
}
71+
}
5972
environmentOverrideMap := toEnvironmentOverrideMap(definition.EnvironmentOverrides)
6073

6174
var results []config.Config

pkg/config/loader/config_loader.go

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,13 @@ import (
3636
)
3737

3838
type LoaderContext struct {
39-
ProjectId string
40-
Path string
41-
Environments []manifest.EnvironmentDefinition
42-
KnownApis map[string]struct{}
43-
ParametersSerDe map[string]parameter.ParameterSerDe
39+
ProjectId string
40+
Path string
41+
Environments []manifest.EnvironmentDefinition
42+
KnownApis map[string]struct{}
43+
KnownEnvironments map[string]struct{}
44+
KnownGroups map[string]struct{}
45+
ParametersSerDe map[string]parameter.ParameterSerDe
4446
}
4547

4648
// configFileLoaderContext is a context for each config-file

pkg/project/project_loader.go

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -323,13 +323,7 @@ func loadConfigsOfProject(ctx context.Context, fs afero.Fs, loadingContext Proje
323323
var configs []config.Config
324324
var errs []error
325325

326-
loaderContext := &loader.LoaderContext{
327-
ProjectId: projectDefinition.Name,
328-
Environments: environments,
329-
Path: projectDefinition.Path,
330-
KnownApis: loadingContext.KnownApis,
331-
ParametersSerDe: loadingContext.ParametersSerde,
332-
}
326+
loaderContext := newLoaderContext(loadingContext, projectDefinition, environments)
333327

334328
for _, file := range configFiles {
335329
log.WithFields(field.F("file", file)).Debug("Loading configuration file %s", file)
@@ -341,6 +335,26 @@ func loadConfigsOfProject(ctx context.Context, fs afero.Fs, loadingContext Proje
341335
return configs, errs
342336
}
343337

338+
func newLoaderContext(loadingContext ProjectLoaderContext, projectDefinition manifest.ProjectDefinition,
339+
environments []manifest.EnvironmentDefinition) *loader.LoaderContext {
340+
knownEnvironments := map[string]struct{}{}
341+
knownGroups := map[string]struct{}{}
342+
for _, env := range environments {
343+
knownEnvironments[env.Name] = struct{}{}
344+
knownGroups[env.Group] = struct{}{}
345+
}
346+
347+
return &loader.LoaderContext{
348+
ProjectId: projectDefinition.Name,
349+
Environments: environments,
350+
Path: projectDefinition.Path,
351+
KnownApis: loadingContext.KnownApis,
352+
KnownEnvironments: knownEnvironments,
353+
KnownGroups: knownGroups,
354+
ParametersSerDe: loadingContext.ParametersSerde,
355+
}
356+
}
357+
344358
func findDuplicatedConfigIdentifiers(ctx context.Context, configs []config.Config, configErrorMap map[coordinate.Coordinate]struct{}) []error {
345359
var errs []error
346360
coordinates := make(map[string]struct{})

pkg/project/project_loader_test.go

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package project
1818

1919
import (
20+
"bytes"
2021
"fmt"
2122
"io/fs"
2223
"reflect"
@@ -27,6 +28,7 @@ import (
2728
"github.com/stretchr/testify/require"
2829

2930
"github.com/dynatrace/dynatrace-configuration-as-code/v2/internal/errutils"
31+
"github.com/dynatrace/dynatrace-configuration-as-code/v2/internal/log"
3032
"github.com/dynatrace/dynatrace-configuration-as-code/v2/internal/testutils"
3133
"github.com/dynatrace/dynatrace-configuration-as-code/v2/pkg/config"
3234
"github.com/dynatrace/dynatrace-configuration-as-code/v2/pkg/config/coordinate"
@@ -1481,6 +1483,112 @@ func TestLoadProjects_NetworkZonesContainsParameterToSetting(t *testing.T) {
14811483
assert.Contains(t, networkZone2.Parameters, "__MONACO_NZONE_ENABLED__")
14821484
}
14831485

1486+
// TestLoadProjects_EnvironmentOverrideWithUndefinedEnvironmentProducesWarning tests that referencing an undefined environment in an environment override produces a warning.
1487+
func TestLoadProjects_EnvironmentOverrideWithUndefinedEnvironmentProducesWarning(t *testing.T) {
1488+
managementZoneConfig := []byte(`configs:
1489+
- id: mz
1490+
config:
1491+
template: mz.json
1492+
type:
1493+
settings:
1494+
schema: builtin:management-zones
1495+
scope: environment
1496+
environmentOverrides:
1497+
- environment: prod
1498+
override:
1499+
skip: true
1500+
`)
1501+
1502+
managementZoneJSON := []byte(`{ "name": "", "rules": [] }`)
1503+
1504+
testFs := testutils.TempFs(t)
1505+
logSpy := bytes.Buffer{}
1506+
log.PrepareLogging(t.Context(), afero.NewMemMapFs(), false, &logSpy, false, false)
1507+
1508+
require.NoError(t, testFs.MkdirAll("a/builtinmanagement-zones", testDirectoryFileMode))
1509+
require.NoError(t, afero.WriteFile(testFs, "a/builtinmanagement-zones/config.yaml", managementZoneConfig, testFileFileMode))
1510+
require.NoError(t, afero.WriteFile(testFs, "a/builtinmanagement-zones/mz.json", managementZoneJSON, testFileFileMode))
1511+
1512+
testContext := ProjectLoaderContext{
1513+
KnownApis: map[string]struct{}{"builtin:management-zones": {}},
1514+
WorkingDir: ".",
1515+
Manifest: manifest.Manifest{
1516+
Projects: manifest.ProjectDefinitionByProjectID{
1517+
"a": {
1518+
Name: "a",
1519+
Path: "a/",
1520+
},
1521+
},
1522+
Environments: manifest.Environments{
1523+
"dev": {
1524+
Name: "dev",
1525+
Auth: manifest.Auth{Token: &manifest.AuthSecret{Name: "ENV_VAR"}},
1526+
},
1527+
},
1528+
},
1529+
ParametersSerde: config.DefaultParameterParsers,
1530+
}
1531+
1532+
gotProjects, gotErrs := LoadProjects(t.Context(), testFs, testContext, nil)
1533+
assert.Len(t, gotErrs, 0, "Expected no errors loading dependent projects ")
1534+
assert.Len(t, gotProjects, 1)
1535+
1536+
assert.Contains(t, logSpy.String(), "unknown environment")
1537+
}
1538+
1539+
// TestLoadProjects_GroupOverrideWithUndefinedGroupProducesWarning tests that referencing an undefined environment group in a group override produces a warning.
1540+
func TestLoadProjects_GroupOverrideWithUndefinedGroupProducesWarning(t *testing.T) {
1541+
managementZoneConfig := []byte(`configs:
1542+
- id: mz
1543+
config:
1544+
template: mz.json
1545+
type:
1546+
settings:
1547+
schema: builtin:management-zones
1548+
scope: environment
1549+
groupOverrides:
1550+
- group: prod
1551+
override:
1552+
skip: true
1553+
`)
1554+
1555+
managementZoneJSON := []byte(`{ "name": "", "rules": [] }`)
1556+
1557+
testFs := testutils.TempFs(t)
1558+
1559+
logSpy := bytes.Buffer{}
1560+
log.PrepareLogging(t.Context(), afero.NewMemMapFs(), false, &logSpy, false, false)
1561+
1562+
require.NoError(t, testFs.MkdirAll("a/builtinmanagement-zones", testDirectoryFileMode))
1563+
require.NoError(t, afero.WriteFile(testFs, "a/builtinmanagement-zones/config.yaml", managementZoneConfig, testFileFileMode))
1564+
require.NoError(t, afero.WriteFile(testFs, "a/builtinmanagement-zones/mz.json", managementZoneJSON, testFileFileMode))
1565+
testContext := ProjectLoaderContext{
1566+
KnownApis: map[string]struct{}{"builtin:management-zones": {}},
1567+
WorkingDir: ".",
1568+
Manifest: manifest.Manifest{
1569+
Projects: manifest.ProjectDefinitionByProjectID{
1570+
"a": {
1571+
Name: "a",
1572+
Path: "a/",
1573+
},
1574+
},
1575+
Environments: manifest.Environments{
1576+
"dev": {
1577+
Name: "dev",
1578+
Auth: manifest.Auth{Token: &manifest.AuthSecret{Name: "ENV_VAR"}},
1579+
},
1580+
},
1581+
},
1582+
ParametersSerde: config.DefaultParameterParsers,
1583+
}
1584+
1585+
gotProjects, gotErrs := LoadProjects(t.Context(), testFs, testContext, nil)
1586+
assert.Len(t, gotErrs, 0, "Expected no errors loading dependent projects ")
1587+
assert.Len(t, gotProjects, 1)
1588+
1589+
assert.Contains(t, logSpy.String(), "unknown group")
1590+
}
1591+
14841592
type propResolver func(coordinate.Coordinate, string) (any, bool)
14851593

14861594
func (p propResolver) GetResolvedProperty(coordinate coordinate.Coordinate, propertyName string) (any, bool) {

0 commit comments

Comments
 (0)