From 539aa8980e5e155d50de5f50597498841e40b251 Mon Sep 17 00:00:00 2001 From: mmerrill3 Date: Wed, 26 May 2021 16:38:44 -0400 Subject: [PATCH] Adding ability to query Infoblox API using regex for fqdn (#2102) Signed-off-by: mmerrill3 --- docs/tutorials/infoblox.md | 8 ++++++++ main.go | 1 + pkg/apis/externaldns/types.go | 3 +++ provider/infoblox/infoblox.go | 31 ++++++++++++++++++++---------- provider/infoblox/infoblox_test.go | 26 +++++++++++++++++++++++-- 5 files changed, 57 insertions(+), 12 deletions(-) diff --git a/docs/tutorials/infoblox.md b/docs/tutorials/infoblox.md index f0b95d557..d7c4b0ad1 100644 --- a/docs/tutorials/infoblox.md +++ b/docs/tutorials/infoblox.md @@ -260,3 +260,11 @@ $ curl -kl \ -u ${WAPI_USERNAME}:${WAPI_PASSWORD} \ https://${GRID_HOST}:${WAPI_PORT}/wapi/v${WAPI_VERSION}/zone_auth?fqdn=example.com ``` + +## Ability to filter results from the zone auth API using a regular expression + +There is also the ability to filter results from the Infoblox zone_auth service based upon a regular expression. See the [Infoblox API document](https://www.infoblox.com/wp-content/uploads/infoblox-deployment-infoblox-rest-api.pdf) for examples. To use this feature for the zone_auth service, set the parameter infoblox-fqdn-regex for external-dns to a regular expression that makes sense for you. For instance, to only return hosted zones that start with staging in the test.com domain (like staging.beta.test.com, or staging.test.com), use the following command line option when starting external-dns + +``` +--infoblox-fqdn-regex=^staging.*test.com$ +``` diff --git a/main.go b/main.go index 1a6f7cf65..9e337edb2 100644 --- a/main.go +++ b/main.go @@ -240,6 +240,7 @@ func main() { View: cfg.InfobloxView, MaxResults: cfg.InfobloxMaxResults, DryRun: cfg.DryRun, + FQDNRexEx: cfg.InfobloxFQDNRegEx, }, ) case "dyn": diff --git a/pkg/apis/externaldns/types.go b/pkg/apis/externaldns/types.go index 8655dc480..539958820 100644 --- a/pkg/apis/externaldns/types.go +++ b/pkg/apis/externaldns/types.go @@ -105,6 +105,7 @@ type Config struct { InfobloxSSLVerify bool InfobloxView string InfobloxMaxResults int + InfobloxFQDNRegEx string DynCustomerName string DynUsername string DynPassword string `secure:"yes"` @@ -228,6 +229,7 @@ var defaultConfig = &Config{ InfobloxSSLVerify: true, InfobloxView: "", InfobloxMaxResults: 0, + InfobloxFQDNRegEx: "", OCIConfigFile: "/etc/kubernetes/oci.yaml", InMemoryZones: []string{}, OVHEndpoint: "ovh-eu", @@ -410,6 +412,7 @@ func (cfg *Config) ParseFlags(args []string) error { app.Flag("infoblox-ssl-verify", "When using the Infoblox provider, specify whether to verify the SSL certificate (default: true, disable with --no-infoblox-ssl-verify)").Default(strconv.FormatBool(defaultConfig.InfobloxSSLVerify)).BoolVar(&cfg.InfobloxSSLVerify) app.Flag("infoblox-view", "DNS view (default: \"\")").Default(defaultConfig.InfobloxView).StringVar(&cfg.InfobloxView) app.Flag("infoblox-max-results", "Add _max_results as query parameter to the URL on all API requests. The default is 0 which means _max_results is not set and the default of the server is used.").Default(strconv.Itoa(defaultConfig.InfobloxMaxResults)).IntVar(&cfg.InfobloxMaxResults) + app.Flag("infoblox-fqdn-regex", "Apply this regular expression as a filter for obtaining zone_auth objects. This is disabled by default.").Default(defaultConfig.InfobloxFQDNRegEx).StringVar(&cfg.InfobloxFQDNRegEx) app.Flag("dyn-customer-name", "When using the Dyn provider, specify the Customer Name").Default("").StringVar(&cfg.DynCustomerName) app.Flag("dyn-username", "When using the Dyn provider, specify the Username").Default("").StringVar(&cfg.DynUsername) app.Flag("dyn-password", "When using the Dyn provider, specify the password").Default("").StringVar(&cfg.DynPassword) diff --git a/provider/infoblox/infoblox.go b/provider/infoblox/infoblox.go index 0cf08969e..9c98adf2e 100644 --- a/provider/infoblox/infoblox.go +++ b/provider/infoblox/infoblox.go @@ -46,6 +46,7 @@ type InfobloxConfig struct { DryRun bool View string MaxResults int + FQDNRexEx string } // InfobloxProvider implements the DNS provider for Infoblox. @@ -56,6 +57,7 @@ type InfobloxProvider struct { zoneIDFilter provider.ZoneIDFilter view string dryRun bool + fqdnRegEx string } type infobloxRecordSet struct { @@ -63,28 +65,36 @@ type infobloxRecordSet struct { res interface{} } -// MaxResultsRequestBuilder implements a HttpRequestBuilder which sets the -// _max_results query parameter on all get requests -type MaxResultsRequestBuilder struct { +// ExtendedRequestBuilder implements a HttpRequestBuilder which sets +// additional query parameter on all get requests +type ExtendedRequestBuilder struct { + fqdnRegEx string maxResults int ibclient.WapiRequestBuilder } -// NewMaxResultsRequestBuilder returns a MaxResultsRequestBuilder which adds +// NewExtendedRequestBuilder returns a ExtendedRequestBuilder which adds // _max_results query parameter to all GET requests -func NewMaxResultsRequestBuilder(maxResults int) *MaxResultsRequestBuilder { - return &MaxResultsRequestBuilder{ +func NewExtendedRequestBuilder(maxResults int, fqdnRegEx string) *ExtendedRequestBuilder { + return &ExtendedRequestBuilder{ + fqdnRegEx: fqdnRegEx, maxResults: maxResults, } } // BuildRequest prepares the api request. it uses BuildRequest of // WapiRequestBuilder and then add the _max_requests parameter -func (mrb *MaxResultsRequestBuilder) BuildRequest(t ibclient.RequestType, obj ibclient.IBObject, ref string, queryParams ibclient.QueryParams) (req *http.Request, err error) { +func (mrb *ExtendedRequestBuilder) BuildRequest(t ibclient.RequestType, obj ibclient.IBObject, ref string, queryParams ibclient.QueryParams) (req *http.Request, err error) { req, err = mrb.WapiRequestBuilder.BuildRequest(t, obj, ref, queryParams) if req.Method == "GET" { query := req.URL.Query() - query.Set("_max_results", strconv.Itoa(mrb.maxResults)) + if mrb.maxResults > 0 { + query.Set("_max_results", strconv.Itoa(mrb.maxResults)) + } + _, ok := obj.(*ibclient.ZoneAuth) + if ok && t == ibclient.GET && mrb.fqdnRegEx != "" { + query.Set("fqdn~", mrb.fqdnRegEx) + } req.URL.RawQuery = query.Encode() } return @@ -110,9 +120,9 @@ func NewInfobloxProvider(infobloxConfig InfobloxConfig) (*InfobloxProvider, erro ) var requestBuilder ibclient.HttpRequestBuilder - if infobloxConfig.MaxResults != 0 { + if infobloxConfig.MaxResults != 0 || infobloxConfig.FQDNRexEx != "" { // use our own HttpRequestBuilder which sets _max_results parameter on GET requests - requestBuilder = NewMaxResultsRequestBuilder(infobloxConfig.MaxResults) + requestBuilder = NewExtendedRequestBuilder(infobloxConfig.MaxResults, infobloxConfig.FQDNRexEx) } else { // use the default HttpRequestBuilder of the infoblox client requestBuilder = &ibclient.WapiRequestBuilder{} @@ -132,6 +142,7 @@ func NewInfobloxProvider(infobloxConfig InfobloxConfig) (*InfobloxProvider, erro zoneIDFilter: infobloxConfig.ZoneIDFilter, dryRun: infobloxConfig.DryRun, view: infobloxConfig.View, + fqdnRegEx: infobloxConfig.FQDNRexEx, } return provider, nil diff --git a/provider/infoblox/infoblox_test.go b/provider/infoblox/infoblox_test.go index 6bccf7e38..a91e03664 100644 --- a/provider/infoblox/infoblox_test.go +++ b/provider/infoblox/infoblox_test.go @@ -533,7 +533,7 @@ func TestInfobloxZones(t *testing.T) { assert.Equal(t, provider.findZone(zones, "lvl2-2.lvl1-2.example.com").Fqdn, "example.com") } -func TestMaxResultsRequestBuilder(t *testing.T) { +func TestExtendedRequestFDQDRegExBuilder(t *testing.T) { hostConfig := ibclient.HostConfig{ Host: "localhost", Port: "8080", @@ -542,7 +542,29 @@ func TestMaxResultsRequestBuilder(t *testing.T) { Version: "2.3.1", } - requestBuilder := NewMaxResultsRequestBuilder(54321) + requestBuilder := NewExtendedRequestBuilder(0, "^staging.*test.com$") + requestBuilder.Init(hostConfig) + + obj := ibclient.NewZoneAuth(ibclient.ZoneAuth{}) + + req, _ := requestBuilder.BuildRequest(ibclient.GET, obj, "", ibclient.QueryParams{}) + + assert.True(t, req.URL.Query().Get("fqdn~") == "^staging.*test.com$") + + req, _ = requestBuilder.BuildRequest(ibclient.CREATE, obj, "", ibclient.QueryParams{}) + + assert.True(t, req.URL.Query().Get("fqdn~") == "") +} +func TestExtendedRequestMaxResultsBuilder(t *testing.T) { + hostConfig := ibclient.HostConfig{ + Host: "localhost", + Port: "8080", + Username: "user", + Password: "abcd", + Version: "2.3.1", + } + + requestBuilder := NewExtendedRequestBuilder(54321, "") requestBuilder.Init(hostConfig) obj := ibclient.NewRecordCNAME(ibclient.RecordCNAME{Zone: "foo.bar.com"})