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

plugin/template: Add parseInt template function #5609

Merged
merged 5 commits into from
Sep 15, 2022

Conversation

erikjoh
Copy link
Contributor

@erikjoh erikjoh commented Sep 11, 2022

Signed-off-by: Erik Johansson ejohansson@spotify.com

1. Why is this pull request needed and what does it do?

This change adds a template function parseInt that can be used in templates to for example parse an IPv4 address
in hexadecimal encoding.
This also allows replicating the PowerDNS feature of getting auto generated A records with the hexadecimal format (for example ip7b7b7b7b.example.). Today, the template plugin only seems to allow for a dashed decimal IPv4 format (for example ip-123-123-123-123.example.).

I've tried to find a way to solve this with native template functions but it seems like adding strconv.ParseUint like this would be the best way to go.

2. Which issues (if any) are related?

No issue found.

3. Which documentation changes (if any) need to be made?

Template plugin README.

4. Does this introduce a backward incompatible change or deprecation?

No.

Signed-off-by: Erik Johansson <ejohansson@spotify.com>
Copy link
Member

@chrisohaver chrisohaver left a comment

Choose a reason for hiding this comment

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

Looks good. Can you add an operational test?

@codecov-commenter
Copy link

codecov-commenter commented Sep 12, 2022

Codecov Report

Merging #5609 (a931050) into master (93c57b6) will increase coverage by 1.17%.
The diff coverage is 57.84%.

@@            Coverage Diff             @@
##           master    #5609      +/-   ##
==========================================
+ Coverage   55.70%   56.87%   +1.17%     
==========================================
  Files         224      243      +19     
  Lines       10016    15609    +5593     
==========================================
+ Hits         5579     8878    +3299     
- Misses       3978     6188    +2210     
- Partials      459      543      +84     
Impacted Files Coverage Δ
core/dnsserver/address.go 100.00% <ø> (ø)
core/dnsserver/config.go 0.00% <ø> (ø)
plugin/auto/auto.go 0.00% <0.00%> (ø)
plugin/auto/zone.go 78.94% <ø> (+0.68%) ⬆️
plugin/autopath/autopath.go 73.61% <ø> (-1.39%) ⬇️
plugin/azure/azure.go 10.61% <0.00%> (-0.57%) ⬇️
plugin/azure/setup.go 56.36% <0.00%> (-4.14%) ⬇️
plugin/backend_lookup.go 0.00% <0.00%> (ø)
plugin/bind/bind.go 50.00% <0.00%> (-50.00%) ⬇️
plugin/bufsize/bufsize.go 100.00% <ø> (ø)
... and 316 more

📣 We’re building smart automated test selection to slash your CI/CD build times. Learn more

Signed-off-by: Erik Johansson <ejohansson@spotify.com>
@erikjoh
Copy link
Contributor Author

erikjoh commented Sep 12, 2022

@chrisohaver Added test/template_test.go since I didn't find any existing file which seemed appropriate.

@chrisohaver
Copy link
Member

chrisohaver commented Sep 12, 2022

I'm sorry I used confusing terminology - perhaps I should have said "functional test". IOW I meant a unit test that covers the functionality of the new operation added. e.g. the tests in /plugin/template/template_test.go. The unit tests in setup_test.go confirm config parsing, but not the operation of the new feature.

/tests/ is used for integration tests where we need to run a server; it's usually reserved for testing things that cannot be tested in a unit test (e.g. functionality across multiple plugins or integrations with dnsserver).

Signed-off-by: Erik Johansson <ejohansson@spotify.com>
Signed-off-by: Erik Johansson <ejohansson@spotify.com>
@erikjoh
Copy link
Contributor Author

erikjoh commented Sep 12, 2022

Sorry for that misunderstanding on my part as well and sorry to everyone who got pinged due to CODEOWNERS! 😓
Does this look like a step in the right direction?
The tests in /plugin/template/template_test.go currently mock all the Go templates so it seems more appropriate to have this functional test in /plugin/template/setup_test.go since what we essentially want to test is that templateParse actually is mapping parseInt to strconv.ParseUint and not some other function.

