Skip to content

Commit 0a39e3f

Browse files
committed
Support processing multiple HTTP listeners
Problem: The Gateway needs to process a Gateway resource. Currently, that is already supported by the 'state' package. However, that support is limited. For example, the package doesn't allow processing multiple listeners. More over, the approach used in the 'state' package is hard to extend to support multiple listeners. This prompts development of a better solution. As a first deliverable, we want to support processing multiple HTTP listeners assuming they all bind to port 80. We also assume that the Gateway only supports a single Gateway resource with known namespace and name. Solution: - Introduce a new package as a replacement of the 'state' package. - Introduce Configuration, which is an internal representation of the Gateway configuration. - Introduce Statuses, which holds status-related information about processed resources. - Introduce ChangeProcessor, which processes changes to Gateway API resources and returns new Configuration and Statuses. Note: the new package is not plugged in yet - it will be done in subsequent commits.
1 parent e6bccad commit 0a39e3f

12 files changed

+1986
-0
lines changed

internal/newstate/change_processor.go

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
package newstate
2+
3+
import (
4+
"fmt"
5+
"sync"
6+
7+
"k8s.io/apimachinery/pkg/types"
8+
"sigs.k8s.io/controller-runtime/pkg/client"
9+
"sigs.k8s.io/gateway-api/apis/v1alpha2"
10+
)
11+
12+
// ChangeProcessor processes the changes to resources producing the internal representation of the Gateway configuration.
13+
// ChangeProcessor only supports one Gateway resource.
14+
type ChangeProcessor struct {
15+
store *store
16+
changed bool
17+
gwNsName types.NamespacedName
18+
19+
lock sync.Mutex
20+
}
21+
22+
// NewChangeProcessor creates a new ChangeProcessor for the Gateway resource with the configured namespace name.
23+
func NewChangeProcessor(gwNsName types.NamespacedName) *ChangeProcessor {
24+
return &ChangeProcessor{
25+
store: newStore(),
26+
gwNsName: gwNsName,
27+
}
28+
}
29+
30+
// CaptureUpsertChange captures an upsert change to a resource.
31+
// It panics if the resource is of unsupported type or if the passed Gateway is different from the one this ChangeProcessor
32+
// was created for.
33+
func (c *ChangeProcessor) CaptureUpsertChange(obj client.Object) {
34+
c.lock.Lock()
35+
defer c.lock.Unlock()
36+
37+
c.changed = true
38+
39+
switch o := obj.(type) {
40+
case *v1alpha2.Gateway:
41+
if o.Namespace != c.gwNsName.Namespace || o.Name != c.gwNsName.Name {
42+
panic(fmt.Errorf("gateway resource must be %s/%s, got %s/%s", c.gwNsName.Namespace, c.gwNsName.Name, o.Namespace, o.Name))
43+
}
44+
c.store.gw = o
45+
case *v1alpha2.HTTPRoute:
46+
c.store.httpRoutes[getNamespacedName(obj)] = o
47+
default:
48+
panic(fmt.Errorf("ChangeProcessor doesn't support %T", obj))
49+
}
50+
}
51+
52+
// CaptureDeleteChange captures a delete change to a resource.
53+
// The method panics if the resource is of unsupported type or if the passed Gateway is different from the one this ChangeProcessor
54+
// was created for.
55+
func (c *ChangeProcessor) CaptureDeleteChange(resourceType client.Object, nsname types.NamespacedName) {
56+
c.lock.Lock()
57+
defer c.lock.Unlock()
58+
59+
c.changed = true
60+
61+
switch o := resourceType.(type) {
62+
case *v1alpha2.Gateway:
63+
if nsname != c.gwNsName {
64+
panic(fmt.Errorf("gateway resource must be %s/%s, got %s/%s", c.gwNsName.Namespace, c.gwNsName.Name, o.Namespace, o.Name))
65+
}
66+
c.store.gw = nil
67+
case *v1alpha2.HTTPRoute:
68+
delete(c.store.httpRoutes, nsname)
69+
default:
70+
panic(fmt.Errorf("ChangeProcessor doesn't support %T", resourceType))
71+
}
72+
}
73+
74+
// Process processes any captured changes and produces an internal representation of the Gateway configuration and
75+
// the status information about the processed resources.
76+
// If no changes were captured, the changed return argument will be false and both the configuration and statuses
77+
// will be empty.
78+
func (c *ChangeProcessor) Process() (changed bool, conf Configuration, statuses Statuses) {
79+
c.lock.Lock()
80+
defer c.lock.Unlock()
81+
82+
if !c.changed {
83+
return false, conf, statuses
84+
}
85+
86+
c.changed = false
87+
88+
graph := buildGraph(c.store, c.gwNsName)
89+
90+
conf = buildConfiguration(graph)
91+
statuses = buildStatuses(graph)
92+
93+
return true, conf, statuses
94+
}

0 commit comments

Comments
 (0)