Skip to content

Commit df62c3e

Browse files
committed
Resolve comments
Signed-off-by: Lubron Zhan <[email protected]>
1 parent 2c0414c commit df62c3e

File tree

8 files changed

+36
-72
lines changed

8 files changed

+36
-72
lines changed

design/automated-provisioning-design.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ It will handle the full provisioning lifecycle for these Gateways: creating a Co
6060
![drawing](images/gatewayapi-provisioner-overview.png)
6161

6262
Importantly, this provisioning model allows for (a) any number of GatewayClasses to be controlled by the Gateway provisioner; and (b) any number of Gateways per controlled GatewayClass.
63-
While the exact use cases for many Contour Gateways remain unclear, these one-to-many relationships between controller and GatewayClass, and GatewayClass and Gateway, offer users the full flexibility that the Gateway API spec intends.
63+
While the exact use cases for many Contour Gateways remain unclear, these one-to-many relationships between controller and GatewayClass, and GatewayClass and Gateway, offer users the full flexibility that the Gateway API spec intends.
6464
Additionally, support for this one-to-many relationship is required in order to pass any of the Gateway API conformance tests.
6565

6666
![drawing](images/gatewayapi-resource-relationships.png)
@@ -77,7 +77,7 @@ Those users can continue to statically provision their Contour + Envoy instances
7777

7878
There will be two ways to configure Contour for Gateway API support in the static provisioning scenario:
7979
- **Controller name** - this is the model implemented today, where Contour is configured with a controller name, and it continuously looks for the oldest GatewayClass with that controller, and the oldest Gateway using that GatewayClass. This model is appropriate for users who expect their GatewayClasses and Gateways to come and go, and who want their Contour instance to dynamically pick up the appropriate Gateway as those changes occur.
80-
- **Gateway name** - Contour can alternately be directly configured with a specific Gateway name, which avoids the multiple levels of indirection of the previous model. This model is appropriate for users who expect their Contour instance to correspond to a single static Gateway; the lifecycle of the Gateway and the lifecycle of the Contour instance are tied together.
80+
- **Gateway name** - Contour can alternately be directly configured with a specific Gateway name, which avoids the multiple levels of indirection of the previous model. This model is appropriate for users who expect their Contour instance to correspond to a single static Gateway; the lifecycle of the Gateway and the lifecycle of the Contour instance are tied together.
8181

8282
Note that the Gateway provisioner will make use of the **Gateway name** mode of configuring Contour, to tie each instance of Contour it provisions directly to a specific Gateway.
8383

@@ -88,13 +88,13 @@ This custom resource definition embeds a ContourConfiguration spec, as well as a
8888
This ContourDeployment resource serves as a template that defines exactly how to customize each Contour + Envoy instance that is created for this GatewayClass.
8989
When a Gateway is provisioned, the Gateway provisioner will use the configuration options specified to customize the YAML that is applied, and will pass through a copy of the ContourConfiguration data to the Gateway’s Contour instance.
9090

