Skip to content

Commit e234621

Browse files
committed
feat: Warn when referencing an unknown environment or group in a config
1 parent 4d3d826 commit e234621

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"
@@ -1487,6 +1489,112 @@ func TestLoadProjects_NetworkZonesContainsParameterToSetting(t *testing.T) {
14871489
assert.Contains(t, networkZone2.Parameters, "__MONACO_NZONE_ENABLED__")
14881490
}
14891491

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

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

0 commit comments

Comments
 (0)