generated from nginxinc/template-repository
-
Notifications
You must be signed in to change notification settings - Fork 20
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* BorderClient basics * Documentation updates * About to apply a broad rename * Rename to support library differences * Add HTTP Border Client * Add TCP Border Client * Use pointers * Synchronizer uses BorderClient * Translator extracts client type from Annotations, default when not found * Copy Paste issue, TCP Border Client need to use the *Stream methods * Fix stupid mistake in the refactor * Put an interface between NKL and the NGINX Plus client Upstream objects
- Loading branch information
Showing
24 changed files
with
753 additions
and
124 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
/* | ||
* Copyright (c) 2023 F5 Inc. All rights reserved. | ||
* Use of this source code is governed by the Apache License that can be found in the LICENSE file. | ||
*/ | ||
|
||
package application | ||
|
||
import ( | ||
"errors" | ||
"github.com/nginxinc/kubernetes-nginx-ingress/internal/core" | ||
"github.com/nginxinc/kubernetes-nginx-ingress/test/mocks" | ||
) | ||
|
||
const ( | ||
deletedEventType = core.Deleted | ||
createEventType = core.Created | ||
upstreamName = "upstreamName" | ||
server = "server" | ||
) | ||
|
||
func buildTerrorizingBorderClient(clientType string) (Interface, *mocks.MockNginxClient, error) { | ||
nginxClient := mocks.NewErroringMockClient(errors.New(`something went horribly horribly wrong`)) | ||
bc, err := NewBorderClient(clientType, nginxClient) | ||
|
||
return bc, nginxClient, err | ||
} | ||
|
||
func buildBorderClient(clientType string) (Interface, *mocks.MockNginxClient, error) { | ||
nginxClient := mocks.NewMockNginxClient() | ||
bc, err := NewBorderClient(clientType, nginxClient) | ||
|
||
return bc, nginxClient, err | ||
} | ||
|
||
func buildServerUpdateEvent(eventType core.EventType, clientType string) *core.ServerUpdateEvent { | ||
upstreamServers := core.UpstreamServers{ | ||
{ | ||
Host: server, | ||
}, | ||
} | ||
|
||
return core.NewServerUpdateEvent(eventType, upstreamName, clientType, upstreamServers) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
/* | ||
* Copyright (c) 2023 F5 Inc. All rights reserved. | ||
* Use of this source code is governed by the Apache License that can be found in the LICENSE file. | ||
*/ | ||
|
||
package application | ||
|
||
const ( | ||
ClientTypeTcp = "tcp" | ||
ClientTypeHttp = "http" | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
/* | ||
* Copyright 2023 F5 Inc. All rights reserved. | ||
* Use of this source code is governed by the Apache License that can be found in the LICENSE file. | ||
*/ | ||
|
||
package application | ||
|
||
import ( | ||
"fmt" | ||
"github.com/nginxinc/kubernetes-nginx-ingress/internal/core" | ||
"github.com/sirupsen/logrus" | ||
) | ||
|
||
type Interface interface { | ||
Update(*core.ServerUpdateEvent) error | ||
Delete(*core.ServerUpdateEvent) error | ||
} | ||
|
||
type BorderClient struct { | ||
} | ||
|
||
// NewBorderClient Returns a NullBorderClient if the type is unknown, this avoids panics due to nil pointer dereferences. | ||
func NewBorderClient(clientType string, borderClient interface{}) (Interface, error) { | ||
logrus.Debugf(`NewBorderClient for type: %s`, clientType) | ||
|
||
switch clientType { | ||
case "tcp": | ||
return NewTcpBorderClient(borderClient) | ||
|
||
case "http": | ||
return NewHttpBorderClient(borderClient) | ||
|
||
default: | ||
borderClient, _ := NewNullBorderClient() | ||
return borderClient, fmt.Errorf(`unknown border client type: %s`, clientType) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
/* | ||
* Copyright 2023 F5 Inc. All rights reserved. | ||
* Use of this source code is governed by the Apache License that can be found in the LICENSE file. | ||
*/ | ||
|
||
package application | ||
|
||
import ( | ||
"github.com/nginxinc/kubernetes-nginx-ingress/test/mocks" | ||
"testing" | ||
) | ||
|
||
func TestBorderClient_CreatesHttpBorderClient(t *testing.T) { | ||
borderClient := mocks.MockNginxClient{} | ||
client, err := NewBorderClient("http", borderClient) | ||
if err != nil { | ||
t.Errorf(`error creating border client: %v`, err) | ||
} | ||
|
||
if _, ok := client.(*HttpBorderClient); !ok { | ||
t.Errorf(`expected client to be of type HttpBorderClient`) | ||
} | ||
} | ||
|
||
func TestBorderClient_CreatesTcpBorderClient(t *testing.T) { | ||
borderClient := mocks.MockNginxClient{} | ||
client, err := NewBorderClient("tcp", borderClient) | ||
if err != nil { | ||
t.Errorf(`error creating border client: %v`, err) | ||
} | ||
|
||
if _, ok := client.(*TcpBorderClient); !ok { | ||
t.Errorf(`expected client to be of type TcpBorderClient`) | ||
} | ||
} | ||
|
||
func TestBorderClient_UnknownClientType(t *testing.T) { | ||
unknownClientType := "unknown" | ||
borderClient := mocks.MockNginxClient{} | ||
client, err := NewBorderClient(unknownClientType, borderClient) | ||
if err == nil { | ||
t.Errorf(`expected error creating border client`) | ||
} | ||
|
||
if err.Error() != `unknown border client type: unknown` { | ||
t.Errorf(`expected error to be 'unknown border client type: unknown', got: %v`, err) | ||
} | ||
|
||
if _, ok := client.(*NullBorderClient); !ok { | ||
t.Errorf(`expected client to be of type NullBorderClient`) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
/* | ||
* Copyright 2023 F5 Inc. All rights reserved. | ||
* Use of this source code is governed by the Apache License that can be found in the LICENSE file. | ||
*/ | ||
|
||
/* | ||
Package application includes support for applying updates to the Border servers. | ||
"Border TcpServers" are the servers that are exposed to the outside world and direct traffic into the cluster. | ||
At this time the only supported Border TcpServers are NGINX Plus servers. The BorderClient module defines | ||
an interface that can be implemented to support other Border Server types. | ||
- HttpBorderClient: updates NGINX Plus servers using HTTP Upstream methods on the NGINX Plus API. | ||
- TcpBorderClient: updates NGINX Plus servers using Stream Upstream methods on the NGINX Plus API. | ||
Selection of the appropriate client is based on the Annotations present on the NodePort Service definition. | ||
*/ | ||
|
||
package application |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
/* | ||
* Copyright 2023 F5 Inc. All rights reserved. | ||
* Use of this source code is governed by the Apache License that can be found in the LICENSE file. | ||
*/ | ||
|
||
package application | ||
|
||
import ( | ||
"fmt" | ||
"github.com/nginxinc/kubernetes-nginx-ingress/internal/core" | ||
nginxClient "github.com/nginxinc/nginx-plus-go-client/client" | ||
) | ||
|
||
type HttpBorderClient struct { | ||
BorderClient | ||
nginxClient NginxClientInterface | ||
} | ||
|
||
func NewHttpBorderClient(client interface{}) (Interface, error) { | ||
ngxClient, ok := client.(NginxClientInterface) | ||
if !ok { | ||
return nil, fmt.Errorf(`expected a NginxClientInterface, got a %v`, client) | ||
} | ||
|
||
return &HttpBorderClient{ | ||
nginxClient: ngxClient, | ||
}, nil | ||
} | ||
|
||
func (hbc *HttpBorderClient) Update(event *core.ServerUpdateEvent) error { | ||
httpUpstreamServers := asNginxHttpUpstreamServers(event.UpstreamServers) | ||
_, _, _, err := hbc.nginxClient.UpdateHTTPServers(event.UpstreamName, httpUpstreamServers) | ||
if err != nil { | ||
return fmt.Errorf(`error occurred updating the nginx+ upstream server: %w`, err) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (hbc *HttpBorderClient) Delete(event *core.ServerUpdateEvent) error { | ||
err := hbc.nginxClient.DeleteHTTPServer(event.UpstreamName, event.UpstreamServers[0].Host) | ||
if err != nil { | ||
return fmt.Errorf(`error occurred deleting the nginx+ upstream server: %w`, err) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func asNginxHttpUpstreamServer(server *core.UpstreamServer) nginxClient.UpstreamServer { | ||
return nginxClient.UpstreamServer{ | ||
Server: server.Host, | ||
} | ||
} | ||
|
||
func asNginxHttpUpstreamServers(servers core.UpstreamServers) []nginxClient.UpstreamServer { | ||
var upstreamServers []nginxClient.UpstreamServer | ||
|
||
for _, server := range servers { | ||
upstreamServers = append(upstreamServers, asNginxHttpUpstreamServer(server)) | ||
} | ||
|
||
return upstreamServers | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
/* | ||
* Copyright 2023 F5 Inc. All rights reserved. | ||
* Use of this source code is governed by the Apache License that can be found in the LICENSE file. | ||
*/ | ||
|
||
package application | ||
|
||
import ( | ||
"testing" | ||
) | ||
|
||
func TestHttpBorderClient_Delete(t *testing.T) { | ||
event := buildServerUpdateEvent(deletedEventType, ClientTypeHttp) | ||
borderClient, nginxClient, err := buildBorderClient(ClientTypeHttp) | ||
if err != nil { | ||
t.Fatalf(`error occurred creating a new border client: %v`, err) | ||
} | ||
|
||
err = borderClient.Delete(event) | ||
if err != nil { | ||
t.Fatalf(`error occurred deleting the nginx+ upstream server: %v`, err) | ||
} | ||
|
||
if !nginxClient.CalledFunctions["DeleteHTTPServer"] { | ||
t.Fatalf(`expected DeleteHTTPServer to be called`) | ||
} | ||
} | ||
|
||
func TestHttpBorderClient_Update(t *testing.T) { | ||
event := buildServerUpdateEvent(createEventType, ClientTypeHttp) | ||
borderClient, nginxClient, err := buildBorderClient(ClientTypeHttp) | ||
if err != nil { | ||
t.Fatalf(`error occurred creating a new border client: %v`, err) | ||
} | ||
|
||
err = borderClient.Update(event) | ||
if err != nil { | ||
t.Fatalf(`error occurred deleting the nginx+ upstream server: %v`, err) | ||
} | ||
|
||
if !nginxClient.CalledFunctions["UpdateHTTPServers"] { | ||
t.Fatalf(`expected UpdateHTTPServers to be called`) | ||
} | ||
} | ||
|
||
func TestHttpBorderClient_BadNginxClient(t *testing.T) { | ||
var emptyInterface interface{} | ||
_, err := NewBorderClient(ClientTypeHttp, emptyInterface) | ||
if err == nil { | ||
t.Fatalf(`expected an error to occur when creating a new border client`) | ||
} | ||
} | ||
|
||
func TestHttpBorderClient_DeleteReturnsError(t *testing.T) { | ||
event := buildServerUpdateEvent(deletedEventType, ClientTypeHttp) | ||
borderClient, _, err := buildTerrorizingBorderClient(ClientTypeHttp) | ||
if err != nil { | ||
t.Fatalf(`error occurred creating a new border client: %v`, err) | ||
} | ||
|
||
err = borderClient.Delete(event) | ||
|
||
if err == nil { | ||
t.Fatalf(`expected an error to occur when deleting the nginx+ upstream server`) | ||
} | ||
} | ||
|
||
func TestHttpBorderClient_UpdateReturnsError(t *testing.T) { | ||
event := buildServerUpdateEvent(createEventType, ClientTypeHttp) | ||
borderClient, _, err := buildTerrorizingBorderClient(ClientTypeHttp) | ||
if err != nil { | ||
t.Fatalf(`error occurred creating a new border client: %v`, err) | ||
} | ||
|
||
err = borderClient.Update(event) | ||
|
||
if err == nil { | ||
t.Fatalf(`expected an error to occur when deleting the nginx+ upstream server`) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
/* | ||
* Copyright (c) 2023 F5 Inc. All rights reserved. | ||
* Use of this source code is governed by the Apache License that can be found in the LICENSE file. | ||
*/ | ||
|
||
package application | ||
|
||
import nginxClient "github.com/nginxinc/nginx-plus-go-client/client" | ||
|
||
type NginxClientInterface interface { | ||
DeleteStreamServer(upstream string, server string) error | ||
UpdateStreamServers(upstream string, servers []nginxClient.StreamUpstreamServer) ([]nginxClient.StreamUpstreamServer, []nginxClient.StreamUpstreamServer, []nginxClient.StreamUpstreamServer, error) | ||
|
||
DeleteHTTPServer(upstream string, server string) error | ||
UpdateHTTPServers(upstream string, servers []nginxClient.UpstreamServer) ([]nginxClient.UpstreamServer, []nginxClient.UpstreamServer, []nginxClient.UpstreamServer, error) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
/* | ||
* Copyright (c) 2023 F5 Inc. All rights reserved. | ||
* Use of this source code is governed by the Apache License that can be found in the LICENSE file. | ||
*/ | ||
|
||
package application | ||
|
||
import ( | ||
"github.com/nginxinc/kubernetes-nginx-ingress/internal/core" | ||
"github.com/sirupsen/logrus" | ||
) | ||
|
||
type NullBorderClient struct { | ||
} | ||
|
||
func NewNullBorderClient() (Interface, error) { | ||
return &NullBorderClient{}, nil | ||
} | ||
|
||
func (nbc *NullBorderClient) Update(_ *core.ServerUpdateEvent) error { | ||
logrus.Warn("NullBorderClient.Update called") | ||
return nil | ||
} | ||
|
||
func (nbc *NullBorderClient) Delete(_ *core.ServerUpdateEvent) error { | ||
logrus.Warn("NullBorderClient.Delete called") | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
/* | ||
* Copyright (c) 2023 F5 Inc. All rights reserved. | ||
* Use of this source code is governed by the Apache License that can be found in the LICENSE file. | ||
*/ | ||
|
||
package application | ||
|
||
import "testing" | ||
|
||
func TestNullBorderClient_Delete(t *testing.T) { | ||
client := NullBorderClient{} | ||
err := client.Delete(nil) | ||
if err != nil { | ||
t.Errorf(`expected no error deleting border client, got: %v`, err) | ||
} | ||
} | ||
|
||
func TestNullBorderClient_Update(t *testing.T) { | ||
client := NullBorderClient{} | ||
err := client.Update(nil) | ||
if err != nil { | ||
t.Errorf(`expected no error updating border client, got: %v`, err) | ||
} | ||
} |
Oops, something went wrong.