91-
Note that, according to the Gateway API documentation:
91+
Note that, according to the Gateway API documentation:
9292
> It is recommended that [GatewayClass] be used as a template for Gateways.
9393
> This means that a Gateway is based on the state of the GatewayClass at the time it was created and changes to the GatewayClass or associated parameters are not propagated down to existing Gateways.
94-
> This recommendation is intended to limit the blast radius of changes to GatewayClass or associated parameters.
95-
(ref. [GatewayClass API reference documentation](https://gateway-api.sigs.k8s.io/v1alpha2/references/spec/#gateway.networking.k8s.io/v1alpha2.GatewayClass))
94+
> This recommendation is intended to limit the blast radius of changes to GatewayClass or associated parameters.
95+
(ref. [GatewayClass API reference documentation](https://gateway-api.sigs.k8s.io/v1alpha2/references/spec/#gateway.networking.k8s.io/v1alpha2.GatewayClass))
9696

97-
For Contour, this means that after a Gateway has been provisioned, the Gateway provisioner will not apply subsequent changes to the GatewayClass/ContourDeployment to it.
97+
For Contour, this means that after a Gateway has been provisioned, the Gateway provisioner will not apply subsequent changes to the GatewayClass/ContourDeployment to it.
9898
This also means that Contour users can modify the ContourConfigurations used by their running Contours after instantiation, without having those changes overwritten by the Gateway provisioner.
9999

100100
Since the Gateway provisioner supports multiple GatewayClasses, each GatewayClass can have a different ContourDeployment reference, corresponding to different sets of Gateway configuration profiles that the infrastructure provider offers (e.g. an external vs. internal profile).
@@ -109,7 +109,7 @@ This proposal is related to, but separate from, the managed Envoy proposal:
109109
- If we don’t implement managed Envoy, then the Gateway provisioner implements the Envoy provisioning logic.
110110
- Either way, the logic needs to be implemented and live somewhere.
111111

112-
Advantages of doing managed Envoy:
112+
Advantages of doing managed Envoy:
113113
- Users who don’t want automated Gateway provisioning, but do want automated Envoy provisioning, can have it
114114
- Users who don’t want to use Gateway API can still take advantage of automated Envoy provisioning
115115
- Listener programming (combo of Envoy service + Envoy listeners) can be done in one place
@@ -122,7 +122,7 @@ Disadvantages of doing managed Envoy:
122122
We considered continuing to invest in the Contour Operator, including the Contour CRD, with an eye towards bringing it to beta and eventually GA, and implementing the Gateway provisioner within the Operator (since they would share much of the underlying logic).
123123
Our first challenge with this option is that we have failed to establish a community of contributors around the Operator, so the work would need to be done by the core Contour team of maintainers, which would detract from Contour development.
124124
Our second challenge is that we have seen and heard of only limited usage of the Operator in the wild, so it’s not clear to us that continuing to develop it is an important priority for our users.
125-
Finally, continuing to maintain the Operator in a separate repository creates development overhead, since various bits of code and configuration must be manually kept in sync between Contour and the Operator.
125+
Finally, continuing to maintain the Operator in a separate repository creates development overhead, since various bits of code and configuration must be manually kept in sync between Contour and the Operator.
126126

127127
### Alternative 2
128128
We also considered converting the existing Contour Operator into a Gateway provisioner, dropping the Contour CRD, and only supporting a Gateway API-based dynamic provisioning workflow.

internal/provisioner/model/names.go

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,9 @@ func (c *Contour) ContourRBACNames() RBACNames {
6767
Role: fmt.Sprintf("contour-%s", c.Name),
6868

6969
// this one has a different prefix to differentiate from the certgen role binding (see below).
70-
RoleBinding: fmt.Sprintf("contour-rolebinding-%s", c.Name),
70+
RoleBinding: fmt.Sprintf("contour-rolebinding-%s", c.Name),
71+
NamespaceScopedResourceRole: fmt.Sprintf("contour-resource-%s-%s", c.Namespace, c.Name),
72+
NamespaceScopedResourceRoleBinding: fmt.Sprintf("contour-resource-%s-%s", c.Namespace, c.Name),
7173
}
7274
}
7375

@@ -129,9 +131,11 @@ func (c *Contour) CommonAnnotations() map[string]string {
129131

130132
// RBACNames holds a set of names of related RBAC resources.
131133
type RBACNames struct {
132-
ServiceAccount string
133-
ClusterRole string
134-
ClusterRoleBinding string
135-
Role string
136-
RoleBinding string
134+
ServiceAccount string
135+
ClusterRole string
136+
ClusterRoleBinding string
137+
Role string
138+
RoleBinding string
139+
NamespaceScopedResourceRole string
140+
NamespaceScopedResourceRoleBinding string
137141
}

internal/provisioner/objects/rbac/rbac.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,10 @@ func ensureContourRBAC(ctx context.Context, cli client.Client, contour *model.Co
7979
ns = append(ns, contour.Namespace)
8080
}
8181
// Ensures role and rolebinding for namespaced scope resources in namespaces specified in contour.spec.watchNamespaces variable and contour's namespace
82-
if err := role.EnsureRolesInNamespaces(ctx, cli, names.Role, contour, ns); err != nil {
82+
if err := role.EnsureRolesInNamespaces(ctx, cli, names.NamespaceScopedResourceRole, contour, ns); err != nil {
8383
return fmt.Errorf("failed to ensure roles in namespace %s: %w", contour.Spec.WatchNamespaces, err)
8484
}
85-
if err := rolebinding.EnsureRoleBindingsInNamespaces(ctx, cli, names.RoleBinding, names.ServiceAccount, names.Role, contour, ns); err != nil {
85+
if err := rolebinding.EnsureRoleBindingsInNamespaces(ctx, cli, names.NamespaceScopedResourceRoleBinding, names.ServiceAccount, names.NamespaceScopedResourceRole, contour, ns); err != nil {
8686
return fmt.Errorf("failed to ensure rolebindings in namespace %s: %w", contour.Spec.WatchNamespaces, err)
8787
}
8888
}

internal/provisioner/objects/rbac/role/role.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ func EnsureControllerRole(ctx context.Context, cli client.Client, name string, c
5050
func EnsureRolesInNamespaces(ctx context.Context, cli client.Client, name string, contour *model.Contour, namespaces []string) error {
5151
errs := []error{}
5252
for _, ns := range namespaces {
53-
desired := desiredRoleForResourceInNamespace(util.ContourResourceName(name), ns, contour)
53+
desired := desiredRoleForResourceInNamespace(name, ns, contour)
5454

5555
updater := func(ctx context.Context, cli client.Client, current, desired *rbacv1.Role) error {
5656
err := updateRoleIfNeeded(ctx, cli, contour, current, desired)

internal/provisioner/objects/rbac/rolebinding/role_binding.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ import (
2121
"github.com/projectcontour/contour/internal/provisioner/labels"
2222
"github.com/projectcontour/contour/internal/provisioner/model"
2323
"github.com/projectcontour/contour/internal/provisioner/objects"
24-
"github.com/projectcontour/contour/internal/provisioner/objects/rbac/util"
2524
corev1 "k8s.io/api/core/v1"
2625
rbacv1 "k8s.io/api/rbac/v1"
2726
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -49,7 +48,7 @@ func EnsureControllerRoleBinding(ctx context.Context, cli client.Client, name, s
4948
func EnsureRoleBindingsInNamespaces(ctx context.Context, cli client.Client, name, svcAct, role string, contour *model.Contour, namespaces []string) error {
5049
errs := []error{}
5150
for _, ns := range namespaces {
52-
desired := desiredRoleBindingInNamespace(util.ContourResourceName(name), svcAct, util.ContourResourceName(role), ns, contour)
51+
desired := desiredRoleBindingInNamespace(name, svcAct, role, ns, contour)
5352

5453
// Enclose contour.
5554
updater := func(ctx context.Context, cli client.Client, current, desired *rbacv1.RoleBinding) error {

internal/provisioner/objects/rbac/util/util.go

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@
1414
package util
1515

1616
import (
17-
"fmt"
18-
1917
corev1 "k8s.io/api/core/v1"
2018
discoveryv1 "k8s.io/api/discovery/v1"
2119
networkingv1 "k8s.io/api/networking/v1"
@@ -79,8 +77,3 @@ func ClusterScopedResourcePolicyRules() []rbacv1.PolicyRule {
7977
PolicyRuleFor(corev1.GroupName, getListWatch, "namespaces"),
8078
}
8179
}
82-
83-
// ContourResourceName returns names for roles/rolebindings for contour resources
84-
func ContourResourceName(name string) string {
85-
return fmt.Sprintf("contour-resource-%s", name)
86-
}

internal/provisioner/objects/rbac/util/util_test.go

Lines changed: 0 additions & 42 deletions
This file was deleted.

test/e2e/provisioner/provisioner_test.go

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -542,7 +542,7 @@ var _ = Describe("Gateway provisioner", func() {
542542
},
543543
}, false))
544544
})
545-
Specify("A gateway with Envoy as a deployment can be provisioned, only routes in watch namespace can be reconciled", func() {
545+
Specify("A gateway can be provisioned that only reconciles routes in a subset of namespaces", func() {
546546
By("This tests deploy 3 dev namespaces testns-1, testns-2, testns-3")
547547
By("Deploy gateway that referencing above gatewayclass")
548548
gateway := &gatewayapi_v1beta1.Gateway{
@@ -620,6 +620,9 @@ var _ = Describe("Gateway provisioner", func() {
620620
if t.expectReconcile {
621621
// set route's parentRef's namespace to the gateway's namespace
622622
route.Spec.CommonRouteSpec.ParentRefs[0].Namespace = (*gatewayapi_v1.Namespace)(&namespace)
623+
// set the route's hostnames to custom name with namespace inside
624+
route.Spec.Hostnames = []gatewayapi_v1beta1.Hostname{gatewayapi_v1beta1.Hostname("provisioner.projectcontour.io." + t.namespace)}
625+
623626
By(fmt.Sprintf("Expect namespace %s to be watched by contour", t.namespace))
624627
hr, ok := f.CreateHTTPRouteAndWaitFor(route, e2e.HTTPRouteAccepted)
625628
By(fmt.Sprintf("Expect httproute under namespace %s is accepted", t.namespace))
@@ -636,15 +639,22 @@ var _ = Describe("Gateway provisioner", func() {
636639
body := f.GetEchoResponseBody(res.Body)
637640
assert.Equal(f.T(), t.namespace, body.Namespace)
638641
assert.Equal(f.T(), "echo", body.Service)
639-
640-
require.NoError(f.T(), f.DeleteHTTPRoute(route, true))
641642
} else {
642643
// Root proxy in non-watched namespace should fail
643644
By(fmt.Sprintf("Expect namespace %s not to be watched by contour", t.namespace))
644645
hr, ok := f.CreateHTTPRouteAndWaitFor(route, e2e.HTTPRouteIngnoredByContour)
645646
By(fmt.Sprintf("Expect httproute under namespace %s is not accepted", t.namespace))
646647
require.True(f.T(), ok, fmt.Sprintf("httproute's is %v", hr))
647-
require.NoError(f.T(), f.DeleteHTTPRoute(route, true))
648+
649+
By(fmt.Sprintf("Expect httproute under namespace %s is not accepted for a period of time", t.namespace))
650+
require.Never(f.T(), func() bool {
651+
r := &gatewayapi_v1beta1.HTTPRoute{}
652+
if err := f.Client.Get(context.Background(), k8s.NamespacedNameOf(hr), r); err != nil {
653+
return false
654+
}
655+
return e2e.HTTPRouteAccepted(r)
656+
}, 10*time.Second, time.Second)
657+
require.True(f.T(), ok, fmt.Sprintf("httproute's is %v", hr))
648658
}
649659
}
650660
})

0 commit comments

Comments
 (0)