package topology import ( "context" "errors" "strconv" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/predicate" "edge-infra.dev/pkg/edge/api/graph/model" linkerd "edge-infra.dev/pkg/edge/linkerd" ) const ( // name of topology info ConfigMap Name string = "topology-info" // namespace for topology info ConfigMap Namespace string = "kube-public" downlinkRateKey string = "downlink_rate_limit" uplinkRateKey string = "uplink_rate_limit" gatewayEnabledKey string = "egress_gateway_enabled" gatewayRateLimitEnabledKey string = "gateway_rate_limiting_enabled" thickPosKey string = "thick_pos" linkerdIdentityCertDurationKey string = "linkerd_identity_issuer_cert_duration" linkerdIdentityCertRenewBeforeKey string = "linkerd_identity_issuer_cert_renew_before" ) // Deprecated: linkerd identity cert fields deprecated in https://github.com/ncrvoyix-swt-retail/edge-infra/pull/10353 var ( // InvalidCertificateDuationErr is thrown when the certificate duration is a a non-positive integer ErrInvalidCertificateDurationOrRenewBefore = errors.New("linkerd identity: certificate duration and renew before must be positive") // InvalidCertificateRenewBeforeErr is thrown when the certificate renew before is a non-positive integer ErrInvalidCertificateRenewBefore = errors.New("linkerd identity: duration must be greater than the certificate renew before") ) // Info contains the fields defined in the topology-info ConfigMap. type Info struct { // Download rate limit in bits per second DownlinkRateLimit uint64 // Upload rate limit in bits per second UplinkRateLimit uint64 // Defines if egress gateway is enabled EgressGatewayEnabled bool // Defines if rate limiting is enabled GatewayRateLimitingEnabled bool // Defines the store clusters topology. // If set to true the store is configured to thick topology. // If set to false the store is configured to thin topology. ThickPOS bool // Linkerd identity certificate duration defines the maximum // duration (hours) a store cluster can be in lan-outage for. LinkerdIdentityCertDuration int // Linkerd identity certificate renew before defines the // how many hours before the certificate duration certificate // renewal can be attempted. LinkerdIdentityCertRenewBefore int } // Instantiates a new topology info with set defaults func New() *Info { return &Info{ DownlinkRateLimit: defaultRateLimit, UplinkRateLimit: defaultRateLimit, EgressGatewayEnabled: false, GatewayRateLimitingEnabled: false, ThickPOS: false, LinkerdIdentityCertDuration: int(linkerd.DefaultThinPosIdentityIssuerCertificateDurationHours), LinkerdIdentityCertRenewBefore: int(linkerd.DefaultThinPosIdentityIssuerCertificateRenewBeforeHours), } } // FromClient constructs the Info object from a kubernetes client func (i *Info) FromClient(ctx context.Context, c client.Client) (*Info, error) { cm := &v1.ConfigMap{} if err := c.Get(ctx, configMapKey(), cm); err != nil { return New(), err } return i.FromConfigMap(cm), nil } // FromConfigMap constructs the Info object from a k8s config map func (i *Info) FromConfigMap(cm *v1.ConfigMap) *Info { i.DownlinkRateLimit = convertRateLimitToBits(cm.Data[downlinkRateKey]) i.UplinkRateLimit = convertRateLimitToBits(cm.Data[uplinkRateKey]) if egressGatewayEnabled, err := strconv.ParseBool(cm.Data[gatewayEnabledKey]); err == nil { i.EgressGatewayEnabled = egressGatewayEnabled } if gatewayRateLimitingEnabled, err := strconv.ParseBool(cm.Data[gatewayRateLimitEnabledKey]); err == nil { i.GatewayRateLimitingEnabled = gatewayRateLimitingEnabled } if thickPOS, err := strconv.ParseBool(cm.Data[thickPosKey]); err == nil { i.ThickPOS = thickPOS } if linkerdIdentityCertDuration, err := strconv.Atoi(cm.Data[linkerdIdentityCertDurationKey]); err == nil { i.LinkerdIdentityCertDuration = i.defaultCertDuration(linkerdIdentityCertDuration) } if linkerdIdentityCertRenewBefore, err := strconv.Atoi(cm.Data[linkerdIdentityCertRenewBeforeKey]); err == nil { i.LinkerdIdentityCertRenewBefore = i.defaultCertRenewBefore(linkerdIdentityCertRenewBefore) } return i } // ensures default cert duration is not zero func (i *Info) defaultCertDuration(certDuration int) int { if certDuration >= 24 { return certDuration } if i.ThickPOS { return int(linkerd.DefaultThickPosIdentityIssuerCertificateDurationHours) } return int(linkerd.DefaultThinPosIdentityIssuerCertificateDurationHours) } // ensures default cert renew before is not zero func (i *Info) defaultCertRenewBefore(certRenewBefore int) int { if certRenewBefore >= 18 { return certRenewBefore } if i.ThickPOS { return int(linkerd.DefaultThickPosIdentityIssuerCertificateRenewBeforeHours) } return int(linkerd.DefaultThinPosIdentityIssuerCertificateRenewBeforeHours) } // FromGraphQLModel constructs Info object from database model func (i *Info) FromGraphQLModel(cfg model.ClusterConfig) *Info { // sets linkerd identity issuer cert values from maximum lan outage duration linkerdIdentityIssuerCertDuration := cfg.MaximumLanOutageHours linkerdIdentityIssuerCertRenewBefore := linkerdIdentityIssuerCertDuration * 3 / 4 tpInfo := &Info{ ThickPOS: cfg.ThickPos, GatewayRateLimitingEnabled: cfg.GatewayRateLimitingEnabled, EgressGatewayEnabled: cfg.EgressGatewayEnabled, LinkerdIdentityCertDuration: linkerdIdentityIssuerCertDuration, LinkerdIdentityCertRenewBefore: linkerdIdentityIssuerCertRenewBefore, DownlinkRateLimit: convertRateLimitToBits(cfg.DownlinkRateLimit), UplinkRateLimit: convertRateLimitToBits(cfg.UplinkRateLimit), } return tpInfo } // Converts the Info struct to a ConfigMap func (i *Info) ToConfigMap() *v1.ConfigMap { return &v1.ConfigMap{ TypeMeta: typemeta(), ObjectMeta: metadata(), Data: map[string]string{ downlinkRateKey: convertBitsToMbits(i.DownlinkRateLimit), uplinkRateKey: convertBitsToMbits(i.UplinkRateLimit), gatewayEnabledKey: strconv.FormatBool(i.EgressGatewayEnabled), thickPosKey: strconv.FormatBool(i.ThickPOS), gatewayRateLimitEnabledKey: strconv.FormatBool(i.GatewayRateLimitingEnabled), linkerdIdentityCertDurationKey: strconv.Itoa(i.LinkerdIdentityCertDuration), linkerdIdentityCertRenewBeforeKey: strconv.Itoa(i.LinkerdIdentityCertRenewBefore), }, } } // PredicateFilter returns the predicate function for topology-info configmap func PredicateFilter() predicate.Funcs { return predicate.NewPredicateFuncs(func(object client.Object) bool { return object.GetNamespace() == Namespace && object.GetName() == Name }) } // generates a blank topology info config map func newTopologyInfoConfigMap() v1.ConfigMap { return v1.ConfigMap{ TypeMeta: typemeta(), ObjectMeta: metadata(), } } // topology info config map type meta func typemeta() metav1.TypeMeta { return metav1.TypeMeta{ Kind: "ConfigMap", APIVersion: v1.SchemeGroupVersion.String(), } } // topology info config map meta data func metadata() metav1.ObjectMeta { return metav1.ObjectMeta{ Name: Name, Namespace: Namespace, } } // constructs the object key for topology info func configMapKey() types.NamespacedName { return types.NamespacedName{ Name: Name, Namespace: Namespace, } }