Skip to content

Commit

Permalink
Extending DepResolver
Browse files Browse the repository at this point in the history
related to (#170)

extensions

validations

tests

EdgeDNSType

move environment variables keys into one place - depresolver

TODO:
  • Loading branch information
kuritka committed Oct 16, 2020
1 parent 5749966 commit 4ea7841
Show file tree
Hide file tree
Showing 8 changed files with 1,043 additions and 169 deletions.
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

0 comments on commit 4ea7841

Please sign in to comment.