From c777004542ee5953de83be67cf52c910db31eb07 Mon Sep 17 00:00:00 2001 From: jm96441n Date: Wed, 12 Apr 2023 21:35:32 -0400 Subject: [PATCH 01/24] normalize status conditions for gateways and routes --- agent/consul/gateways/controller_gateways.go | 198 ++++--- .../gateways/controller_gateways_test.go | 14 +- agent/structs/config_entry_status.go | 515 +++++++++++++++++- agent/structs/config_entry_status_test.go | 311 +++++++++++ .../private/pbconfigentry/config_entry.gen.go | 4 +- proto/private/pbconfigentry/config_entry.go | 17 + .../private/pbconfigentry/config_entry.pb.go | 3 +- .../private/pbconfigentry/config_entry.proto | 1 + 8 files changed, 929 insertions(+), 134 deletions(-) create mode 100644 agent/structs/config_entry_status_test.go diff --git a/agent/consul/gateways/controller_gateways.go b/agent/consul/gateways/controller_gateways.go index afb687fe097..3a792db1966 100644 --- a/agent/consul/gateways/controller_gateways.go +++ b/agent/consul/gateways/controller_gateways.go @@ -853,138 +853,132 @@ func newGatewayConditionGenerator() *gatewayConditionGenerator { } } +// gatewayAccepted marks the APIGateway as valid. +func (g *gatewayConditionGenerator) gatewayAccepted() structs.Condition { + return structs.NewGatewayCondition( + structs.GatewayConditionAccepted, + structs.ConditionStatusTrue, + structs.GatewayReasonAccepted, + "gateway is valid", + structs.ResourceReference{}, + ) +} + // invalidCertificate returns a condition used when a gateway references a // certificate that does not exist. It takes a ref used to scope the condition // to a given APIGateway listener. func (g *gatewayConditionGenerator) invalidCertificate(ref structs.ResourceReference, err error) structs.Condition { - return structs.Condition{ - Type: "Accepted", - Status: "False", - Reason: "InvalidCertificate", - Message: err.Error(), - Resource: pointerTo(ref), - LastTransitionTime: g.now, - } + return structs.NewGatewayCondition( + structs.GatewayConditionAccepted, + structs.ConditionStatusFalse, + structs.GatewayListenerReasonInvalidCertificateRef, + err.Error(), + ref, + ) } // invalidCertificates is used to set the overall condition of the APIGateway // to invalid due to missing certificates that it references. func (g *gatewayConditionGenerator) invalidCertificates() structs.Condition { - return structs.Condition{ - Type: "Accepted", - Status: "False", - Reason: "InvalidCertificates", - Message: "gateway references invalid certificates", - LastTransitionTime: g.now, - } + return structs.NewGatewayCondition( + structs.GatewayConditionAccepted, + structs.ConditionStatusFalse, + structs.GatewayListenerReasonInvalidCertificateRef, + "gateway references invalid certificates", + structs.ResourceReference{}, + ) } -// gatewayAccepted marks the APIGateway as valid. -func (g *gatewayConditionGenerator) gatewayAccepted() structs.Condition { - return structs.Condition{ - Type: "Accepted", - Status: "True", - Reason: "Accepted", - Message: "gateway is valid", - LastTransitionTime: g.now, - } +// gatewayListenerNoConflicts marks an APIGateway listener as having no conflicts within its +// bound routes +func (g *gatewayConditionGenerator) gatewayListenerNoConflicts(ref structs.ResourceReference) structs.Condition { + return structs.NewGatewayCondition( + structs.GatewayConditionListenersConfigured, + structs.ConditionStatusTrue, + structs.GatewayReasonListenersConfigured, + "listener has no route conflicts", + ref, + ) +} + +// gatewayListenerConflicts marks an APIGateway listener as having bound routes that conflict with each other +// and make the listener, therefore invalid +func (g *gatewayConditionGenerator) gatewayListenerConflicts(ref structs.ResourceReference) structs.Condition { + return structs.NewGatewayCondition( + structs.GatewayConditionListenersConfigured, + structs.ConditionStatusFalse, + structs.GatewayListenerReasonProtocolConflict, + "TCP-based listeners currently only support binding a single route", + ref, + ) } // routeBound marks a Route as bound to the referenced APIGateway func (g *gatewayConditionGenerator) routeBound(ref structs.ResourceReference) structs.Condition { - return structs.Condition{ - Type: "Bound", - Status: "True", - Reason: "Bound", - Resource: pointerTo(ref), - Message: "successfully bound route", - LastTransitionTime: g.now, - } + return structs.NewRouteCondition( + structs.RouteConditionBound, + structs.ConditionStatusTrue, + structs.RouteReasonBound, + "successfully bound route", + ref, + ) } -// routeAccepted marks the Route as valid -func (g *gatewayConditionGenerator) routeAccepted() structs.Condition { - return structs.Condition{ - Type: "Accepted", - Status: "True", - Reason: "Accepted", - Message: "route is valid", - LastTransitionTime: g.now, - } +// gatewayNotFound marks a Route as having failed to bind to a referenced APIGateway due to +// the Gateway not existing (or having not been reconciled yet) +func (g *gatewayConditionGenerator) gatewayNotFound(ref structs.ResourceReference) structs.Condition { + return structs.NewRouteCondition( + structs.RouteConditionBound, + structs.ConditionStatusFalse, + structs.RouteReasonGatewayNotFound, + "gateway was not found", + ref, + ) } // routeUnbound marks the route as having failed to bind to the referenced APIGateway func (g *gatewayConditionGenerator) routeUnbound(ref structs.ResourceReference, err error) structs.Condition { - return structs.Condition{ - Type: "Bound", - Status: "False", - Reason: "FailedToBind", - Resource: pointerTo(ref), - Message: err.Error(), - LastTransitionTime: g.now, - } + return structs.NewRouteCondition( + structs.RouteConditionBound, + structs.ConditionStatusFalse, + structs.RouteReasonFailedToBind, + err.Error(), + ref, + ) +} + +// routeAccepted marks the Route as valid +func (g *gatewayConditionGenerator) routeAccepted() structs.Condition { + return structs.NewRouteCondition( + structs.RouteConditionAccepted, + structs.ConditionStatusTrue, + structs.RouteReasonAccepted, + "route is valid", + structs.ResourceReference{}, + ) } // routeInvalidDiscoveryChain marks the route as invalid due to an error while validating its referenced // discovery chian func (g *gatewayConditionGenerator) routeInvalidDiscoveryChain(err error) structs.Condition { - return structs.Condition{ - Type: "Accepted", - Status: "False", - Reason: "InvalidDiscoveryChain", - Message: err.Error(), - LastTransitionTime: g.now, - } + return structs.NewRouteCondition( + structs.RouteConditionAccepted, + structs.ConditionStatusFalse, + structs.RouteReasonInvalidDiscoveryChain, + err.Error(), + structs.ResourceReference{}, + ) } // routeNoUpstreams marks the route as invalid because it has no upstreams that it targets func (g *gatewayConditionGenerator) routeNoUpstreams() structs.Condition { - return structs.Condition{ - Type: "Accepted", - Status: "False", - Reason: "NoUpstreamServicesTargeted", - Message: "route must target at least one upstream service", - LastTransitionTime: g.now, - } -} - -// gatewayListenerConflicts marks an APIGateway listener as having bound routes that conflict with each other -// and make the listener, therefore invalid -func (g *gatewayConditionGenerator) gatewayListenerConflicts(ref structs.ResourceReference) structs.Condition { - return structs.Condition{ - Type: "Conflicted", - Status: "True", - Reason: "RouteConflict", - Resource: pointerTo(ref), - Message: "TCP-based listeners currently only support binding a single route", - LastTransitionTime: g.now, - } -} - -// gatewayListenerNoConflicts marks an APIGateway listener as having no conflicts within its -// bound routes -func (g *gatewayConditionGenerator) gatewayListenerNoConflicts(ref structs.ResourceReference) structs.Condition { - return structs.Condition{ - Type: "Conflicted", - Status: "False", - Reason: "NoConflict", - Resource: pointerTo(ref), - Message: "listener has no route conflicts", - LastTransitionTime: g.now, - } -} - -// gatewayNotFound marks a Route as having failed to bind to a referenced APIGateway due to -// the Gateway not existing (or having not been reconciled yet) -func (g *gatewayConditionGenerator) gatewayNotFound(ref structs.ResourceReference) structs.Condition { - return structs.Condition{ - Type: "Bound", - Status: "False", - Reason: "GatewayNotFound", - Resource: pointerTo(ref), - Message: "gateway was not found", - LastTransitionTime: g.now, - } + return structs.NewRouteCondition( + structs.RouteConditionAccepted, + structs.ConditionStatusFalse, + structs.RouteReasonInvalidDiscoveryChain, + "route must target at least one upstream service", + structs.ResourceReference{}, + ) } // bindRoutesToGateways takes a route variadic number of gateways. diff --git a/agent/consul/gateways/controller_gateways_test.go b/agent/consul/gateways/controller_gateways_test.go index 3049dd60c1e..39a379cf57e 100644 --- a/agent/consul/gateways/controller_gateways_test.go +++ b/agent/consul/gateways/controller_gateways_test.go @@ -3287,10 +3287,16 @@ func TestAPIGatewayController(t *testing.T) { }}, Status: structs.Status{ Conditions: []structs.Condition{ - conditions.invalidCertificate(structs.ResourceReference{ - Kind: structs.InlineCertificate, - Name: "certificate", - }, errors.New("certificate not found")), + structs.NewGatewayCondition( + structs.GatewayConditionAccepted, + structs.ConditionStatusFalse, + structs.GatewayListenerReasonInvalidCertificateRef, + errors.New("certificate not found").Error(), + structs.ResourceReference{ + Kind: structs.InlineCertificate, + Name: "certificate", + }, + ), conditions.invalidCertificates(), conditions.gatewayListenerNoConflicts(structs.ResourceReference{ Kind: structs.APIGateway, diff --git a/agent/structs/config_entry_status.go b/agent/structs/config_entry_status.go index 264efb1fa67..b3cf06eca75 100644 --- a/agent/structs/config_entry_status.go +++ b/agent/structs/config_entry_status.go @@ -8,6 +8,8 @@ import ( "sort" "time" + "golang.org/x/exp/slices" + "github.com/hashicorp/consul/acl" ) @@ -67,30 +69,6 @@ func (s Status) SameConditions(other Status) bool { if len(s.Conditions) != len(other.Conditions) { return false } - lessResource := func(one, two *ResourceReference) bool { - if one == nil && two == nil { - return false - } - if one == nil { - return true - } - if two == nil { - return false - } - if one.Kind < two.Kind { - return true - } - if one.Kind > two.Kind { - return false - } - if one.Name < two.Name { - return true - } - if one.Name > two.Name { - return false - } - return one.SectionName < two.SectionName - } sortConditions := func(conditions []Condition) []Condition { sort.SliceStable(conditions, func(i, j int) bool { if conditions[i].Type < conditions[j].Type { @@ -114,6 +92,42 @@ func (s Status) SameConditions(other Status) bool { return true } +func lessResource(one, two *ResourceReference) bool { + if one == nil && two == nil { + return false + } + if one == nil { + return true + } + if two == nil { + return false + } + if one.Kind < two.Kind { + return true + } + if one.Kind > two.Kind { + return false + } + if one.Name < two.Name { + return true + } + if one.Name > two.Name { + return false + } + return one.SectionName < two.SectionName +} + +type ( + ConditionStatus string + ConditionReason string +) + +const ( + ConditionStatusTrue ConditionStatus = "True" + ConditionStatusFalse ConditionStatus = "False" + ConditionStatusUnknown ConditionStatus = "Unknown" +) + // Condition is used for a single message and state associated // with an object. For example, a ConfigEntry that references // multiple other resources may have different statuses with @@ -122,7 +136,7 @@ type Condition struct { // Type is a value from a bounded set of types that an object might have Type string // Status is a value from a bounded set of statuses that an object might have - Status string + Status ConditionStatus // Reason is a value from a bounded set of reasons for a given status Reason string // Message is a message that gives more detailed information about @@ -141,6 +155,7 @@ func (c *Condition) IsCondition(other *Condition) bool { func (c *Condition) IsSame(other *Condition) bool { return c.IsCondition(other) && + c.Type == c.Type && c.Status == other.Status && c.Reason == other.Reason && c.Message == other.Message @@ -195,3 +210,453 @@ func (u *StatusUpdater) UpdateEntry() (ControlledConfigEntry, bool) { u.entry.SetStatus(u.status) return u.entry, true } + +// GatewayConditionType is a type of condition associated with a +// Gateway. This type should be used with the GatewayStatus.Conditions +// field. +type GatewayConditionType string + +// GatewayConditionReason defines the set of reasons that explain why a +// particular Gateway condition type has been raised. +type GatewayConditionReason string + +const ( + // This condition is true when the controller managing the Gateway is + // syntactically and semantically valid enough to produce some configuration + // in the underlying data plane. This does not indicate whether or not the + // configuration has been propagated to the data plane. + // + // Possible reasons for this condition to be True are: + // + // * "Accepted" + // + // Possible reasons for this condition to be False are: + // + // * "Invalid" + // + // Possible reasons for this condition to be Unknown are: + // + // * "Pending" + // + GatewayConditionAccepted GatewayConditionType = "Accepted" + + // This reason is used with the "Accepted" condition when the condition is + // True. + GatewayReasonAccepted GatewayConditionReason = "Accepted" + + // This reason is used with the "Accepted" condition when the Gateway is + // syntactically or semantically invalid. + GatewayReasonInvalid GatewayConditionReason = "Invalid" + + // This reason is used with the "Accepted" and "ListenersConfigured" + // conditions when the status is "Unknown" and no controller has reconciled + // the Gateway. + GatewayReasonPending GatewayConditionReason = "Pending" + // This condition indicates that the controller was able to resolve + // all specification requirements for all Gateway Listeners. If a Listener is + // conflicted, its network port should not be configured on any network + // elements. Even if a Listener is syntactically and semantically valid, + // the controller may not able to configure it on the underlying Gateway + // infrastructure. When setting this condition to False, a ResourceReference to + // the misconfigured Listener should be provided. + + // + // Possible reasons for this condition to be True are: + // + // * "ListenersConfigured" + // + // Possible reasons for this condition to be False are: + // + // * "ListenerHostnameConflict" + // * "ListenerProtocolConflict" + // * "ListenerPortUnavailable" + // * "ListenerUnsupportedProtocol" + // * "ListenerUnsupportedAddress" + // + // Possible reasons for this condition to be Unknown are: + // + // * "Pending" + // + GatewayConditionListenersConfigured GatewayConditionType = "ListenersConfigured" + + // This reason is used with the "ListenersConfigured" condition when the + // condition is True. + GatewayReasonListenersConfigured GatewayConditionReason = "ListenersConfigured" + + // This reason is used with the "ListenersConfigured" condition when + // the Listener conflicts with hostnames in other Listeners. For + // example, this reason would be used when multiple Listeners on + // the same port use `example.com` in the hostname field. + GatewayListenerReasonHostnameConflict GatewayConditionReason = "ListenerHostnameConflict" + + // This reason is used with the "ListenersConfigured" condition when + // multiple Listeners are specified with the same Listener port + // number, but have conflicting protocol specifications. + GatewayListenerReasonProtocolConflict GatewayConditionReason = "ListenerProtocolConflict" + + // This reason is used with the "ListenersConfigured" condition when the Listener + // requests a port that cannot be used on the Gateway. This reason could be + // used in a number of instances, including: + // + // * The port is already in use. + // * The port is not supported by the implementation. + GatewayListenerReasonPortUnavailable GatewayConditionReason = "ListenerPortUnavailable" + + // This reason is used with the "ListenersConfigured" condition when the + // Listener could not be attached to be Gateway because its + // protocol type is not supported. + GatewayListenerReasonUnsupportedProtocol GatewayConditionReason = "ListenerUnsupportedProtocol" + + // This reason is used with the "ListenersConfigured" condition when a + // Listener could not be attached to the Gateway because the requested address + // is not supported. This reason could be used in a number of instances, + // including: + // + // * The address is already in use. + // * The type of address is not supported by the implementation. + GatewayListenerReasonUnsupportedAddress GatewayConditionReason = "ListenerUnsupportedAddress" + + // This condition indicates whether the controller was able to + // resolve all the object references for the Gateway. When setting this + // condition to False, a ResourceReference to the misconfigured Listener should + // be provided. + // + // Possible reasons for this condition to be true are: + // + // * "ResolvedRefs" + // + // Possible reasons for this condition to be False are: + // + // * "InvalidCertificateRef" + // * "InvalidRouteKinds" + // * "RefNotPermitted" + // + GatewayConditionResolvedRefs GatewayConditionType = "ResolvedRefs" + + // This reason is used with the "ResolvedRefs" condition when the condition + // is true. + GatewayReasonResolvedRefs GatewayConditionReason = "ResolvedRefs" + + // This reason is used with the "ResolvedRefs" condition when a + // Listener has a TLS configuration with at least one TLS CertificateRef + // that is invalid or does not exist. + // A CertificateRef is considered invalid when it refers to a nonexistent + // or unsupported resource or kind, or when the data within that resource + // is malformed. + // This reason must be used only when the reference is allowed, either by + // referencing an object in the same namespace as the Gateway, or when + // a cross-namespace reference has been explicitly allowed by a ReferenceGrant. + // If the reference is not allowed, the reason RefNotPermitted must be used + // instead. + GatewayListenerReasonInvalidCertificateRef GatewayConditionReason = "InvalidCertificateRef" + + // This reason is used with the "ResolvedRefs" condition when an invalid or + // unsupported Route kind is specified by a Listener. + GatewayListenerReasonInvalidRouteKinds GatewayConditionReason = "InvalidRouteKinds" + + // This reason is used with the "ResolvedRefs" condition when a + // Listener has a TLS configuration that references an object in another + // namespace, where the object in the other namespace does not have a + // ReferenceGrant explicitly allowing the reference. + GatewayListenerReasonRefNotPermitted GatewayConditionReason = "RefNotPermitted" +) + +var validGatewayConditionReasonsMapping = map[GatewayConditionType]map[ConditionStatus][]GatewayConditionReason{ + GatewayConditionAccepted: { + ConditionStatusTrue: { + GatewayReasonAccepted, + }, + ConditionStatusFalse: { + GatewayReasonInvalid, + }, + ConditionStatusUnknown: { + GatewayReasonPending, + }, + }, + GatewayConditionListenersConfigured: { + ConditionStatusTrue: { + GatewayReasonListenersConfigured, + }, + ConditionStatusFalse: { + GatewayListenerReasonHostnameConflict, + GatewayListenerReasonProtocolConflict, + GatewayListenerReasonPortUnavailable, + GatewayListenerReasonUnsupportedProtocol, + GatewayListenerReasonUnsupportedAddress, + }, + ConditionStatusUnknown: { + GatewayReasonPending, + }, + }, + GatewayConditionResolvedRefs: { + ConditionStatusTrue: { + GatewayReasonResolvedRefs, + }, + ConditionStatusFalse: { + GatewayListenerReasonInvalidCertificateRef, + GatewayListenerReasonInvalidRouteKinds, + GatewayListenerReasonRefNotPermitted, + }, + ConditionStatusUnknown: {}, + }, +} + +func NewGatewayCondition(name GatewayConditionType, status ConditionStatus, reason GatewayConditionReason, message string, resource ResourceReference) Condition { + if err := validateGatewayConfigReason(name, status, reason); err != nil { + // note we panic here because an invalid combination is a programmer error + // this should never actually be hit + panic(err) + } + + return Condition{ + Type: string(name), + Status: status, + Reason: string(reason), + Message: message, + Resource: ptrTo(resource), + LastTransitionTime: ptrTo(time.Now().UTC()), + } +} + +func validateGatewayConfigReason(name GatewayConditionType, status ConditionStatus, reason GatewayConditionReason) error { + reasons, ok := validGatewayConditionReasonsMapping[name] + if !ok { + return fmt.Errorf("unrecognized GatewayConditionType %q", name) + } + + reasonsForStatus, ok := reasons[status] + if !ok { + return fmt.Errorf("unrecognized ConditionStatus %q", status) + } + + if !slices.Contains(reasonsForStatus, reason) { + return fmt.Errorf("gateway condition reason %q not allowed for gateway condition type %q with status %q", reason, name, status) + } + return nil +} + +// RouteConditionType is a type of condition for a route. +type RouteConditionType string + +// RouteConditionReason is a reason for a route condition. +type RouteConditionReason string + +// The following statuses are taken from the K8's Spec +// With the exception of: "RouteReasonInvalidDiscoveryChain" and "NoUpstreamServicesTargeted" +const ( + // This condition indicates whether the route has been accepted or rejected + // by a Gateway, and why. + // + // Possible reasons for this condition to be true are: + // + // * "Accepted" + // + // Possible reasons for this condition to be False are: + // + // * "NotAllowedByListeners" + // * "NoMatchingListenerHostname" + // * "NoMatchingParent" + // * "UnsupportedValue" + // * "ParentRefNotPermitted" + // * "InvalidDiscoveryChain" + // * "NoUpstreamServicesTargeted" + // + // Possible reasons for this condition to be Unknown are: + // + // * "Pending" + // + // Controllers may raise this condition with other reasons, + // but should prefer to use the reasons listed above to improve + // interoperability. + RouteConditionAccepted RouteConditionType = "Accepted" + + // This reason is used with the "Accepted" condition when the Route has been + // accepted by the Gateway. + RouteReasonAccepted RouteConditionReason = "Accepted" + + // This reason is used with the "Accepted" condition when the route has not + // been accepted by a Gateway because the Gateway has no Listener whose + // allowedRoutes criteria permit the route + RouteReasonNotAllowedByListeners RouteConditionReason = "NotAllowedByListeners" + + // This reason is used with the "Accepted" condition when the Gateway has no + // compatible Listeners whose Hostname matches the route + RouteReasonNoMatchingListenerHostname RouteConditionReason = "NoMatchingListenerHostname" + + // This reason is used with the "Accepted" condition when there are + // no matching Parents. In the case of Gateways, this can occur when + // a Route ParentRef specifies a Port and/or SectionName that does not + // match any Listeners in the Gateway. + RouteReasonNoMatchingParent RouteConditionReason = "NoMatchingParent" + + // This reason is used with the "Accepted" condition when a value for an Enum + // is not recognized. + RouteReasonUnsupportedValue RouteConditionReason = "UnsupportedValue" + + // This reason is used with the "Accepted" condition when the route has not + // been accepted by a Gateway because it has a cross-namespace parentRef, + // but no ReferenceGrant in the other namespace allows such a reference. + RouteReasonParentRefNotPermitted RouteConditionReason = "ParentRefNotPermitted" + + // This reason is used with the "Accepted" when a controller has not yet + // reconciled the route. + RouteReasonPending RouteConditionReason = "Pending" + + // This reason is used with the "Accepted" condition when the route has an + // invalid discovery chain, this includes conditions like the protocol being invalid + // or the discovery chain failing to compile + RouteReasonInvalidDiscoveryChain RouteConditionReason = "InvalidDiscoveryChain" + + // This reason is used with the "Accepted" condition when the route + RouteReasonNoUpstreamServicesTargeted RouteConditionReason = "NoUpstreamServicesTargeted" + + // This condition indicates whether the controller was able to resolve all + // the object references for the Route. + // + // Possible reasons for this condition to be true are: + // + // * "ResolvedRefs" + // + // Possible reasons for this condition to be false are: + // + // * "RefNotPermitted" + // * "InvalidKind" + // * "BackendNotFound" + // + // Controllers may raise this condition with other reasons, + // but should prefer to use the reasons listed above to improve + // interoperability. + RouteConditionResolvedRefs RouteConditionType = "ResolvedRefs" + + // This reason is used with the "ResolvedRefs" condition when the condition + // is true. + RouteReasonResolvedRefs RouteConditionReason = "ResolvedRefs" + + // This reason is used with the "ResolvedRefs" condition when + // one of the Listener's Routes has a BackendRef to an object in + // another namespace, where the object in the other namespace does + // not have a ReferenceGrant explicitly allowing the reference. + RouteReasonRefNotPermitted RouteConditionReason = "RefNotPermitted" + + // This reason is used with the "ResolvedRefs" condition when + // one of the Route's rules has a reference to an unknown or unsupported + // Group and/or Kind. + RouteReasonInvalidKind RouteConditionReason = "InvalidKind" + + // This reason is used with the "ResolvedRefs" condition when one of the + // Route's rules has a reference to a resource that does not exist. + RouteReasonBackendNotFound RouteConditionReason = "BackendNotFound" +) + +// the following statuses are custom to Consul +const ( + // This condition indicates whether the route was able to successfully bind the + // Listener on the gateway + // Possible reasons for this condition to be true are: + // + // * "Bound" + // + // Possible reasons for this condition to be false are: + // + // * "FailedToBind" + // * "GatewayNotFound" + // + RouteConditionBound RouteConditionType = "Bound" + + // This reason is used with the "Bound" condition when the condition + // is true + RouteReasonBound RouteConditionReason = "Bound" + + // This reason is used with the "Bound" condition when the route failed + // to bind to the gateway + RouteReasonFailedToBind RouteConditionReason = "FailedToBind" + + // This reason is used with the "Bound" condition when the route fails + // to find the gateway + RouteReasonGatewayNotFound RouteConditionReason = "GatewayNotFound" +) + +// NewRouteCondition is a helper to build allowable Conditions for a Route config entry +func NewRouteCondition(name RouteConditionType, status ConditionStatus, reason RouteConditionReason, message string, ref ResourceReference) Condition { + if err := checkRouteConditionReason(name, status, reason); err != nil { + // note we panic here because an invalid combination is a programmer error + // this should never actually be hit + panic(err) + } + + return Condition{ + Type: string(name), + Status: status, + Reason: string(reason), + Message: message, + Resource: ptrTo(ref), + LastTransitionTime: ptrTo(time.Now().UTC()), + } +} + +var validRouteConditionReasonsMapping = map[RouteConditionType]map[ConditionStatus][]RouteConditionReason{ + RouteConditionAccepted: { + ConditionStatusTrue: { + RouteReasonAccepted, + }, + ConditionStatusFalse: { + RouteReasonNotAllowedByListeners, + RouteReasonNoMatchingListenerHostname, + RouteReasonNoMatchingParent, + RouteReasonUnsupportedValue, + RouteReasonParentRefNotPermitted, + RouteReasonInvalidDiscoveryChain, + RouteReasonNoUpstreamServicesTargeted, + }, + ConditionStatusUnknown: { + RouteReasonPending, + }, + }, + RouteConditionResolvedRefs: { + ConditionStatusTrue: { + RouteReasonResolvedRefs, + }, + ConditionStatusFalse: { + RouteReasonRefNotPermitted, + RouteReasonInvalidKind, + RouteReasonBackendNotFound, + }, + ConditionStatusUnknown: {}, + }, + RouteConditionBound: { + ConditionStatusTrue: { + RouteReasonBound, + }, + ConditionStatusFalse: { + RouteReasonGatewayNotFound, + RouteReasonFailedToBind, + }, + ConditionStatusUnknown: {}, + }, +} + +func checkRouteConditionReason(name RouteConditionType, status ConditionStatus, reason RouteConditionReason) error { + // if err := checkConditionStatus(status); err != nil { + // return err + // } + + reasons, ok := validRouteConditionReasonsMapping[name] + if !ok { + return fmt.Errorf("unrecognized RouteConditionType %s", name) + } + + reasonsForStatus, ok := reasons[status] + if !ok { + return fmt.Errorf("unrecognized ConditionStatus %s", name) + } + + if !slices.Contains(reasonsForStatus, reason) { + return fmt.Errorf("route condition reason %s not allowed for route condition type %s with status %s", reason, name, status) + } + + return nil +} + +func ptrTo[T any](val T) *T { + return &val +} diff --git a/agent/structs/config_entry_status_test.go b/agent/structs/config_entry_status_test.go new file mode 100644 index 00000000000..8795c1fa6c5 --- /dev/null +++ b/agent/structs/config_entry_status_test.go @@ -0,0 +1,311 @@ +package structs + +import "testing" + +func TestNewGatewayConditionWithValidCombinations(t *testing.T) { + testCases := map[string]struct { + status ConditionStatus + reason GatewayConditionReason + condType GatewayConditionType + message string + ref ResourceReference + }{ + "accepted all around": { + status: ConditionStatusTrue, + reason: GatewayReasonAccepted, + condType: GatewayConditionAccepted, + message: "it's all good", + ref: ResourceReference{Name: "name", Kind: "httproute"}, + }, + "accepted false gateway reason invalid": { + status: ConditionStatusFalse, + reason: GatewayReasonInvalid, + condType: GatewayConditionAccepted, + message: "no bueno", + ref: ResourceReference{Name: "name", Kind: "httproute"}, + }, + "accepted false gateway reason pending": { + status: ConditionStatusFalse, + reason: GatewayReasonPending, + condType: GatewayConditionAccepted, + message: "pending", + ref: ResourceReference{Name: "name", Kind: "httproute"}, + }, + "listener configured true": { + status: ConditionStatusTrue, + reason: GatewayReasonListenersConfigured, + condType: GatewayConditionListenersConfigured, + message: "listeners configured", + ref: ResourceReference{Name: "name", Kind: "httproute"}, + }, + "listener configured hostname conflict": { + status: ConditionStatusFalse, + reason: GatewayListenerReasonHostnameConflict, + condType: GatewayConditionListenersConfigured, + message: "conflict", + ref: ResourceReference{Name: "name", Kind: "httproute"}, + }, + "listener configured port unvailable": { + status: ConditionStatusFalse, + reason: GatewayListenerReasonPortUnavailable, + condType: GatewayConditionListenersConfigured, + message: "no port", + ref: ResourceReference{Name: "name", Kind: "httproute"}, + }, + + "listener configured unsupported protocol": { + status: ConditionStatusFalse, + reason: GatewayListenerReasonUnsupportedProtocol, + condType: GatewayConditionListenersConfigured, + message: "unsupported procotol", + ref: ResourceReference{Name: "name", Kind: "httproute"}, + }, + "listener configured unsupported address": { + status: ConditionStatusFalse, + reason: GatewayListenerReasonUnsupportedAddress, + condType: GatewayConditionListenersConfigured, + message: "unsupported address", + ref: ResourceReference{Name: "name", Kind: "httproute"}, + }, + "listener configured status unknown": { + status: ConditionStatusUnknown, + reason: GatewayReasonPending, + condType: GatewayConditionListenersConfigured, + message: "unknown", + ref: ResourceReference{Name: "name", Kind: "httproute"}, + }, + "resolved refs": { + status: ConditionStatusTrue, + reason: GatewayReasonResolvedRefs, + condType: GatewayConditionResolvedRefs, + message: "resolved refs", + ref: ResourceReference{Name: "name", Kind: "httproute"}, + }, + "resolved refs invalid certificate ref": { + status: ConditionStatusFalse, + reason: GatewayListenerReasonInvalidCertificateRef, + condType: GatewayConditionResolvedRefs, + message: "invalid certificate", + ref: ResourceReference{Name: "name", Kind: "httproute"}, + }, + "resolved refs invalid route kinds": { + status: ConditionStatusFalse, + reason: GatewayListenerReasonInvalidRouteKinds, + condType: GatewayConditionResolvedRefs, + message: "invalid route kinds", + ref: ResourceReference{Name: "name", Kind: "httproute"}, + }, + "resolved refs ref not permitted": { + status: ConditionStatusFalse, + reason: GatewayListenerReasonRefNotPermitted, + condType: GatewayConditionResolvedRefs, + message: "not permitted", + ref: ResourceReference{Name: "name", Kind: "httproute"}, + }, + } + + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { + cond := NewGatewayCondition(tc.condType, tc.status, tc.reason, tc.message, tc.ref) + expectedCond := Condition{ + Type: string(tc.condType), + Status: tc.status, + Reason: string(tc.reason), + Message: tc.message, + Resource: &tc.ref, + } + if !cond.IsSame(&expectedCond) { + t.Errorf("Expected condition to be\n%+v\ngot\n%+v", expectedCond, cond) + } + }) + } +} + +func TestNewGatewayInvalidCombinationsCausePanic(t *testing.T) { + // This is not an exhaustive list of all invalid combinations, just a few to confirm + testCases := map[string]struct { + status ConditionStatus + reason GatewayConditionReason + condType GatewayConditionType + message string + ref ResourceReference + }{ + "reason and condition type are valid but status is not": { + status: ConditionStatusTrue, + reason: GatewayReasonInvalid, + condType: GatewayConditionAccepted, + message: "almost there", + ref: ResourceReference{Name: "name", Kind: "httproute"}, + }, + "reason and status are valid but condition type is not": { + status: ConditionStatusFalse, + reason: GatewayListenerReasonHostnameConflict, + condType: GatewayConditionResolvedRefs, + message: "not quite", + ref: ResourceReference{Name: "name", Kind: "httproute"}, + }, + "condition type and status are valid but status is not": { + status: ConditionStatusUnknown, + reason: GatewayReasonInvalid, + condType: GatewayConditionAccepted, + message: "still not working", + ref: ResourceReference{Name: "name", Kind: "httproute"}, + }, + "all are invalid": { + status: ConditionStatusUnknown, + reason: GatewayReasonInvalid, + condType: GatewayConditionResolvedRefs, + message: "still not working", + ref: ResourceReference{Name: "name", Kind: "httproute"}, + }, + } + + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { + defer func() { + if r := recover(); r == nil { + t.Errorf("Expected combination %+v to be invalid", tc) + } + }() + _ = NewGatewayCondition(tc.condType, tc.status, tc.reason, tc.message, tc.ref) + }) + } +} + +func TestNewRouteConditionWithValidCombinations(t *testing.T) { + testCases := map[string]struct { + status ConditionStatus + reason RouteConditionReason + condType RouteConditionType + message string + ref ResourceReference + }{ + "accepted all around": { + status: ConditionStatusTrue, + reason: RouteReasonAccepted, + condType: RouteConditionAccepted, + message: "it's all good", + ref: ResourceReference{Name: "name", Kind: "httproute"}, + }, + "accepted not allowed by listeners": { + status: ConditionStatusFalse, + reason: RouteReasonNotAllowedByListeners, + condType: RouteConditionAccepted, + message: "not allowed by listeners", + ref: ResourceReference{Name: "name", Kind: "httproute"}, + }, + "accepted no matching hostname": { + status: ConditionStatusFalse, + reason: RouteReasonNoMatchingListenerHostname, + condType: RouteConditionAccepted, + message: "no matching listener hostname", + ref: ResourceReference{Name: "name", Kind: "httproute"}, + }, + "accepted no matching parent": { + status: ConditionStatusFalse, + reason: RouteReasonNoMatchingParent, + condType: RouteConditionAccepted, + message: "no matching parent", + ref: ResourceReference{Name: "name", Kind: "httproute"}, + }, + "accepted unsupported value": { + status: ConditionStatusFalse, + reason: RouteReasonUnsupportedValue, + condType: RouteConditionAccepted, + message: "unsupported value", + ref: ResourceReference{Name: "name", Kind: "httproute"}, + }, + "accepted parent ref not permitted": { + status: ConditionStatusFalse, + reason: RouteReasonParentRefNotPermitted, + condType: RouteConditionAccepted, + message: "parent ref not permitted", + ref: ResourceReference{Name: "name", Kind: "httproute"}, + }, + "accepted invalid discovery chain": { + status: ConditionStatusFalse, + reason: RouteReasonInvalidDiscoveryChain, + condType: RouteConditionAccepted, + message: "invalid discovery chain", + ref: ResourceReference{Name: "name", Kind: "httproute"}, + }, + "accepted no upstream services targeted": { + status: ConditionStatusFalse, + reason: RouteReasonNoUpstreamServicesTargeted, + condType: RouteConditionAccepted, + message: "no upstreams", + ref: ResourceReference{Name: "name", Kind: "httproute"}, + }, + "accepted pending": { + status: ConditionStatusUnknown, + reason: RouteReasonPending, + condType: RouteConditionAccepted, + message: "pending", + ref: ResourceReference{Name: "name", Kind: "httproute"}, + }, + "resolved refs": { + status: ConditionStatusTrue, + reason: RouteReasonResolvedRefs, + condType: RouteConditionResolvedRefs, + message: "resolved refs", + ref: ResourceReference{Name: "name", Kind: "httproute"}, + }, + "resolved refs not permitted": { + status: ConditionStatusFalse, + reason: RouteReasonRefNotPermitted, + condType: RouteConditionResolvedRefs, + message: "not permitted", + ref: ResourceReference{Name: "name", Kind: "httproute"}, + }, + "resolved refs invalid kind": { + status: ConditionStatusFalse, + reason: RouteReasonInvalidKind, + condType: RouteConditionResolvedRefs, + message: "invalid kind", + ref: ResourceReference{Name: "name", Kind: "httproute"}, + }, + "resolved refs bakend not found": { + status: ConditionStatusFalse, + reason: RouteReasonBackendNotFound, + condType: RouteConditionResolvedRefs, + message: "backend not found", + ref: ResourceReference{Name: "name", Kind: "httproute"}, + }, + "route bound": { + status: ConditionStatusTrue, + reason: RouteReasonBound, + condType: RouteConditionBound, + message: "bound", + ref: ResourceReference{Name: "name", Kind: "httproute"}, + }, + "route bound gateway not found": { + status: ConditionStatusFalse, + reason: RouteReasonGatewayNotFound, + condType: RouteConditionBound, + message: "gateway not found", + ref: ResourceReference{Name: "name", Kind: "httproute"}, + }, + "route bound failed to bind": { + status: ConditionStatusFalse, + reason: RouteReasonFailedToBind, + condType: RouteConditionBound, + message: "failed to bind", + ref: ResourceReference{Name: "name", Kind: "httproute"}, + }, + } + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { + cond := NewRouteCondition(tc.condType, tc.status, tc.reason, tc.message, tc.ref) + expectedCond := Condition{ + Type: string(tc.condType), + Status: tc.status, + Reason: string(tc.reason), + Message: tc.message, + Resource: &tc.ref, + } + if !cond.IsSame(&expectedCond) { + t.Errorf("Expected condition to be\n%+v\ngot\n%+v", expectedCond, cond) + } + }) + } +} diff --git a/proto/private/pbconfigentry/config_entry.gen.go b/proto/private/pbconfigentry/config_entry.gen.go index bba47b9cf90..3de97a6d55e 100644 --- a/proto/private/pbconfigentry/config_entry.gen.go +++ b/proto/private/pbconfigentry/config_entry.gen.go @@ -185,7 +185,7 @@ func ConditionToStructs(s *Condition, t *structs.Condition) { return } t.Type = s.Type - t.Status = s.Status + t.Status = conditionStatusToStructs(s.Status) t.Reason = s.Reason t.Message = s.Message if s.Resource != nil { @@ -200,7 +200,7 @@ func ConditionFromStructs(t *structs.Condition, s *Condition) { return } s.Type = t.Type - s.Status = t.Status + s.Status = conditionStatusFromStructs(t.Status) s.Reason = t.Reason s.Message = t.Message if t.Resource != nil { diff --git a/proto/private/pbconfigentry/config_entry.go b/proto/private/pbconfigentry/config_entry.go index 7cecbf02024..b47da5c3390 100644 --- a/proto/private/pbconfigentry/config_entry.go +++ b/proto/private/pbconfigentry/config_entry.go @@ -392,6 +392,23 @@ func apiGatewayProtocolToStructs(a APIGatewayListenerProtocol) structs.APIGatewa } } +func conditionStatusToStructs(s string) structs.ConditionStatus { + switch s { + case "True": + return structs.ConditionStatusTrue + case "False": + return structs.ConditionStatusFalse + case "Unknown": + fallthrough + default: + return structs.ConditionStatusUnknown + } +} + +func conditionStatusFromStructs(s structs.ConditionStatus) string { + return string(s) +} + func httpMatchMethodFromStructs(a structs.HTTPMatchMethod) HTTPMatchMethod { switch a { case structs.HTTPMatchMethodAll: diff --git a/proto/private/pbconfigentry/config_entry.pb.go b/proto/private/pbconfigentry/config_entry.pb.go index fae2340cf52..72d2b2db16f 100644 --- a/proto/private/pbconfigentry/config_entry.pb.go +++ b/proto/private/pbconfigentry/config_entry.pb.go @@ -4127,7 +4127,8 @@ type Condition struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Type string `protobuf:"bytes,1,opt,name=Type,proto3" json:"Type,omitempty"` + Type string `protobuf:"bytes,1,opt,name=Type,proto3" json:"Type,omitempty"` + // mog: func-to=conditionStatusToStructs func-from=conditionStatusFromStructs Status string `protobuf:"bytes,2,opt,name=Status,proto3" json:"Status,omitempty"` Reason string `protobuf:"bytes,3,opt,name=Reason,proto3" json:"Reason,omitempty"` Message string `protobuf:"bytes,4,opt,name=Message,proto3" json:"Message,omitempty"` diff --git a/proto/private/pbconfigentry/config_entry.proto b/proto/private/pbconfigentry/config_entry.proto index 14a600cefa0..5c38bbf29a3 100644 --- a/proto/private/pbconfigentry/config_entry.proto +++ b/proto/private/pbconfigentry/config_entry.proto @@ -633,6 +633,7 @@ message Status { // name=Structs message Condition { string Type = 1; + // mog: func-to=conditionStatusToStructs func-from=conditionStatusFromStructs string Status = 2; string Reason = 3; string Message = 4; From eb62bef3cf63f9cb3a237c051699d9f3027eb60a Mon Sep 17 00:00:00 2001 From: jm96441n Date: Wed, 12 Apr 2023 22:10:20 -0400 Subject: [PATCH 02/24] Added tests for checking condition status and panic conditions for validating combinations, added dummy code for fsm store --- agent/consul/fsm_data_store.go | 8 +-- agent/structs/config_entry_status.go | 19 +++++-- agent/structs/config_entry_status_test.go | 65 +++++++++++++++++++++++ 3 files changed, 83 insertions(+), 9 deletions(-) diff --git a/agent/consul/fsm_data_store.go b/agent/consul/fsm_data_store.go index 46c3ca2f0f4..708f6614739 100644 --- a/agent/consul/fsm_data_store.go +++ b/agent/consul/fsm_data_store.go @@ -56,15 +56,11 @@ func (f *FSMDataStore) Update(entry structs.ConfigEntry) error { // UpdateStatus takes a config entry, an error, and updates the status field as needed in the FSM state func (f *FSMDataStore) UpdateStatus(entry structs.ControlledConfigEntry, err error) error { if err == nil { - //TODO additional status messages for success? + // TODO additional status messages for success? return nil } status := structs.Status{ - Conditions: []structs.Condition{{ - - Status: err.Error() + ": Accepted == false", - }, - }, + Conditions: entry.GetStatus().Conditions, } entry.SetStatus(status) return f.Update(entry) diff --git a/agent/structs/config_entry_status.go b/agent/structs/config_entry_status.go index b3cf06eca75..f4475b2b9b7 100644 --- a/agent/structs/config_entry_status.go +++ b/agent/structs/config_entry_status.go @@ -419,6 +419,10 @@ func NewGatewayCondition(name GatewayConditionType, status ConditionStatus, reas } func validateGatewayConfigReason(name GatewayConditionType, status ConditionStatus, reason GatewayConditionReason) error { + if err := checkConditionStatus(status); err != nil { + return err + } + reasons, ok := validGatewayConditionReasonsMapping[name] if !ok { return fmt.Errorf("unrecognized GatewayConditionType %q", name) @@ -636,9 +640,9 @@ var validRouteConditionReasonsMapping = map[RouteConditionType]map[ConditionStat } func checkRouteConditionReason(name RouteConditionType, status ConditionStatus, reason RouteConditionReason) error { - // if err := checkConditionStatus(status); err != nil { - // return err - // } + if err := checkConditionStatus(status); err != nil { + return err + } reasons, ok := validRouteConditionReasonsMapping[name] if !ok { @@ -657,6 +661,15 @@ func checkRouteConditionReason(name RouteConditionType, status ConditionStatus, return nil } +func checkConditionStatus(status ConditionStatus) error { + switch status { + case ConditionStatusTrue, ConditionStatusFalse, ConditionStatusUnknown: + return nil + default: + return fmt.Errorf("unrecognized condition status: %q", status) + } +} + func ptrTo[T any](val T) *T { return &val } diff --git a/agent/structs/config_entry_status_test.go b/agent/structs/config_entry_status_test.go index 8795c1fa6c5..5d2824641eb 100644 --- a/agent/structs/config_entry_status_test.go +++ b/agent/structs/config_entry_status_test.go @@ -158,6 +158,13 @@ func TestNewGatewayInvalidCombinationsCausePanic(t *testing.T) { message: "still not working", ref: ResourceReference{Name: "name", Kind: "httproute"}, }, + "pass something other than a condition status": { + status: ConditionStatus("hello"), + reason: GatewayReasonInvalid, + condType: GatewayConditionResolvedRefs, + message: "still not working", + ref: ResourceReference{Name: "name", Kind: "httproute"}, + }, } for name, tc := range testCases { @@ -309,3 +316,61 @@ func TestNewRouteConditionWithValidCombinations(t *testing.T) { }) } } + +func TestNewRouteInvalidCombinationsCausePanic(t *testing.T) { + // This is not an exhaustive list of all invalid combinations, just a few to confirm + testCases := map[string]struct { + status ConditionStatus + reason RouteConditionReason + condType RouteConditionType + message string + ref ResourceReference + }{ + "reason and condition type are valid but status is not": { + status: ConditionStatusTrue, + reason: RouteReasonNotAllowedByListeners, + condType: RouteConditionAccepted, + message: "almost there", + ref: ResourceReference{Name: "name", Kind: "httproute"}, + }, + "reason and status are valid but condition type is not": { + status: ConditionStatusFalse, + reason: RouteReasonRefNotPermitted, + condType: RouteConditionBound, + message: "not quite", + ref: ResourceReference{Name: "name", Kind: "httproute"}, + }, + "condition type and status are valid but status is not": { + status: ConditionStatusUnknown, + reason: RouteReasonBound, + condType: RouteConditionBound, + message: "still not working", + ref: ResourceReference{Name: "name", Kind: "httproute"}, + }, + "all are invalid": { + status: ConditionStatusUnknown, + reason: RouteReasonGatewayNotFound, + condType: RouteConditionResolvedRefs, + message: "still not working", + ref: ResourceReference{Name: "name", Kind: "httproute"}, + }, + "pass something other than a condition status": { + status: ConditionStatus("hello"), + reason: RouteReasonAccepted, + condType: RouteConditionAccepted, + message: "still not working", + ref: ResourceReference{Name: "name", Kind: "httproute"}, + }, + } + + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { + defer func() { + if r := recover(); r == nil { + t.Errorf("Expected combination %+v to be invalid", tc) + } + }() + _ = NewRouteCondition(tc.condType, tc.status, tc.reason, tc.message, tc.ref) + }) + } +} From bb50b9625ff318fd7a7af5aefb27007efcdd26a8 Mon Sep 17 00:00:00 2001 From: jm96441n Date: Wed, 12 Apr 2023 22:17:23 -0400 Subject: [PATCH 03/24] get rid of unneeded gateway condition generator struct --- agent/consul/gateways/controller_gateways.go | 83 +++++++------------- 1 file changed, 29 insertions(+), 54 deletions(-) diff --git a/agent/consul/gateways/controller_gateways.go b/agent/consul/gateways/controller_gateways.go index 3a792db1966..08d485d13fc 100644 --- a/agent/consul/gateways/controller_gateways.go +++ b/agent/consul/gateways/controller_gateways.go @@ -8,7 +8,6 @@ import ( "errors" "fmt" "sync" - "time" "github.com/hashicorp/go-hclog" "github.com/hashicorp/go-memdb" @@ -211,8 +210,6 @@ func (r *apiGatewayReconciler) cleanupGateway(_ context.Context, req controller. // referenced this gateway. It then persists any status updates for the gateway, // the modified routes, and updates the bound gateway. func (r *apiGatewayReconciler) reconcileGateway(_ context.Context, req controller.Request, store *state.Store, gateway *structs.APIGatewayConfigEntry) error { - conditions := newGatewayConditionGenerator() - logger := gatewayRequestLogger(r.logger, req) logger.Trace("started reconciling gateway") @@ -244,13 +241,13 @@ func (r *apiGatewayReconciler) reconcileGateway(_ context.Context, req controlle } for ref, err := range certificateErrors { - updater.SetCondition(conditions.invalidCertificate(ref, err)) + updater.SetCondition(invalidCertificate(ref, err)) } if len(certificateErrors) > 0 { - updater.SetCondition(conditions.invalidCertificates()) + updater.SetCondition(invalidCertificates()) } else { - updater.SetCondition(conditions.gatewayAccepted()) + updater.SetCondition(gatewayAccepted()) } // now we bind all of the routes we can @@ -262,19 +259,19 @@ func (r *apiGatewayReconciler) reconcileGateway(_ context.Context, req controlle // unset the old gateway binding in case it's stale for _, parent := range route.GetParents() { if parent.Kind == gateway.Kind && parent.Name == gateway.Name && parent.EnterpriseMeta.IsSame(&gateway.EnterpriseMeta) { - routeUpdater.RemoveCondition(conditions.routeBound(parent)) + routeUpdater.RemoveCondition(routeBound(parent)) } } // set the status for parents that have bound successfully for _, ref := range boundRefs { - routeUpdater.SetCondition(conditions.routeBound(ref)) + routeUpdater.SetCondition(routeBound(ref)) } // set the status for any parents that have errored trying to // bind for ref, err := range bindErrors { - routeUpdater.SetCondition(conditions.routeUnbound(ref, err)) + routeUpdater.SetCondition(routeUnbound(ref, err)) } // if we've updated any statuses, then store them as needing @@ -354,8 +351,6 @@ func (r *apiGatewayReconciler) cleanupRoute(_ context.Context, req controller.Re // gateways that now have route conflicts, and updates all statuses and states // as necessary. func (r *apiGatewayReconciler) reconcileRoute(_ context.Context, req controller.Request, store *state.Store, route structs.BoundRoute) error { - conditions := newGatewayConditionGenerator() - logger := routeRequestLogger(r.logger, req) logger.Trace("reconciling route") @@ -435,23 +430,23 @@ func (r *apiGatewayReconciler) reconcileRoute(_ context.Context, req controller. Entries: chainSet, }) if err != nil { - updater.SetCondition(conditions.routeInvalidDiscoveryChain(err)) + updater.SetCondition(routeInvalidDiscoveryChain(err)) continue } if chain.Protocol != string(route.GetProtocol()) { - updater.SetCondition(conditions.routeInvalidDiscoveryChain(errInvalidProtocol)) + updater.SetCondition(routeInvalidDiscoveryChain(errInvalidProtocol)) continue } - updater.SetCondition(conditions.routeAccepted()) + updater.SetCondition(routeAccepted()) } // if we have no upstream targets, then set the route as invalid // this should already happen in the validation check on write, but // we'll do it here too just in case if len(route.GetServiceNames()) == 0 { - updater.SetCondition(conditions.routeNoUpstreams()) + updater.SetCondition(routeNoUpstreams()) } // the route is valid, attempt to bind it to all gateways @@ -460,12 +455,12 @@ func (r *apiGatewayReconciler) reconcileRoute(_ context.Context, req controller. // set the status of the references that are bound for _, ref := range boundRefs { - updater.SetCondition(conditions.routeBound(ref)) + updater.SetCondition(routeBound(ref)) } // set any binding errors for ref, err := range bindErrors { - updater.SetCondition(conditions.routeUnbound(ref, err)) + updater.SetCondition(routeUnbound(ref, err)) } // set any refs that haven't been bound or explicitly errored @@ -479,7 +474,7 @@ PARENT_LOOP: if _, ok := bindErrors[ref]; ok { continue PARENT_LOOP } - updater.SetCondition(conditions.gatewayNotFound(ref)) + updater.SetCondition(gatewayNotFound(ref)) } return finalize(modifiedGateways) @@ -549,8 +544,6 @@ type gatewayMeta struct { // the map values are pointers so that we can update them directly // and have the changes propagate back to the container gateways. boundListeners map[string]*structs.BoundAPIGatewayListener - - generator *gatewayConditionGenerator } // getAllGatewayMeta returns a pre-constructed list of all valid gateway and state @@ -678,13 +671,13 @@ func (g *gatewayMeta) bindRoute(listener *structs.APIGatewayListener, bound *str } // check to make sure we're not binding to an invalid gateway - if !g.Gateway.Status.MatchesConditionStatus(g.generator.gatewayAccepted()) { + if !g.Gateway.Status.MatchesConditionStatus(gatewayAccepted()) { return false, fmt.Errorf("failed to bind route to gateway %s: gateway has not been accepted", g.Gateway.Name) } // check to make sure we're not binding to an invalid route status := route.GetStatus() - if !status.MatchesConditionStatus(g.generator.routeAccepted()) { + if !status.MatchesConditionStatus(routeAccepted()) { return false, fmt.Errorf("failed to bind route to gateway %s: route has not been accepted", g.Gateway.Name) } @@ -773,8 +766,6 @@ func (g *gatewayMeta) checkConflicts() (structs.ControlledConfigEntry, bool) { // setConflicts ensures that no TCP listener has more than the one allowed route and // assigns an appropriate status func (g *gatewayMeta) setConflicts(updater *structs.StatusUpdater) { - conditions := newGatewayConditionGenerator() - g.eachListener(func(listener *structs.APIGatewayListener, bound *structs.BoundAPIGatewayListener) error { ref := structs.ResourceReference{ Kind: structs.APIGateway, @@ -785,19 +776,17 @@ func (g *gatewayMeta) setConflicts(updater *structs.StatusUpdater) { switch listener.Protocol { case structs.ListenerProtocolTCP: if len(bound.Routes) > 1 { - updater.SetCondition(conditions.gatewayListenerConflicts(ref)) + updater.SetCondition(gatewayListenerConflicts(ref)) return nil } } - updater.SetCondition(conditions.gatewayListenerNoConflicts(ref)) + updater.SetCondition(gatewayListenerNoConflicts(ref)) return nil }) } // initialize sets up the listener maps that we use for quickly indexing the listeners in our binding logic func (g *gatewayMeta) initialize() *gatewayMeta { - g.generator = newGatewayConditionGenerator() - // set up the maps for fast access g.boundListeners = make(map[string]*structs.BoundAPIGatewayListener, len(g.BoundGateway.Listeners)) for i, listener := range g.BoundGateway.Listeners { @@ -840,21 +829,8 @@ func newGatewayMeta(gateway *structs.APIGatewayConfigEntry, bound structs.Config }).initialize() } -// gatewayConditionGenerator is a simple struct used for isolating -// the status conditions that we generate for our components -type gatewayConditionGenerator struct { - now *time.Time -} - -// newGatewayConditionGenerator initializes a status conditions generator -func newGatewayConditionGenerator() *gatewayConditionGenerator { - return &gatewayConditionGenerator{ - now: pointerTo(time.Now().UTC()), - } -} - // gatewayAccepted marks the APIGateway as valid. -func (g *gatewayConditionGenerator) gatewayAccepted() structs.Condition { +func gatewayAccepted() structs.Condition { return structs.NewGatewayCondition( structs.GatewayConditionAccepted, structs.ConditionStatusTrue, @@ -867,7 +843,7 @@ func (g *gatewayConditionGenerator) gatewayAccepted() structs.Condition { // invalidCertificate returns a condition used when a gateway references a // certificate that does not exist. It takes a ref used to scope the condition // to a given APIGateway listener. -func (g *gatewayConditionGenerator) invalidCertificate(ref structs.ResourceReference, err error) structs.Condition { +func invalidCertificate(ref structs.ResourceReference, err error) structs.Condition { return structs.NewGatewayCondition( structs.GatewayConditionAccepted, structs.ConditionStatusFalse, @@ -879,7 +855,7 @@ func (g *gatewayConditionGenerator) invalidCertificate(ref structs.ResourceRefer // invalidCertificates is used to set the overall condition of the APIGateway // to invalid due to missing certificates that it references. -func (g *gatewayConditionGenerator) invalidCertificates() structs.Condition { +func invalidCertificates() structs.Condition { return structs.NewGatewayCondition( structs.GatewayConditionAccepted, structs.ConditionStatusFalse, @@ -891,7 +867,7 @@ func (g *gatewayConditionGenerator) invalidCertificates() structs.Condition { // gatewayListenerNoConflicts marks an APIGateway listener as having no conflicts within its // bound routes -func (g *gatewayConditionGenerator) gatewayListenerNoConflicts(ref structs.ResourceReference) structs.Condition { +func gatewayListenerNoConflicts(ref structs.ResourceReference) structs.Condition { return structs.NewGatewayCondition( structs.GatewayConditionListenersConfigured, structs.ConditionStatusTrue, @@ -903,7 +879,7 @@ func (g *gatewayConditionGenerator) gatewayListenerNoConflicts(ref structs.Resou // gatewayListenerConflicts marks an APIGateway listener as having bound routes that conflict with each other // and make the listener, therefore invalid -func (g *gatewayConditionGenerator) gatewayListenerConflicts(ref structs.ResourceReference) structs.Condition { +func gatewayListenerConflicts(ref structs.ResourceReference) structs.Condition { return structs.NewGatewayCondition( structs.GatewayConditionListenersConfigured, structs.ConditionStatusFalse, @@ -914,7 +890,7 @@ func (g *gatewayConditionGenerator) gatewayListenerConflicts(ref structs.Resourc } // routeBound marks a Route as bound to the referenced APIGateway -func (g *gatewayConditionGenerator) routeBound(ref structs.ResourceReference) structs.Condition { +func routeBound(ref structs.ResourceReference) structs.Condition { return structs.NewRouteCondition( structs.RouteConditionBound, structs.ConditionStatusTrue, @@ -926,7 +902,7 @@ func (g *gatewayConditionGenerator) routeBound(ref structs.ResourceReference) st // gatewayNotFound marks a Route as having failed to bind to a referenced APIGateway due to // the Gateway not existing (or having not been reconciled yet) -func (g *gatewayConditionGenerator) gatewayNotFound(ref structs.ResourceReference) structs.Condition { +func gatewayNotFound(ref structs.ResourceReference) structs.Condition { return structs.NewRouteCondition( structs.RouteConditionBound, structs.ConditionStatusFalse, @@ -937,7 +913,7 @@ func (g *gatewayConditionGenerator) gatewayNotFound(ref structs.ResourceReferenc } // routeUnbound marks the route as having failed to bind to the referenced APIGateway -func (g *gatewayConditionGenerator) routeUnbound(ref structs.ResourceReference, err error) structs.Condition { +func routeUnbound(ref structs.ResourceReference, err error) structs.Condition { return structs.NewRouteCondition( structs.RouteConditionBound, structs.ConditionStatusFalse, @@ -948,7 +924,7 @@ func (g *gatewayConditionGenerator) routeUnbound(ref structs.ResourceReference, } // routeAccepted marks the Route as valid -func (g *gatewayConditionGenerator) routeAccepted() structs.Condition { +func routeAccepted() structs.Condition { return structs.NewRouteCondition( structs.RouteConditionAccepted, structs.ConditionStatusTrue, @@ -960,7 +936,7 @@ func (g *gatewayConditionGenerator) routeAccepted() structs.Condition { // routeInvalidDiscoveryChain marks the route as invalid due to an error while validating its referenced // discovery chian -func (g *gatewayConditionGenerator) routeInvalidDiscoveryChain(err error) structs.Condition { +func routeInvalidDiscoveryChain(err error) structs.Condition { return structs.NewRouteCondition( structs.RouteConditionAccepted, structs.ConditionStatusFalse, @@ -971,7 +947,7 @@ func (g *gatewayConditionGenerator) routeInvalidDiscoveryChain(err error) struct } // routeNoUpstreams marks the route as invalid because it has no upstreams that it targets -func (g *gatewayConditionGenerator) routeNoUpstreams() structs.Condition { +func routeNoUpstreams() structs.Condition { return structs.NewRouteCondition( structs.RouteConditionAccepted, structs.ConditionStatusFalse, @@ -1018,7 +994,6 @@ func bindRoutesToGateways(route structs.BoundRoute, gateways ...*gatewayMeta) ([ // removeGateway sets the route's status appropriately when the gateway that it's // attempting to bind to does not exist func removeGateway(gateway structs.ResourceReference, entries ...structs.BoundRoute) []structs.ControlledConfigEntry { - conditions := newGatewayConditionGenerator() modified := []structs.ControlledConfigEntry{} for _, route := range entries { @@ -1026,7 +1001,7 @@ func removeGateway(gateway structs.ResourceReference, entries ...structs.BoundRo for _, parent := range route.GetParents() { if parent.Kind == gateway.Kind && parent.Name == gateway.Name && parent.EnterpriseMeta.IsSame(&gateway.EnterpriseMeta) { - updater.SetCondition(conditions.gatewayNotFound(parent)) + updater.SetCondition(gatewayNotFound(parent)) } } From 2659a062f66bef50ec5ededd550e88ba16a34acf Mon Sep 17 00:00:00 2001 From: jm96441n Date: Thu, 13 Apr 2023 11:09:55 -0400 Subject: [PATCH 04/24] Remove unused file --- agent/consul/fsm_data_store.go | 76 ---------------------------------- 1 file changed, 76 deletions(-) delete mode 100644 agent/consul/fsm_data_store.go diff --git a/agent/consul/fsm_data_store.go b/agent/consul/fsm_data_store.go deleted file mode 100644 index 708f6614739..00000000000 --- a/agent/consul/fsm_data_store.go +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package consul - -import ( - "github.com/hashicorp/consul/acl" - "github.com/hashicorp/consul/agent/consul/fsm" - "github.com/hashicorp/consul/agent/structs" -) - -// FSMDataStore implements the DataStore interface using the Consul server and finite state manager. -type FSMDataStore struct { - server *Server - fsm *fsm.FSM -} - -func NewFSMDataStore(server *Server, fsm *fsm.FSM) *FSMDataStore { - return &FSMDataStore{ - server: server, - fsm: fsm, - } -} - -// GetConfigEntry takes in a kind, name, and meta and returns a configentry and an error from the FSM state -func (f *FSMDataStore) GetConfigEntry(kind string, name string, meta *acl.EnterpriseMeta) (structs.ConfigEntry, error) { - store := f.fsm.State() - - _, entry, err := store.ConfigEntry(nil, kind, name, meta) - if err != nil { - return nil, err - } - return entry, nil -} - -// GetConfigEntriesByKind takes in a kind and returns all instances of that kind of config entry from the FSM state -func (f *FSMDataStore) GetConfigEntriesByKind(kind string) ([]structs.ConfigEntry, error) { - store := f.fsm.State() - - _, entries, err := store.ConfigEntriesByKind(nil, kind, acl.WildcardEnterpriseMeta()) - if err != nil { - return nil, err - } - return entries, nil -} - -// Update takes a config entry and upserts it in the FSM state -func (f *FSMDataStore) Update(entry structs.ConfigEntry) error { - _, err := f.server.leaderRaftApply("ConfigEntry.Apply", structs.ConfigEntryRequestType, &structs.ConfigEntryRequest{ - Op: structs.ConfigEntryUpsertCAS, - Entry: entry, - }) - return err -} - -// UpdateStatus takes a config entry, an error, and updates the status field as needed in the FSM state -func (f *FSMDataStore) UpdateStatus(entry structs.ControlledConfigEntry, err error) error { - if err == nil { - // TODO additional status messages for success? - return nil - } - status := structs.Status{ - Conditions: entry.GetStatus().Conditions, - } - entry.SetStatus(status) - return f.Update(entry) -} - -// Delete takes a config entry and deletes it from the FSM state -func (f *FSMDataStore) Delete(entry structs.ConfigEntry) error { - _, err := f.server.leaderRaftApply("ConfigEntry.Delete", structs.ConfigEntryRequestType, &structs.ConfigEntryRequest{ - Op: structs.ConfigEntryDelete, - Entry: entry, - }) - return err -} From b84cd213262c4d584b739f2b5f6a75dd9878d1ab Mon Sep 17 00:00:00 2001 From: jm96441n Date: Thu, 13 Apr 2023 11:13:39 -0400 Subject: [PATCH 05/24] run go mod tidy --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index e477ce61aa9..6b3eba11a65 100644 --- a/go.mod +++ b/go.mod @@ -98,6 +98,7 @@ require ( go.uber.org/goleak v1.1.10 golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d golang.org/x/net v0.7.0 + golang.org/x/exp v0.0.0-20220827204233-334a2380cb91 golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1 golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 golang.org/x/sys v0.5.0 @@ -227,7 +228,6 @@ require ( go.opencensus.io v0.23.0 // indirect go.opentelemetry.io/proto/otlp v0.7.0 // indirect go.uber.org/atomic v1.9.0 // indirect - golang.org/x/exp v0.0.0-20220827204233-334a2380cb91 // indirect golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 // indirect golang.org/x/term v0.5.0 // indirect golang.org/x/text v0.7.0 // indirect From 740a4e53739c2e7e2ab8858c5a2a6f89fb7492fe Mon Sep 17 00:00:00 2001 From: jm96441n Date: Thu, 13 Apr 2023 12:26:15 -0400 Subject: [PATCH 06/24] Update tests, add conflicted gateway status --- agent/consul/gateways/controller_gateways.go | 17 +- .../gateways/controller_gateways_test.go | 277 +++++++++--------- agent/structs/config_entry_status.go | 18 ++ 3 files changed, 162 insertions(+), 150 deletions(-) diff --git a/agent/consul/gateways/controller_gateways.go b/agent/consul/gateways/controller_gateways.go index 08d485d13fc..fe2478f85c9 100644 --- a/agent/consul/gateways/controller_gateways.go +++ b/agent/consul/gateways/controller_gateways.go @@ -748,7 +748,6 @@ func (g *gatewayMeta) checkCertificates(store *state.Store) (map[structs.Resourc } return nil }) - if err != nil { return nil, err } @@ -845,7 +844,7 @@ func gatewayAccepted() structs.Condition { // to a given APIGateway listener. func invalidCertificate(ref structs.ResourceReference, err error) structs.Condition { return structs.NewGatewayCondition( - structs.GatewayConditionAccepted, + structs.GatewayConditionResolvedRefs, structs.ConditionStatusFalse, structs.GatewayListenerReasonInvalidCertificateRef, err.Error(), @@ -857,7 +856,7 @@ func invalidCertificate(ref structs.ResourceReference, err error) structs.Condit // to invalid due to missing certificates that it references. func invalidCertificates() structs.Condition { return structs.NewGatewayCondition( - structs.GatewayConditionAccepted, + structs.GatewayConditionResolvedRefs, structs.ConditionStatusFalse, structs.GatewayListenerReasonInvalidCertificateRef, "gateway references invalid certificates", @@ -869,9 +868,9 @@ func invalidCertificates() structs.Condition { // bound routes func gatewayListenerNoConflicts(ref structs.ResourceReference) structs.Condition { return structs.NewGatewayCondition( - structs.GatewayConditionListenersConfigured, - structs.ConditionStatusTrue, - structs.GatewayReasonListenersConfigured, + structs.GatewayConditionConflicted, + structs.ConditionStatusFalse, + structs.GatewayReasonNoConflicts, "listener has no route conflicts", ref, ) @@ -881,9 +880,9 @@ func gatewayListenerNoConflicts(ref structs.ResourceReference) structs.Condition // and make the listener, therefore invalid func gatewayListenerConflicts(ref structs.ResourceReference) structs.Condition { return structs.NewGatewayCondition( - structs.GatewayConditionListenersConfigured, - structs.ConditionStatusFalse, - structs.GatewayListenerReasonProtocolConflict, + structs.GatewayConditionConflicted, + structs.ConditionStatusTrue, + structs.GatewayReasonRouteConflict, "TCP-based listeners currently only support binding a single route", ref, ) diff --git a/agent/consul/gateways/controller_gateways_test.go b/agent/consul/gateways/controller_gateways_test.go index 39a379cf57e..ce818578d9f 100644 --- a/agent/consul/gateways/controller_gateways_test.go +++ b/agent/consul/gateways/controller_gateways_test.go @@ -11,9 +11,10 @@ import ( "testing" "time" - "github.com/hashicorp/go-hclog" "github.com/stretchr/testify/require" + "github.com/hashicorp/go-hclog" + "github.com/hashicorp/consul/acl" "github.com/hashicorp/consul/agent/consul/controller" "github.com/hashicorp/consul/agent/consul/fsm" @@ -55,7 +56,7 @@ func TestBoundAPIGatewayBindRoute(t *testing.T) { }, Status: structs.Status{ Conditions: []structs.Condition{ - newGatewayConditionGenerator().gatewayAccepted(), + gatewayAccepted(), }, }, }, @@ -72,7 +73,7 @@ func TestBoundAPIGatewayBindRoute(t *testing.T) { }, Status: structs.Status{ Conditions: []structs.Condition{ - newGatewayConditionGenerator().routeAccepted(), + routeAccepted(), }, }, }, @@ -132,7 +133,7 @@ func TestBoundAPIGatewayBindRoute(t *testing.T) { }, Status: structs.Status{ Conditions: []structs.Condition{ - newGatewayConditionGenerator().gatewayAccepted(), + gatewayAccepted(), }, }, }, @@ -148,7 +149,7 @@ func TestBoundAPIGatewayBindRoute(t *testing.T) { }, Status: structs.Status{ Conditions: []structs.Condition{ - newGatewayConditionGenerator().routeAccepted(), + routeAccepted(), }, }, }, @@ -443,7 +444,7 @@ func TestBindRoutesToGateways(t *testing.T) { }, Status: structs.Status{ Conditions: []structs.Condition{ - newGatewayConditionGenerator().gatewayAccepted(), + gatewayAccepted(), }, }, }, @@ -462,7 +463,7 @@ func TestBindRoutesToGateways(t *testing.T) { }, Status: structs.Status{ Conditions: []structs.Condition{ - newGatewayConditionGenerator().routeAccepted(), + routeAccepted(), }, }, }, @@ -557,7 +558,7 @@ func TestBindRoutesToGateways(t *testing.T) { }, Status: structs.Status{ Conditions: []structs.Condition{ - newGatewayConditionGenerator().gatewayAccepted(), + gatewayAccepted(), }, }, }, @@ -582,7 +583,7 @@ func TestBindRoutesToGateways(t *testing.T) { }, Status: structs.Status{ Conditions: []structs.Condition{ - newGatewayConditionGenerator().gatewayAccepted(), + gatewayAccepted(), }, }, }, @@ -606,7 +607,7 @@ func TestBindRoutesToGateways(t *testing.T) { }, Status: structs.Status{ Conditions: []structs.Condition{ - newGatewayConditionGenerator().routeAccepted(), + routeAccepted(), }, }, }, @@ -675,7 +676,7 @@ func TestBindRoutesToGateways(t *testing.T) { }, Status: structs.Status{ Conditions: []structs.Condition{ - newGatewayConditionGenerator().gatewayAccepted(), + gatewayAccepted(), }, }, }, @@ -694,7 +695,7 @@ func TestBindRoutesToGateways(t *testing.T) { }, Status: structs.Status{ Conditions: []structs.Condition{ - newGatewayConditionGenerator().routeAccepted(), + routeAccepted(), }, }, }, @@ -752,7 +753,7 @@ func TestBindRoutesToGateways(t *testing.T) { }, Status: structs.Status{ Conditions: []structs.Condition{ - newGatewayConditionGenerator().gatewayAccepted(), + gatewayAccepted(), }, }, }, @@ -771,7 +772,7 @@ func TestBindRoutesToGateways(t *testing.T) { }, Status: structs.Status{ Conditions: []structs.Condition{ - newGatewayConditionGenerator().routeAccepted(), + routeAccepted(), }, }, }, @@ -841,7 +842,7 @@ func TestBindRoutesToGateways(t *testing.T) { }, Status: structs.Status{ Conditions: []structs.Condition{ - newGatewayConditionGenerator().gatewayAccepted(), + gatewayAccepted(), }, }, }, @@ -860,7 +861,7 @@ func TestBindRoutesToGateways(t *testing.T) { }, Status: structs.Status{ Conditions: []structs.Condition{ - newGatewayConditionGenerator().routeAccepted(), + routeAccepted(), }, }, }, @@ -924,7 +925,7 @@ func TestBindRoutesToGateways(t *testing.T) { }, Status: structs.Status{ Conditions: []structs.Condition{ - newGatewayConditionGenerator().gatewayAccepted(), + gatewayAccepted(), }, }, }, @@ -957,7 +958,7 @@ func TestBindRoutesToGateways(t *testing.T) { }, Status: structs.Status{ Conditions: []structs.Condition{ - newGatewayConditionGenerator().gatewayAccepted(), + gatewayAccepted(), }, }, }, @@ -981,7 +982,7 @@ func TestBindRoutesToGateways(t *testing.T) { }, Status: structs.Status{ Conditions: []structs.Condition{ - newGatewayConditionGenerator().routeAccepted(), + routeAccepted(), }, }, }, @@ -1064,7 +1065,7 @@ func TestBindRoutesToGateways(t *testing.T) { }, Status: structs.Status{ Conditions: []structs.Condition{ - newGatewayConditionGenerator().gatewayAccepted(), + gatewayAccepted(), }, }, }, @@ -1083,7 +1084,7 @@ func TestBindRoutesToGateways(t *testing.T) { }, Status: structs.Status{ Conditions: []structs.Condition{ - newGatewayConditionGenerator().routeAccepted(), + routeAccepted(), }, }, }, @@ -1133,7 +1134,7 @@ func TestBindRoutesToGateways(t *testing.T) { }, Status: structs.Status{ Conditions: []structs.Condition{ - newGatewayConditionGenerator().gatewayAccepted(), + gatewayAccepted(), }, }, }, @@ -1158,7 +1159,7 @@ func TestBindRoutesToGateways(t *testing.T) { }, Status: structs.Status{ Conditions: []structs.Condition{ - newGatewayConditionGenerator().gatewayAccepted(), + gatewayAccepted(), }, }, }, @@ -1177,7 +1178,7 @@ func TestBindRoutesToGateways(t *testing.T) { }, Status: structs.Status{ Conditions: []structs.Condition{ - newGatewayConditionGenerator().routeAccepted(), + routeAccepted(), }, }, }, @@ -1193,7 +1194,7 @@ func TestBindRoutesToGateways(t *testing.T) { }, Status: structs.Status{ Conditions: []structs.Condition{ - newGatewayConditionGenerator().routeAccepted(), + routeAccepted(), }, }, }, @@ -1254,7 +1255,7 @@ func TestBindRoutesToGateways(t *testing.T) { }, Status: structs.Status{ Conditions: []structs.Condition{ - newGatewayConditionGenerator().gatewayAccepted(), + gatewayAccepted(), }, }, }, @@ -1273,7 +1274,7 @@ func TestBindRoutesToGateways(t *testing.T) { }, Status: structs.Status{ Conditions: []structs.Condition{ - newGatewayConditionGenerator().routeAccepted(), + routeAccepted(), }, }, }, @@ -1317,7 +1318,7 @@ func TestBindRoutesToGateways(t *testing.T) { }, Status: structs.Status{ Conditions: []structs.Condition{ - newGatewayConditionGenerator().gatewayAccepted(), + gatewayAccepted(), }, }, }, @@ -1336,14 +1337,13 @@ func TestBindRoutesToGateways(t *testing.T) { }, Status: structs.Status{ Conditions: []structs.Condition{ - newGatewayConditionGenerator().routeAccepted(), + routeAccepted(), }, }, }, }, expectedBoundAPIGateways: []*structs.BoundAPIGatewayConfigEntry{ { - Name: "Gateway", Listeners: []structs.BoundAPIGatewayListener{ { @@ -1435,7 +1435,7 @@ func TestBindRoutesToGateways(t *testing.T) { }, Status: structs.Status{ Conditions: []structs.Condition{ - newGatewayConditionGenerator().gatewayAccepted(), + gatewayAccepted(), }, }, }, @@ -1453,7 +1453,7 @@ func TestBindRoutesToGateways(t *testing.T) { }, Status: structs.Status{ Conditions: []structs.Condition{ - newGatewayConditionGenerator().routeAccepted(), + routeAccepted(), }, }, }, @@ -1493,7 +1493,6 @@ func TestBindRoutesToGateways(t *testing.T) { } func TestAPIGatewayController(t *testing.T) { - conditions := newGatewayConditionGenerator() defaultMeta := acl.DefaultEnterpriseMeta() for name, tc := range map[string]struct { requests []controller.Request @@ -1521,7 +1520,7 @@ func TestAPIGatewayController(t *testing.T) { EnterpriseMeta: *defaultMeta, Status: structs.Status{ Conditions: []structs.Condition{ - conditions.gatewayAccepted(), + gatewayAccepted(), }, }, }, @@ -1552,7 +1551,7 @@ func TestAPIGatewayController(t *testing.T) { EnterpriseMeta: *defaultMeta, Status: structs.Status{ Conditions: []structs.Condition{ - conditions.routeNoUpstreams(), + routeNoUpstreams(), }, }, }, @@ -1578,7 +1577,7 @@ func TestAPIGatewayController(t *testing.T) { EnterpriseMeta: *defaultMeta, Status: structs.Status{ Conditions: []structs.Condition{ - conditions.routeNoUpstreams(), + routeNoUpstreams(), }, }, }, @@ -1628,8 +1627,8 @@ func TestAPIGatewayController(t *testing.T) { EnterpriseMeta: *defaultMeta, Status: structs.Status{ Conditions: []structs.Condition{ - conditions.routeAccepted(), - conditions.routeUnbound(structs.ResourceReference{ + routeAccepted(), + routeUnbound(structs.ResourceReference{ Name: "api-gateway", EnterpriseMeta: *defaultMeta, }, errors.New("failed to bind route to gateway api-gateway: gateway has not been accepted")), @@ -1646,7 +1645,7 @@ func TestAPIGatewayController(t *testing.T) { }}, Status: structs.Status{ Conditions: []structs.Condition{ - conditions.gatewayListenerNoConflicts(structs.ResourceReference{ + gatewayListenerNoConflicts(structs.ResourceReference{ Kind: structs.APIGateway, Name: "api-gateway", SectionName: "listener", @@ -1694,7 +1693,7 @@ func TestAPIGatewayController(t *testing.T) { EnterpriseMeta: *defaultMeta, Status: structs.Status{ Conditions: []structs.Condition{ - conditions.routeInvalidDiscoveryChain(errInvalidProtocol), + routeInvalidDiscoveryChain(errInvalidProtocol), }, }, }, @@ -1733,8 +1732,8 @@ func TestAPIGatewayController(t *testing.T) { EnterpriseMeta: *defaultMeta, Status: structs.Status{ Conditions: []structs.Condition{ - conditions.routeAccepted(), - conditions.gatewayNotFound(structs.ResourceReference{ + routeAccepted(), + gatewayNotFound(structs.ResourceReference{ Kind: structs.APIGateway, Name: "gateway", EnterpriseMeta: *defaultMeta, @@ -1787,8 +1786,8 @@ func TestAPIGatewayController(t *testing.T) { EnterpriseMeta: *defaultMeta, Status: structs.Status{ Conditions: []structs.Condition{ - conditions.routeAccepted(), - conditions.gatewayNotFound(structs.ResourceReference{ + routeAccepted(), + gatewayNotFound(structs.ResourceReference{ Kind: structs.APIGateway, Name: "gateway", EnterpriseMeta: *defaultMeta, @@ -1851,8 +1850,8 @@ func TestAPIGatewayController(t *testing.T) { EnterpriseMeta: *defaultMeta, Status: structs.Status{ Conditions: []structs.Condition{ - conditions.routeAccepted(), - conditions.routeUnbound(structs.ResourceReference{ + routeAccepted(), + routeUnbound(structs.ResourceReference{ Kind: structs.APIGateway, Name: "gateway", EnterpriseMeta: *defaultMeta, @@ -1920,8 +1919,8 @@ func TestAPIGatewayController(t *testing.T) { EnterpriseMeta: *defaultMeta, Status: structs.Status{ Conditions: []structs.Condition{ - conditions.routeAccepted(), - conditions.gatewayNotFound(structs.ResourceReference{ + routeAccepted(), + gatewayNotFound(structs.ResourceReference{ Kind: structs.APIGateway, Name: "gateway", EnterpriseMeta: *defaultMeta, @@ -1956,7 +1955,7 @@ func TestAPIGatewayController(t *testing.T) { }}, Status: structs.Status{ Conditions: []structs.Condition{ - newGatewayConditionGenerator().routeAccepted(), + routeAccepted(), }, }, }, @@ -1976,7 +1975,7 @@ func TestAPIGatewayController(t *testing.T) { }}, Status: structs.Status{ Conditions: []structs.Condition{ - newGatewayConditionGenerator().gatewayAccepted(), + gatewayAccepted(), }, }, }, @@ -2006,8 +2005,8 @@ func TestAPIGatewayController(t *testing.T) { EnterpriseMeta: *defaultMeta, Status: structs.Status{ Conditions: []structs.Condition{ - conditions.gatewayAccepted(), - conditions.gatewayListenerNoConflicts(structs.ResourceReference{ + gatewayAccepted(), + gatewayListenerNoConflicts(structs.ResourceReference{ Kind: structs.APIGateway, Name: "gateway", EnterpriseMeta: *defaultMeta, @@ -2022,8 +2021,8 @@ func TestAPIGatewayController(t *testing.T) { EnterpriseMeta: *defaultMeta, Status: structs.Status{ Conditions: []structs.Condition{ - conditions.routeAccepted(), - conditions.routeBound(structs.ResourceReference{ + routeAccepted(), + routeBound(structs.ResourceReference{ Kind: structs.APIGateway, Name: "gateway", EnterpriseMeta: *defaultMeta, @@ -2058,7 +2057,7 @@ func TestAPIGatewayController(t *testing.T) { }}, Status: structs.Status{ Conditions: []structs.Condition{ - newGatewayConditionGenerator().routeAccepted(), + routeAccepted(), }, }, }, @@ -2098,8 +2097,8 @@ func TestAPIGatewayController(t *testing.T) { EnterpriseMeta: *defaultMeta, Status: structs.Status{ Conditions: []structs.Condition{ - conditions.gatewayAccepted(), - conditions.gatewayListenerNoConflicts(structs.ResourceReference{ + gatewayAccepted(), + gatewayListenerNoConflicts(structs.ResourceReference{ Kind: structs.APIGateway, Name: "gateway", EnterpriseMeta: *defaultMeta, @@ -2114,8 +2113,8 @@ func TestAPIGatewayController(t *testing.T) { EnterpriseMeta: *defaultMeta, Status: structs.Status{ Conditions: []structs.Condition{ - conditions.routeAccepted(), - conditions.routeUnbound(structs.ResourceReference{ + routeAccepted(), + routeUnbound(structs.ResourceReference{ Kind: structs.APIGateway, Name: "gateway", EnterpriseMeta: *defaultMeta, @@ -2154,7 +2153,7 @@ func TestAPIGatewayController(t *testing.T) { }}, Status: structs.Status{ Conditions: []structs.Condition{ - newGatewayConditionGenerator().routeAccepted(), + routeAccepted(), }, }, }, @@ -2172,7 +2171,7 @@ func TestAPIGatewayController(t *testing.T) { }}, Status: structs.Status{ Conditions: []structs.Condition{ - newGatewayConditionGenerator().routeAccepted(), + routeAccepted(), }, }, }, @@ -2221,8 +2220,8 @@ func TestAPIGatewayController(t *testing.T) { EnterpriseMeta: *defaultMeta, Status: structs.Status{ Conditions: []structs.Condition{ - conditions.gatewayAccepted(), - conditions.gatewayListenerConflicts(structs.ResourceReference{ + gatewayAccepted(), + gatewayListenerConflicts(structs.ResourceReference{ Kind: structs.APIGateway, Name: "gateway", EnterpriseMeta: *defaultMeta, @@ -2237,8 +2236,8 @@ func TestAPIGatewayController(t *testing.T) { EnterpriseMeta: *defaultMeta, Status: structs.Status{ Conditions: []structs.Condition{ - conditions.routeAccepted(), - conditions.routeBound(structs.ResourceReference{ + routeAccepted(), + routeBound(structs.ResourceReference{ Kind: structs.APIGateway, Name: "gateway", EnterpriseMeta: *defaultMeta, @@ -2252,8 +2251,8 @@ func TestAPIGatewayController(t *testing.T) { EnterpriseMeta: *defaultMeta, Status: structs.Status{ Conditions: []structs.Condition{ - conditions.routeAccepted(), - conditions.routeBound(structs.ResourceReference{ + routeAccepted(), + routeBound(structs.ResourceReference{ Kind: structs.APIGateway, Name: "gateway", EnterpriseMeta: *defaultMeta, @@ -2294,7 +2293,7 @@ func TestAPIGatewayController(t *testing.T) { }}, Status: structs.Status{ Conditions: []structs.Condition{ - newGatewayConditionGenerator().routeAccepted(), + routeAccepted(), }, }, }, @@ -2314,7 +2313,7 @@ func TestAPIGatewayController(t *testing.T) { }}, Status: structs.Status{ Conditions: []structs.Condition{ - newGatewayConditionGenerator().routeAccepted(), + routeAccepted(), }, }, }, @@ -2364,8 +2363,8 @@ func TestAPIGatewayController(t *testing.T) { EnterpriseMeta: *defaultMeta, Status: structs.Status{ Conditions: []structs.Condition{ - conditions.gatewayAccepted(), - conditions.gatewayListenerNoConflicts(structs.ResourceReference{ + gatewayAccepted(), + gatewayListenerNoConflicts(structs.ResourceReference{ Kind: structs.APIGateway, Name: "gateway", EnterpriseMeta: *defaultMeta, @@ -2380,8 +2379,8 @@ func TestAPIGatewayController(t *testing.T) { EnterpriseMeta: *defaultMeta, Status: structs.Status{ Conditions: []structs.Condition{ - conditions.routeAccepted(), - conditions.routeBound(structs.ResourceReference{ + routeAccepted(), + routeBound(structs.ResourceReference{ Kind: structs.APIGateway, Name: "gateway", EnterpriseMeta: *defaultMeta, @@ -2395,8 +2394,8 @@ func TestAPIGatewayController(t *testing.T) { EnterpriseMeta: *defaultMeta, Status: structs.Status{ Conditions: []structs.Condition{ - conditions.routeAccepted(), - conditions.routeBound(structs.ResourceReference{ + routeAccepted(), + routeBound(structs.ResourceReference{ Kind: structs.APIGateway, Name: "gateway", EnterpriseMeta: *defaultMeta, @@ -2505,8 +2504,8 @@ func TestAPIGatewayController(t *testing.T) { EnterpriseMeta: *defaultMeta, Status: structs.Status{ Conditions: []structs.Condition{ - conditions.gatewayAccepted(), - conditions.gatewayListenerNoConflicts(structs.ResourceReference{ + gatewayAccepted(), + gatewayListenerNoConflicts(structs.ResourceReference{ Kind: structs.APIGateway, Name: "gateway", EnterpriseMeta: *defaultMeta, @@ -2521,8 +2520,8 @@ func TestAPIGatewayController(t *testing.T) { EnterpriseMeta: *defaultMeta, Status: structs.Status{ Conditions: []structs.Condition{ - conditions.routeAccepted(), - conditions.routeBound(structs.ResourceReference{ + routeAccepted(), + routeBound(structs.ResourceReference{ Kind: structs.APIGateway, Name: "gateway", EnterpriseMeta: *defaultMeta, @@ -2536,8 +2535,8 @@ func TestAPIGatewayController(t *testing.T) { EnterpriseMeta: *defaultMeta, Status: structs.Status{ Conditions: []structs.Condition{ - conditions.routeAccepted(), - conditions.routeUnbound(structs.ResourceReference{ + routeAccepted(), + routeUnbound(structs.ResourceReference{ Kind: structs.APIGateway, Name: "gateway", EnterpriseMeta: *defaultMeta, @@ -2578,7 +2577,7 @@ func TestAPIGatewayController(t *testing.T) { }}, Status: structs.Status{ Conditions: []structs.Condition{ - newGatewayConditionGenerator().routeAccepted(), + routeAccepted(), }, }, }, @@ -2596,7 +2595,7 @@ func TestAPIGatewayController(t *testing.T) { }}, Status: structs.Status{ Conditions: []structs.Condition{ - newGatewayConditionGenerator().routeAccepted(), + routeAccepted(), }, }, }, @@ -2659,13 +2658,13 @@ func TestAPIGatewayController(t *testing.T) { EnterpriseMeta: *defaultMeta, Status: structs.Status{ Conditions: []structs.Condition{ - conditions.gatewayAccepted(), - conditions.gatewayListenerNoConflicts(structs.ResourceReference{ + gatewayAccepted(), + gatewayListenerNoConflicts(structs.ResourceReference{ Kind: structs.APIGateway, Name: "gateway", SectionName: "http-listener", }), - conditions.gatewayListenerNoConflicts(structs.ResourceReference{ + gatewayListenerNoConflicts(structs.ResourceReference{ Kind: structs.APIGateway, Name: "gateway", SectionName: "tcp-listener", @@ -2679,8 +2678,8 @@ func TestAPIGatewayController(t *testing.T) { EnterpriseMeta: *defaultMeta, Status: structs.Status{ Conditions: []structs.Condition{ - conditions.routeAccepted(), - conditions.routeBound(structs.ResourceReference{ + routeAccepted(), + routeBound(structs.ResourceReference{ Kind: structs.APIGateway, Name: "gateway", EnterpriseMeta: *defaultMeta, @@ -2694,8 +2693,8 @@ func TestAPIGatewayController(t *testing.T) { EnterpriseMeta: *defaultMeta, Status: structs.Status{ Conditions: []structs.Condition{ - conditions.routeAccepted(), - conditions.routeBound(structs.ResourceReference{ + routeAccepted(), + routeBound(structs.ResourceReference{ Kind: structs.APIGateway, Name: "gateway", EnterpriseMeta: *defaultMeta, @@ -2721,8 +2720,8 @@ func TestAPIGatewayController(t *testing.T) { }}, Status: structs.Status{ Conditions: []structs.Condition{ - conditions.routeAccepted(), - conditions.routeBound(structs.ResourceReference{ + routeAccepted(), + routeBound(structs.ResourceReference{ Kind: structs.APIGateway, Name: "gateway", EnterpriseMeta: *defaultMeta, @@ -2776,7 +2775,7 @@ func TestAPIGatewayController(t *testing.T) { EnterpriseMeta: *defaultMeta, Status: structs.Status{ Conditions: []structs.Condition{ - conditions.gatewayListenerNoConflicts(structs.ResourceReference{ + gatewayListenerNoConflicts(structs.ResourceReference{ Kind: structs.APIGateway, Name: "gateway", SectionName: "tcp-listener", @@ -2791,7 +2790,7 @@ func TestAPIGatewayController(t *testing.T) { EnterpriseMeta: *defaultMeta, Status: structs.Status{ Conditions: []structs.Condition{ - conditions.routeAccepted(), + routeAccepted(), }, }, }, @@ -2810,8 +2809,8 @@ func TestAPIGatewayController(t *testing.T) { EnterpriseMeta: *defaultMeta, Status: structs.Status{ Conditions: []structs.Condition{ - conditions.routeAccepted(), - conditions.routeBound(structs.ResourceReference{ + routeAccepted(), + routeBound(structs.ResourceReference{ Kind: structs.APIGateway, Name: "gateway", EnterpriseMeta: *defaultMeta, @@ -2865,7 +2864,7 @@ func TestAPIGatewayController(t *testing.T) { EnterpriseMeta: *defaultMeta, Status: structs.Status{ Conditions: []structs.Condition{ - conditions.gatewayListenerNoConflicts(structs.ResourceReference{ + gatewayListenerNoConflicts(structs.ResourceReference{ Kind: structs.APIGateway, Name: "gateway", SectionName: "tcp-listener", @@ -2880,7 +2879,7 @@ func TestAPIGatewayController(t *testing.T) { EnterpriseMeta: *defaultMeta, Status: structs.Status{ Conditions: []structs.Condition{ - conditions.routeNoUpstreams(), + routeNoUpstreams(), }, }, }, @@ -2908,8 +2907,8 @@ func TestAPIGatewayController(t *testing.T) { }}, Status: structs.Status{ Conditions: []structs.Condition{ - conditions.routeAccepted(), - conditions.routeBound(structs.ResourceReference{ + routeAccepted(), + routeBound(structs.ResourceReference{ Kind: structs.APIGateway, Name: "gateway", EnterpriseMeta: *defaultMeta, @@ -2934,8 +2933,7 @@ func TestAPIGatewayController(t *testing.T) { }}, Status: structs.Status{ Conditions: []structs.Condition{ - conditions.routeAccepted(), - conditions.routeUnbound(structs.ResourceReference{ + routeUnbound(structs.ResourceReference{ Kind: structs.APIGateway, Name: "gateway", }, errors.New("foo")), @@ -2965,8 +2963,8 @@ func TestAPIGatewayController(t *testing.T) { }}, Status: structs.Status{ Conditions: []structs.Condition{ - conditions.gatewayAccepted(), - conditions.gatewayListenerNoConflicts(structs.ResourceReference{ + gatewayAccepted(), + gatewayListenerNoConflicts(structs.ResourceReference{ Kind: structs.APIGateway, Name: "gateway", SectionName: "tcp-listener", @@ -3008,8 +3006,8 @@ func TestAPIGatewayController(t *testing.T) { EnterpriseMeta: *defaultMeta, Status: structs.Status{ Conditions: []structs.Condition{ - conditions.gatewayAccepted(), - conditions.gatewayListenerNoConflicts(structs.ResourceReference{ + gatewayAccepted(), + gatewayListenerNoConflicts(structs.ResourceReference{ Kind: structs.APIGateway, Name: "gateway", SectionName: "http-listener", @@ -3023,8 +3021,8 @@ func TestAPIGatewayController(t *testing.T) { EnterpriseMeta: *defaultMeta, Status: structs.Status{ Conditions: []structs.Condition{ - conditions.routeAccepted(), - conditions.routeUnbound(structs.ResourceReference{ + routeAccepted(), + routeUnbound(structs.ResourceReference{ Kind: structs.APIGateway, Name: "gateway", }, errors.New("failed to bind route tcp-route to gateway gateway with listener ''")), @@ -3037,8 +3035,8 @@ func TestAPIGatewayController(t *testing.T) { EnterpriseMeta: *defaultMeta, Status: structs.Status{ Conditions: []structs.Condition{ - conditions.routeAccepted(), - conditions.routeBound(structs.ResourceReference{ + routeAccepted(), + routeBound(structs.ResourceReference{ Kind: structs.APIGateway, Name: "gateway", }), @@ -3073,8 +3071,8 @@ func TestAPIGatewayController(t *testing.T) { }}, Status: structs.Status{ Conditions: []structs.Condition{ - conditions.routeAccepted(), - conditions.routeBound(structs.ResourceReference{ + routeAccepted(), + routeBound(structs.ResourceReference{ Kind: structs.APIGateway, Name: "gateway", EnterpriseMeta: *defaultMeta, @@ -3109,8 +3107,8 @@ func TestAPIGatewayController(t *testing.T) { EnterpriseMeta: *defaultMeta, Status: structs.Status{ Conditions: []structs.Condition{ - conditions.routeAccepted(), - conditions.gatewayNotFound(structs.ResourceReference{ + routeAccepted(), + gatewayNotFound(structs.ResourceReference{ Kind: structs.APIGateway, Name: "gateway", }), @@ -3150,8 +3148,8 @@ func TestAPIGatewayController(t *testing.T) { }}, Status: structs.Status{ Conditions: []structs.Condition{ - conditions.gatewayAccepted(), - conditions.gatewayListenerNoConflicts(structs.ResourceReference{ + gatewayAccepted(), + gatewayListenerNoConflicts(structs.ResourceReference{ Kind: structs.APIGateway, Name: "gateway", SectionName: "tcp-listener", @@ -3176,8 +3174,8 @@ func TestAPIGatewayController(t *testing.T) { EnterpriseMeta: *defaultMeta, Status: structs.Status{ Conditions: []structs.Condition{ - conditions.gatewayAccepted(), - conditions.gatewayListenerNoConflicts(structs.ResourceReference{ + gatewayAccepted(), + gatewayListenerNoConflicts(structs.ResourceReference{ Kind: structs.APIGateway, Name: "gateway", SectionName: "tcp-listener", @@ -3221,8 +3219,8 @@ func TestAPIGatewayController(t *testing.T) { }}, Status: structs.Status{ Conditions: []structs.Condition{ - conditions.routeAccepted(), - conditions.routeBound(structs.ResourceReference{ + routeAccepted(), + routeBound(structs.ResourceReference{ Kind: structs.APIGateway, Name: "gateway", }), @@ -3237,8 +3235,8 @@ func TestAPIGatewayController(t *testing.T) { EnterpriseMeta: *defaultMeta, Status: structs.Status{ Conditions: []structs.Condition{ - conditions.routeAccepted(), - conditions.gatewayNotFound(structs.ResourceReference{ + routeAccepted(), + gatewayNotFound(structs.ResourceReference{ Kind: structs.APIGateway, Name: "gateway", }), @@ -3287,18 +3285,12 @@ func TestAPIGatewayController(t *testing.T) { }}, Status: structs.Status{ Conditions: []structs.Condition{ - structs.NewGatewayCondition( - structs.GatewayConditionAccepted, - structs.ConditionStatusFalse, - structs.GatewayListenerReasonInvalidCertificateRef, - errors.New("certificate not found").Error(), - structs.ResourceReference{ - Kind: structs.InlineCertificate, - Name: "certificate", - }, - ), - conditions.invalidCertificates(), - conditions.gatewayListenerNoConflicts(structs.ResourceReference{ + invalidCertificate(structs.ResourceReference{ + Kind: structs.InlineCertificate, + Name: "certificate", + }, errors.New("certificate not found")), + invalidCertificates(), + gatewayListenerNoConflicts(structs.ResourceReference{ Kind: structs.APIGateway, Name: "gateway", SectionName: "http-listener", @@ -3361,8 +3353,8 @@ func TestAPIGatewayController(t *testing.T) { }}, Status: structs.Status{ Conditions: []structs.Condition{ - conditions.gatewayAccepted(), - conditions.gatewayListenerNoConflicts(structs.ResourceReference{ + gatewayAccepted(), + gatewayListenerNoConflicts(structs.ResourceReference{ Kind: structs.APIGateway, Name: "gateway", SectionName: "http-listener", @@ -3408,12 +3400,12 @@ func TestAPIGatewayController(t *testing.T) { }}, Status: structs.Status{ Conditions: []structs.Condition{ - conditions.invalidCertificate(structs.ResourceReference{ + invalidCertificate(structs.ResourceReference{ Kind: structs.InlineCertificate, Name: "certificate", }, errors.New("certificate not found")), - conditions.invalidCertificates(), - conditions.gatewayListenerNoConflicts(structs.ResourceReference{ + invalidCertificates(), + gatewayListenerNoConflicts(structs.ResourceReference{ Kind: structs.APIGateway, Name: "gateway", SectionName: "http-listener", @@ -3444,8 +3436,8 @@ func TestAPIGatewayController(t *testing.T) { }}, Status: structs.Status{ Conditions: []structs.Condition{ - conditions.gatewayAccepted(), - conditions.gatewayListenerNoConflicts(structs.ResourceReference{ + gatewayAccepted(), + gatewayListenerNoConflicts(structs.ResourceReference{ Kind: structs.APIGateway, Name: "gateway", SectionName: "http-listener", @@ -3711,12 +3703,15 @@ func (n *noopController) WithWorkers(i int) controller.Controller func (n *noopController) WithQueueFactory(fn func(ctx context.Context, baseBackoff time.Duration, maxBackoff time.Duration) controller.WorkQueue) controller.Controller { return n } + func (n *noopController) AddTrigger(request controller.Request, trigger func(ctx context.Context) error) { n.triggers[request] = struct{}{} } + func (n *noopController) RemoveTrigger(request controller.Request) { delete(n.triggers, request) } + func (n *noopController) Enqueue(requests ...controller.Request) { n.enqueued = append(n.enqueued, requests...) } diff --git a/agent/structs/config_entry_status.go b/agent/structs/config_entry_status.go index f4475b2b9b7..b4ac76e2288 100644 --- a/agent/structs/config_entry_status.go +++ b/agent/structs/config_entry_status.go @@ -220,6 +220,7 @@ type GatewayConditionType string // particular Gateway condition type has been raised. type GatewayConditionReason string +// the following are directly from the k8s spec const ( // This condition is true when the controller managing the Gateway is // syntactically and semantically valid enough to produce some configuration @@ -361,6 +362,14 @@ const ( GatewayListenerReasonRefNotPermitted GatewayConditionReason = "RefNotPermitted" ) +// these are custom to Consul +const ( + GatewayConditionConflicted GatewayConditionType = "Conflicted" + + GatewayReasonNoConflicts GatewayConditionReason = "NoConflicts" + GatewayReasonRouteConflict GatewayConditionReason = "RouteConflict" +) + var validGatewayConditionReasonsMapping = map[GatewayConditionType]map[ConditionStatus][]GatewayConditionReason{ GatewayConditionAccepted: { ConditionStatusTrue: { @@ -373,6 +382,15 @@ var validGatewayConditionReasonsMapping = map[GatewayConditionType]map[Condition GatewayReasonPending, }, }, + GatewayConditionConflicted: { + ConditionStatusTrue: { + GatewayReasonRouteConflict, + }, + ConditionStatusFalse: { + GatewayReasonNoConflicts, + }, + ConditionStatusUnknown: {}, + }, GatewayConditionListenersConfigured: { ConditionStatusTrue: { GatewayReasonListenersConfigured, From 8a8662b0f8d56b92d25793e6076f74881a17796a Mon Sep 17 00:00:00 2001 From: jm96441n Date: Thu, 13 Apr 2023 13:12:55 -0400 Subject: [PATCH 07/24] put back removed status for test --- agent/consul/gateways/controller_gateways_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/agent/consul/gateways/controller_gateways_test.go b/agent/consul/gateways/controller_gateways_test.go index ce818578d9f..2b304989e48 100644 --- a/agent/consul/gateways/controller_gateways_test.go +++ b/agent/consul/gateways/controller_gateways_test.go @@ -2933,6 +2933,7 @@ func TestAPIGatewayController(t *testing.T) { }}, Status: structs.Status{ Conditions: []structs.Condition{ + routeAccepted(), routeUnbound(structs.ResourceReference{ Kind: structs.APIGateway, Name: "gateway", From 886498634e8e8b29cfa49e787ae84d44686a609b Mon Sep 17 00:00:00 2001 From: jm96441n Date: Thu, 13 Apr 2023 13:51:12 -0400 Subject: [PATCH 08/24] Fix linting violation, remove custom conflicted status --- agent/consul/gateways/controller_gateways.go | 12 ++++++------ agent/structs/config_entry_status.go | 19 +------------------ 2 files changed, 7 insertions(+), 24 deletions(-) diff --git a/agent/consul/gateways/controller_gateways.go b/agent/consul/gateways/controller_gateways.go index fe2478f85c9..eb20b0b728e 100644 --- a/agent/consul/gateways/controller_gateways.go +++ b/agent/consul/gateways/controller_gateways.go @@ -868,9 +868,9 @@ func invalidCertificates() structs.Condition { // bound routes func gatewayListenerNoConflicts(ref structs.ResourceReference) structs.Condition { return structs.NewGatewayCondition( - structs.GatewayConditionConflicted, - structs.ConditionStatusFalse, - structs.GatewayReasonNoConflicts, + structs.GatewayConditionListenersConfigured, + structs.ConditionStatusTrue, + structs.GatewayReasonListenersConfigured, "listener has no route conflicts", ref, ) @@ -880,9 +880,9 @@ func gatewayListenerNoConflicts(ref structs.ResourceReference) structs.Condition // and make the listener, therefore invalid func gatewayListenerConflicts(ref structs.ResourceReference) structs.Condition { return structs.NewGatewayCondition( - structs.GatewayConditionConflicted, - structs.ConditionStatusTrue, - structs.GatewayReasonRouteConflict, + structs.GatewayConditionListenersConfigured, + structs.ConditionStatusFalse, + structs.GatewayListenerReasonProtocolConflict, "TCP-based listeners currently only support binding a single route", ref, ) diff --git a/agent/structs/config_entry_status.go b/agent/structs/config_entry_status.go index b4ac76e2288..a03fcfcc852 100644 --- a/agent/structs/config_entry_status.go +++ b/agent/structs/config_entry_status.go @@ -155,7 +155,7 @@ func (c *Condition) IsCondition(other *Condition) bool { func (c *Condition) IsSame(other *Condition) bool { return c.IsCondition(other) && - c.Type == c.Type && + c.Type == other.Type && c.Status == other.Status && c.Reason == other.Reason && c.Message == other.Message @@ -362,14 +362,6 @@ const ( GatewayListenerReasonRefNotPermitted GatewayConditionReason = "RefNotPermitted" ) -// these are custom to Consul -const ( - GatewayConditionConflicted GatewayConditionType = "Conflicted" - - GatewayReasonNoConflicts GatewayConditionReason = "NoConflicts" - GatewayReasonRouteConflict GatewayConditionReason = "RouteConflict" -) - var validGatewayConditionReasonsMapping = map[GatewayConditionType]map[ConditionStatus][]GatewayConditionReason{ GatewayConditionAccepted: { ConditionStatusTrue: { @@ -382,15 +374,6 @@ var validGatewayConditionReasonsMapping = map[GatewayConditionType]map[Condition GatewayReasonPending, }, }, - GatewayConditionConflicted: { - ConditionStatusTrue: { - GatewayReasonRouteConflict, - }, - ConditionStatusFalse: { - GatewayReasonNoConflicts, - }, - ConditionStatusUnknown: {}, - }, GatewayConditionListenersConfigured: { ConditionStatusTrue: { GatewayReasonListenersConfigured, From 01a39fb019d99fa7ee509342eac0b5998fd2fa4b Mon Sep 17 00:00:00 2001 From: jm96441n Date: Thu, 13 Apr 2023 14:06:18 -0400 Subject: [PATCH 09/24] Update fsm commands oss --- agent/consul/fsm/commands_oss_test.go | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/agent/consul/fsm/commands_oss_test.go b/agent/consul/fsm/commands_oss_test.go index 981de232a6b..89f8bdebb3f 100644 --- a/agent/consul/fsm/commands_oss_test.go +++ b/agent/consul/fsm/commands_oss_test.go @@ -13,11 +13,6 @@ import ( "testing" "time" - "github.com/hashicorp/go-raftchunking" - raftchunkingtypes "github.com/hashicorp/go-raftchunking/types" - "github.com/hashicorp/go-uuid" - "github.com/hashicorp/raft" - "github.com/hashicorp/serf/coordinate" "github.com/mitchellh/mapstructure" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -34,6 +29,11 @@ import ( "github.com/hashicorp/consul/proto/private/prototest" "github.com/hashicorp/consul/sdk/testutil" "github.com/hashicorp/consul/types" + "github.com/hashicorp/go-raftchunking" + raftchunkingtypes "github.com/hashicorp/go-raftchunking/types" + "github.com/hashicorp/go-uuid" + "github.com/hashicorp/raft" + "github.com/hashicorp/serf/coordinate" ) func generateUUID() (ret string) { @@ -1372,9 +1372,10 @@ func TestFSM_ConfigEntry_StatusCAS(t *testing.T) { EnterpriseMeta: *structs.DefaultEnterpriseMetaInDefaultPartition(), Status: structs.Status{ Conditions: []structs.Condition{{ - Status: "Foo", + Status: structs.ConditionStatusTrue, }}, - }} + }, + } // Create a new request. req := &structs.ConfigEntryRequest{ @@ -1403,7 +1404,7 @@ func TestFSM_ConfigEntry_StatusCAS(t *testing.T) { // do a status update entry.Status = structs.Status{ Conditions: []structs.Condition{{ - Status: "Foo", + Status: structs.ConditionStatusTrue, }}, } req = &structs.ConfigEntryRequest{ @@ -1427,7 +1428,7 @@ func TestFSM_ConfigEntry_StatusCAS(t *testing.T) { entry.RaftIndex.ModifyIndex = 2 conditions := config.(*structs.APIGatewayConfigEntry).Status.Conditions require.Len(t, conditions, 1) - require.Equal(t, "Foo", conditions[0].Status) + require.Equal(t, structs.ConditionStatusTrue, conditions[0].Status) } // attempt to change the status with a regular update and make sure it's ignored @@ -1456,7 +1457,7 @@ func TestFSM_ConfigEntry_StatusCAS(t *testing.T) { require.NoError(t, err) conditions := config.(*structs.APIGatewayConfigEntry).Status.Conditions require.Len(t, conditions, 1) - require.Equal(t, "Foo", conditions[0].Status) + require.Equal(t, structs.ConditionStatusTrue, conditions[0].Status) } } From b9f369aa701ed0aaf26fa45e3812f3426c5a03c2 Mon Sep 17 00:00:00 2001 From: jm96441n Date: Thu, 13 Apr 2023 14:11:48 -0400 Subject: [PATCH 10/24] Fix incorrect combination of type/condition/status --- agent/structs/config_entry_status_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/agent/structs/config_entry_status_test.go b/agent/structs/config_entry_status_test.go index 5d2824641eb..c254756f981 100644 --- a/agent/structs/config_entry_status_test.go +++ b/agent/structs/config_entry_status_test.go @@ -24,8 +24,8 @@ func TestNewGatewayConditionWithValidCombinations(t *testing.T) { message: "no bueno", ref: ResourceReference{Name: "name", Kind: "httproute"}, }, - "accepted false gateway reason pending": { - status: ConditionStatusFalse, + "accepted unknown gateway reason pending": { + status: ConditionStatusUnknown, reason: GatewayReasonPending, condType: GatewayConditionAccepted, message: "pending", From 1b6a5b68d78f4b94cf5212e266ca8dff3931fa5d Mon Sep 17 00:00:00 2001 From: jm96441n Date: Thu, 13 Apr 2023 16:38:26 -0400 Subject: [PATCH 11/24] cleaning up from PR review --- agent/consul/gateways/controller_gateways.go | 14 +- agent/structs/config_entry_status.go | 216 ++----------------- agent/structs/config_entry_status_test.go | 161 +------------- 3 files changed, 40 insertions(+), 351 deletions(-) diff --git a/agent/consul/gateways/controller_gateways.go b/agent/consul/gateways/controller_gateways.go index eb20b0b728e..fcf5d0feb88 100644 --- a/agent/consul/gateways/controller_gateways.go +++ b/agent/consul/gateways/controller_gateways.go @@ -868,9 +868,9 @@ func invalidCertificates() structs.Condition { // bound routes func gatewayListenerNoConflicts(ref structs.ResourceReference) structs.Condition { return structs.NewGatewayCondition( - structs.GatewayConditionListenersConfigured, - structs.ConditionStatusTrue, - structs.GatewayReasonListenersConfigured, + structs.GatewayConditionConflicted, + structs.ConditionStatusFalse, + structs.GatewayReasonNoConflicts, "listener has no route conflicts", ref, ) @@ -880,9 +880,9 @@ func gatewayListenerNoConflicts(ref structs.ResourceReference) structs.Condition // and make the listener, therefore invalid func gatewayListenerConflicts(ref structs.ResourceReference) structs.Condition { return structs.NewGatewayCondition( - structs.GatewayConditionListenersConfigured, - structs.ConditionStatusFalse, - structs.GatewayListenerReasonProtocolConflict, + structs.GatewayConditionConflicted, + structs.ConditionStatusTrue, + structs.GatewayReasonRouteConflicted, "TCP-based listeners currently only support binding a single route", ref, ) @@ -950,7 +950,7 @@ func routeNoUpstreams() structs.Condition { return structs.NewRouteCondition( structs.RouteConditionAccepted, structs.ConditionStatusFalse, - structs.RouteReasonInvalidDiscoveryChain, + structs.RouteReasonNoUpstreamServicesTargeted, "route must target at least one upstream service", structs.ResourceReference{}, ) diff --git a/agent/structs/config_entry_status.go b/agent/structs/config_entry_status.go index a03fcfcc852..60b7fff958c 100644 --- a/agent/structs/config_entry_status.go +++ b/agent/structs/config_entry_status.go @@ -155,7 +155,6 @@ func (c *Condition) IsCondition(other *Condition) bool { func (c *Condition) IsSame(other *Condition) bool { return c.IsCondition(other) && - c.Type == other.Type && c.Status == other.Status && c.Reason == other.Reason && c.Message == other.Message @@ -231,91 +230,35 @@ const ( // // * "Accepted" // - // Possible reasons for this condition to be False are: - // - // * "Invalid" - // - // Possible reasons for this condition to be Unknown are: - // - // * "Pending" - // GatewayConditionAccepted GatewayConditionType = "Accepted" // This reason is used with the "Accepted" condition when the condition is // True. GatewayReasonAccepted GatewayConditionReason = "Accepted" - // This reason is used with the "Accepted" condition when the Gateway is - // syntactically or semantically invalid. - GatewayReasonInvalid GatewayConditionReason = "Invalid" - - // This reason is used with the "Accepted" and "ListenersConfigured" - // conditions when the status is "Unknown" and no controller has reconciled - // the Gateway. - GatewayReasonPending GatewayConditionReason = "Pending" - // This condition indicates that the controller was able to resolve - // all specification requirements for all Gateway Listeners. If a Listener is - // conflicted, its network port should not be configured on any network - // elements. Even if a Listener is syntactically and semantically valid, - // the controller may not able to configure it on the underlying Gateway - // infrastructure. When setting this condition to False, a ResourceReference to - // the misconfigured Listener should be provided. - + // This condition indicates that the gateway was unable to resolve + // conflicting specification requirements for this Listener. If a + // Listener is conflicted, its network port should not be configured + // on any network elements. // - // Possible reasons for this condition to be True are: + // Possible reasons for this condition to be true are: // - // * "ListenersConfigured" + // * "RouteConflict" // // Possible reasons for this condition to be False are: // - // * "ListenerHostnameConflict" - // * "ListenerProtocolConflict" - // * "ListenerPortUnavailable" - // * "ListenerUnsupportedProtocol" - // * "ListenerUnsupportedAddress" - // - // Possible reasons for this condition to be Unknown are: - // - // * "Pending" - // - GatewayConditionListenersConfigured GatewayConditionType = "ListenersConfigured" - - // This reason is used with the "ListenersConfigured" condition when the - // condition is True. - GatewayReasonListenersConfigured GatewayConditionReason = "ListenersConfigured" - - // This reason is used with the "ListenersConfigured" condition when - // the Listener conflicts with hostnames in other Listeners. For - // example, this reason would be used when multiple Listeners on - // the same port use `example.com` in the hostname field. - GatewayListenerReasonHostnameConflict GatewayConditionReason = "ListenerHostnameConflict" - - // This reason is used with the "ListenersConfigured" condition when - // multiple Listeners are specified with the same Listener port - // number, but have conflicting protocol specifications. - GatewayListenerReasonProtocolConflict GatewayConditionReason = "ListenerProtocolConflict" - - // This reason is used with the "ListenersConfigured" condition when the Listener - // requests a port that cannot be used on the Gateway. This reason could be - // used in a number of instances, including: + // * "NoConflicts" // - // * The port is already in use. - // * The port is not supported by the implementation. - GatewayListenerReasonPortUnavailable GatewayConditionReason = "ListenerPortUnavailable" - - // This reason is used with the "ListenersConfigured" condition when the - // Listener could not be attached to be Gateway because its - // protocol type is not supported. - GatewayListenerReasonUnsupportedProtocol GatewayConditionReason = "ListenerUnsupportedProtocol" - - // This reason is used with the "ListenersConfigured" condition when a - // Listener could not be attached to the Gateway because the requested address - // is not supported. This reason could be used in a number of instances, - // including: - // - // * The address is already in use. - // * The type of address is not supported by the implementation. - GatewayListenerReasonUnsupportedAddress GatewayConditionReason = "ListenerUnsupportedAddress" + // Controllers may raise this condition with other reasons, + // but should prefer to use the reasons listed above to improve + // interoperability. + GatewayConditionConflicted GatewayConditionType = "Conflicted" + // This reason is used with the "Conflicted" condition when the condition + // is False. + GatewayReasonNoConflicts GatewayConditionReason = "NoConflicts" + // This reason is used with the "Conflicted" condition when the route is + // in a conflicted state, such as when a TCPListener attempts to bind to two routes + GatewayReasonRouteConflicted GatewayConditionReason = "RouteConflicted" // This condition indicates whether the controller was able to // resolve all the object references for the Gateway. When setting this @@ -350,16 +293,6 @@ const ( // If the reference is not allowed, the reason RefNotPermitted must be used // instead. GatewayListenerReasonInvalidCertificateRef GatewayConditionReason = "InvalidCertificateRef" - - // This reason is used with the "ResolvedRefs" condition when an invalid or - // unsupported Route kind is specified by a Listener. - GatewayListenerReasonInvalidRouteKinds GatewayConditionReason = "InvalidRouteKinds" - - // This reason is used with the "ResolvedRefs" condition when a - // Listener has a TLS configuration that references an object in another - // namespace, where the object in the other namespace does not have a - // ReferenceGrant explicitly allowing the reference. - GatewayListenerReasonRefNotPermitted GatewayConditionReason = "RefNotPermitted" ) var validGatewayConditionReasonsMapping = map[GatewayConditionType]map[ConditionStatus][]GatewayConditionReason{ @@ -367,27 +300,17 @@ var validGatewayConditionReasonsMapping = map[GatewayConditionType]map[Condition ConditionStatusTrue: { GatewayReasonAccepted, }, - ConditionStatusFalse: { - GatewayReasonInvalid, - }, - ConditionStatusUnknown: { - GatewayReasonPending, - }, + ConditionStatusFalse: {}, + ConditionStatusUnknown: {}, }, - GatewayConditionListenersConfigured: { + GatewayConditionConflicted: { ConditionStatusTrue: { - GatewayReasonListenersConfigured, + GatewayReasonRouteConflicted, }, ConditionStatusFalse: { - GatewayListenerReasonHostnameConflict, - GatewayListenerReasonProtocolConflict, - GatewayListenerReasonPortUnavailable, - GatewayListenerReasonUnsupportedProtocol, - GatewayListenerReasonUnsupportedAddress, - }, - ConditionStatusUnknown: { - GatewayReasonPending, + GatewayReasonNoConflicts, }, + ConditionStatusUnknown: {}, }, GatewayConditionResolvedRefs: { ConditionStatusTrue: { @@ -395,8 +318,6 @@ var validGatewayConditionReasonsMapping = map[GatewayConditionType]map[Condition }, ConditionStatusFalse: { GatewayListenerReasonInvalidCertificateRef, - GatewayListenerReasonInvalidRouteKinds, - GatewayListenerReasonRefNotPermitted, }, ConditionStatusUnknown: {}, }, @@ -458,17 +379,9 @@ const ( // // Possible reasons for this condition to be False are: // - // * "NotAllowedByListeners" - // * "NoMatchingListenerHostname" - // * "NoMatchingParent" - // * "UnsupportedValue" - // * "ParentRefNotPermitted" // * "InvalidDiscoveryChain" // * "NoUpstreamServicesTargeted" // - // Possible reasons for this condition to be Unknown are: - // - // * "Pending" // // Controllers may raise this condition with other reasons, // but should prefer to use the reasons listed above to improve @@ -479,34 +392,6 @@ const ( // accepted by the Gateway. RouteReasonAccepted RouteConditionReason = "Accepted" - // This reason is used with the "Accepted" condition when the route has not - // been accepted by a Gateway because the Gateway has no Listener whose - // allowedRoutes criteria permit the route - RouteReasonNotAllowedByListeners RouteConditionReason = "NotAllowedByListeners" - - // This reason is used with the "Accepted" condition when the Gateway has no - // compatible Listeners whose Hostname matches the route - RouteReasonNoMatchingListenerHostname RouteConditionReason = "NoMatchingListenerHostname" - - // This reason is used with the "Accepted" condition when there are - // no matching Parents. In the case of Gateways, this can occur when - // a Route ParentRef specifies a Port and/or SectionName that does not - // match any Listeners in the Gateway. - RouteReasonNoMatchingParent RouteConditionReason = "NoMatchingParent" - - // This reason is used with the "Accepted" condition when a value for an Enum - // is not recognized. - RouteReasonUnsupportedValue RouteConditionReason = "UnsupportedValue" - - // This reason is used with the "Accepted" condition when the route has not - // been accepted by a Gateway because it has a cross-namespace parentRef, - // but no ReferenceGrant in the other namespace allows such a reference. - RouteReasonParentRefNotPermitted RouteConditionReason = "ParentRefNotPermitted" - - // This reason is used with the "Accepted" when a controller has not yet - // reconciled the route. - RouteReasonPending RouteConditionReason = "Pending" - // This reason is used with the "Accepted" condition when the route has an // invalid discovery chain, this includes conditions like the protocol being invalid // or the discovery chain failing to compile @@ -514,43 +399,6 @@ const ( // This reason is used with the "Accepted" condition when the route RouteReasonNoUpstreamServicesTargeted RouteConditionReason = "NoUpstreamServicesTargeted" - - // This condition indicates whether the controller was able to resolve all - // the object references for the Route. - // - // Possible reasons for this condition to be true are: - // - // * "ResolvedRefs" - // - // Possible reasons for this condition to be false are: - // - // * "RefNotPermitted" - // * "InvalidKind" - // * "BackendNotFound" - // - // Controllers may raise this condition with other reasons, - // but should prefer to use the reasons listed above to improve - // interoperability. - RouteConditionResolvedRefs RouteConditionType = "ResolvedRefs" - - // This reason is used with the "ResolvedRefs" condition when the condition - // is true. - RouteReasonResolvedRefs RouteConditionReason = "ResolvedRefs" - - // This reason is used with the "ResolvedRefs" condition when - // one of the Listener's Routes has a BackendRef to an object in - // another namespace, where the object in the other namespace does - // not have a ReferenceGrant explicitly allowing the reference. - RouteReasonRefNotPermitted RouteConditionReason = "RefNotPermitted" - - // This reason is used with the "ResolvedRefs" condition when - // one of the Route's rules has a reference to an unknown or unsupported - // Group and/or Kind. - RouteReasonInvalidKind RouteConditionReason = "InvalidKind" - - // This reason is used with the "ResolvedRefs" condition when one of the - // Route's rules has a reference to a resource that does not exist. - RouteReasonBackendNotFound RouteConditionReason = "BackendNotFound" ) // the following statuses are custom to Consul @@ -605,27 +453,9 @@ var validRouteConditionReasonsMapping = map[RouteConditionType]map[ConditionStat RouteReasonAccepted, }, ConditionStatusFalse: { - RouteReasonNotAllowedByListeners, - RouteReasonNoMatchingListenerHostname, - RouteReasonNoMatchingParent, - RouteReasonUnsupportedValue, - RouteReasonParentRefNotPermitted, RouteReasonInvalidDiscoveryChain, RouteReasonNoUpstreamServicesTargeted, }, - ConditionStatusUnknown: { - RouteReasonPending, - }, - }, - RouteConditionResolvedRefs: { - ConditionStatusTrue: { - RouteReasonResolvedRefs, - }, - ConditionStatusFalse: { - RouteReasonRefNotPermitted, - RouteReasonInvalidKind, - RouteReasonBackendNotFound, - }, ConditionStatusUnknown: {}, }, RouteConditionBound: { diff --git a/agent/structs/config_entry_status_test.go b/agent/structs/config_entry_status_test.go index c254756f981..f4b899dd985 100644 --- a/agent/structs/config_entry_status_test.go +++ b/agent/structs/config_entry_status_test.go @@ -17,63 +17,6 @@ func TestNewGatewayConditionWithValidCombinations(t *testing.T) { message: "it's all good", ref: ResourceReference{Name: "name", Kind: "httproute"}, }, - "accepted false gateway reason invalid": { - status: ConditionStatusFalse, - reason: GatewayReasonInvalid, - condType: GatewayConditionAccepted, - message: "no bueno", - ref: ResourceReference{Name: "name", Kind: "httproute"}, - }, - "accepted unknown gateway reason pending": { - status: ConditionStatusUnknown, - reason: GatewayReasonPending, - condType: GatewayConditionAccepted, - message: "pending", - ref: ResourceReference{Name: "name", Kind: "httproute"}, - }, - "listener configured true": { - status: ConditionStatusTrue, - reason: GatewayReasonListenersConfigured, - condType: GatewayConditionListenersConfigured, - message: "listeners configured", - ref: ResourceReference{Name: "name", Kind: "httproute"}, - }, - "listener configured hostname conflict": { - status: ConditionStatusFalse, - reason: GatewayListenerReasonHostnameConflict, - condType: GatewayConditionListenersConfigured, - message: "conflict", - ref: ResourceReference{Name: "name", Kind: "httproute"}, - }, - "listener configured port unvailable": { - status: ConditionStatusFalse, - reason: GatewayListenerReasonPortUnavailable, - condType: GatewayConditionListenersConfigured, - message: "no port", - ref: ResourceReference{Name: "name", Kind: "httproute"}, - }, - - "listener configured unsupported protocol": { - status: ConditionStatusFalse, - reason: GatewayListenerReasonUnsupportedProtocol, - condType: GatewayConditionListenersConfigured, - message: "unsupported procotol", - ref: ResourceReference{Name: "name", Kind: "httproute"}, - }, - "listener configured unsupported address": { - status: ConditionStatusFalse, - reason: GatewayListenerReasonUnsupportedAddress, - condType: GatewayConditionListenersConfigured, - message: "unsupported address", - ref: ResourceReference{Name: "name", Kind: "httproute"}, - }, - "listener configured status unknown": { - status: ConditionStatusUnknown, - reason: GatewayReasonPending, - condType: GatewayConditionListenersConfigured, - message: "unknown", - ref: ResourceReference{Name: "name", Kind: "httproute"}, - }, "resolved refs": { status: ConditionStatusTrue, reason: GatewayReasonResolvedRefs, @@ -88,20 +31,6 @@ func TestNewGatewayConditionWithValidCombinations(t *testing.T) { message: "invalid certificate", ref: ResourceReference{Name: "name", Kind: "httproute"}, }, - "resolved refs invalid route kinds": { - status: ConditionStatusFalse, - reason: GatewayListenerReasonInvalidRouteKinds, - condType: GatewayConditionResolvedRefs, - message: "invalid route kinds", - ref: ResourceReference{Name: "name", Kind: "httproute"}, - }, - "resolved refs ref not permitted": { - status: ConditionStatusFalse, - reason: GatewayListenerReasonRefNotPermitted, - condType: GatewayConditionResolvedRefs, - message: "not permitted", - ref: ResourceReference{Name: "name", Kind: "httproute"}, - }, } for name, tc := range testCases { @@ -132,35 +61,35 @@ func TestNewGatewayInvalidCombinationsCausePanic(t *testing.T) { }{ "reason and condition type are valid but status is not": { status: ConditionStatusTrue, - reason: GatewayReasonInvalid, - condType: GatewayConditionAccepted, + reason: GatewayReasonNoConflicts, + condType: GatewayConditionConflicted, message: "almost there", ref: ResourceReference{Name: "name", Kind: "httproute"}, }, "reason and status are valid but condition type is not": { status: ConditionStatusFalse, - reason: GatewayListenerReasonHostnameConflict, + reason: GatewayReasonNoConflicts, condType: GatewayConditionResolvedRefs, message: "not quite", ref: ResourceReference{Name: "name", Kind: "httproute"}, }, "condition type and status are valid but status is not": { - status: ConditionStatusUnknown, - reason: GatewayReasonInvalid, + status: ConditionStatusTrue, + reason: GatewayReasonNoConflicts, condType: GatewayConditionAccepted, message: "still not working", ref: ResourceReference{Name: "name", Kind: "httproute"}, }, "all are invalid": { status: ConditionStatusUnknown, - reason: GatewayReasonInvalid, + reason: GatewayReasonAccepted, condType: GatewayConditionResolvedRefs, message: "still not working", ref: ResourceReference{Name: "name", Kind: "httproute"}, }, "pass something other than a condition status": { status: ConditionStatus("hello"), - reason: GatewayReasonInvalid, + reason: GatewayReasonAccepted, condType: GatewayConditionResolvedRefs, message: "still not working", ref: ResourceReference{Name: "name", Kind: "httproute"}, @@ -194,41 +123,6 @@ func TestNewRouteConditionWithValidCombinations(t *testing.T) { message: "it's all good", ref: ResourceReference{Name: "name", Kind: "httproute"}, }, - "accepted not allowed by listeners": { - status: ConditionStatusFalse, - reason: RouteReasonNotAllowedByListeners, - condType: RouteConditionAccepted, - message: "not allowed by listeners", - ref: ResourceReference{Name: "name", Kind: "httproute"}, - }, - "accepted no matching hostname": { - status: ConditionStatusFalse, - reason: RouteReasonNoMatchingListenerHostname, - condType: RouteConditionAccepted, - message: "no matching listener hostname", - ref: ResourceReference{Name: "name", Kind: "httproute"}, - }, - "accepted no matching parent": { - status: ConditionStatusFalse, - reason: RouteReasonNoMatchingParent, - condType: RouteConditionAccepted, - message: "no matching parent", - ref: ResourceReference{Name: "name", Kind: "httproute"}, - }, - "accepted unsupported value": { - status: ConditionStatusFalse, - reason: RouteReasonUnsupportedValue, - condType: RouteConditionAccepted, - message: "unsupported value", - ref: ResourceReference{Name: "name", Kind: "httproute"}, - }, - "accepted parent ref not permitted": { - status: ConditionStatusFalse, - reason: RouteReasonParentRefNotPermitted, - condType: RouteConditionAccepted, - message: "parent ref not permitted", - ref: ResourceReference{Name: "name", Kind: "httproute"}, - }, "accepted invalid discovery chain": { status: ConditionStatusFalse, reason: RouteReasonInvalidDiscoveryChain, @@ -243,41 +137,6 @@ func TestNewRouteConditionWithValidCombinations(t *testing.T) { message: "no upstreams", ref: ResourceReference{Name: "name", Kind: "httproute"}, }, - "accepted pending": { - status: ConditionStatusUnknown, - reason: RouteReasonPending, - condType: RouteConditionAccepted, - message: "pending", - ref: ResourceReference{Name: "name", Kind: "httproute"}, - }, - "resolved refs": { - status: ConditionStatusTrue, - reason: RouteReasonResolvedRefs, - condType: RouteConditionResolvedRefs, - message: "resolved refs", - ref: ResourceReference{Name: "name", Kind: "httproute"}, - }, - "resolved refs not permitted": { - status: ConditionStatusFalse, - reason: RouteReasonRefNotPermitted, - condType: RouteConditionResolvedRefs, - message: "not permitted", - ref: ResourceReference{Name: "name", Kind: "httproute"}, - }, - "resolved refs invalid kind": { - status: ConditionStatusFalse, - reason: RouteReasonInvalidKind, - condType: RouteConditionResolvedRefs, - message: "invalid kind", - ref: ResourceReference{Name: "name", Kind: "httproute"}, - }, - "resolved refs bakend not found": { - status: ConditionStatusFalse, - reason: RouteReasonBackendNotFound, - condType: RouteConditionResolvedRefs, - message: "backend not found", - ref: ResourceReference{Name: "name", Kind: "httproute"}, - }, "route bound": { status: ConditionStatusTrue, reason: RouteReasonBound, @@ -328,14 +187,14 @@ func TestNewRouteInvalidCombinationsCausePanic(t *testing.T) { }{ "reason and condition type are valid but status is not": { status: ConditionStatusTrue, - reason: RouteReasonNotAllowedByListeners, + reason: RouteReasonNoUpstreamServicesTargeted, condType: RouteConditionAccepted, message: "almost there", ref: ResourceReference{Name: "name", Kind: "httproute"}, }, "reason and status are valid but condition type is not": { status: ConditionStatusFalse, - reason: RouteReasonRefNotPermitted, + reason: RouteReasonInvalidDiscoveryChain, condType: RouteConditionBound, message: "not quite", ref: ResourceReference{Name: "name", Kind: "httproute"}, @@ -350,7 +209,7 @@ func TestNewRouteInvalidCombinationsCausePanic(t *testing.T) { "all are invalid": { status: ConditionStatusUnknown, reason: RouteReasonGatewayNotFound, - condType: RouteConditionResolvedRefs, + condType: RouteConditionBound, message: "still not working", ref: ResourceReference{Name: "name", Kind: "httproute"}, }, From 7129105402873227be3c59978644a04e03de5249 Mon Sep 17 00:00:00 2001 From: jm96441n Date: Mon, 17 Apr 2023 12:58:28 -0400 Subject: [PATCH 12/24] Change "invalidCertificate" to be of accepted status --- agent/consul/gateways/controller_gateways.go | 4 ++-- agent/structs/config_entry_status.go | 12 +++++++++++- agent/structs/config_entry_status_test.go | 10 +++++++++- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/agent/consul/gateways/controller_gateways.go b/agent/consul/gateways/controller_gateways.go index fcf5d0feb88..80e17ce9d27 100644 --- a/agent/consul/gateways/controller_gateways.go +++ b/agent/consul/gateways/controller_gateways.go @@ -856,9 +856,9 @@ func invalidCertificate(ref structs.ResourceReference, err error) structs.Condit // to invalid due to missing certificates that it references. func invalidCertificates() structs.Condition { return structs.NewGatewayCondition( - structs.GatewayConditionResolvedRefs, + structs.GatewayConditionAccepted, structs.ConditionStatusFalse, - structs.GatewayListenerReasonInvalidCertificateRef, + structs.GatewayReasonInvalidCertificates, "gateway references invalid certificates", structs.ResourceReference{}, ) diff --git a/agent/structs/config_entry_status.go b/agent/structs/config_entry_status.go index 60b7fff958c..a93b7a03b94 100644 --- a/agent/structs/config_entry_status.go +++ b/agent/structs/config_entry_status.go @@ -230,12 +230,20 @@ const ( // // * "Accepted" // + // Possible reasons for this condition to be False are: + // + // * InvalidCertificates + // GatewayConditionAccepted GatewayConditionType = "Accepted" // This reason is used with the "Accepted" condition when the condition is // True. GatewayReasonAccepted GatewayConditionReason = "Accepted" + // This reason is used with the "Accepted" condition when the gateway has multiple invalid + // certificates and cannot bind to any routes + GatewayReasonInvalidCertificates GatewayConditionReason = "InvalidCertificates" + // This condition indicates that the gateway was unable to resolve // conflicting specification requirements for this Listener. If a // Listener is conflicted, its network port should not be configured @@ -300,7 +308,9 @@ var validGatewayConditionReasonsMapping = map[GatewayConditionType]map[Condition ConditionStatusTrue: { GatewayReasonAccepted, }, - ConditionStatusFalse: {}, + ConditionStatusFalse: { + GatewayReasonInvalidCertificates, + }, ConditionStatusUnknown: {}, }, GatewayConditionConflicted: { diff --git a/agent/structs/config_entry_status_test.go b/agent/structs/config_entry_status_test.go index f4b899dd985..aa7a94f676a 100644 --- a/agent/structs/config_entry_status_test.go +++ b/agent/structs/config_entry_status_test.go @@ -10,13 +10,21 @@ func TestNewGatewayConditionWithValidCombinations(t *testing.T) { message string ref ResourceReference }{ - "accepted all around": { + "accepted": { status: ConditionStatusTrue, reason: GatewayReasonAccepted, condType: GatewayConditionAccepted, message: "it's all good", ref: ResourceReference{Name: "name", Kind: "httproute"}, }, + "accepted invalid certificates": { + status: ConditionStatusFalse, + reason: GatewayReasonInvalidCertificates, + condType: GatewayConditionAccepted, + message: "invalid certificates", + ref: ResourceReference{Name: "name", Kind: "httproute"}, + }, + "resolved refs": { status: ConditionStatusTrue, reason: GatewayReasonResolvedRefs, From c6f1615d7ce042ee8e1791f9d289db96db1c8426 Mon Sep 17 00:00:00 2001 From: jm96441n Date: Tue, 18 Apr 2023 11:37:32 -0400 Subject: [PATCH 13/24] Move status condition enums into api package --- agent/structs/config_entry_status.go | 294 +----------------- api/config_entry_status.go | 281 ++++++++++++++++- .../config_entry_status_test.go | 104 ++----- api/go.mod | 6 +- api/go.sum | 12 +- go.mod | 4 +- go.sum | 8 +- 7 files changed, 322 insertions(+), 387 deletions(-) rename {agent/structs => api}/config_entry_status_test.go (54%) diff --git a/agent/structs/config_entry_status.go b/agent/structs/config_entry_status.go index a93b7a03b94..fb91a0add37 100644 --- a/agent/structs/config_entry_status.go +++ b/agent/structs/config_entry_status.go @@ -8,9 +8,8 @@ import ( "sort" "time" - "golang.org/x/exp/slices" - "github.com/hashicorp/consul/acl" + "github.com/hashicorp/consul/api" ) // ResourceReference is a reference to a ConfigEntry @@ -117,17 +116,6 @@ func lessResource(one, two *ResourceReference) bool { return one.SectionName < two.SectionName } -type ( - ConditionStatus string - ConditionReason string -) - -const ( - ConditionStatusTrue ConditionStatus = "True" - ConditionStatusFalse ConditionStatus = "False" - ConditionStatusUnknown ConditionStatus = "Unknown" -) - // Condition is used for a single message and state associated // with an object. For example, a ConfigEntry that references // multiple other resources may have different statuses with @@ -136,7 +124,7 @@ type Condition struct { // Type is a value from a bounded set of types that an object might have Type string // Status is a value from a bounded set of statuses that an object might have - Status ConditionStatus + Status string // Reason is a value from a bounded set of reasons for a given status Reason string // Message is a message that gives more detailed information about @@ -210,131 +198,8 @@ func (u *StatusUpdater) UpdateEntry() (ControlledConfigEntry, bool) { return u.entry, true } -// GatewayConditionType is a type of condition associated with a -// Gateway. This type should be used with the GatewayStatus.Conditions -// field. -type GatewayConditionType string - -// GatewayConditionReason defines the set of reasons that explain why a -// particular Gateway condition type has been raised. -type GatewayConditionReason string - -// the following are directly from the k8s spec -const ( - // This condition is true when the controller managing the Gateway is - // syntactically and semantically valid enough to produce some configuration - // in the underlying data plane. This does not indicate whether or not the - // configuration has been propagated to the data plane. - // - // Possible reasons for this condition to be True are: - // - // * "Accepted" - // - // Possible reasons for this condition to be False are: - // - // * InvalidCertificates - // - GatewayConditionAccepted GatewayConditionType = "Accepted" - - // This reason is used with the "Accepted" condition when the condition is - // True. - GatewayReasonAccepted GatewayConditionReason = "Accepted" - - // This reason is used with the "Accepted" condition when the gateway has multiple invalid - // certificates and cannot bind to any routes - GatewayReasonInvalidCertificates GatewayConditionReason = "InvalidCertificates" - - // This condition indicates that the gateway was unable to resolve - // conflicting specification requirements for this Listener. If a - // Listener is conflicted, its network port should not be configured - // on any network elements. - // - // Possible reasons for this condition to be true are: - // - // * "RouteConflict" - // - // Possible reasons for this condition to be False are: - // - // * "NoConflicts" - // - // Controllers may raise this condition with other reasons, - // but should prefer to use the reasons listed above to improve - // interoperability. - GatewayConditionConflicted GatewayConditionType = "Conflicted" - // This reason is used with the "Conflicted" condition when the condition - // is False. - GatewayReasonNoConflicts GatewayConditionReason = "NoConflicts" - // This reason is used with the "Conflicted" condition when the route is - // in a conflicted state, such as when a TCPListener attempts to bind to two routes - GatewayReasonRouteConflicted GatewayConditionReason = "RouteConflicted" - - // This condition indicates whether the controller was able to - // resolve all the object references for the Gateway. When setting this - // condition to False, a ResourceReference to the misconfigured Listener should - // be provided. - // - // Possible reasons for this condition to be true are: - // - // * "ResolvedRefs" - // - // Possible reasons for this condition to be False are: - // - // * "InvalidCertificateRef" - // * "InvalidRouteKinds" - // * "RefNotPermitted" - // - GatewayConditionResolvedRefs GatewayConditionType = "ResolvedRefs" - - // This reason is used with the "ResolvedRefs" condition when the condition - // is true. - GatewayReasonResolvedRefs GatewayConditionReason = "ResolvedRefs" - - // This reason is used with the "ResolvedRefs" condition when a - // Listener has a TLS configuration with at least one TLS CertificateRef - // that is invalid or does not exist. - // A CertificateRef is considered invalid when it refers to a nonexistent - // or unsupported resource or kind, or when the data within that resource - // is malformed. - // This reason must be used only when the reference is allowed, either by - // referencing an object in the same namespace as the Gateway, or when - // a cross-namespace reference has been explicitly allowed by a ReferenceGrant. - // If the reference is not allowed, the reason RefNotPermitted must be used - // instead. - GatewayListenerReasonInvalidCertificateRef GatewayConditionReason = "InvalidCertificateRef" -) - -var validGatewayConditionReasonsMapping = map[GatewayConditionType]map[ConditionStatus][]GatewayConditionReason{ - GatewayConditionAccepted: { - ConditionStatusTrue: { - GatewayReasonAccepted, - }, - ConditionStatusFalse: { - GatewayReasonInvalidCertificates, - }, - ConditionStatusUnknown: {}, - }, - GatewayConditionConflicted: { - ConditionStatusTrue: { - GatewayReasonRouteConflicted, - }, - ConditionStatusFalse: { - GatewayReasonNoConflicts, - }, - ConditionStatusUnknown: {}, - }, - GatewayConditionResolvedRefs: { - ConditionStatusTrue: { - GatewayReasonResolvedRefs, - }, - ConditionStatusFalse: { - GatewayListenerReasonInvalidCertificateRef, - }, - ConditionStatusUnknown: {}, - }, -} - -func NewGatewayCondition(name GatewayConditionType, status ConditionStatus, reason GatewayConditionReason, message string, resource ResourceReference) Condition { - if err := validateGatewayConfigReason(name, status, reason); err != nil { +func NewGatewayCondition(name api.GatewayConditionType, status api.ConditionStatus, reason api.GatewayConditionReason, message string, resource ResourceReference) Condition { + if err := api.ValidateGatewayConditionReason(name, status, reason); err != nil { // note we panic here because an invalid combination is a programmer error // this should never actually be hit panic(err) @@ -342,7 +207,7 @@ func NewGatewayCondition(name GatewayConditionType, status ConditionStatus, reas return Condition{ Type: string(name), - Status: status, + Status: string(status), Reason: string(reason), Message: message, Resource: ptrTo(resource), @@ -350,98 +215,9 @@ func NewGatewayCondition(name GatewayConditionType, status ConditionStatus, reas } } -func validateGatewayConfigReason(name GatewayConditionType, status ConditionStatus, reason GatewayConditionReason) error { - if err := checkConditionStatus(status); err != nil { - return err - } - - reasons, ok := validGatewayConditionReasonsMapping[name] - if !ok { - return fmt.Errorf("unrecognized GatewayConditionType %q", name) - } - - reasonsForStatus, ok := reasons[status] - if !ok { - return fmt.Errorf("unrecognized ConditionStatus %q", status) - } - - if !slices.Contains(reasonsForStatus, reason) { - return fmt.Errorf("gateway condition reason %q not allowed for gateway condition type %q with status %q", reason, name, status) - } - return nil -} - -// RouteConditionType is a type of condition for a route. -type RouteConditionType string - -// RouteConditionReason is a reason for a route condition. -type RouteConditionReason string - -// The following statuses are taken from the K8's Spec -// With the exception of: "RouteReasonInvalidDiscoveryChain" and "NoUpstreamServicesTargeted" -const ( - // This condition indicates whether the route has been accepted or rejected - // by a Gateway, and why. - // - // Possible reasons for this condition to be true are: - // - // * "Accepted" - // - // Possible reasons for this condition to be False are: - // - // * "InvalidDiscoveryChain" - // * "NoUpstreamServicesTargeted" - // - // - // Controllers may raise this condition with other reasons, - // but should prefer to use the reasons listed above to improve - // interoperability. - RouteConditionAccepted RouteConditionType = "Accepted" - - // This reason is used with the "Accepted" condition when the Route has been - // accepted by the Gateway. - RouteReasonAccepted RouteConditionReason = "Accepted" - - // This reason is used with the "Accepted" condition when the route has an - // invalid discovery chain, this includes conditions like the protocol being invalid - // or the discovery chain failing to compile - RouteReasonInvalidDiscoveryChain RouteConditionReason = "InvalidDiscoveryChain" - - // This reason is used with the "Accepted" condition when the route - RouteReasonNoUpstreamServicesTargeted RouteConditionReason = "NoUpstreamServicesTargeted" -) - -// the following statuses are custom to Consul -const ( - // This condition indicates whether the route was able to successfully bind the - // Listener on the gateway - // Possible reasons for this condition to be true are: - // - // * "Bound" - // - // Possible reasons for this condition to be false are: - // - // * "FailedToBind" - // * "GatewayNotFound" - // - RouteConditionBound RouteConditionType = "Bound" - - // This reason is used with the "Bound" condition when the condition - // is true - RouteReasonBound RouteConditionReason = "Bound" - - // This reason is used with the "Bound" condition when the route failed - // to bind to the gateway - RouteReasonFailedToBind RouteConditionReason = "FailedToBind" - - // This reason is used with the "Bound" condition when the route fails - // to find the gateway - RouteReasonGatewayNotFound RouteConditionReason = "GatewayNotFound" -) - // NewRouteCondition is a helper to build allowable Conditions for a Route config entry -func NewRouteCondition(name RouteConditionType, status ConditionStatus, reason RouteConditionReason, message string, ref ResourceReference) Condition { - if err := checkRouteConditionReason(name, status, reason); err != nil { +func NewRouteCondition(name api.RouteConditionType, status api.ConditionStatus, reason api.RouteConditionReason, message string, ref ResourceReference) Condition { + if err := api.ValidateRouteConditionReason(name, status, reason); err != nil { // note we panic here because an invalid combination is a programmer error // this should never actually be hit panic(err) @@ -449,7 +225,7 @@ func NewRouteCondition(name RouteConditionType, status ConditionStatus, reason R return Condition{ Type: string(name), - Status: status, + Status: string(status), Reason: string(reason), Message: message, Resource: ptrTo(ref), @@ -457,60 +233,6 @@ func NewRouteCondition(name RouteConditionType, status ConditionStatus, reason R } } -var validRouteConditionReasonsMapping = map[RouteConditionType]map[ConditionStatus][]RouteConditionReason{ - RouteConditionAccepted: { - ConditionStatusTrue: { - RouteReasonAccepted, - }, - ConditionStatusFalse: { - RouteReasonInvalidDiscoveryChain, - RouteReasonNoUpstreamServicesTargeted, - }, - ConditionStatusUnknown: {}, - }, - RouteConditionBound: { - ConditionStatusTrue: { - RouteReasonBound, - }, - ConditionStatusFalse: { - RouteReasonGatewayNotFound, - RouteReasonFailedToBind, - }, - ConditionStatusUnknown: {}, - }, -} - -func checkRouteConditionReason(name RouteConditionType, status ConditionStatus, reason RouteConditionReason) error { - if err := checkConditionStatus(status); err != nil { - return err - } - - reasons, ok := validRouteConditionReasonsMapping[name] - if !ok { - return fmt.Errorf("unrecognized RouteConditionType %s", name) - } - - reasonsForStatus, ok := reasons[status] - if !ok { - return fmt.Errorf("unrecognized ConditionStatus %s", name) - } - - if !slices.Contains(reasonsForStatus, reason) { - return fmt.Errorf("route condition reason %s not allowed for route condition type %s with status %s", reason, name, status) - } - - return nil -} - -func checkConditionStatus(status ConditionStatus) error { - switch status { - case ConditionStatusTrue, ConditionStatusFalse, ConditionStatusUnknown: - return nil - default: - return fmt.Errorf("unrecognized condition status: %q", status) - } -} - func ptrTo[T any](val T) *T { return &val } diff --git a/api/config_entry_status.go b/api/config_entry_status.go index 45197dcc6a5..d87029538f7 100644 --- a/api/config_entry_status.go +++ b/api/config_entry_status.go @@ -4,7 +4,10 @@ package api import ( + "fmt" "time" + + "golang.org/x/exp/slices" ) // ResourceReference is a reference to a ConfigEntry @@ -46,7 +49,7 @@ type Condition struct { // Type is a value from a bounded set of types that an object might have Type string // Status is a value from a bounded set of statuses that an object might have - Status string + Status ConditionStatus // Reason is a value from a bounded set of reasons for a given status Reason string // Message is a message that gives more detailed information about @@ -58,3 +61,279 @@ type Condition struct { // LastTransitionTime is the time at which this Condition was created LastTransitionTime *time.Time } + +type ( + ConditionStatus string +) + +const ( + ConditionStatusTrue ConditionStatus = "True" + ConditionStatusFalse ConditionStatus = "False" + ConditionStatusUnknown ConditionStatus = "Unknown" +) + +// GatewayConditionType is a type of condition associated with a +// Gateway. This type should be used with the GatewayStatus.Conditions +// field. +type GatewayConditionType string + +// GatewayConditionReason defines the set of reasons that explain why a +// particular Gateway condition type has been raised. +type GatewayConditionReason string + +// the following are directly from the k8s spec +const ( + // This condition is true when the controller managing the Gateway is + // syntactically and semantically valid enough to produce some configuration + // in the underlying data plane. This does not indicate whether or not the + // configuration has been propagated to the data plane. + // + // Possible reasons for this condition to be True are: + // + // * "Accepted" + // + // Possible reasons for this condition to be False are: + // + // * InvalidCertificates + // + GatewayConditionAccepted GatewayConditionType = "Accepted" + + // This reason is used with the "Accepted" condition when the condition is + // True. + GatewayReasonAccepted GatewayConditionReason = "Accepted" + + // This reason is used with the "Accepted" condition when the gateway has multiple invalid + // certificates and cannot bind to any routes + GatewayReasonInvalidCertificates GatewayConditionReason = "InvalidCertificates" + + // This condition indicates that the gateway was unable to resolve + // conflicting specification requirements for this Listener. If a + // Listener is conflicted, its network port should not be configured + // on any network elements. + // + // Possible reasons for this condition to be true are: + // + // * "RouteConflict" + // + // Possible reasons for this condition to be False are: + // + // * "NoConflicts" + // + // Controllers may raise this condition with other reasons, + // but should prefer to use the reasons listed above to improve + // interoperability. + GatewayConditionConflicted GatewayConditionType = "Conflicted" + // This reason is used with the "Conflicted" condition when the condition + // is False. + GatewayReasonNoConflicts GatewayConditionReason = "NoConflicts" + // This reason is used with the "Conflicted" condition when the route is + // in a conflicted state, such as when a TCPListener attempts to bind to two routes + GatewayReasonRouteConflicted GatewayConditionReason = "RouteConflicted" + + // This condition indicates whether the controller was able to + // resolve all the object references for the Gateway. When setting this + // condition to False, a ResourceReference to the misconfigured Listener should + // be provided. + // + // Possible reasons for this condition to be true are: + // + // * "ResolvedRefs" + // + // Possible reasons for this condition to be False are: + // + // * "InvalidCertificateRef" + // * "InvalidRouteKinds" + // * "RefNotPermitted" + // + GatewayConditionResolvedRefs GatewayConditionType = "ResolvedRefs" + + // This reason is used with the "ResolvedRefs" condition when the condition + // is true. + GatewayReasonResolvedRefs GatewayConditionReason = "ResolvedRefs" + + // This reason is used with the "ResolvedRefs" condition when a + // Listener has a TLS configuration with at least one TLS CertificateRef + // that is invalid or does not exist. + // A CertificateRef is considered invalid when it refers to a nonexistent + // or unsupported resource or kind, or when the data within that resource + // is malformed. + // This reason must be used only when the reference is allowed, either by + // referencing an object in the same namespace as the Gateway, or when + // a cross-namespace reference has been explicitly allowed by a ReferenceGrant. + // If the reference is not allowed, the reason RefNotPermitted must be used + // instead. + GatewayListenerReasonInvalidCertificateRef GatewayConditionReason = "InvalidCertificateRef" +) + +var validGatewayConditionReasonsMapping = map[GatewayConditionType]map[ConditionStatus][]GatewayConditionReason{ + GatewayConditionAccepted: { + ConditionStatusTrue: { + GatewayReasonAccepted, + }, + ConditionStatusFalse: { + GatewayReasonInvalidCertificates, + }, + ConditionStatusUnknown: {}, + }, + GatewayConditionConflicted: { + ConditionStatusTrue: { + GatewayReasonRouteConflicted, + }, + ConditionStatusFalse: { + GatewayReasonNoConflicts, + }, + ConditionStatusUnknown: {}, + }, + GatewayConditionResolvedRefs: { + ConditionStatusTrue: { + GatewayReasonResolvedRefs, + }, + ConditionStatusFalse: { + GatewayListenerReasonInvalidCertificateRef, + }, + ConditionStatusUnknown: {}, + }, +} + +func ValidateGatewayConditionReason(name GatewayConditionType, status ConditionStatus, reason GatewayConditionReason) error { + if err := checkConditionStatus(status); err != nil { + return err + } + + reasons, ok := validGatewayConditionReasonsMapping[name] + if !ok { + return fmt.Errorf("unrecognized GatewayConditionType %q", name) + } + + reasonsForStatus, ok := reasons[status] + if !ok { + return fmt.Errorf("unrecognized ConditionStatus %q", status) + } + + if !slices.Contains(reasonsForStatus, reason) { + return fmt.Errorf("gateway condition reason %q not allowed for gateway condition type %q with status %q", reason, name, status) + } + return nil +} + +// RouteConditionType is a type of condition for a route. +type RouteConditionType string + +// RouteConditionReason is a reason for a route condition. +type RouteConditionReason string + +// The following statuses are taken from the K8's Spec +// With the exception of: "RouteReasonInvalidDiscoveryChain" and "NoUpstreamServicesTargeted" +const ( + // This condition indicates whether the route has been accepted or rejected + // by a Gateway, and why. + // + // Possible reasons for this condition to be true are: + // + // * "Accepted" + // + // Possible reasons for this condition to be False are: + // + // * "InvalidDiscoveryChain" + // * "NoUpstreamServicesTargeted" + // + // + // Controllers may raise this condition with other reasons, + // but should prefer to use the reasons listed above to improve + // interoperability. + RouteConditionAccepted RouteConditionType = "Accepted" + + // This reason is used with the "Accepted" condition when the Route has been + // accepted by the Gateway. + RouteReasonAccepted RouteConditionReason = "Accepted" + + // This reason is used with the "Accepted" condition when the route has an + // invalid discovery chain, this includes conditions like the protocol being invalid + // or the discovery chain failing to compile + RouteReasonInvalidDiscoveryChain RouteConditionReason = "InvalidDiscoveryChain" + + // This reason is used with the "Accepted" condition when the route + RouteReasonNoUpstreamServicesTargeted RouteConditionReason = "NoUpstreamServicesTargeted" +) + +// the following statuses are custom to Consul +const ( + // This condition indicates whether the route was able to successfully bind the + // Listener on the gateway + // Possible reasons for this condition to be true are: + // + // * "Bound" + // + // Possible reasons for this condition to be false are: + // + // * "FailedToBind" + // * "GatewayNotFound" + // + RouteConditionBound RouteConditionType = "Bound" + + // This reason is used with the "Bound" condition when the condition + // is true + RouteReasonBound RouteConditionReason = "Bound" + + // This reason is used with the "Bound" condition when the route failed + // to bind to the gateway + RouteReasonFailedToBind RouteConditionReason = "FailedToBind" + + // This reason is used with the "Bound" condition when the route fails + // to find the gateway + RouteReasonGatewayNotFound RouteConditionReason = "GatewayNotFound" +) + +var validRouteConditionReasonsMapping = map[RouteConditionType]map[ConditionStatus][]RouteConditionReason{ + RouteConditionAccepted: { + ConditionStatusTrue: { + RouteReasonAccepted, + }, + ConditionStatusFalse: { + RouteReasonInvalidDiscoveryChain, + RouteReasonNoUpstreamServicesTargeted, + }, + ConditionStatusUnknown: {}, + }, + RouteConditionBound: { + ConditionStatusTrue: { + RouteReasonBound, + }, + ConditionStatusFalse: { + RouteReasonGatewayNotFound, + RouteReasonFailedToBind, + }, + ConditionStatusUnknown: {}, + }, +} + +func ValidateRouteConditionReason(name RouteConditionType, status ConditionStatus, reason RouteConditionReason) error { + if err := checkConditionStatus(status); err != nil { + return err + } + + reasons, ok := validRouteConditionReasonsMapping[name] + if !ok { + return fmt.Errorf("unrecognized RouteConditionType %s", name) + } + + reasonsForStatus, ok := reasons[status] + if !ok { + return fmt.Errorf("unrecognized ConditionStatus %s", name) + } + + if !slices.Contains(reasonsForStatus, reason) { + return fmt.Errorf("route condition reason %s not allowed for route condition type %s with status %s", reason, name, status) + } + + return nil +} + +func checkConditionStatus(status ConditionStatus) error { + switch status { + case ConditionStatusTrue, ConditionStatusFalse, ConditionStatusUnknown: + return nil + default: + return fmt.Errorf("unrecognized condition status: %q", status) + } +} diff --git a/agent/structs/config_entry_status_test.go b/api/config_entry_status_test.go similarity index 54% rename from agent/structs/config_entry_status_test.go rename to api/config_entry_status_test.go index aa7a94f676a..6fc4c9052ce 100644 --- a/agent/structs/config_entry_status_test.go +++ b/api/config_entry_status_test.go @@ -1,243 +1,177 @@ -package structs +package api import "testing" -func TestNewGatewayConditionWithValidCombinations(t *testing.T) { +func TestValidateGatewayConditionReasonWithValidCombinations(t *testing.T) { testCases := map[string]struct { status ConditionStatus reason GatewayConditionReason condType GatewayConditionType - message string - ref ResourceReference }{ "accepted": { status: ConditionStatusTrue, reason: GatewayReasonAccepted, condType: GatewayConditionAccepted, - message: "it's all good", - ref: ResourceReference{Name: "name", Kind: "httproute"}, }, "accepted invalid certificates": { status: ConditionStatusFalse, reason: GatewayReasonInvalidCertificates, condType: GatewayConditionAccepted, - message: "invalid certificates", - ref: ResourceReference{Name: "name", Kind: "httproute"}, }, "resolved refs": { status: ConditionStatusTrue, reason: GatewayReasonResolvedRefs, condType: GatewayConditionResolvedRefs, - message: "resolved refs", - ref: ResourceReference{Name: "name", Kind: "httproute"}, }, "resolved refs invalid certificate ref": { status: ConditionStatusFalse, reason: GatewayListenerReasonInvalidCertificateRef, condType: GatewayConditionResolvedRefs, - message: "invalid certificate", - ref: ResourceReference{Name: "name", Kind: "httproute"}, }, } for name, tc := range testCases { t.Run(name, func(t *testing.T) { - cond := NewGatewayCondition(tc.condType, tc.status, tc.reason, tc.message, tc.ref) - expectedCond := Condition{ - Type: string(tc.condType), - Status: tc.status, - Reason: string(tc.reason), - Message: tc.message, - Resource: &tc.ref, - } - if !cond.IsSame(&expectedCond) { - t.Errorf("Expected condition to be\n%+v\ngot\n%+v", expectedCond, cond) + err := ValidateGatewayConditionReason(tc.condType, tc.status, tc.reason) + if err != nil { + t.Error("Expected gateway condition reason to be valid but it was not") } }) } } -func TestNewGatewayInvalidCombinationsCausePanic(t *testing.T) { +func TestValidateGatewayConditionReasonWithInvalidCombinationsReturnsError(t *testing.T) { // This is not an exhaustive list of all invalid combinations, just a few to confirm testCases := map[string]struct { status ConditionStatus reason GatewayConditionReason condType GatewayConditionType - message string - ref ResourceReference }{ "reason and condition type are valid but status is not": { status: ConditionStatusTrue, reason: GatewayReasonNoConflicts, condType: GatewayConditionConflicted, - message: "almost there", - ref: ResourceReference{Name: "name", Kind: "httproute"}, }, "reason and status are valid but condition type is not": { status: ConditionStatusFalse, reason: GatewayReasonNoConflicts, condType: GatewayConditionResolvedRefs, - message: "not quite", - ref: ResourceReference{Name: "name", Kind: "httproute"}, }, "condition type and status are valid but status is not": { status: ConditionStatusTrue, reason: GatewayReasonNoConflicts, condType: GatewayConditionAccepted, - message: "still not working", - ref: ResourceReference{Name: "name", Kind: "httproute"}, }, "all are invalid": { status: ConditionStatusUnknown, reason: GatewayReasonAccepted, condType: GatewayConditionResolvedRefs, - message: "still not working", - ref: ResourceReference{Name: "name", Kind: "httproute"}, }, "pass something other than a condition status": { status: ConditionStatus("hello"), reason: GatewayReasonAccepted, condType: GatewayConditionResolvedRefs, - message: "still not working", - ref: ResourceReference{Name: "name", Kind: "httproute"}, }, } for name, tc := range testCases { t.Run(name, func(t *testing.T) { - defer func() { - if r := recover(); r == nil { - t.Errorf("Expected combination %+v to be invalid", tc) - } - }() - _ = NewGatewayCondition(tc.condType, tc.status, tc.reason, tc.message, tc.ref) + err := ValidateGatewayConditionReason(tc.condType, tc.status, tc.reason) + if err == nil { + t.Error("Expected route condition reason to be invalid, but it was valid") + } }) } } -func TestNewRouteConditionWithValidCombinations(t *testing.T) { +func TestValidateRouteConfigReasonWithValidCombinations(t *testing.T) { testCases := map[string]struct { status ConditionStatus reason RouteConditionReason condType RouteConditionType - message string - ref ResourceReference }{ "accepted all around": { status: ConditionStatusTrue, reason: RouteReasonAccepted, condType: RouteConditionAccepted, - message: "it's all good", - ref: ResourceReference{Name: "name", Kind: "httproute"}, }, "accepted invalid discovery chain": { status: ConditionStatusFalse, reason: RouteReasonInvalidDiscoveryChain, condType: RouteConditionAccepted, - message: "invalid discovery chain", - ref: ResourceReference{Name: "name", Kind: "httproute"}, }, "accepted no upstream services targeted": { status: ConditionStatusFalse, reason: RouteReasonNoUpstreamServicesTargeted, condType: RouteConditionAccepted, - message: "no upstreams", - ref: ResourceReference{Name: "name", Kind: "httproute"}, }, "route bound": { status: ConditionStatusTrue, reason: RouteReasonBound, condType: RouteConditionBound, - message: "bound", - ref: ResourceReference{Name: "name", Kind: "httproute"}, }, "route bound gateway not found": { status: ConditionStatusFalse, reason: RouteReasonGatewayNotFound, condType: RouteConditionBound, - message: "gateway not found", - ref: ResourceReference{Name: "name", Kind: "httproute"}, }, "route bound failed to bind": { status: ConditionStatusFalse, reason: RouteReasonFailedToBind, condType: RouteConditionBound, - message: "failed to bind", - ref: ResourceReference{Name: "name", Kind: "httproute"}, }, } for name, tc := range testCases { t.Run(name, func(t *testing.T) { - cond := NewRouteCondition(tc.condType, tc.status, tc.reason, tc.message, tc.ref) - expectedCond := Condition{ - Type: string(tc.condType), - Status: tc.status, - Reason: string(tc.reason), - Message: tc.message, - Resource: &tc.ref, - } - if !cond.IsSame(&expectedCond) { - t.Errorf("Expected condition to be\n%+v\ngot\n%+v", expectedCond, cond) + err := ValidateRouteConditionReason(tc.condType, tc.status, tc.reason) + if err != nil { + t.Errorf("Expected route condition reason to be valid, it was not") } }) } } -func TestNewRouteInvalidCombinationsCausePanic(t *testing.T) { +func TestValidateRouteConditionReasonInvalidCombinationsCausePanic(t *testing.T) { // This is not an exhaustive list of all invalid combinations, just a few to confirm testCases := map[string]struct { status ConditionStatus reason RouteConditionReason condType RouteConditionType - message string - ref ResourceReference }{ "reason and condition type are valid but status is not": { status: ConditionStatusTrue, reason: RouteReasonNoUpstreamServicesTargeted, condType: RouteConditionAccepted, - message: "almost there", - ref: ResourceReference{Name: "name", Kind: "httproute"}, }, "reason and status are valid but condition type is not": { status: ConditionStatusFalse, reason: RouteReasonInvalidDiscoveryChain, condType: RouteConditionBound, - message: "not quite", - ref: ResourceReference{Name: "name", Kind: "httproute"}, }, "condition type and status are valid but status is not": { status: ConditionStatusUnknown, reason: RouteReasonBound, condType: RouteConditionBound, - message: "still not working", - ref: ResourceReference{Name: "name", Kind: "httproute"}, }, "all are invalid": { status: ConditionStatusUnknown, reason: RouteReasonGatewayNotFound, condType: RouteConditionBound, - message: "still not working", - ref: ResourceReference{Name: "name", Kind: "httproute"}, }, "pass something other than a condition status": { status: ConditionStatus("hello"), reason: RouteReasonAccepted, condType: RouteConditionAccepted, - message: "still not working", - ref: ResourceReference{Name: "name", Kind: "httproute"}, }, } for name, tc := range testCases { t.Run(name, func(t *testing.T) { - defer func() { - if r := recover(); r == nil { - t.Errorf("Expected combination %+v to be invalid", tc) - } - }() - _ = NewRouteCondition(tc.condType, tc.status, tc.reason, tc.message, tc.ref) + err := ValidateRouteConditionReason(tc.condType, tc.status, tc.reason) + if err == nil { + t.Error("Expected route condition reason to be invalid, it was valid") + } }) } } diff --git a/api/go.mod b/api/go.mod index e53e4908c43..bd9b2c6780f 100644 --- a/api/go.mod +++ b/api/go.mod @@ -5,7 +5,7 @@ go 1.19 replace github.com/hashicorp/consul/sdk => ../sdk require ( - github.com/google/go-cmp v0.5.7 + github.com/google/go-cmp v0.5.8 github.com/hashicorp/consul/sdk v0.13.1 github.com/hashicorp/go-cleanhttp v0.5.1 github.com/hashicorp/go-hclog v0.12.0 @@ -14,6 +14,7 @@ require ( github.com/hashicorp/serf v0.10.1 github.com/mitchellh/mapstructure v1.4.1 github.com/stretchr/testify v1.7.0 + golang.org/x/exp v0.0.0-20230321023759-10a507213a29 ) require ( @@ -40,7 +41,6 @@ require ( github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 // indirect github.com/stretchr/objx v0.1.0 // indirect golang.org/x/net v0.0.0-20211216030914-fe4d6282115f // indirect - golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 // indirect - golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect + golang.org/x/sys v0.1.0 // indirect gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect ) diff --git a/api/go.sum b/api/go.sum index 043db4cd1ef..8e56a6b16f4 100644 --- a/api/go.sum +++ b/api/go.sum @@ -13,8 +13,8 @@ github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c h1:964Od4U6p2jUkFxvCydnIczKteheJEzHRToSGK3Bnlw= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= -github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM= @@ -96,6 +96,8 @@ github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5Cc github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= +golang.org/x/exp v0.0.0-20230321023759-10a507213a29 h1:ooxPy7fPvB4kwsA2h+iBNHkAbp/4JxTSwCmvdjEYmug= +golang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -118,8 +120,9 @@ golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 h1:WIoqL4EROvwiPdUtaip4VcDdpZ4kha7wBWZrbVKCIZg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= @@ -128,9 +131,6 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/go.mod b/go.mod index 6b3eba11a65..8558647f454 100644 --- a/go.mod +++ b/go.mod @@ -98,7 +98,6 @@ require ( go.uber.org/goleak v1.1.10 golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d golang.org/x/net v0.7.0 - golang.org/x/exp v0.0.0-20220827204233-334a2380cb91 golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1 golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 golang.org/x/sys v0.5.0 @@ -228,10 +227,11 @@ require ( go.opencensus.io v0.23.0 // indirect go.opentelemetry.io/proto/otlp v0.7.0 // indirect go.uber.org/atomic v1.9.0 // indirect + golang.org/x/exp v0.0.0-20230321023759-10a507213a29 // indirect golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 // indirect golang.org/x/term v0.5.0 // indirect golang.org/x/text v0.7.0 // indirect - golang.org/x/tools v0.1.12 // indirect + golang.org/x/tools v0.2.0 // indirect google.golang.org/api v0.57.0 // indirect google.golang.org/appengine v1.6.7 // indirect gopkg.in/inf.v0 v0.9.1 // indirect diff --git a/go.sum b/go.sum index 7c42a6f141c..b4f8bdb16fb 100644 --- a/go.sum +++ b/go.sum @@ -1115,8 +1115,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20220827204233-334a2380cb91 h1:tnebWN09GYg9OLPss1KXj8txwZc6X6uMr6VFdcGNbHw= -golang.org/x/exp v0.0.0-20220827204233-334a2380cb91/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= +golang.org/x/exp v0.0.0-20230321023759-10a507213a29 h1:ooxPy7fPvB4kwsA2h+iBNHkAbp/4JxTSwCmvdjEYmug= +golang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -1426,8 +1426,8 @@ golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.2.0 h1:G6AHpWxTMGY1KyEYoAQ5WTtIekUUvDNjan3ugu60JvE= +golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= From fa978fdc29a7c5fe708dac2be185925b001248bf Mon Sep 17 00:00:00 2001 From: jm96441n Date: Tue, 18 Apr 2023 11:59:10 -0400 Subject: [PATCH 14/24] Update gateways controller and generated code --- agent/consul/gateways/controller_gateways.go | 67 ++++++++++--------- .../private/pbconfigentry/config_entry.gen.go | 4 +- proto/private/pbconfigentry/config_entry.go | 17 ----- .../private/pbconfigentry/config_entry.pb.go | 3 +- .../private/pbconfigentry/config_entry.proto | 1 - 5 files changed, 37 insertions(+), 55 deletions(-) diff --git a/agent/consul/gateways/controller_gateways.go b/agent/consul/gateways/controller_gateways.go index 80e17ce9d27..c3e03d130ae 100644 --- a/agent/consul/gateways/controller_gateways.go +++ b/agent/consul/gateways/controller_gateways.go @@ -19,6 +19,7 @@ import ( "github.com/hashicorp/consul/agent/consul/state" "github.com/hashicorp/consul/agent/consul/stream" "github.com/hashicorp/consul/agent/structs" + "github.com/hashicorp/consul/api" ) var ( @@ -831,9 +832,9 @@ func newGatewayMeta(gateway *structs.APIGatewayConfigEntry, bound structs.Config // gatewayAccepted marks the APIGateway as valid. func gatewayAccepted() structs.Condition { return structs.NewGatewayCondition( - structs.GatewayConditionAccepted, - structs.ConditionStatusTrue, - structs.GatewayReasonAccepted, + api.GatewayConditionAccepted, + api.ConditionStatusTrue, + api.GatewayReasonAccepted, "gateway is valid", structs.ResourceReference{}, ) @@ -844,9 +845,9 @@ func gatewayAccepted() structs.Condition { // to a given APIGateway listener. func invalidCertificate(ref structs.ResourceReference, err error) structs.Condition { return structs.NewGatewayCondition( - structs.GatewayConditionResolvedRefs, - structs.ConditionStatusFalse, - structs.GatewayListenerReasonInvalidCertificateRef, + api.GatewayConditionResolvedRefs, + api.ConditionStatusFalse, + api.GatewayListenerReasonInvalidCertificateRef, err.Error(), ref, ) @@ -856,9 +857,9 @@ func invalidCertificate(ref structs.ResourceReference, err error) structs.Condit // to invalid due to missing certificates that it references. func invalidCertificates() structs.Condition { return structs.NewGatewayCondition( - structs.GatewayConditionAccepted, - structs.ConditionStatusFalse, - structs.GatewayReasonInvalidCertificates, + api.GatewayConditionAccepted, + api.ConditionStatusFalse, + api.GatewayReasonInvalidCertificates, "gateway references invalid certificates", structs.ResourceReference{}, ) @@ -868,9 +869,9 @@ func invalidCertificates() structs.Condition { // bound routes func gatewayListenerNoConflicts(ref structs.ResourceReference) structs.Condition { return structs.NewGatewayCondition( - structs.GatewayConditionConflicted, - structs.ConditionStatusFalse, - structs.GatewayReasonNoConflicts, + api.GatewayConditionConflicted, + api.ConditionStatusFalse, + api.GatewayReasonNoConflicts, "listener has no route conflicts", ref, ) @@ -880,9 +881,9 @@ func gatewayListenerNoConflicts(ref structs.ResourceReference) structs.Condition // and make the listener, therefore invalid func gatewayListenerConflicts(ref structs.ResourceReference) structs.Condition { return structs.NewGatewayCondition( - structs.GatewayConditionConflicted, - structs.ConditionStatusTrue, - structs.GatewayReasonRouteConflicted, + api.GatewayConditionConflicted, + api.ConditionStatusTrue, + api.GatewayReasonRouteConflicted, "TCP-based listeners currently only support binding a single route", ref, ) @@ -891,9 +892,9 @@ func gatewayListenerConflicts(ref structs.ResourceReference) structs.Condition { // routeBound marks a Route as bound to the referenced APIGateway func routeBound(ref structs.ResourceReference) structs.Condition { return structs.NewRouteCondition( - structs.RouteConditionBound, - structs.ConditionStatusTrue, - structs.RouteReasonBound, + api.RouteConditionBound, + api.ConditionStatusTrue, + api.RouteReasonBound, "successfully bound route", ref, ) @@ -903,9 +904,9 @@ func routeBound(ref structs.ResourceReference) structs.Condition { // the Gateway not existing (or having not been reconciled yet) func gatewayNotFound(ref structs.ResourceReference) structs.Condition { return structs.NewRouteCondition( - structs.RouteConditionBound, - structs.ConditionStatusFalse, - structs.RouteReasonGatewayNotFound, + api.RouteConditionBound, + api.ConditionStatusFalse, + api.RouteReasonGatewayNotFound, "gateway was not found", ref, ) @@ -914,9 +915,9 @@ func gatewayNotFound(ref structs.ResourceReference) structs.Condition { // routeUnbound marks the route as having failed to bind to the referenced APIGateway func routeUnbound(ref structs.ResourceReference, err error) structs.Condition { return structs.NewRouteCondition( - structs.RouteConditionBound, - structs.ConditionStatusFalse, - structs.RouteReasonFailedToBind, + api.RouteConditionBound, + api.ConditionStatusFalse, + api.RouteReasonFailedToBind, err.Error(), ref, ) @@ -925,9 +926,9 @@ func routeUnbound(ref structs.ResourceReference, err error) structs.Condition { // routeAccepted marks the Route as valid func routeAccepted() structs.Condition { return structs.NewRouteCondition( - structs.RouteConditionAccepted, - structs.ConditionStatusTrue, - structs.RouteReasonAccepted, + api.RouteConditionAccepted, + api.ConditionStatusTrue, + api.RouteReasonAccepted, "route is valid", structs.ResourceReference{}, ) @@ -937,9 +938,9 @@ func routeAccepted() structs.Condition { // discovery chian func routeInvalidDiscoveryChain(err error) structs.Condition { return structs.NewRouteCondition( - structs.RouteConditionAccepted, - structs.ConditionStatusFalse, - structs.RouteReasonInvalidDiscoveryChain, + api.RouteConditionAccepted, + api.ConditionStatusFalse, + api.RouteReasonInvalidDiscoveryChain, err.Error(), structs.ResourceReference{}, ) @@ -948,9 +949,9 @@ func routeInvalidDiscoveryChain(err error) structs.Condition { // routeNoUpstreams marks the route as invalid because it has no upstreams that it targets func routeNoUpstreams() structs.Condition { return structs.NewRouteCondition( - structs.RouteConditionAccepted, - structs.ConditionStatusFalse, - structs.RouteReasonNoUpstreamServicesTargeted, + api.RouteConditionAccepted, + api.ConditionStatusFalse, + api.RouteReasonNoUpstreamServicesTargeted, "route must target at least one upstream service", structs.ResourceReference{}, ) diff --git a/proto/private/pbconfigentry/config_entry.gen.go b/proto/private/pbconfigentry/config_entry.gen.go index 3de97a6d55e..bba47b9cf90 100644 --- a/proto/private/pbconfigentry/config_entry.gen.go +++ b/proto/private/pbconfigentry/config_entry.gen.go @@ -185,7 +185,7 @@ func ConditionToStructs(s *Condition, t *structs.Condition) { return } t.Type = s.Type - t.Status = conditionStatusToStructs(s.Status) + t.Status = s.Status t.Reason = s.Reason t.Message = s.Message if s.Resource != nil { @@ -200,7 +200,7 @@ func ConditionFromStructs(t *structs.Condition, s *Condition) { return } s.Type = t.Type - s.Status = conditionStatusFromStructs(t.Status) + s.Status = t.Status s.Reason = t.Reason s.Message = t.Message if t.Resource != nil { diff --git a/proto/private/pbconfigentry/config_entry.go b/proto/private/pbconfigentry/config_entry.go index b47da5c3390..7cecbf02024 100644 --- a/proto/private/pbconfigentry/config_entry.go +++ b/proto/private/pbconfigentry/config_entry.go @@ -392,23 +392,6 @@ func apiGatewayProtocolToStructs(a APIGatewayListenerProtocol) structs.APIGatewa } } -func conditionStatusToStructs(s string) structs.ConditionStatus { - switch s { - case "True": - return structs.ConditionStatusTrue - case "False": - return structs.ConditionStatusFalse - case "Unknown": - fallthrough - default: - return structs.ConditionStatusUnknown - } -} - -func conditionStatusFromStructs(s structs.ConditionStatus) string { - return string(s) -} - func httpMatchMethodFromStructs(a structs.HTTPMatchMethod) HTTPMatchMethod { switch a { case structs.HTTPMatchMethodAll: diff --git a/proto/private/pbconfigentry/config_entry.pb.go b/proto/private/pbconfigentry/config_entry.pb.go index 72d2b2db16f..fae2340cf52 100644 --- a/proto/private/pbconfigentry/config_entry.pb.go +++ b/proto/private/pbconfigentry/config_entry.pb.go @@ -4127,8 +4127,7 @@ type Condition struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Type string `protobuf:"bytes,1,opt,name=Type,proto3" json:"Type,omitempty"` - // mog: func-to=conditionStatusToStructs func-from=conditionStatusFromStructs + Type string `protobuf:"bytes,1,opt,name=Type,proto3" json:"Type,omitempty"` Status string `protobuf:"bytes,2,opt,name=Status,proto3" json:"Status,omitempty"` Reason string `protobuf:"bytes,3,opt,name=Reason,proto3" json:"Reason,omitempty"` Message string `protobuf:"bytes,4,opt,name=Message,proto3" json:"Message,omitempty"` diff --git a/proto/private/pbconfigentry/config_entry.proto b/proto/private/pbconfigentry/config_entry.proto index 5c38bbf29a3..14a600cefa0 100644 --- a/proto/private/pbconfigentry/config_entry.proto +++ b/proto/private/pbconfigentry/config_entry.proto @@ -633,7 +633,6 @@ message Status { // name=Structs message Condition { string Type = 1; - // mog: func-to=conditionStatusToStructs func-from=conditionStatusFromStructs string Status = 2; string Reason = 3; string Message = 4; From 11d59a318388d060e56421866bfffc239f7d6cf1 Mon Sep 17 00:00:00 2001 From: jm96441n Date: Tue, 18 Apr 2023 12:06:20 -0400 Subject: [PATCH 15/24] Update conditions in fsm oss tests --- agent/consul/fsm/commands_oss_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/agent/consul/fsm/commands_oss_test.go b/agent/consul/fsm/commands_oss_test.go index 89f8bdebb3f..cea6f05f54f 100644 --- a/agent/consul/fsm/commands_oss_test.go +++ b/agent/consul/fsm/commands_oss_test.go @@ -1372,7 +1372,7 @@ func TestFSM_ConfigEntry_StatusCAS(t *testing.T) { EnterpriseMeta: *structs.DefaultEnterpriseMetaInDefaultPartition(), Status: structs.Status{ Conditions: []structs.Condition{{ - Status: structs.ConditionStatusTrue, + Status: string(api.ConditionStatusTrue), }}, }, } @@ -1404,7 +1404,7 @@ func TestFSM_ConfigEntry_StatusCAS(t *testing.T) { // do a status update entry.Status = structs.Status{ Conditions: []structs.Condition{{ - Status: structs.ConditionStatusTrue, + Status: string(api.ConditionStatusTrue), }}, } req = &structs.ConfigEntryRequest{ @@ -1428,7 +1428,7 @@ func TestFSM_ConfigEntry_StatusCAS(t *testing.T) { entry.RaftIndex.ModifyIndex = 2 conditions := config.(*structs.APIGatewayConfigEntry).Status.Conditions require.Len(t, conditions, 1) - require.Equal(t, structs.ConditionStatusTrue, conditions[0].Status) + require.Equal(t, string(api.ConditionStatusTrue), conditions[0].Status) } // attempt to change the status with a regular update and make sure it's ignored @@ -1457,7 +1457,7 @@ func TestFSM_ConfigEntry_StatusCAS(t *testing.T) { require.NoError(t, err) conditions := config.(*structs.APIGatewayConfigEntry).Status.Conditions require.Len(t, conditions, 1) - require.Equal(t, structs.ConditionStatusTrue, conditions[0].Status) + require.Equal(t, string(api.ConditionStatusTrue), conditions[0].Status) } } From d26c63a1fbb7be8c61b740c43a26e1eb1347f1da Mon Sep 17 00:00:00 2001 From: jm96441n Date: Tue, 18 Apr 2023 12:14:48 -0400 Subject: [PATCH 16/24] run go mod tidy on consul-container module to fix linting --- test/integration/consul-container/go.mod | 2 +- test/integration/consul-container/go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/integration/consul-container/go.mod b/test/integration/consul-container/go.mod index 395bc2fe47a..34d88a063b7 100644 --- a/test/integration/consul-container/go.mod +++ b/test/integration/consul-container/go.mod @@ -73,7 +73,7 @@ require ( github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 // indirect github.com/sirupsen/logrus v1.8.1 // indirect go.opencensus.io v0.23.0 // indirect - golang.org/x/exp v0.0.0-20230303215020-44a13b063f3e // indirect + golang.org/x/exp v0.0.0-20230321023759-10a507213a29 // indirect golang.org/x/net v0.8.0 // indirect golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 // indirect golang.org/x/sys v0.6.0 // indirect diff --git a/test/integration/consul-container/go.sum b/test/integration/consul-container/go.sum index 5fcb65084ad..695d8ef57ff 100644 --- a/test/integration/consul-container/go.sum +++ b/test/integration/consul-container/go.sum @@ -827,8 +827,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20230303215020-44a13b063f3e h1:S8xf0d0OEmWrClvbMiUSp+7cGD00txONylwExlf9wR0= -golang.org/x/exp v0.0.0-20230303215020-44a13b063f3e/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= +golang.org/x/exp v0.0.0-20230321023759-10a507213a29 h1:ooxPy7fPvB4kwsA2h+iBNHkAbp/4JxTSwCmvdjEYmug= +golang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= From 519acc472befde277506fef91d1b8abda593c7da Mon Sep 17 00:00:00 2001 From: jm96441n Date: Tue, 18 Apr 2023 12:45:10 -0400 Subject: [PATCH 17/24] Fix type for gateway endpoint test --- .../consul-container/test/gateways/gateway_endpoint_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/integration/consul-container/test/gateways/gateway_endpoint_test.go b/test/integration/consul-container/test/gateways/gateway_endpoint_test.go index b08bb471502..309538e89ce 100644 --- a/test/integration/consul-container/test/gateways/gateway_endpoint_test.go +++ b/test/integration/consul-container/test/gateways/gateway_endpoint_test.go @@ -137,7 +137,7 @@ func isBound(conditions []api.Condition) bool { func conditionStatusIsValue(typeName string, statusValue string, conditions []api.Condition) bool { for _, c := range conditions { - if c.Type == typeName && c.Status == statusValue { + if c.Type == typeName && string(c.Status) == statusValue { return true } } From 2da0633c4abc3aacaac8b5d52baaa7ffe782785a Mon Sep 17 00:00:00 2001 From: jm96441n Date: Tue, 18 Apr 2023 14:07:23 -0400 Subject: [PATCH 18/24] go mod tidy from changes to api --- envoyextensions/go.mod | 3 ++- envoyextensions/go.sum | 8 +++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/envoyextensions/go.mod b/envoyextensions/go.mod index 6dc8e782b88..225ed86d581 100644 --- a/envoyextensions/go.mod +++ b/envoyextensions/go.mod @@ -36,6 +36,7 @@ require ( github.com/mitchellh/mapstructure v1.4.1 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 // indirect + golang.org/x/exp v0.0.0-20230321023759-10a507213a29 // indirect + golang.org/x/sys v0.1.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/envoyextensions/go.sum b/envoyextensions/go.sum index 28b2402b3ec..c0b34dd3c70 100644 --- a/envoyextensions/go.sum +++ b/envoyextensions/go.sum @@ -55,7 +55,7 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= +github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/hashicorp/consul/sdk v0.13.1 h1:EygWVWWMczTzXGpO93awkHFzfUka6hLYJ0qhETd+6lY= @@ -143,6 +143,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20230321023759-10a507213a29 h1:ooxPy7fPvB4kwsA2h+iBNHkAbp/4JxTSwCmvdjEYmug= +golang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= @@ -185,8 +187,9 @@ golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 h1:WIoqL4EROvwiPdUtaip4VcDdpZ4kha7wBWZrbVKCIZg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= @@ -200,7 +203,6 @@ golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBn golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= From c1686a93e69f04e9bdbbb9bf3d52566f221d76b6 Mon Sep 17 00:00:00 2001 From: jm96441n Date: Tue, 18 Apr 2023 14:13:00 -0400 Subject: [PATCH 19/24] go mod tidy on troubleshoot --- troubleshoot/go.mod | 2 +- troubleshoot/go.sum | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/troubleshoot/go.mod b/troubleshoot/go.mod index 54838b51d79..48529793be0 100644 --- a/troubleshoot/go.mod +++ b/troubleshoot/go.mod @@ -28,7 +28,6 @@ require ( github.com/fatih/color v1.13.0 // indirect github.com/golang/protobuf v1.5.2 // indirect github.com/google/btree v1.0.0 // indirect - github.com/google/go-cmp v0.5.8 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-hclog v1.2.1 // indirect @@ -47,6 +46,7 @@ require ( github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_model v0.2.0 // indirect go.opentelemetry.io/proto/otlp v0.7.0 // indirect + golang.org/x/exp v0.0.0-20230321023759-10a507213a29 // indirect golang.org/x/net v0.4.0 // indirect golang.org/x/sys v0.3.0 // indirect golang.org/x/text v0.5.0 // indirect diff --git a/troubleshoot/go.sum b/troubleshoot/go.sum index b8177b292c8..7629cbde9e5 100644 --- a/troubleshoot/go.sum +++ b/troubleshoot/go.sum @@ -79,7 +79,6 @@ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= -github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= @@ -211,6 +210,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20230321023759-10a507213a29 h1:ooxPy7fPvB4kwsA2h+iBNHkAbp/4JxTSwCmvdjEYmug= +golang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= From 3c7df32d596a61f70c132f4358e443a872cf44b5 Mon Sep 17 00:00:00 2001 From: jm96441n Date: Tue, 18 Apr 2023 14:40:50 -0400 Subject: [PATCH 20/24] Fix route conflicted reason --- agent/consul/gateways/controller_gateways.go | 2 +- api/config_entry_status.go | 2 +- api/config_entry_status_test.go | 10 ++++++++++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/agent/consul/gateways/controller_gateways.go b/agent/consul/gateways/controller_gateways.go index c3e03d130ae..4e7acdf7ff1 100644 --- a/agent/consul/gateways/controller_gateways.go +++ b/agent/consul/gateways/controller_gateways.go @@ -883,7 +883,7 @@ func gatewayListenerConflicts(ref structs.ResourceReference) structs.Condition { return structs.NewGatewayCondition( api.GatewayConditionConflicted, api.ConditionStatusTrue, - api.GatewayReasonRouteConflicted, + api.GatewayReasonRouteConflict, "TCP-based listeners currently only support binding a single route", ref, ) diff --git a/api/config_entry_status.go b/api/config_entry_status.go index d87029538f7..e69f472ecbe 100644 --- a/api/config_entry_status.go +++ b/api/config_entry_status.go @@ -128,7 +128,7 @@ const ( GatewayReasonNoConflicts GatewayConditionReason = "NoConflicts" // This reason is used with the "Conflicted" condition when the route is // in a conflicted state, such as when a TCPListener attempts to bind to two routes - GatewayReasonRouteConflicted GatewayConditionReason = "RouteConflicted" + GatewayReasonRouteConflict GatewayConditionReason = "RouteConflict" // This condition indicates whether the controller was able to // resolve all the object references for the Gateway. When setting this diff --git a/api/config_entry_status_test.go b/api/config_entry_status_test.go index 6fc4c9052ce..945efbb95fd 100644 --- a/api/config_entry_status_test.go +++ b/api/config_entry_status_test.go @@ -18,6 +18,16 @@ func TestValidateGatewayConditionReasonWithValidCombinations(t *testing.T) { reason: GatewayReasonInvalidCertificates, condType: GatewayConditionAccepted, }, + "conflicted": { + status: ConditionStatusTrue, + reason: GatewayReasonRouteConflict, + condType: GatewayConditionConflicted, + }, + "conflicted no conflicts": { + status: ConditionStatusFalse, + reason: GatewayReasonNoConflicts, + condType: GatewayConditionConflicted, + }, "resolved refs": { status: ConditionStatusTrue, From 0b3ec3a487c97c8c28fb87d269cf08b7eaf80e44 Mon Sep 17 00:00:00 2001 From: jm96441n Date: Tue, 18 Apr 2023 14:50:26 -0400 Subject: [PATCH 21/24] fix route conflict reason rename --- api/config_entry_status.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/config_entry_status.go b/api/config_entry_status.go index e69f472ecbe..9f01b047d60 100644 --- a/api/config_entry_status.go +++ b/api/config_entry_status.go @@ -177,7 +177,7 @@ var validGatewayConditionReasonsMapping = map[GatewayConditionType]map[Condition }, GatewayConditionConflicted: { ConditionStatusTrue: { - GatewayReasonRouteConflicted, + GatewayReasonRouteConflict, }, ConditionStatusFalse: { GatewayReasonNoConflicts, From 9277645bb478a745d0a7d4cca6895594e233f2c8 Mon Sep 17 00:00:00 2001 From: jm96441n Date: Tue, 18 Apr 2023 16:05:20 -0400 Subject: [PATCH 22/24] Fix text for gateway conflicted status --- agent/consul/gateways/controller_gateways.go | 2 +- api/config_entry_status.go | 6 +++--- api/config_entry_status_test.go | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/agent/consul/gateways/controller_gateways.go b/agent/consul/gateways/controller_gateways.go index 4e7acdf7ff1..88d51da121f 100644 --- a/agent/consul/gateways/controller_gateways.go +++ b/agent/consul/gateways/controller_gateways.go @@ -871,7 +871,7 @@ func gatewayListenerNoConflicts(ref structs.ResourceReference) structs.Condition return structs.NewGatewayCondition( api.GatewayConditionConflicted, api.ConditionStatusFalse, - api.GatewayReasonNoConflicts, + api.GatewayReasonNoConflict, "listener has no route conflicts", ref, ) diff --git a/api/config_entry_status.go b/api/config_entry_status.go index 9f01b047d60..2d16ea0fc4e 100644 --- a/api/config_entry_status.go +++ b/api/config_entry_status.go @@ -117,7 +117,7 @@ const ( // // Possible reasons for this condition to be False are: // - // * "NoConflicts" + // * "NoConflict" // // Controllers may raise this condition with other reasons, // but should prefer to use the reasons listed above to improve @@ -125,7 +125,7 @@ const ( GatewayConditionConflicted GatewayConditionType = "Conflicted" // This reason is used with the "Conflicted" condition when the condition // is False. - GatewayReasonNoConflicts GatewayConditionReason = "NoConflicts" + GatewayReasonNoConflict GatewayConditionReason = "NoConflict" // This reason is used with the "Conflicted" condition when the route is // in a conflicted state, such as when a TCPListener attempts to bind to two routes GatewayReasonRouteConflict GatewayConditionReason = "RouteConflict" @@ -180,7 +180,7 @@ var validGatewayConditionReasonsMapping = map[GatewayConditionType]map[Condition GatewayReasonRouteConflict, }, ConditionStatusFalse: { - GatewayReasonNoConflicts, + GatewayReasonNoConflict, }, ConditionStatusUnknown: {}, }, diff --git a/api/config_entry_status_test.go b/api/config_entry_status_test.go index 945efbb95fd..9c6eaf034c3 100644 --- a/api/config_entry_status_test.go +++ b/api/config_entry_status_test.go @@ -25,7 +25,7 @@ func TestValidateGatewayConditionReasonWithValidCombinations(t *testing.T) { }, "conflicted no conflicts": { status: ConditionStatusFalse, - reason: GatewayReasonNoConflicts, + reason: GatewayReasonNoConflict, condType: GatewayConditionConflicted, }, @@ -60,17 +60,17 @@ func TestValidateGatewayConditionReasonWithInvalidCombinationsReturnsError(t *te }{ "reason and condition type are valid but status is not": { status: ConditionStatusTrue, - reason: GatewayReasonNoConflicts, + reason: GatewayReasonNoConflict, condType: GatewayConditionConflicted, }, "reason and status are valid but condition type is not": { status: ConditionStatusFalse, - reason: GatewayReasonNoConflicts, + reason: GatewayReasonNoConflict, condType: GatewayConditionResolvedRefs, }, "condition type and status are valid but status is not": { status: ConditionStatusTrue, - reason: GatewayReasonNoConflicts, + reason: GatewayReasonNoConflict, condType: GatewayConditionAccepted, }, "all are invalid": { From d83a09c1268fd83dafa0e205cfa4352304877444 Mon Sep 17 00:00:00 2001 From: jm96441n Date: Mon, 24 Apr 2023 15:24:33 -0400 Subject: [PATCH 23/24] Add valid certificate ref condition setting --- agent/consul/gateways/controller_gateways.go | 21 ++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/agent/consul/gateways/controller_gateways.go b/agent/consul/gateways/controller_gateways.go index 88d51da121f..3bdd232a9c8 100644 --- a/agent/consul/gateways/controller_gateways.go +++ b/agent/consul/gateways/controller_gateways.go @@ -245,6 +245,14 @@ func (r *apiGatewayReconciler) reconcileGateway(_ context.Context, req controlle updater.SetCondition(invalidCertificate(ref, err)) } + if len(certificateErrors) == 0 { + for _, listener := range gateway.Listeners { + for _, ref := range listener.TLS.Certificates { + updater.SetCondition(validCertificate(ref)) + } + } + } + if len(certificateErrors) > 0 { updater.SetCondition(invalidCertificates()) } else { @@ -840,6 +848,19 @@ func gatewayAccepted() structs.Condition { ) } +// validCertificate returns a condition used when a gateway references a +// certificate that does not exist. It takes a ref used to scope the condition +// to a given APIGateway listener. +func validCertificate(ref structs.ResourceReference) structs.Condition { + return structs.NewGatewayCondition( + api.GatewayConditionResolvedRefs, + api.ConditionStatusTrue, + api.GatewayReasonResolvedRefs, + "resolved refs", + ref, + ) +} + // invalidCertificate returns a condition used when a gateway references a // certificate that does not exist. It takes a ref used to scope the condition // to a given APIGateway listener. From f1fa81aad72e8b1f507348d126c485cc7983fd18 Mon Sep 17 00:00:00 2001 From: jm96441n Date: Mon, 24 Apr 2023 15:35:43 -0400 Subject: [PATCH 24/24] Revert change to resolved refs to be handled in future PR --- agent/consul/gateways/controller_gateways.go | 23 +------------------- api/config_entry_status.go | 1 + 2 files changed, 2 insertions(+), 22 deletions(-) diff --git a/agent/consul/gateways/controller_gateways.go b/agent/consul/gateways/controller_gateways.go index 3bdd232a9c8..e399503f355 100644 --- a/agent/consul/gateways/controller_gateways.go +++ b/agent/consul/gateways/controller_gateways.go @@ -245,14 +245,6 @@ func (r *apiGatewayReconciler) reconcileGateway(_ context.Context, req controlle updater.SetCondition(invalidCertificate(ref, err)) } - if len(certificateErrors) == 0 { - for _, listener := range gateway.Listeners { - for _, ref := range listener.TLS.Certificates { - updater.SetCondition(validCertificate(ref)) - } - } - } - if len(certificateErrors) > 0 { updater.SetCondition(invalidCertificates()) } else { @@ -848,25 +840,12 @@ func gatewayAccepted() structs.Condition { ) } -// validCertificate returns a condition used when a gateway references a -// certificate that does not exist. It takes a ref used to scope the condition -// to a given APIGateway listener. -func validCertificate(ref structs.ResourceReference) structs.Condition { - return structs.NewGatewayCondition( - api.GatewayConditionResolvedRefs, - api.ConditionStatusTrue, - api.GatewayReasonResolvedRefs, - "resolved refs", - ref, - ) -} - // invalidCertificate returns a condition used when a gateway references a // certificate that does not exist. It takes a ref used to scope the condition // to a given APIGateway listener. func invalidCertificate(ref structs.ResourceReference, err error) structs.Condition { return structs.NewGatewayCondition( - api.GatewayConditionResolvedRefs, + api.GatewayConditionAccepted, api.ConditionStatusFalse, api.GatewayListenerReasonInvalidCertificateRef, err.Error(), diff --git a/api/config_entry_status.go b/api/config_entry_status.go index 2d16ea0fc4e..dfb97eb4c9b 100644 --- a/api/config_entry_status.go +++ b/api/config_entry_status.go @@ -171,6 +171,7 @@ var validGatewayConditionReasonsMapping = map[GatewayConditionType]map[Condition GatewayReasonAccepted, }, ConditionStatusFalse: { + GatewayListenerReasonInvalidCertificateRef, // TODO: remove this in follow up PR GatewayReasonInvalidCertificates, }, ConditionStatusUnknown: {},