Skip to content
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

Rework internal config structure #261

Merged
merged 2 commits into from
Jul 21, 2021

Conversation

patrickpichler
Copy link
Contributor

@patrickpichler patrickpichler commented Mar 19, 2021

This PR contains a proof of concept of a new configuration scheme.

It basically breaks with the current one completely. For further information have a look at
discussion #165

I opened this PR just to make my code changes more visible.

@patrickpichler patrickpichler force-pushed the poc-new-config branch 3 times, most recently from 7fe58d3 to a4cf2cf Compare March 26, 2021 14:31
@patrickpichler
Copy link
Contributor Author

This PR is getting more and more in a state where we could merge it.
There is now a conversion layer between the old config structs and the new ones. I
hooked up the CLI to convert the converter and use the new deployment logic.

There is also now the possibility to test the new config syntax, by setting the NEW_CONFIG
env variable to 1.

What is still missing for now are tests. I'm now focusing on those.

@dynatrace-oss/mac-maintainers would be nice if somebody could read through the PR

@patrickpichler patrickpichler requested a review from a team March 30, 2021 05:46
@patrickpichler patrickpichler force-pushed the poc-new-config branch 4 times, most recently from f1af432 to 8d9f817 Compare April 6, 2021 10:27
@patrickpichler patrickpichler added the run-e2e-test Manually trigger the E2E tests for reviewed PRs label Apr 6, 2021
@github-actions
Copy link

github-actions bot commented Apr 6, 2021

❌ Integration tests failed on ubuntu-latest

@patrickpichler patrickpichler added run-e2e-test Manually trigger the E2E tests for reviewed PRs and removed run-e2e-test Manually trigger the E2E tests for reviewed PRs labels Apr 6, 2021
@github-actions
Copy link

github-actions bot commented Apr 6, 2021

❌ Integration tests failed on ubuntu-latest

@patrickpichler patrickpichler marked this pull request as ready for review April 9, 2021 06:54
@patrickpichler patrickpichler added run-e2e-test Manually trigger the E2E tests for reviewed PRs and removed run-e2e-test Manually trigger the E2E tests for reviewed PRs labels Apr 9, 2021
@github-actions
Copy link

github-actions bot commented Apr 9, 2021

🎉 Integration tests ran successfully on ubuntu-latest 🥳

@patrickpichler patrickpichler force-pushed the poc-new-config branch 2 times, most recently from 49e73b3 to 02b591d Compare April 9, 2021 11:18
@patrickpichler patrickpichler added run-e2e-test Manually trigger the E2E tests for reviewed PRs and removed run-e2e-test Manually trigger the E2E tests for reviewed PRs labels Apr 9, 2021
@github-actions
Copy link

github-actions bot commented Apr 9, 2021

🎉 Integration tests ran successfully on ubuntu-latest 🥳

@patrickpichler patrickpichler changed the title Proof of concept for new config format Rework internal config structure Apr 13, 2021
@@ -16,4 +16,4 @@

package version

const MonitoringAsCode = "1.5.0"
const MonitoringAsCode = "config-poc"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

random note cause I started by scrolling to the bottom: this should change before merging this ;)

tatomir146
tatomir146 previously approved these changes Jul 13, 2021
const (
// id is a special parameter. it is not allowed to be set via the config,
// but needs to work as normal parameter otherwise (e.g. it can be referenced).
ID_PARAMETER = "id"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Goland complains we shoud use camel and not snake case for these constants.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TIL that golang uses camel case as naming convention for constants.
THX! I will fix it!

)

const (
// id is a special parameter. it is not allowed to be set via the config,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These comments should start with
// ID_PARAMETER is a special...

return c.Coordinate.Match(ref)
}

// test if this config has a dependency on the given config.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same for method comments, they should start with method name
// HasDependencyOn

// map of all parameters which will be resolved and are then available
// in the template
Parameters Parameters
// slice of references as specified by the paramters. needed so that the
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// slice of references as specified by the paramters. needed so that the
// slice of references as specified by the parameters. needed so that the

}

func parseSkip(context *ConfigLoaderContext, environment manifest.EnvironmentDefinition,
configId string, definition configDefinition, param interface{}) (bool, error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused param

Suggested change
configId string, definition configDefinition, param interface{}) (bool, error) {
configId string, param interface{}) (bool, error) {

}

