Skip to content
This repository was archived by the owner on Aug 22, 2025. It is now read-only.
Prev Previous commit
Next Next commit
Add HTTP Border Client
  • Loading branch information
ciroque committed Mar 31, 2023
commit 0458c6bd75d057df2a1a5303afbd716e796c96e8
2 changes: 1 addition & 1 deletion internal/application/http_border_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ func (hbc *HttpBorderClient) Update(event core.ServerUpdateEvent) error {
}

func (hbc *HttpBorderClient) Delete(event core.ServerUpdateEvent) error {
err := hbc.nginxClient.DeleteHTTPServer(event.NginxHost, event.TcpServers[0].Server) // TODO: SW: This needs to be HttpServers not TcpServers
err := hbc.nginxClient.DeleteHTTPServer(event.NginxHost, event.HttpServers[0].Server)
if err != nil {
return fmt.Errorf(`error occurred deleting the nginx+ upstream server: %w`, err)
}
Expand Down
78 changes: 60 additions & 18 deletions internal/application/http_border_client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
package application

import (
"errors"
"github.com/nginxinc/kubernetes-nginx-ingress/internal/core"
"github.com/nginxinc/kubernetes-nginx-ingress/test/mocks"
nginxClient2 "github.com/nginxinc/nginx-plus-go-client/client"
Expand All @@ -20,20 +21,16 @@ const (
server = "server"
)

var emptyStreamServers = []nginxClient2.StreamUpstreamServer{}

func TestHttpBorderClient_Delete(t *testing.T) {
servers := []nginxClient2.StreamUpstreamServer{
{
Server: server,
},
}
event := core.NewServerUpdateEvent(deletedEventType, upstreamName, servers)
nginxClient := mocks.NewMockNginxClient()
borderClient, err := NewBorderClient(clientType, nginxClient)
event := buildServerUpdateEvent(deletedEventType)
borderClient, nginxClient, err := buildBorderClient()
if err != nil {
t.Fatalf(`error occurred creating a new border client: %v`, err)
}

err = borderClient.Delete(*event)
err = borderClient.Delete(event)
if err != nil {
t.Fatalf(`error occurred deleting the nginx+ upstream server: %v`, err)
}
Expand All @@ -44,19 +41,13 @@ func TestHttpBorderClient_Delete(t *testing.T) {
}

func TestHttpBorderClient_Update(t *testing.T) {
servers := []nginxClient2.StreamUpstreamServer{
{
Server: server,
},
}
event := core.NewServerUpdateEvent(deletedEventType, upstreamName, servers)
nginxClient := mocks.NewMockNginxClient()
borderClient, err := NewBorderClient(clientType, nginxClient)
event := buildServerUpdateEvent(createEventType)
borderClient, nginxClient, err := buildBorderClient()
if err != nil {
t.Fatalf(`error occurred creating a new border client: %v`, err)
}

err = borderClient.Update(*event)
err = borderClient.Update(event)
if err != nil {
t.Fatalf(`error occurred deleting the nginx+ upstream server: %v`, err)
}
Expand All @@ -73,3 +64,54 @@ func TestHttpBorderClient_BadNginxClient(t *testing.T) {
t.Fatalf(`expected an error to occur when creating a new border client`)
}
}

func TestHttpBorderClient_DeleteReturnsError(t *testing.T) {
event := buildServerUpdateEvent(deletedEventType)
borderClient, _, err := buildTerrorizingBorderClient()
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)
borderClient, _, err := buildTerrorizingBorderClient()
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`)
}
}

func buildTerrorizingBorderClient() (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() (Interface, *mocks.MockNginxClient, error) {
nginxClient := mocks.NewMockNginxClient()
bc, err := NewBorderClient(clientType, nginxClient)

return bc, nginxClient, err
}

func buildServerUpdateEvent(eventType core.EventType) core.ServerUpdateEvent {
servers := []nginxClient2.UpstreamServer{
{
Server: server,
},
}
return *core.NewServerUpdateEvent(eventType, upstreamName, emptyStreamServers, servers)
}
6 changes: 4 additions & 2 deletions internal/core/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,12 @@ func NewEvent(eventType EventType, service *v1.Service, previousService *v1.Serv
}
}

func NewServerUpdateEvent(eventType EventType, upstreamName string, servers []nginxClient.StreamUpstreamServer) *ServerUpdateEvent {
func NewServerUpdateEvent(eventType EventType, upstreamName string, tcpServers []nginxClient.StreamUpstreamServer, httpServers []nginxClient.UpstreamServer) *ServerUpdateEvent {
return &ServerUpdateEvent{
Type: eventType,
UpstreamName: upstreamName,
TcpServers: servers,
TcpServers: tcpServers,
HttpServers: httpServers,
}
}

Expand All @@ -60,6 +61,7 @@ func ServerUpdateEventWithIdAndHost(event *ServerUpdateEvent, id string, nginxHo
Type: event.Type,
UpstreamName: event.UpstreamName,
TcpServers: event.TcpServers,
HttpServers: event.HttpServers,
}
}

Expand Down
13 changes: 8 additions & 5 deletions internal/core/events_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,11 @@ import (
"testing"
)

var emptyStreamServers []nginxClient.StreamUpstreamServer
var emptyHttpServers []nginxClient.UpstreamServer

func TestServerUpdateEventWithIdAndHost(t *testing.T) {
event := NewServerUpdateEvent(Created, "upstream", []nginxClient.StreamUpstreamServer{})
event := NewServerUpdateEvent(Created, "upstream", emptyStreamServers, emptyHttpServers)

if event.Id != "" {
t.Errorf("expected empty Id, got %s", event.Id)
Expand All @@ -33,31 +36,31 @@ func TestServerUpdateEventWithIdAndHost(t *testing.T) {
}

func TestTypeNameCreated(t *testing.T) {
event := NewServerUpdateEvent(Created, "upstream", []nginxClient.StreamUpstreamServer{})
event := NewServerUpdateEvent(Created, "upstream", emptyStreamServers, emptyHttpServers)

if event.TypeName() != "Created" {
t.Errorf("expected 'Created', got %s", event.TypeName())
}
}

func TestTypeNameUpdated(t *testing.T) {
event := NewServerUpdateEvent(Updated, "upstream", []nginxClient.StreamUpstreamServer{})
event := NewServerUpdateEvent(Updated, "upstream", emptyStreamServers, emptyHttpServers)

if event.TypeName() != "Updated" {
t.Errorf("expected 'Updated', got %s", event.TypeName())
}
}

func TestTypeNameDeleted(t *testing.T) {
event := NewServerUpdateEvent(Deleted, "upstream", []nginxClient.StreamUpstreamServer{})
event := NewServerUpdateEvent(Deleted, "upstream", emptyStreamServers, emptyHttpServers)

if event.TypeName() != "Deleted" {
t.Errorf("expected 'Deleted', got %s", event.TypeName())
}
}

func TestTypeNameUnknown(t *testing.T) {
event := NewServerUpdateEvent(EventType(100), "upstream", []nginxClient.StreamUpstreamServer{})
event := NewServerUpdateEvent(EventType(100), "upstream", emptyStreamServers, emptyHttpServers)

if event.TypeName() != "Unknown" {
t.Errorf("expected 'Unknown', got %s", event.TypeName())
Expand Down
23 changes: 17 additions & 6 deletions internal/translation/translator.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,17 +45,24 @@ func buildServerUpdateEvents(ports []v1.ServicePort, event *core.Event) (core.Se
events := core.ServerUpdateEvents{}
for _, port := range ports {
ingressName := fixIngressName(port.Name)
servers, _ := buildServers(event.NodeIps, port)
tcpServers, _ := buildTcpServers(event.NodeIps, port)
httpServers, _ := buildHttpServers(event.NodeIps, port)

switch event.Type {
case core.Created:
fallthrough

case core.Updated:
events = append(events, core.NewServerUpdateEvent(event.Type, ingressName, servers))
case core.Deleted:
for _, server := range servers {
events = append(events, core.NewServerUpdateEvent(event.Type, ingressName, []nginxClient.StreamUpstreamServer{server}))
events = append(events, core.NewServerUpdateEvent(event.Type, ingressName, tcpServers, httpServers))

case core.Deleted: // TODO: SW: This will be interesting, need to distinguish between a TCP and HTTP target
for _, server := range tcpServers {
events = append(events, core.NewServerUpdateEvent(event.Type, ingressName, []nginxClient.StreamUpstreamServer{server}, httpServers))
}
for _, server := range httpServers {
events = append(events, core.NewServerUpdateEvent(event.Type, ingressName, tcpServers, []nginxClient.UpstreamServer{server}))
}

default:
logrus.Warnf(`Translator::buildServerUpdateEvents: unknown event type: %d`, event.Type)
}
Expand All @@ -65,7 +72,11 @@ func buildServerUpdateEvents(ports []v1.ServicePort, event *core.Event) (core.Se
return events, nil
}

func buildServers(nodeIps []string, port v1.ServicePort) ([]nginxClient.StreamUpstreamServer, error) {
func buildHttpServers(_ []string, _ v1.ServicePort) ([]nginxClient.UpstreamServer, error) {
return []nginxClient.UpstreamServer{}, nil
}

func buildTcpServers(nodeIps []string, port v1.ServicePort) ([]nginxClient.StreamUpstreamServer, error) {
var servers []nginxClient.StreamUpstreamServer

for _, nodeIp := range nodeIps {
Expand Down
37 changes: 33 additions & 4 deletions test/mocks/mock_nginx_plus_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,30 +9,59 @@ import nginxClient "github.com/nginxinc/nginx-plus-go-client/client"

type MockNginxClient struct {
CalledFunctions map[string]bool
Error error
}

func NewMockNginxClient() *MockNginxClient {
return &MockNginxClient{
CalledFunctions: make(map[string]bool),
Error: nil,
}
}

func (m MockNginxClient) DeleteStreamServer(upstream string, server string) error {
func NewErroringMockClient(err error) *MockNginxClient {
return &MockNginxClient{
CalledFunctions: make(map[string]bool),
Error: err,
}
}

func (m MockNginxClient) DeleteStreamServer(_ string, _ string) error {
m.CalledFunctions["DeleteStreamServer"] = true

if m.Error != nil {
return m.Error
}

return nil
}

func (m MockNginxClient) UpdateStreamServers(upstream string, servers []nginxClient.StreamUpstreamServer) ([]nginxClient.StreamUpstreamServer, []nginxClient.StreamUpstreamServer, []nginxClient.StreamUpstreamServer, error) {
func (m MockNginxClient) UpdateStreamServers(_ string, _ []nginxClient.StreamUpstreamServer) ([]nginxClient.StreamUpstreamServer, []nginxClient.StreamUpstreamServer, []nginxClient.StreamUpstreamServer, error) {
m.CalledFunctions["UpdateStreamServers"] = true

if m.Error != nil {
return nil, nil, nil, m.Error
}

return nil, nil, nil, nil
}

func (m MockNginxClient) DeleteHTTPServer(upstream string, server string) error {
func (m MockNginxClient) DeleteHTTPServer(_ string, _ string) error {
m.CalledFunctions["DeleteHTTPServer"] = true

if m.Error != nil {
return m.Error
}

return nil
}

func (m MockNginxClient) UpdateHTTPServers(upstream string, servers []nginxClient.UpstreamServer) ([]nginxClient.UpstreamServer, []nginxClient.UpstreamServer, []nginxClient.UpstreamServer, error) {
func (m MockNginxClient) UpdateHTTPServers(_ string, _ []nginxClient.UpstreamServer) ([]nginxClient.UpstreamServer, []nginxClient.UpstreamServer, []nginxClient.UpstreamServer, error) {
m.CalledFunctions["UpdateHTTPServers"] = true

if m.Error != nil {
return nil, nil, nil, m.Error
}

return nil, nil, nil, nil
}