@chrisohaver
Copy link
Member

OK - I don't see that as mocking, but I see what you mean - the template objects are being created manually in the test.

So, either you'd need to replicate the function addition in the test, or better, break out the template creation into a function to be called from setup and the test e.g.

				for _, answer := range args {
					tmpl, err := gotmpl.New("answer").Funcs(funcMap).Parse(answer)
					if err != nil {
						return handler, c.Errf("could not compile template: %s, %v", c.Val(), err)
					}
					t.answer = append(t.answer, tmpl)
				}

becomes

				for _, answer := range args {
					err := t.addTemplate("answer", answer)
					if err != nil {
						return handler, c.Errf("could not compile template: %s, %v", c.Val(), err)
					}
				}

@erikjoh
Copy link
Contributor Author

erikjoh commented Sep 14, 2022

Based on your suggestion, wouldn't addTemplate require either reflect or a switch like this to find the correct field to append the template to:

func (t template) addTemplate(field, text string) (error) {
  funcMap := gotmpl.FuncMap{
    "parseInt": strconv.ParseUint,
  }
  tmpl, err := gotmpl.New(field).Funcs(funcMap).Parse(text)
  if err != nil {
    return err
  }
  switch field {
  case "answer":
    t.answer = append(t.answer, tmpl)
  case "additional":
    t.additional = append(t.additional, tmpl)
  case "authority":
    t.authority = append(t.authority, tmpl)
  default:
    return errors.New("not a valid field")
  }
}

Is that what you had in mind or would it be enough to just have a function to get a new template?

func newTemplate(name, text string) (*gotmpl.Template, error) {
  funcMap := gotmpl.FuncMap{
    "parseInt": strconv.ParseUint,
  }
  return gotmpl.New(name).Funcs(funcMap).Parse(text)
}

Considering how the objects are created in the test now I think the second option would be simpler.

exampleDomainATemplate := template{
regex: []*regexp.Regexp{regexp.MustCompile("(^|[.])ip-10-(?P<b>[0-9]*)-(?P<c>[0-9]*)-(?P<d>[0-9]*)[.]example[.]$")},
answer: []*gotmpl.Template{gotmpl.Must(gotmpl.New("answer").Parse("{{ .Name }} 60 IN A 10.{{ .Group.b }}.{{ .Group.c }}.{{ .Group.d }}"))},
qclass: dns.ClassANY,
qtype: dns.TypeANY,
fall: fall.Root,
zones: []string{"."},
}

Also would you like me to remove the test from the last commit?
Currently that test should cover the functionality that is added.

@chrisohaver chrisohaver reopened this Sep 14, 2022
@chrisohaver
Copy link
Member

Sorry. Fat fingered close on my phone.

@chrisohaver
Copy link
Member

Yes, the 2nd is what I had in mind, to fit easily into the existing tests. It’s not how it came out when I gave the code example though. Thanks for catching that.

@chrisohaver
Copy link
Member

Also would you like me to remove the test from the last commit?
Currently that test should cover the functionality that is added.

Yes. I don’t think they are necessary. Sorry again about misleading you to write them.

Signed-off-by: Erik Johansson <ejohansson@spotify.com>
Copy link
Member

@chrisohaver chrisohaver left a comment

Choose a reason for hiding this comment

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

LGTM Thanks!

@chrisohaver chrisohaver merged commit e93e932 into coredns:master Sep 15, 2022
@erikjoh erikjoh deleted the template-parse-int branch September 15, 2022 19:26
gonzalop pushed a commit to gonzalop/coredns that referenced this pull request Jan 14, 2023
* plugin/template: Add parseInt template function

Signed-off-by: Erik Johansson <ejohansson@spotify.com>
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.

3 participants