Skip to content

Update status reporting to use new types #125

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

Merged
merged 4 commits into from
Jun 22, 2022
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
1 change: 1 addition & 0 deletions deploy/manifests/nginx-gateway.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ rules:
- gateway.networking.k8s.io
resources:
- httproutes/status
- gateways/status
verbs:
- update
---
Expand Down
12 changes: 5 additions & 7 deletions internal/events/loop.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/nginxinc/nginx-kubernetes-gateway/internal/nginx/file"
"github.com/nginxinc/nginx-kubernetes-gateway/internal/nginx/runtime"
"github.com/nginxinc/nginx-kubernetes-gateway/internal/state"
"github.com/nginxinc/nginx-kubernetes-gateway/internal/status"
)

// EventLoop is the main event loop of the Gateway.
Expand All @@ -24,6 +25,7 @@ type EventLoop struct {
logger logr.Logger
nginxFileMgr file.Manager
nginxRuntimeMgr runtime.Manager
statusUpdater status.Updater
}

// NewEventLoop creates a new EventLoop.
Expand All @@ -35,6 +37,7 @@ func NewEventLoop(
logger logr.Logger,
nginxFileMgr file.Manager,
nginxRuntimeMgr runtime.Manager,
statusUpdater status.Updater,
) *EventLoop {
return &EventLoop{
processor: processor,
Expand All @@ -44,6 +47,7 @@ func NewEventLoop(
logger: logger.WithName("eventLoop"),
nginxFileMgr: nginxFileMgr,
nginxRuntimeMgr: nginxRuntimeMgr,
statusUpdater: statusUpdater,
}
}

Expand Down Expand Up @@ -85,13 +89,7 @@ func (el *EventLoop) handleEvent(ctx context.Context, event interface{}) {
el.logger.Error(err, "Failed to update NGINX configuration")
}

// FIXME(pleshakov) Update resource statuses instead of printing to stdout
for name, s := range statuses.ListenerStatuses {
fmt.Printf("Listener %q, Statuses: %v\n", name, s)
}
for nsname, s := range statuses.HTTPRouteStatuses {
fmt.Printf("HTTPRoute %q, Statuses: %v\n", nsname, s)
}
el.statusUpdater.Update(ctx, statuses)
}

func (el *EventLoop) updateNginx(ctx context.Context, conf newstate.Configuration) error {
Expand Down
12 changes: 10 additions & 2 deletions internal/events/loop_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"github.com/nginxinc/nginx-kubernetes-gateway/internal/nginx/file/filefakes"
"github.com/nginxinc/nginx-kubernetes-gateway/internal/nginx/runtime/runtimefakes"
"github.com/nginxinc/nginx-kubernetes-gateway/internal/state/statefakes"
"github.com/nginxinc/nginx-kubernetes-gateway/internal/status/statusfakes"
)

