Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion internal/controller/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import (
gatewayv1 "sigs.k8s.io/gateway-api/apis/v1"
gatewayv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
gatewayv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1"
"sigs.k8s.io/gateway-api/pkg/consts"

ngfAPIv1alpha1 "github.com/nginx/nginx-gateway-fabric/v2/apis/v1alpha1"
ngfAPIv1alpha2 "github.com/nginx/nginx-gateway-fabric/v2/apis/v1alpha2"
Expand Down Expand Up @@ -493,7 +494,7 @@ func registerControllers(
options: []controller.Option{
controller.WithOnlyMetadata(),
controller.WithK8sPredicate(
predicate.AnnotationPredicate{Annotation: graph.BundleVersionAnnotation},
predicate.AnnotationPredicate{Annotation: consts.BundleVersionAnnotation},
),
},
},
Expand Down
6 changes: 5 additions & 1 deletion internal/controller/state/change_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
v1 "sigs.k8s.io/gateway-api/apis/v1"
"sigs.k8s.io/gateway-api/apis/v1alpha2"
"sigs.k8s.io/gateway-api/apis/v1beta1"
"sigs.k8s.io/gateway-api/pkg/consts"

ngfAPIv1alpha1 "github.com/nginx/nginx-gateway-fabric/v2/apis/v1alpha1"
ngfAPIv1alpha2 "github.com/nginx/nginx-gateway-fabric/v2/apis/v1alpha2"
Expand Down Expand Up @@ -63,6 +64,8 @@ type ChangeProcessorConfig struct {
GatewayCtlrName string
// GatewayClassName is the name of the GatewayClass resource.
GatewayClassName string
// ExperimentalFeatures indicates if experimental features are enabled.
ExperimentalFeatures bool
}

// ChangeProcessorImpl is an implementation of ChangeProcessor.
Expand Down Expand Up @@ -190,7 +193,7 @@ func NewChangeProcessorImpl(cfg ChangeProcessorConfig) *ChangeProcessorImpl {
{
gvk: cfg.MustExtractGVK(&apiext.CustomResourceDefinition{}),
store: newObjectStoreMapAdapter(clusterStore.CRDMetadata),
predicate: annotationChangedPredicate{annotation: graph.BundleVersionAnnotation},
predicate: annotationChangedPredicate{annotation: consts.BundleVersionAnnotation},
},
{
gvk: cfg.MustExtractGVK(&ngfAPIv1alpha2.NginxProxy{}),
Expand Down Expand Up @@ -275,6 +278,7 @@ func (c *ChangeProcessorImpl) Process() *graph.Graph {
c.cfg.PlusSecrets,
c.cfg.Validators,
c.cfg.Logger,
c.cfg.ExperimentalFeatures,
)

return c.latestGraph
Expand Down
9 changes: 5 additions & 4 deletions internal/controller/state/change_processor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
v1 "sigs.k8s.io/gateway-api/apis/v1"
"sigs.k8s.io/gateway-api/apis/v1alpha2"
"sigs.k8s.io/gateway-api/apis/v1beta1"
"sigs.k8s.io/gateway-api/pkg/consts"

ngfAPIv1alpha1 "github.com/nginx/nginx-gateway-fabric/v2/apis/v1alpha1"
ngfAPIv1alpha2 "github.com/nginx/nginx-gateway-fabric/v2/apis/v1alpha2"
Expand Down Expand Up @@ -666,13 +667,13 @@ var _ = Describe("ChangeProcessor", func() {
ObjectMeta: metav1.ObjectMeta{
Name: "gatewayclasses.gateway.networking.k8s.io",
Annotations: map[string]string{
graph.BundleVersionAnnotation: graph.SupportedVersion,
consts.BundleVersionAnnotation: consts.BundleVersion,
},
},
}

gatewayAPICRDUpdated = gatewayAPICRD.DeepCopy()
gatewayAPICRDUpdated.Annotations[graph.BundleVersionAnnotation] = "v1.99.0"
gatewayAPICRDUpdated.Annotations[consts.BundleVersionAnnotation] = "v1.99.0"
})
BeforeEach(func() {
expRouteHR1 = &graph.L7Route{
Expand Down Expand Up @@ -1556,7 +1557,7 @@ var _ = Describe("ChangeProcessor", func() {
}

expGraph.GatewayClass.Conditions = conditions.NewGatewayClassSupportedVersionBestEffort(
graph.SupportedVersion,
consts.BundleVersion,
)

processAndValidateGraph(expGraph)
Expand All @@ -1574,7 +1575,7 @@ var _ = Describe("ChangeProcessor", func() {
}

expGraph.GatewayClass.Conditions = conditions.NewGatewayClassSupportedVersionBestEffort(
graph.SupportedVersion,
consts.BundleVersion,
)

graphCfg := processor.Process()
Expand Down
76 changes: 48 additions & 28 deletions internal/controller/state/graph/gatewayclass.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,14 @@ import (
"k8s.io/apimachinery/pkg/util/validation/field"
"sigs.k8s.io/controller-runtime/pkg/client"
v1 "sigs.k8s.io/gateway-api/apis/v1"
"sigs.k8s.io/gateway-api/pkg/consts"
"sigs.k8s.io/gateway-api/pkg/features"

"github.com/nginx/nginx-gateway-fabric/v2/internal/controller/state/conditions"
"github.com/nginx/nginx-gateway-fabric/v2/internal/framework/helpers"
"github.com/nginx/nginx-gateway-fabric/v2/internal/framework/kinds"
)

const (
// BundleVersionAnnotation is the annotation on Gateway API CRDs that contains the installed version.
BundleVersionAnnotation = "gateway.networking.k8s.io/bundle-version"
// SupportedVersion is the supported version of the Gateway API CRDs.
SupportedVersion = "v1.4.0"
)

var gatewayCRDs = map[string]apiVersion{
"gatewayclasses.gateway.networking.k8s.io": {},
"gateways.gateway.networking.k8s.io": {},
Expand All @@ -41,6 +36,8 @@ type GatewayClass struct {
Conditions []conditions.Condition
// Valid shows whether the GatewayClass is valid.
Valid bool
// ExperimentalSupported indicates whether experimental features are supported.
ExperimentalSupported bool
}

// processedGatewayClasses holds the resources that belong to NGF.
Expand Down Expand Up @@ -83,6 +80,7 @@ func buildGatewayClass(
gc *v1.GatewayClass,
nps map[types.NamespacedName]*NginxProxy,
crdVersions map[types.NamespacedName]*metav1.PartialObjectMetadata,
experimentalEnabled bool,
) *GatewayClass {
if gc == nil {
return nil
Expand All @@ -93,13 +91,17 @@ func buildGatewayClass(
np = getNginxProxyForGatewayClass(*gc.Spec.ParametersRef, nps)
}

conds, valid := validateGatewayClass(gc, np, crdVersions)
conds, valid, crdExperimental := validateGatewayClass(gc, np, crdVersions)

// Experimental features are supported only if both the config flag AND CRD channel are experimental
experimental := experimentalEnabled && crdExperimental

return &GatewayClass{
Source: gc,
NginxProxy: np,
Valid: valid,
Conditions: conds,
Source: gc,
NginxProxy: np,
Valid: valid,
Conditions: conds,
ExperimentalSupported: experimental,
}
}

Expand Down Expand Up @@ -145,14 +147,14 @@ func validateGatewayClass(
gc *v1.GatewayClass,
npCfg *NginxProxy,
crdVersions map[types.NamespacedName]*metav1.PartialObjectMetadata,
) ([]conditions.Condition, bool) {
) ([]conditions.Condition, bool, bool) {
var conds []conditions.Condition

supportedVersionConds, versionsValid := validateCRDVersions(crdVersions)
supportedVersionConds, versionsValid, experimental := validateCRDVersions(crdVersions)
conds = append(conds, supportedVersionConds...)

if gc.Spec.ParametersRef == nil {
return conds, versionsValid
return conds, versionsValid, experimental
}

path := field.NewPath("spec").Child("parametersRef")
Expand All @@ -161,7 +163,7 @@ func validateGatewayClass(
// return early since parametersRef isn't valid
if len(refConds) > 0 {
conds = append(conds, refConds...)
return conds, versionsValid
return conds, versionsValid, experimental
}

if npCfg == nil {
Expand All @@ -172,7 +174,7 @@ func validateGatewayClass(
field.NotFound(path.Child("name"), gc.Spec.ParametersRef.Name).Error(),
),
)
return conds, versionsValid
return conds, versionsValid, experimental
}

if !npCfg.Valid {
Expand All @@ -182,10 +184,10 @@ func validateGatewayClass(
conditions.NewGatewayClassRefInvalid(msg),
conditions.NewGatewayClassInvalidParameters(msg),
)
return conds, versionsValid
return conds, versionsValid, experimental
}

return append(conds, conditions.NewGatewayClassResolvedRefs()), versionsValid
return append(conds, conditions.NewGatewayClassResolvedRefs()), versionsValid, experimental
}

var supportedParamKinds = map[string]struct{}{
Expand All @@ -199,9 +201,9 @@ type apiVersion struct {

func validateCRDVersions(
crdMetadata map[types.NamespacedName]*metav1.PartialObjectMetadata,
) (conds []conditions.Condition, valid bool) {
installedAPIVersions := getBundleVersions(crdMetadata)
supportedAPIVersion := parseVersionString(SupportedVersion)
) (conds []conditions.Condition, valid bool, experimental bool) {
installedAPIVersions, channels := getBundleVersions(crdMetadata)
supportedAPIVersion := parseVersionString(consts.BundleVersion)

var unsupported, bestEffort bool

Expand All @@ -213,15 +215,23 @@ func validateCRDVersions(
}
}

// Check if any CRD is using experimental channel
for _, ch := range channels {
if ch == features.FeatureChannelExperimental {
experimental = true
break
}
}

if unsupported {
return conditions.NewGatewayClassUnsupportedVersion(SupportedVersion), false
return conditions.NewGatewayClassUnsupportedVersion(consts.BundleVersion), false, experimental
}

if bestEffort {
return conditions.NewGatewayClassSupportedVersionBestEffort(SupportedVersion), true
return conditions.NewGatewayClassSupportedVersionBestEffort(consts.BundleVersion), true, experimental
}

return nil, true
return nil, true, experimental
}

func parseVersionString(version string) apiVersion {
Expand All @@ -246,15 +256,25 @@ func parseVersionString(version string) apiVersion {
}
}

func getBundleVersions(crdMetadata map[types.NamespacedName]*metav1.PartialObjectMetadata) []apiVersion {
func getBundleVersions(
crdMetadata map[types.NamespacedName]*metav1.PartialObjectMetadata,
) ([]apiVersion, []features.FeatureChannel) {
versions := make([]apiVersion, 0, len(gatewayCRDs))
channels := make([]features.FeatureChannel, 0, len(gatewayCRDs))

for nsname, md := range crdMetadata {
if _, ok := gatewayCRDs[nsname.Name]; ok {
bundleVersion := md.Annotations[BundleVersionAnnotation]
bundleVersion := md.Annotations[consts.BundleVersionAnnotation]
versions = append(versions, parseVersionString(bundleVersion))

// Default to standard channel if annotation is missing
ch := md.Annotations[consts.ChannelAnnotation]
if ch == "" {
ch = string(features.FeatureChannelStandard)
}
channels = append(channels, features.FeatureChannel(ch))
}
}

return versions
return versions, channels
}
Loading
Loading