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

Extending DepResolver #173

Merged
merged 1 commit into from
Oct 19, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 46 additions & 13 deletions controllers/depresolver/depresolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
// - provides predefined values when configuration is missing
// - validates configuration
// - executes once
// TODO: Add the rest of configuration to be resolved
package depresolver

import (
Expand All @@ -14,17 +13,57 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
)

//Config holds operator configuration
// EdgeDNSType specifies to which edge DNS is k8gb connecting
type EdgeDNSType int

const (
// DNSTypeNoEdgeDNS is default DNSType. Is used during integration testing when no edgeDNS provider exists
DNSTypeNoEdgeDNS EdgeDNSType = 1 << iota
// DNSTypeInfoblox type
DNSTypeInfoblox
// DNSTypeRoute53 type
DNSTypeRoute53
)

//Infoblox configuration
// TODO: consider to make this private after refactor
type Infoblox struct {
// Host
Host string
// Version
Version string
// Port
Port int
// Username
Username string
// Password
Password string
}

// Config is operator configuration returned by depResolver
type Config struct {
//Reschedule of Reconcile loop to pickup external Gslb targets
// Reschedule of Reconcile loop to pickup external Gslb targets
ReconcileRequeueSeconds int
// Cluster Geo Tag to determine specific location
// ClusterGeoTag to determine specific location
ClusterGeoTag string
// Route53 switch
// ExtClustersGeoTags to identify clusters in other locations in format separated by comma. i.e.: "eu,uk,us"
ExtClustersGeoTags []string
// EdgeDNSType is READONLY and is set automatically by configuration
EdgeDNSType EdgeDNSType
// EdgeDNSServer
EdgeDNSServer string
// EdgeDNSZone main zone which would contain gslb zone to delegate; e.g. example.com
EdgeDNSZone string
// DNSZone controlled by gslb; e.g. cloud.example.com
DNSZone string
// DNSTypeRoute53 switch
// TODO: hide for depresolver subscriber as depresolver retrieves EdgeDNSType. Maybe we can change configuration and set EdgeDNSType directly instead of DNSTypeRoute53 boolean
Route53Enabled bool
// Infoblox configuration
Infoblox Infoblox
}

