Skip to content

Commit fe0175f

Browse files
authored
Support Config Generation (#71)
This commit adds a new component - Generator - for generating NGINX config.
1 parent 452af34 commit fe0175f

File tree

13 files changed

+795
-54
lines changed

13 files changed

+795
-54
lines changed

internal/events/loop.go

Lines changed: 24 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -5,28 +5,36 @@ import (
55
"fmt"
66

77
"github.com/go-logr/logr"
8+
"github.com/nginxinc/nginx-gateway-kubernetes/internal/nginx/config"
89
"github.com/nginxinc/nginx-gateway-kubernetes/internal/state"
910
"github.com/nginxinc/nginx-gateway-kubernetes/internal/status"
1011
apiv1 "k8s.io/api/core/v1"
11-
"k8s.io/apimachinery/pkg/types"
1212
"sigs.k8s.io/gateway-api/apis/v1alpha2"
1313
)
1414

1515
// EventLoop is the main event loop of the Gateway.
1616
type EventLoop struct {
1717
conf state.Configuration
1818
serviceStore state.ServiceStore
19+
generator config.Generator
1920
eventCh <-chan interface{}
2021
logger logr.Logger
2122
statusUpdater status.Updater
2223
}
2324

2425
// NewEventLoop creates a new EventLoop.
25-
func NewEventLoop(conf state.Configuration, serviceStore state.ServiceStore, eventCh <-chan interface{},
26-
statusUpdater status.Updater, logger logr.Logger) *EventLoop {
26+
func NewEventLoop(
27+
conf state.Configuration,
28+
serviceStore state.ServiceStore,
29+
generator config.Generator,
30+
eventCh <-chan interface{},
31+
statusUpdater status.Updater,
32+
logger logr.Logger,
33+
) *EventLoop {
2734
return &EventLoop{
2835
conf: conf,
2936
serviceStore: serviceStore,
37+
generator: generator,
3038
eventCh: eventCh,
3139
statusUpdater: statusUpdater,
3240
logger: logger.WithName("eventLoop"),
@@ -114,38 +122,19 @@ func (el *EventLoop) processChangesAndStatusUpdates(ctx context.Context, changes
114122
fmt.Printf("%+v\n", c)
115123

116124
if c.Op == state.Upsert {
117-
// The code below resolves service backend refs into their cluster IPs
118-
// TO-DO: this code will be removed once we have the component that generates NGINX config and
119-
// uses the ServiceStore to resolve services.
120-
for _, g := range c.Host.PathRouteGroups {
121-
for _, r := range g.Routes {
122-
for _, b := range r.Source.Spec.Rules[r.RuleIdx].BackendRefs {
123-
if b.BackendRef.Kind == nil || *b.BackendRef.Kind == "Service" {
124-
ns := r.Source.Namespace
125-
if b.BackendRef.Namespace != nil {
126-
ns = string(*b.BackendRef.Namespace)
127-
}
128-
129-
address, err := el.serviceStore.Resolve(types.NamespacedName{
130-
Namespace: ns,
131-
Name: string(b.BackendRef.Name),
132-
})
133-
134-
if err != nil {
135-
fmt.Printf("Service %s/%s error: %v\n", ns, b.BackendRef.Name, err)
136-
continue
137-
}
138-
139-
var port int32 = 80
140-
if b.BackendRef.Port != nil {
141-
port = int32(*b.BackendRef.Port)
142-
}
143-
144-
address = fmt.Sprintf("%s:%d", address, port)
145-
146-
fmt.Printf("Service %s/%s: %s\n", ns, b.BackendRef.Name, address)
147-
}
148-
}
125+
cfg, warnings := el.generator.GenerateForHost(c.Host)
126+
// TO-DO: for now, we only print the generated config, without writing it on the file system
127+
// and reloading NGINX.
128+
fmt.Println(string(cfg))
129+
130+
for obj, objWarnings := range warnings {
131+
for _, w := range objWarnings {
132+
// TO-DO: report warnings via Object status
133+
el.logger.Info("got warning while generating config",
134+
"kind", obj.GetObjectKind().GroupVersionKind().Kind,
135+
"namespace", obj.GetNamespace(),
136+
"name", obj.GetName(),
137+
"warning", w)
149138
}
150139
}
151140
}

internal/events/loop_test.go

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55

66
"github.com/nginxinc/nginx-gateway-kubernetes/internal/events"
7+
"github.com/nginxinc/nginx-gateway-kubernetes/internal/nginx/config/configfakes"
78
"github.com/nginxinc/nginx-gateway-kubernetes/internal/state"
89
"github.com/nginxinc/nginx-gateway-kubernetes/internal/state/statefakes"
910
"github.com/nginxinc/nginx-gateway-kubernetes/internal/status/statusfakes"
@@ -35,6 +36,7 @@ var _ = Describe("EventLoop", func() {
3536
var fakeConf *statefakes.FakeConfiguration
3637
var fakeUpdater *statusfakes.FakeUpdater
3738
var fakeServiceStore *statefakes.FakeServiceStore
39+
var fakeGenerator *configfakes.FakeGenerator
3840
var cancel context.CancelFunc
3941
var eventCh chan interface{}
4042
var errorCh chan error
@@ -44,7 +46,8 @@ var _ = Describe("EventLoop", func() {
4446
eventCh = make(chan interface{})
4547
fakeUpdater = &statusfakes.FakeUpdater{}
4648
fakeServiceStore = &statefakes.FakeServiceStore{}
47-
ctrl = events.NewEventLoop(fakeConf, fakeServiceStore, eventCh, fakeUpdater, zap.New())
49+
fakeGenerator = &configfakes.FakeGenerator{}
50+
ctrl = events.NewEventLoop(fakeConf, fakeServiceStore, fakeGenerator, eventCh, fakeUpdater, zap.New())
4851

4952
var ctx context.Context
5053

@@ -66,15 +69,19 @@ var _ = Describe("EventLoop", func() {
6669
})
6770

6871
It("should process upsert event", func() {
72+
fakeChanges := []state.Change{
73+
{
74+
Op: state.Upsert,
75+
Host: state.Host{},
76+
},
77+
}
6978
fakeStatusUpdates := []state.StatusUpdate{
7079
{
7180
NamespacedName: types.NamespacedName{},
7281
Status: nil,
7382
},
7483
}
75-
// for now, we pass nil, because we don't need to test how EventLoop processes changes yet. We will start
76-
// testing once we have NGINX Configuration Manager component.
77-
fakeConf.UpsertHTTPRouteReturns(nil, fakeStatusUpdates)
84+
fakeConf.UpsertHTTPRouteReturns(fakeChanges, fakeStatusUpdates)
7885

7986
hr := &v1alpha2.HTTPRoute{}
8087

@@ -87,23 +94,30 @@ var _ = Describe("EventLoop", func() {
8794
return fakeConf.UpsertHTTPRouteArgsForCall(0)
8895
}).Should(Equal(hr))
8996

90-
Eventually(fakeUpdater.ProcessStatusUpdatesCallCount()).Should(Equal(1))
97+
Eventually(fakeUpdater.ProcessStatusUpdatesCallCount).Should(Equal(1))
9198
Eventually(func() []state.StatusUpdate {
9299
_, updates := fakeUpdater.ProcessStatusUpdatesArgsForCall(0)
93100
return updates
94101
}).Should(Equal(fakeStatusUpdates))
102+
103+
Eventually(fakeGenerator.GenerateForHostCallCount).Should(Equal(1))
104+
Expect(fakeGenerator.GenerateForHostArgsForCall(0)).Should(Equal(fakeChanges[0].Host))
95105
})
96106

97107
It("should process delete event", func() {
108+
fakeChanges := []state.Change{
109+
{
110+
Op: state.Delete,
111+
Host: state.Host{},
112+
},
113+
}
98114
fakeStatusUpdates := []state.StatusUpdate{
99115
{
100116
NamespacedName: types.NamespacedName{},
101117
Status: nil,
102118
},
103119
}
104-
// for now, we pass nil, because we don't need to test how EventLoop processes changes yet. We will start
105-
// testing once we have NGINX Configuration Manager component.
106-
fakeConf.DeleteHTTPRouteReturns(nil, fakeStatusUpdates)
120+
fakeConf.DeleteHTTPRouteReturns(fakeChanges, fakeStatusUpdates)
107121

108122
nsname := types.NamespacedName{Namespace: "test", Name: "route"}
109123

@@ -117,11 +131,15 @@ var _ = Describe("EventLoop", func() {
117131
return fakeConf.DeleteHTTPRouteArgsForCall(0)
118132
}).Should(Equal(nsname))
119133

120-
Eventually(fakeUpdater.ProcessStatusUpdatesCallCount()).Should(Equal(1))
134+
Eventually(fakeUpdater.ProcessStatusUpdatesCallCount).Should(Equal(1))
121135
Eventually(func() []state.StatusUpdate {
122136
_, updates := fakeUpdater.ProcessStatusUpdatesArgsForCall(0)
123137
return updates
124138
}).Should(Equal(fakeStatusUpdates))
139+
140+
// TO-DO:
141+
// once we have a component that processes host deletion, ensure that
142+
// its corresponding method is eventually called
125143
})
126144
})
127145

internal/helpers/helpers.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,13 @@ func Diff(x, y interface{}) string {
1313
}
1414
return r
1515
}
16+
17+
// GetStringPointer takes a string and returns a pointer to it. Useful in unit tests when initializing structs.
18+
func GetStringPointer(s string) *string {
19+
return &s
20+
}
21+
22+
// GetInt32Pointer takes an int32 and returns a pointer to it. Useful in unit tests when initializing structs.
23+
func GetInt32Pointer(i int32) *int32 {
24+
return &i
25+
}

internal/manager/manager.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
gcfg "github.com/nginxinc/nginx-gateway-kubernetes/internal/implementations/gatewayconfig"
1212
hr "github.com/nginxinc/nginx-gateway-kubernetes/internal/implementations/httproute"
1313
svc "github.com/nginxinc/nginx-gateway-kubernetes/internal/implementations/service"
14+
ngxcfg "github.com/nginxinc/nginx-gateway-kubernetes/internal/nginx/config"
1415
"github.com/nginxinc/nginx-gateway-kubernetes/internal/state"
1516
"github.com/nginxinc/nginx-gateway-kubernetes/internal/status"
1617
nginxgwv1alpha1 "github.com/nginxinc/nginx-gateway-kubernetes/pkg/apis/gateway/v1alpha1"
@@ -76,7 +77,8 @@ func Start(cfg config.Config) error {
7677
conf := state.NewConfiguration(cfg.GatewayCtlrName, state.NewRealClock())
7778
serviceStore := state.NewServiceStore()
7879
reporter := status.NewUpdater(mgr.GetClient(), cfg.Logger)
79-
eventLoop := events.NewEventLoop(conf, serviceStore, eventCh, reporter, cfg.Logger)
80+
configGenerator := ngxcfg.NewGeneratorImpl(serviceStore)
81+
eventLoop := events.NewEventLoop(conf, serviceStore, configGenerator, eventCh, reporter, cfg.Logger)
8082

8183
err = mgr.Add(eventLoop)
8284
if err != nil {

internal/nginx/config/configfakes/fake_generator.go

Lines changed: 117 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)