diff --git a/docs/tutorials/infoblox.md b/docs/tutorials/infoblox.md index 8c3b2bfbd..71a3cafc3 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 06b4eba1c..92ab0c53b 100644 --- a/main.go +++ b/main.go @@ -241,6 +241,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 96a96f70b..05c392a0c 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"})