//DependencyResolver resolves configuration for GSLB
// DependencyResolver resolves configuration for GSLB
type DependencyResolver struct {
client client.Client
config *Config
Expand All @@ -35,13 +74,7 @@ type DependencyResolver struct {
errorSpec error
}

const (
lessOrEqualToZeroErrorMessage = "\"%s is less or equal to zero\""
lessThanZeroErrorMessage = "\"%s is less than zero\""
doesNotMatchRegexMessage = "\"%s does not match /%s/ regexp rule\""
)

//NewDependencyResolver returns a new depresolver.DependencyResolver
// NewDependencyResolver returns a new depresolver.DependencyResolver
func NewDependencyResolver(context context.Context, client client.Client) *DependencyResolver {
resolver := new(DependencyResolver)
resolver.client = client
Expand Down
109 changes: 94 additions & 15 deletions controllers/depresolver/depresolver_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,39 +2,118 @@ package depresolver

import (
"fmt"
"regexp"

"github.com/AbsaOSS/k8gb/controllers/internal/env"
)

// Environment variables keys
const (
reconcileRequeueSecondsKey = "RECONCILE_REQUEUE_SECONDS"
clusterGeoTagKey = "CLUSTER_GEO_TAG"
route53EnabledKey = "ROUTE53_ENABLED"
ReconcileRequeueSecondsKey = "RECONCILE_REQUEUE_SECONDS"
ClusterGeoTagKey = "CLUSTER_GEO_TAG"
ExtClustersGeoTagsKey = "EXT_GSLB_CLUSTERS_GEO_TAGS"
Route53EnabledKey = "ROUTE53_ENABLED"
EdgeDNSServerKey = "EDGE_DNS_SERVER"
EdgeDNSZoneKey = "EDGE_DNS_ZONE"
DNSZoneKey = "DNS_ZONE"
InfobloxGridHostKey = "INFOBLOX_GRID_HOST"
InfobloxVersionKey = "INFOBLOX_WAPI_VERSION"
InfobloxPortKey = "INFOBLOX_WAPI_PORT"
InfobloxUsernameKey = "EXTERNAL_DNS_INFOBLOX_WAPI_USERNAME"
// #nosec G101; ignore false positive gosec; see: https://securego.io/docs/rules/g101.html
InfobloxPasswordKey = "EXTERNAL_DNS_INFOBLOX_WAPI_PASSWORD"
)

// ResolveOperatorConfig executes once. It reads operator's configuration
// from environment variables into &Config and validates
func (dr *DependencyResolver) ResolveOperatorConfig() (*Config, error) {
dr.onceConfig.Do(func() {
dr.config = &Config{}
// set predefined values when not read from the environment variables
dr.config.ReconcileRequeueSeconds, _ = env.GetEnvAsIntOrFallback(reconcileRequeueSecondsKey, 30)
dr.config.ClusterGeoTag = env.GetEnvAsStringOrFallback(clusterGeoTagKey, "unset")
dr.config.Route53Enabled = env.GetEnvAsBoolOrFallback(route53EnabledKey, false)
dr.config.ReconcileRequeueSeconds, _ = env.GetEnvAsIntOrFallback(ReconcileRequeueSecondsKey, 30)
dr.config.ClusterGeoTag = env.GetEnvAsStringOrFallback(ClusterGeoTagKey, "")
dr.config.ExtClustersGeoTags = env.GetEnvAsArrayOfStringsOrFallback(ExtClustersGeoTagsKey, []string{})
dr.config.Route53Enabled = env.GetEnvAsBoolOrFallback(Route53EnabledKey, false)
dr.config.EdgeDNSServer = env.GetEnvAsStringOrFallback(EdgeDNSServerKey, "")
dr.config.EdgeDNSZone = env.GetEnvAsStringOrFallback(EdgeDNSZoneKey, "")
dr.config.DNSZone = env.GetEnvAsStringOrFallback(DNSZoneKey, "")
dr.config.Infoblox.Host = env.GetEnvAsStringOrFallback(InfobloxGridHostKey, "")
dr.config.Infoblox.Version = env.GetEnvAsStringOrFallback(InfobloxVersionKey, "")
dr.config.Infoblox.Port, _ = env.GetEnvAsIntOrFallback(InfobloxPortKey, 0)
dr.config.Infoblox.Username = env.GetEnvAsStringOrFallback(InfobloxUsernameKey, "")
dr.config.Infoblox.Password = env.GetEnvAsStringOrFallback(InfobloxPasswordKey, "")
dr.errorConfig = dr.validateConfig(dr.config)
dr.config.EdgeDNSType = getEdgeDNSType(dr.config)
})
return dr.config, dr.errorConfig
}

func (dr *DependencyResolver) validateConfig(config *Config) error {
if config.ReconcileRequeueSeconds <= 0 {
return fmt.Errorf(lessOrEqualToZeroErrorMessage, "ReconcileRequeueSeconds")
func (dr *DependencyResolver) validateConfig(config *Config) (err error) {
err = field("reconcileRequeueSeconds", config.ReconcileRequeueSeconds).isHigherThanZero().err
if err != nil {
return err
}
geoTagRegexString := "^[a-zA-Z\\-\\d]*$"
geoTagRegex, _ := regexp.Compile(geoTagRegexString)
if !geoTagRegex.Match([]byte(config.ClusterGeoTag)) {
return fmt.Errorf(doesNotMatchRegexMessage, "ClusterGeoTag", geoTagRegexString)
err = field("clusterGeoTag", config.ClusterGeoTag).isNotEmpty().matchRegexp(geoTagRegex).err
if err != nil {
return err
}
err = field("extClusterGeoTags", config.ExtClustersGeoTags).hasItems().hasUniqueItems().err
if err != nil {
return err
}
for i, geoTag := range config.ExtClustersGeoTags {
err = field(fmt.Sprintf("extClustersGeoTags[%v]", i), geoTag).isNotEmpty().matchRegexp(geoTagRegex).isNotEqualTo(config.ClusterGeoTag).err
if err != nil {
return err
}
}
err = field("edgeDNSServer", config.EdgeDNSServer).isNotEmpty().matchRegexps(hostNameRegex, ipAddressRegex).err
if err != nil {
return err
}
err = field("edgeDNSZone", config.EdgeDNSZone).isNotEmpty().matchRegexp(hostNameRegex).err
if err != nil {
return err
}
err = field("DNSZone", config.DNSZone).isNotEmpty().matchRegexp(hostNameRegex).err
if err != nil {
return err
}
// do full Infoblox validation only in case that Host exists
if isNotEmpty(config.Infoblox.Host) {
err = field("InfobloxGridHost", config.Infoblox.Host).matchRegexps(hostNameRegex, ipAddressRegex).err
if err != nil {
return err
}
err = field("InfobloxVersion", config.Infoblox.Version).isNotEmpty().matchRegexp(versionNumberRegex).err
if err != nil {
return err
}
err = field("InfobloxPort", config.Infoblox.Port).isHigherThanZero().isLessOrEqualTo(65535).err
if err != nil {
return err
}
err = field("InfobloxUsername", config.Infoblox.Username).isNotEmpty().err
if err != nil {
return err
}
err = field("InfobloxPassword", config.Infoblox.Password).isNotEmpty().err
if err != nil {
return err
}
}
return nil
}

// getEdgeDNSType contains logic retrieving EdgeDNSType
func getEdgeDNSType(config *Config) EdgeDNSType {
var t = DNSTypeNoEdgeDNS
if config.Route53Enabled {
t = t | DNSTypeRoute53
}
if isNotEmpty(config.Infoblox.Host) {
t = t | DNSTypeInfoblox
}
if t > DNSTypeNoEdgeDNS {
t = t - DNSTypeNoEdgeDNS
}
return t
}
16 changes: 8 additions & 8 deletions controllers/depresolver/depresolver_spec.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package depresolver

import (
"fmt"

k8gbv1beta1 "github.com/AbsaOSS/k8gb/api/v1beta1"
)

Expand Down Expand Up @@ -32,12 +30,14 @@ func (dr *DependencyResolver) ResolveGslbSpec(gslb *k8gbv1beta1.Gslb) error {
return dr.errorSpec
}

func (dr *DependencyResolver) validateSpec(strategy *k8gbv1beta1.Strategy) error {
if strategy.DNSTtlSeconds < 0 {
return fmt.Errorf(lessThanZeroErrorMessage, "DNSTtlSeconds")
func (dr *DependencyResolver) validateSpec(strategy *k8gbv1beta1.Strategy) (err error) {
err = field("DNSTtlSeconds", strategy.DNSTtlSeconds).isHigherOrEqualToZero().err
if err != nil {
return
}
if strategy.SplitBrainThresholdSeconds < 0 {
return fmt.Errorf(lessThanZeroErrorMessage, "SplitBrainThresholdSeconds")
err = field("SplitBrainThresholdSeconds", strategy.SplitBrainThresholdSeconds).isHigherOrEqualToZero().err
if err != nil {
return
}
return nil
return
}
Loading