func parseParameter(context *ConfigLoaderContext, environment manifest.EnvironmentDefinition,
configId string, definition configDefinition, name string, param interface{}) (parameter.Parameter, error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused param

Suggested change
configId string, definition configDefinition, name string, param interface{}) (parameter.Parameter, error) {
configId string, name string, param interface{}) (parameter.Parameter, error) {

}

switch valueParam.Value.(type) {
// map/array values need special handling to not collide with oter paramters
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

other parameters

}

// tests if this coordinate is the same as the given one
func (c *Coordinate) Match(coordinate Coordinate) bool {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using different receiver names


type knownEntityMap map[string]map[string]struct{}

// deployes the given configs with the given apis via the given client
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// deployes the given configs with the given apis via the given client
// DeployConfigs deploys the given configs with the given apis via the given client

// as they will never be resolved before we validate
// the parameters
if ref.Config == configCoordinates {
// parameters referencing themselfs makes no sense
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// parameters referencing themselfs makes no sense
// parameters referencing themselves makes no sense

@@ -33,7 +33,7 @@ func LoadEnvironmentList(specificEnvironment string, environmentsFile string, fs

environmentsFromFile, errorList := readEnvironments(environmentsFile, fs)

if environmentsFromFile == nil || len(environmentsFromFile) == 0 {
if len(environmentsFromFile) == 0 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we fix the typo on line 30:
"no environment file provided"

}

func (m *Manifest) GetEnvironmentsAsSlice() []EnvironmentDefinition {
var result []EnvironmentDefinition = make([]EnvironmentDefinition, 0, len(m.Environments))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
var result []EnvironmentDefinition = make([]EnvironmentDefinition, 0, len(m.Environments))
var result = make([]EnvironmentDefinition, 0, len(m.Environments))

"path/filepath"
"time"

api "github.com/dynatrace-oss/dynatrace-monitoring-as-code/pkg/api"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
api "github.com/dynatrace-oss/dynatrace-monitoring-as-code/pkg/api"
"github.com/dynatrace-oss/dynatrace-monitoring-as-code/pkg/api"

@@ -88,6 +87,11 @@ func NewConfigForDelete(id string, fileName string, properties map[string]map[st
return newConfig(id, "", nil, filterProperties(id, properties), api, fileName)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NewConfigForDelete seems to not be used anywhere.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is legacy config file. I would rather not touch it any more than necessary 😆
I guess the plan would be, to get rid of all legacy files within the next few versions.

@@ -16,4 +16,4 @@

package version

const MonitoringAsCode = "1.6.0"
const MonitoringAsCode = "2.0.0-new-config"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not simply

Suggested change
const MonitoringAsCode = "2.0.0-new-config"
const MonitoringAsCode = "2.0.0"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was just for local debug builds. I would not go with 2.0.0 yet.
Maybe 2.0.0-next, since we are going to build next binaries. That
way people don't mistake it for a full release.

Aliases: []string{"v"},
},
&cli.StringFlag{
Name: "specific-environment",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would be a good opportunity to modify this: how about using -e or -environment. Not sure we need specific

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you ask me, we should delete this file anyway. The new main is located
in cmd/monaco/v2/main.go.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just kept this file as I wasn't sure how we want to go on with it.

deployCommand := getDeployCommand(fs)
var deployCommand cli.Command

if isEnvFlagEnabled("NEW_CONFIG") {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't we make NEW_CONFIG a default? We should rather allow compatibility mode with CONFIG_V1 flag, but use new config as default.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As pointed out above, I would ignore this file and delete it.

@patrickpichler patrickpichler force-pushed the poc-new-config branch 2 times, most recently from 1b119ef to fc0a49c Compare July 15, 2021 07:06
})

if errs != nil {
return errors.New("error while loading projects")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return errors.New("error while loading projects")
util.PrintErrors(errs)
return errors.New("error while loading projects")

Is there any reason not to print the errors? Just dropping them and returning a new error doesn't seem very favorable

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch 😆

sortedConfigs, errs := sort.GetSortedConfigsForEnvironments(projects, environmentNames)

if errs != nil {
return errors.New("error during sort")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return errors.New("error during sort")
util.PrintErrors(errs)
return errors.New("error during sort")

Comment on lines 47 to 49
for _, err := range errs {
util.Log.Error(err.Error())
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
for _, err := range errs {
util.Log.Error(err.Error())
}
util.PrintErrors(errs)

Comment on lines 132 to 134
if errors != nil {
deploymentErrors = append(deploymentErrors, errors...)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if errors != nil {
deploymentErrors = append(deploymentErrors, errors...)
}
deploymentErrors = append(deploymentErrors, errors...)

No need to check for nil, appending a nil slice is perfectly fine

Comment on lines +161 to +171
for _, err := range generalErrors {
util.Log.Error(util.ErrorString(err))
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
for _, err := range generalErrors {
util.Log.Error(util.ErrorString(err))
}
util.PrintErrors(generalErrors)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs to change anyway. We should create a proper error report here.
I'll add an TODO.

return result, nil
}

func parseProjectDefinition(context *projectLoaderContext, project project) ([]ProjectDefinition, []error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I see it only one error is ever returned, is a slice really needed here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As this method is designed with adding new project types in mind,
I would personally keep it.

Comment on lines 206 to 207
if errs != nil {
errors = append(errors, errs...)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if errs != nil {
errors = append(errors, errs...)
}
errors = append(errors, errs...)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should short-circuit anyway here, as the sortedProjectsPerEnvironment will anyway be nil.

Comment on lines 85 to 87
if len(errs) > 0 {
errors = append(errors, errs...)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if len(errs) > 0 {
errors = append(errors, errs...)
}
errors = append(errors, errs...)

Comment on lines 97 to 98
func collectAllConfigs(p project.Project) []config.Config {
var result []config.Config
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
func collectAllConfigs(p project.Project) []config.Config {
var result []config.Config
func collectAllConfigs(p project.Project) (result []config.Config) {


func (c *DummyClient) BulkDeleteByName(a api.Api, names []string) error {
for _, name := range names {
err := c.DeleteByName(a, name)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The dummy client's DeleteByName only returns nil error, so no need to check for that tbh

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, for now. The interface specifies that it could return an error,
so imho we should handle it (even though it is pretty much useless
now ^^)

@patrickpichler patrickpichler force-pushed the poc-new-config branch 2 times, most recently from e941c0a to ad0117a Compare July 20, 2021 13:51
@tatomir146 tatomir146 self-requested a review July 20, 2021 13:54
tatomir146
tatomir146 previously approved these changes Jul 20, 2021
Patrick Pichler added 2 commits July 20, 2021 16:30
As the current config structure was a bit complicated to use, it has
been completely reworked.

First of all, there is now a central manifest file, which specifies all
the details needed for deployment. This includes a list of all available
projects (including paths to them, so goodbye recursive project
discovery) and a grouping of available environment (including the name
of the env variable holding the token).

The structure within a project now has to follow a strict scheme,
naminly `[api]/[config]`. Auto-discovery of sub-Projects are no
longer supported. This was done to make things more explicit.

The configuration yaml also looks now different. Instead of splitting
configuration definitions in two parts (template location, rest of the
config), everything is now in one structure. The top level structure of
each yaml file is now called `configs`. For examples please see the
documentation.

Config paramters also have been reworked. They now support more values
besides strings. There are some special parameter though. One of this
special parameter is the reference parameter. References no longer
depend on a special formatted string, instead you have to explicitly
define the location of the config you want to reference. It is now also
possible to depend on **any** reference of a config, not just id and
name.

Another special parameter is the environment parameter. It is **no longer**
possible to reference env variables via the `{ .env.XYZ }` syntax in the
config yaml or the template. This decision was made, to make configs
more explicit.

For more details on how the new parameter syntax works, please see the
documentation.

The delete.yaml now also supports deleting configs with multiple `/` in
its name.

Fixes Dynatrace#351
Fixes Dynatrace#255
Since we reworked the configuration syntax, the current configuration
file syntax won't work. In order to support different types of
integration tests, they have been moved into their own package. Also
all the command parsing logic of the main file was factored out into a
runner package. This way we can easily use it from the integration test
packages.
@patrickpichler patrickpichler merged commit fcfdf99 into Dynatrace:next Jul 21, 2021
@patrickpichler patrickpichler deleted the poc-new-config branch July 21, 2021 05:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants