consul-terraform-sync icon indicating copy to clipboard operation
consul-terraform-sync copied to clipboard

TerraformConfig: Add KeyValues method

Open thisisommore opened this issue 4 years ago • 14 comments

Work in progress PR to fix #377

thisisommore avatar Nov 13 '21 04:11 thisisommore

CLA assistant check
All committers have signed the CLA.

hashicorp-cla avatar Nov 13 '21 04:11 hashicorp-cla

@wilkermichael Is this the way we should go over all the structs?

thisisommore avatar Nov 13 '21 04:11 thisisommore

Hey @thisisommore, thanks for taking a look at this! This solution definitely is an improvement towards querying and computer parsing.

After doing some investigation myself, I realised that the log library we’re using supports JSON output which would be the ideal format for querying tools. Therefore, it makes more sense to make sure the JSON is queryable, and the focus of the human-readable output should be on clarity. For example, I've written a test case that demos what that might look like with your change:

func TestInterface(t *testing.T) {
	tc := TerraformConfig{
		Version:    String("test"),
		Log:        Bool(true),
		WorkingDir: String("test"),
	}
	var cc ConsulConfig
	cc.Finalize()
	tc.Finalize(&cc)

        // Output human readable
	logging.Global().Info("test", tc.KeyValues()...)

	logger := hclog.New(&hclog.LoggerOptions{
		JSONFormat: true, // in the future support a flag to toggle this JSON format
		TimeFormat: hclog.TimeFormat,
	})
	hclog.SetDefault(logger)
        
        // Output JSON
	logging.Global().Info("test", tc.KeyValues()...)
}

Which outputs the human readable:

2021-11-16T11:58:24.640-0800 [INFO] test: Version=test Log=true PersistLog=false Path=/Users/mwilkerson/dev/consul-terraform-sync/config WorkingDir=test Backend="map[consul:map[address:localhost:8500 gzip:true path:consul-terraform-sync/terraform]]" RequiredProviders=map[]

and the json

{
   "@level":"info",
   "@message":"test",
   "@timestamp":"2021-11-16T11:49:13.914-0800",
   "Backend":{
      "consul":{
         "address":"localhost:8500",
         "gzip":true,
         "path":"consul-terraform-sync/terraform"
      }
   },
   "Log":true,
   "Path":"/Users/mwilkerson/dev/consul-terraform-sync/config",
   "PersistLog":false,
   "RequiredProviders":{
      
   },
   "Version":"test",
   "WorkingDir":"test"
}

One limitation with the solution here is that the JSON object doesn't include any reference to the original object, in this case TerraformConfig, so a user wouldn't be able to query for example terraformConfig.Version="test".

After investigating a bit more, I’ve added a possible alternative solution, more information and examples can now be found in the issue details. Let me know how you feel about them. I know it's a lot of information at once, so don’t hesitate to reach out if you have more questions.

wilkermichael avatar Nov 17 '21 17:11 wilkermichael

@wilkermichael Sorry for the late response, was going through a lot of study work, and now I am looking at this.

thisisommore avatar Dec 13 '21 08:12 thisisommore

Hey @wilkermichael I have a few questions

  • What can be done here? Should this field be omitted in json using json:"-" https://github.com/hashicorp/consul-terraform-sync/blob/cf630a15e69a6342fe44fd7434283022b36b457c/config/condition_catalog_services.go#L12-L14

  • Some structs are implementing this interface which has GoString so I cannot rename GoString method to String of these structs, should we rename the method in MonitorConfig interface too? https://github.com/hashicorp/consul-terraform-sync/blob/c0c4728b7ded880bc5ad47e951a79b81fd5cb6d3/config/monitor.go#L9-L15

thisisommore avatar Dec 16 '21 04:12 thisisommore

Hey @wilkermichael I have a few questions

  • What can be done here? Should this field be omitted in json using json:"-" https://github.com/hashicorp/consul-terraform-sync/blob/cf630a15e69a6342fe44fd7434283022b36b457c/config/condition_catalog_services.go#L12-L14
  • Some structs are implementing this interface which has GoString so I cannot rename GoString method to String of these structs, should we rename the method in MonitorConfig interface too? https://github.com/hashicorp/consul-terraform-sync/blob/c0c4728b7ded880bc5ad47e951a79b81fd5cb6d3/config/monitor.go#L9-L15

Hey @thisisommore, thanks for your patience while I got back to you. I'll address each question here:

(1) I just did a quick test to verify the current default behaviour of that squashed field when logging json:

c := &CatalogServicesConditionConfig{
				CatalogServicesMonitorConfig{
					Regexp:            String(".*"),
					SourceIncludesVar: Bool(true),
					Datacenter:        String("dc2"),
					Namespace:         String("ns2"),
					NodeMeta: map[string]string{
						"key1": "value1",
						"key2": "value2",
					},
				},
			}

// JSON logging enabled
logging.Global().Info("this is a json log", "catalogServicesConditionConfig", c)`

yields the following log:

{
    "@level": "info",
    "@message": "this is a json log",
    "@timestamp": "2021-12-20T11:31:26.262-0800",
    "catalogServicesConditionConfig": {
        "Regexp": ".*",
        "SourceIncludesVar": true,
        "Datacenter": "dc2",
        "Namespace": "ns2",
        "NodeMeta": {
            "key1": "value1",
            "key2": "value2"
        }
    }
}

Ignoring the field names since I didn't setup struct tags for them, the general structure of this json makes sense to me. It looks like it doesn't include the squashed field name in the JSON which I think is good. If you add the json:"-" tag I believe the struct won't be included at all. I therefore suggest you not add json tags to squashed fields like in the example you provided.

(2) I think renaming the interface method to String() makes sense!

wilkermichael avatar Dec 20 '21 19:12 wilkermichael

@wilkermichael Thanks for addressing this, I have committed the changes, and now will try creating tests. You can review my changes and let me know if any change is needed.

thisisommore avatar Dec 22 '21 09:12 thisisommore

@wilkermichael do I have a write the test for each struct?

thisisommore avatar Jan 02 '22 15:01 thisisommore

@wilkermichael do I have a write the test for each struct?

@thisisommore thanks for your patience, I've been on holidays the last couple of weeks. I think it would be a good idea to have a test for each struct, however, you can just test whether or not the object marshal's successfully. You don't need to check that the string matches for each case.

wilkermichael avatar Jan 06 '22 22:01 wilkermichael

@wilkermichael Thanks for addressing this, I have committed the changes, and now will try creating tests. You can review my changes and let me know if any change is needed.

@thisisommore I was looking through again and noticed you asked me to do a preliminary review. I'm happy to do one for you, however, can you please rebase your changes onto main first and resolve the conflicts? There have been a number of changes to the config since work was started on this PR.

wilkermichael avatar Jan 18 '22 22:01 wilkermichael

@thisisommore I was looking through again and noticed you asked me to do a preliminary review. I'm happy to do one for you, however, can you please rebase your changes onto main first and resolve the conflicts? There have been a number of changes to the config since work was started on this PR.

@wilkermichael sorry for being late, I have merged main into this PR, also I was not going into the test due to now sure where to start, I hope this is not urgent or feel free to assign this to someone else, I will be trying hands on it again this Sunday.

Also Happy New Year 🥳, hope you are doing well.

thisisommore avatar Jan 20 '22 15:01 thisisommore

@thisisommore Happy New Year!

No rush on this, take your time. I probably won't get a chance to review until next week.

wilkermichael avatar Jan 21 '22 16:01 wilkermichael

@thisisommore I changed some settings on our end as I noticed that the pipeline wasn't running for your PR. The checks should now show the areas where the PR is failing.

wilkermichael avatar Jan 28 '22 21:01 wilkermichael

You can ignore the Slack failure, that one is on our end. It requires a setting change, but won't affect your PR.

EDIT: This has been resolved now in the latest main, if you rebase on the latest main it should resolve the slack failure in the pipeline

wilkermichael avatar Jan 28 '22 21:01 wilkermichael