Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Set SupportedVersion on GatewayClass #1301

Merged
merged 11 commits into from
Dec 5, 2023
7 changes: 7 additions & 0 deletions conformance/provisioner/provisioner.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,13 @@ rules:
- gatewayclasses/status
verbs:
- update
- apiGroups:
- apiextensions.k8s.io
resources:
- customresourcedefinitions
verbs:
- list
- watch
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
Expand Down
7 changes: 7 additions & 0 deletions deploy/helm-chart/templates/rbac.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,13 @@ rules:
- get
- update
{{- end }}
- apiGroups:
- apiextensions.k8s.io
resources:
- customresourcedefinitions
verbs:
- list
- watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
Expand Down
7 changes: 7 additions & 0 deletions deploy/manifests/nginx-gateway.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,13 @@ rules:
- create
- get
- update
- apiGroups:
- apiextensions.k8s.io
resources:
- customresourcedefinitions
verbs:
- list
- watch
---
# Source: nginx-gateway-fabric/templates/rbac.yaml
apiVersion: rbac.authorization.k8s.io/v1
Expand Down
22 changes: 12 additions & 10 deletions docs/developer/release-process.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,10 @@ To create a new release, follow these steps:
3. Test the main branch for release-readiness. For that, use the `edge` containers, which are built from the main
branch, and the [example applications](/examples).
4. If a problem is found, prepare a fix PR, merge it into the main branch and return to the previous step.
5. Create a release branch with a name that follows the `release-X.Y` format.
6. Prepare and merge a PR into the release branch to update the repo files for the release:
5. If the supported Gateway API minor version has changed since the last release, test NGINX Gateway Fabric with the previous version of the Gateway API CRDs.
6. If a compatibility issue is found, add a note to the release notes explaining that the previous version is not supported.
7. Create a release branch following the `release-X.Y` naming convention.
8. Prepare and merge a PR into the release branch to update the repo files for the release:
1. Update the Helm [Chart.yaml](/deploy/helm-chart/Chart.yaml): the `appVersion` to `X.Y.Z`, the icon and source
URLs to point at `vX.Y.Z`, and bump the `version`.
2. Adjust the `VERSION` variable in the [Makefile](/Makefile) and the `TAG` in the
Expand All @@ -52,17 +54,17 @@ To create a new release, follow these steps:
draft of the full changelog. This draft can be found under
the [GitHub releases](https://github.com/nginxinc/nginx-gateway-fabric/releases) after the release branch is
created. Use the previous changelog entries for formatting and content guidance.
7. Create and push the release tag in the format `vX.Y.Z`. As a result, the CI/CD pipeline will:
9. Create and push the release tag in the format `vX.Y.Z`. As a result, the CI/CD pipeline will:
- Build NGF container images with the release tag `X.Y.Z` and push it to the registry.
- Package and publish the Helm chart to the registry.
- Create a GitHub release with an autogenerated changelog and attached release artifacts.
8. Prepare and merge a PR into the main branch to update the [README](/README.md) to include the information about
the latest release and also the [changelog](/CHANGELOG.md). Also update any installation instructions to ensure
that the supported Gateway API and NGF versions are correct. Specifically, helm README and `site/content/includes/installation/install-gateway-api-resources.md`.
9. Close the issue created in Step 1.
10. Ensure that the [associated milestone](https://github.com/nginxinc/nginx-gateway-fabric/milestones) is closed.
11. Verify that published artifacts in the release can be installed properly.
12. Submit the `conformance-profile.yaml` artifact from the release to the [Gateway API repo](https://github.com/kubernetes-sigs/gateway-api/tree/main/conformance/reports).
10. Prepare and merge a PR into the main branch to update the [README](/README.md) to include the information about
the latest release and also the [changelog](/CHANGELOG.md). Also update any installation instructions to ensure
that the supported Gateway API and NGF versions are correct. Specifically, helm README and `site/content/includes/installation/install-gateway-api-resources.md`.
11. Close the issue created in Step 1.
12. Ensure that the [associated milestone](https://github.com/nginxinc/nginx-gateway-fabric/milestones) is closed.
13. Verify that published artifacts in the release can be installed properly.
14. Submit the `conformance-profile.yaml` artifact from the release to the [Gateway API repo](https://github.com/kubernetes-sigs/gateway-api/tree/main/conformance/reports).
- Create a fork of the repository
- Name the file `nginxinc-nginx-gateway-fabric.yaml` and set `gatewayAPIVersion` in the file to the
supported version by NGF. Also update the site source if necessary (see following example).
Expand Down
85 changes: 84 additions & 1 deletion internal/framework/conditions/conditions.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package conditions

import (
"fmt"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
v1 "sigs.k8s.io/gateway-api/apis/v1"
)
Expand All @@ -24,7 +26,40 @@ type Condition struct {
Message string
}

// NewDefaultGatewayClassConditions returns the default Conditions that must be present in the status of a GatewayClass.
// DeduplicateConditions removes duplicate conditions based on the condition type.
// The last condition wins. The order of conditions is preserved.
func DeduplicateConditions(conds []Condition) []Condition {
type elem struct {
cond Condition
reverseIdx int
}

uniqueElems := make(map[string]elem)

idx := 0
for i := len(conds) - 1; i >= 0; i-- {
if _, exist := uniqueElems[conds[i].Type]; exist {
continue
}

uniqueElems[conds[i].Type] = elem{
cond: conds[i],
reverseIdx: idx,
}
idx++
}

result := make([]Condition, len(uniqueElems))

for _, el := range uniqueElems {
result[len(result)-el.reverseIdx-1] = el.cond
}

return result
}

// NewDefaultGatewayClassConditions returns Conditions that indicate that the GatewayClass is accepted and that the
// Gateway API CRD versions are supported.
func NewDefaultGatewayClassConditions() []Condition {
return []Condition{
{
Expand All @@ -33,6 +68,54 @@ func NewDefaultGatewayClassConditions() []Condition {
Reason: string(v1.GatewayClassReasonAccepted),
Message: "GatewayClass is accepted",
},
{
Type: string(v1.GatewayClassConditionStatusSupportedVersion),
Status: metav1.ConditionTrue,
Reason: string(v1.GatewayClassReasonSupportedVersion),
Message: "Gateway API CRD versions are supported",
},
}
}

// NewGatewayClassSupportedVersionBestEffort returns a Condition that indicates that the GatewayClass is accepted,
// but the Gateway API CRD versions are not supported. This means NGF will attempt to generate configuration,
// but it does not guarantee support.
func NewGatewayClassSupportedVersionBestEffort(recommendedVersion string) []Condition {
pleshakov marked this conversation as resolved.
Show resolved Hide resolved
return []Condition{
{
Type: string(v1.GatewayClassConditionStatusSupportedVersion),
Status: metav1.ConditionFalse,
Reason: string(v1.GatewayClassReasonUnsupportedVersion),
Message: fmt.Sprintf(
"Gateway API CRD versions are not recommended. Recommended version is %s",
recommendedVersion,
),
},
}
}

// NewGatewayClassUnsupportedVersion returns Conditions that indicate that the GatewayClass is not accepted because
// the Gateway API CRD versions are not supported. NGF will not generate configuration in this case.
func NewGatewayClassUnsupportedVersion(recommendedVersion string) []Condition {
return []Condition{
{
Type: string(v1.GatewayClassConditionStatusAccepted),
Status: metav1.ConditionFalse,
Reason: string(v1.GatewayClassReasonUnsupportedVersion),
Message: fmt.Sprintf(
"Gateway API CRD versions are not supported. Please install version %s",
recommendedVersion,
),
},
{
Type: string(v1.GatewayClassConditionStatusSupportedVersion),
Status: metav1.ConditionFalse,
Reason: string(v1.GatewayClassReasonUnsupportedVersion),
Message: fmt.Sprintf(
"Gateway API CRD versions are not supported. Please install version %s",
recommendedVersion,
),
},
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,12 @@ import (

. "github.com/onsi/gomega"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

"github.com/nginxinc/nginx-gateway-fabric/internal/framework/conditions"
)

func TestDeduplicateConditions(t *testing.T) {
g := NewWithT(t)

conds := []conditions.Condition{
conds := []Condition{
{
Type: "Type1",
Status: metav1.ConditionTrue,
Expand Down Expand Up @@ -40,7 +38,7 @@ func TestDeduplicateConditions(t *testing.T) {
},
}

expected := []conditions.Condition{
expected := []Condition{
{
Type: "Type1",
Status: metav1.ConditionFalse,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ func TestServiceNameIndexFunc(t *testing.T) {
func TestServiceNameIndexFuncPanics(t *testing.T) {
defer func() {
g := NewWithT(t)
g.Expect(recover()).ShouldNot(BeNil())
g.Expect(recover()).ToNot(BeNil())
}()

ServiceNameIndexFunc(&v1.Namespace{})
Expand Down
39 changes: 39 additions & 0 deletions internal/framework/controller/predicate/annotation.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package predicate

import (
"sigs.k8s.io/controller-runtime/pkg/event"
"sigs.k8s.io/controller-runtime/pkg/predicate"
)

// AnnotationPredicate implements a predicate function based on the Annotation.
//
// This predicate will skip the following events:
// 1. Create events that do not contain the Annotation.
// 2. Update events where the Annotation value has not changed.
type AnnotationPredicate struct {
predicate.Funcs
Annotation string
}

// Create filters CreateEvents based on the Annotation.
func (cp AnnotationPredicate) Create(e event.CreateEvent) bool {
if e.Object == nil {
return false
}

_, ok := e.Object.GetAnnotations()[cp.Annotation]
return ok
}

// Update filters UpdateEvents based on the Annotation.
func (cp AnnotationPredicate) Update(e event.UpdateEvent) bool {
if e.ObjectOld == nil || e.ObjectNew == nil {
// this case should not happen
return false
}

oldAnnotationVal := e.ObjectOld.GetAnnotations()[cp.Annotation]
newAnnotationVal := e.ObjectNew.GetAnnotations()[cp.Annotation]

return oldAnnotationVal != newAnnotationVal
}
Loading
Loading