type unsupportedResource struct {
Expand All @@ -42,6 +43,7 @@ var _ = Describe("EventLoop", func() {
fakeGenerator *configfakes.FakeGenerator
fakeNginxFimeMgr *filefakes.FakeManager
fakeNginxRuntimeMgr *runtimefakes.FakeManager
fakeStatusUpdater *statusfakes.FakeUpdater
cancel context.CancelFunc
eventCh chan interface{}
errorCh chan error
Expand All @@ -55,7 +57,8 @@ var _ = Describe("EventLoop", func() {
fakeGenerator = &configfakes.FakeGenerator{}
fakeNginxFimeMgr = &filefakes.FakeManager{}
fakeNginxRuntimeMgr = &runtimefakes.FakeManager{}
ctrl := events.NewEventLoop(fakeProcessor, fakeServiceStore, fakeGenerator, eventCh, zap.New(), fakeNginxFimeMgr, fakeNginxRuntimeMgr)
fakeStatusUpdater = &statusfakes.FakeUpdater{}
ctrl := events.NewEventLoop(fakeProcessor, fakeServiceStore, fakeGenerator, eventCh, zap.New(), fakeNginxFimeMgr, fakeNginxRuntimeMgr, fakeStatusUpdater)

var ctx context.Context
ctx, cancel = context.WithCancel(context.Background())
Expand All @@ -82,7 +85,8 @@ var _ = Describe("EventLoop", func() {
func(e *events.UpsertEvent) {
fakeConf := newstate.Configuration{}
changed := true
fakeProcessor.ProcessReturns(changed, fakeConf, newstate.Statuses{})
fakeStatuses := newstate.Statuses{}
fakeProcessor.ProcessReturns(changed, fakeConf, fakeStatuses)

fakeCfg := []byte("fake")
fakeGenerator.GenerateReturns(fakeCfg, config.Warnings{})
Expand All @@ -102,6 +106,10 @@ var _ = Describe("EventLoop", func() {
Expect(cfg).Should(Equal(fakeCfg))

Eventually(fakeNginxRuntimeMgr.ReloadCallCount).Should(Equal(1))

Eventually(fakeStatusUpdater.UpdateCallCount).Should(Equal(1))
_, statuses := fakeStatusUpdater.UpdateArgsForCall(0)
Expect(statuses).Should(Equal(fakeStatuses))
},
Entry("HTTPRoute", &events.UpsertEvent{Resource: &v1alpha2.HTTPRoute{}}),
Entry("Gateway", &events.UpsertEvent{Resource: &v1alpha2.Gateway{}}),
Expand Down
4 changes: 3 additions & 1 deletion internal/manager/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"github.com/nginxinc/nginx-kubernetes-gateway/internal/nginx/file"
ngxruntime "github.com/nginxinc/nginx-kubernetes-gateway/internal/nginx/runtime"
"github.com/nginxinc/nginx-kubernetes-gateway/internal/state"
"github.com/nginxinc/nginx-kubernetes-gateway/internal/status"
"github.com/nginxinc/nginx-kubernetes-gateway/pkg/sdk"
)

Expand Down Expand Up @@ -69,7 +70,8 @@ func Start(cfg config.Config) error {
configGenerator := ngxcfg.NewGeneratorImpl(serviceStore)
nginxFileMgr := file.NewManagerImpl()
nginxRuntimeMgr := ngxruntime.NewManagerImpl()
eventLoop := events.NewEventLoop(processor, serviceStore, configGenerator, eventCh, cfg.Logger, nginxFileMgr, nginxRuntimeMgr)
statusUpdater := status.NewUpdater(cfg.GatewayCtlrName, cfg.GatewayNsName, mgr.GetClient(), cfg.Logger, status.NewRealClock())
eventLoop := events.NewEventLoop(processor, serviceStore, configGenerator, eventCh, cfg.Logger, nginxFileMgr, nginxRuntimeMgr, statusUpdater)

err = mgr.Add(eventLoop)
if err != nil {
Expand Down
9 changes: 9 additions & 0 deletions internal/newstate/change_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,17 @@ func (c *ChangeProcessorImpl) CaptureUpsertChange(obj client.Object) {
if o.Namespace != c.gwNsName.Namespace || o.Name != c.gwNsName.Name {
panic(fmt.Errorf("gateway resource must be %s/%s, got %s/%s", c.gwNsName.Namespace, c.gwNsName.Name, o.Namespace, o.Name))
}
// if the resource spec hasn't changed (its generation is the same), ignore the upsert
if c.store.gw != nil && c.store.gw.Generation == o.Generation {
c.changed = false
}
c.store.gw = o
case *v1alpha2.HTTPRoute:
// if the resource spec hasn't changed (its generation is the same), ignore the upsert
prev, exist := c.store.httpRoutes[getNamespacedName(obj)]
if exist && o.Generation == prev.Generation {
c.changed = false
}
c.store.httpRoutes[getNamespacedName(obj)] = o
default:
panic(fmt.Errorf("ChangeProcessor doesn't support %T", obj))
Expand Down
129 changes: 124 additions & 5 deletions internal/newstate/change_processor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@ import (

var _ = Describe("ChangeProcessor", func() {
Describe("Normal cases of processing changes", func() {
var hr1, hr2 *v1alpha2.HTTPRoute
var gw *v1alpha2.Gateway
var processor newstate.ChangeProcessor
var (
hr1, hr1Updated, hr2 *v1alpha2.HTTPRoute
gw, gwUpdated *v1alpha2.Gateway
processor newstate.ChangeProcessor
)

BeforeEach(OncePerOrdered, func() {
createRoute := func(name string, hostname string) *v1alpha2.HTTPRoute {
Expand Down Expand Up @@ -54,6 +56,10 @@ var _ = Describe("ChangeProcessor", func() {
}

hr1 = createRoute("hr-1", "foo.example.com")

hr1Updated = hr1.DeepCopy()
hr1Updated.Generation++

hr2 = createRoute("hr-2", "bar.example.com")

gw = &v1alpha2.Gateway{
Expand All @@ -73,6 +79,9 @@ var _ = Describe("ChangeProcessor", func() {
},
}

gwUpdated = gw.DeepCopy()
gwUpdated.Generation++

processor = newstate.NewChangeProcessorImpl(types.NamespacedName{Namespace: "test", Name: "gateway"})
})

Expand Down Expand Up @@ -149,6 +158,116 @@ var _ = Describe("ChangeProcessor", func() {
Expect(helpers.Diff(expectedStatuses, statuses)).To(BeEmpty())
})

It("should return empty configuration and statuses after processing upserting the HTTPRoute without generation change", func() {
hr1UpdatedSameGen := hr1.DeepCopy()
// hr1UpdatedSameGen.Generation has not been changed
processor.CaptureUpsertChange(hr1UpdatedSameGen)

changed, conf, statuses := processor.Process()
Expect(changed).To(BeFalse())
Expect(conf).To(BeZero())
Expect(statuses).To(BeZero())
})

It("should return updated configuration and statuses after upserting the HTTPRoute with generation change", func() {
processor.CaptureUpsertChange(hr1Updated)

expectedConf := newstate.Configuration{
HTTPServers: []newstate.HTTPServer{
{
Hostname: "foo.example.com",
PathRules: []newstate.PathRule{
{
Path: "/",
MatchRules: []newstate.MatchRule{
{
MatchIdx: 0,
RuleIdx: 0,
Source: hr1Updated,
},
},
},
},
},
},
}
expectedStatuses := newstate.Statuses{
ListenerStatuses: map[string]newstate.ListenerStatus{
"listener-80-1": {
Valid: true,
AttachedRoutes: 1,
},
},
HTTPRouteStatuses: map[types.NamespacedName]newstate.HTTPRouteStatus{
{Namespace: "test", Name: "hr-1"}: {
ParentStatuses: map[string]newstate.ParentStatus{
"listener-80-1": {Attached: true},
},
},
},
}

changed, conf, statuses := processor.Process()
Expect(changed).To(BeTrue())
Expect(helpers.Diff(expectedConf, conf)).To(BeEmpty())
Expect(helpers.Diff(expectedStatuses, statuses)).To(BeEmpty())
})

It("should return empty configuration and statuses after processing upserting the Gateway without generation change", func() {
gwUpdatedSameGen := gw.DeepCopy()
// gwUpdatedSameGen.Generation has not been changed
processor.CaptureUpsertChange(gwUpdatedSameGen)

changed, conf, statuses := processor.Process()
Expect(changed).To(BeFalse())
Expect(conf).To(BeZero())
Expect(statuses).To(BeZero())
})

It("should return updated configuration and statuses after upserting the Gateway with generation change", func() {
processor.CaptureUpsertChange(gwUpdated)

expectedConf := newstate.Configuration{
HTTPServers: []newstate.HTTPServer{
{
Hostname: "foo.example.com",
PathRules: []newstate.PathRule{
{
Path: "/",
MatchRules: []newstate.MatchRule{
{
MatchIdx: 0,
RuleIdx: 0,
Source: hr1Updated,
},
},
},
},
},
},
}
expectedStatuses := newstate.Statuses{
ListenerStatuses: map[string]newstate.ListenerStatus{
"listener-80-1": {
Valid: true,
AttachedRoutes: 1,
},
},
HTTPRouteStatuses: map[types.NamespacedName]newstate.HTTPRouteStatus{
{Namespace: "test", Name: "hr-1"}: {
ParentStatuses: map[string]newstate.ParentStatus{
"listener-80-1": {Attached: true},
},
},
},
}

changed, conf, statuses := processor.Process()
Expect(changed).To(BeTrue())
Expect(helpers.Diff(expectedConf, conf)).To(BeEmpty())
Expect(helpers.Diff(expectedStatuses, statuses)).To(BeEmpty())
})

It("should return empty configuration and statuses after processing without capturing any changes", func() {
changed, conf, statuses := processor.Process()

Expand Down Expand Up @@ -186,7 +305,7 @@ var _ = Describe("ChangeProcessor", func() {
{
MatchIdx: 0,
RuleIdx: 0,
Source: hr1,
Source: hr1Updated,
},
},
},
Expand Down Expand Up @@ -235,7 +354,7 @@ var _ = Describe("ChangeProcessor", func() {
{
MatchIdx: 0,
RuleIdx: 0,
Source: hr1,
Source: hr1Updated,
},
},
},
Expand Down
26 changes: 26 additions & 0 deletions internal/status/clock.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package status

import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 . Clock

// Clock returns the current local time.
type Clock interface {
Now() metav1.Time
}

// Real clock returns the current local time.
type RealClock struct {
}

// NewRealClock creates a new RealClock.
func NewRealClock() *RealClock {
return &RealClock{}
}

// Now returns the current local time.
func (c *RealClock) Now() metav1.Time {
return metav1.Now()
}
Loading