Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
2 changes: 1 addition & 1 deletion build/Dockerfile.nginx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ WORKDIR /tmp
RUN apk add --no-cache git make \
&& git clone https://github.com/nginx/agent.git \
&& cd agent \
&& git checkout e745a3236e0f02a579461a5a435b3bcd410a686c \
&& git checkout 9b574fa90848c9a7c123e6e7e6153ccd602ae724 \
&& make build

FROM nginx:1.28.0-alpine-otel
Expand Down
2 changes: 1 addition & 1 deletion build/Dockerfile.nginxplus
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ WORKDIR /tmp
RUN apk add --no-cache git make \
&& git clone https://github.com/nginx/agent.git \
&& cd agent \
&& git checkout e745a3236e0f02a579461a5a435b3bcd410a686c \
&& git checkout 9b574fa90848c9a7c123e6e7e6153ccd602ae724 \
&& make build

FROM alpine:3.21
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ require (
github.com/go-logr/logr v1.4.2
github.com/google/go-cmp v0.7.0
github.com/google/uuid v1.6.0
github.com/nginx/agent/v3 v3.0.0-20250513105855-e745a3236e0f
github.com/nginx/agent/v3 v3.0.0-20250520100419-9b574fa90848
github.com/nginx/telemetry-exporter v0.1.4
github.com/onsi/ginkgo/v2 v2.23.4
github.com/onsi/gomega v1.37.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,8 @@ github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/nginx/agent/v3 v3.0.0-20250513105855-e745a3236e0f h1:fSUAaR1AxmmbmGMRkvKGY2+LhuVpBp7tbBFLLgDMjNQ=
github.com/nginx/agent/v3 v3.0.0-20250513105855-e745a3236e0f/go.mod h1:O/31aKtii/mpiZmFGMcTNDoLtKzwTyTXOBMSRkMaPvs=
github.com/nginx/agent/v3 v3.0.0-20250520100419-9b574fa90848 h1:BZ5WY30Ojw/+/SmmvsdbM7SXuEpUy9zgBkuMSVet540=
github.com/nginx/agent/v3 v3.0.0-20250520100419-9b574fa90848/go.mod h1:O/31aKtii/mpiZmFGMcTNDoLtKzwTyTXOBMSRkMaPvs=
github.com/nginx/telemetry-exporter v0.1.4 h1:3ikgKlyz/O57oaBLkxCInMjr74AhGTKr9rHdRAkkl/w=
github.com/nginx/telemetry-exporter v0.1.4/go.mod h1:bl6qmsxgk4a9D0X8R5E3sUNXN2iECPEK1JNbRLhN5C4=
github.com/nginxinc/nginx-plus-go-client/v2 v2.0.1 h1:5VVK38bnELMDWnwfF6dSv57ResXh9AUzeDa72ENj94o=
Expand Down
6 changes: 3 additions & 3 deletions internal/mode/static/nginx/agent/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -522,9 +522,9 @@ func getNginxInstanceID(instances []*pb.Instance) string {
}

// UpdateDataPlaneHealth includes full health information about the data plane as reported by the agent.
func (cs *commandService) UpdateDataPlaneHealth(
_ context.Context,
_ *pb.UpdateDataPlaneHealthRequest,
func (*commandService) UpdateDataPlaneHealth(
context.Context,
*pb.UpdateDataPlaneHealthRequest,
) (*pb.UpdateDataPlaneHealthResponse, error) {
return &pb.UpdateDataPlaneHealthResponse{}, nil
}
121 changes: 99 additions & 22 deletions internal/mode/static/nginx/agent/file.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package agent

import (
"bytes"
"context"
"math"

"github.com/go-logr/logr"
pb "github.com/nginx/agent/v3/api/grpc/mpi/v1"
"github.com/nginx/agent/v3/pkg/files"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
Expand All @@ -13,6 +16,8 @@
grpcContext "github.com/nginx/nginx-gateway-fabric/internal/mode/static/nginx/agent/grpc/context"
)

const defaultChunkSize uint32 = 2097152 // 2MB

// File is an nginx configuration file that the nginx agent gets from the control plane
// after a ConfigApplyRequest.
type File struct {
Expand Down Expand Up @@ -51,15 +56,83 @@
ctx context.Context,
req *pb.GetFileRequest,
) (*pb.GetFileResponse, error) {
filename := req.GetFileMeta().GetName()
hash := req.GetFileMeta().GetHash()

gi, ok := grpcContext.GrpcInfoFromContext(ctx)
if !ok {
return nil, agentgrpc.ErrStatusInvalidConnection
}

conn := fs.connTracker.GetConnection(gi.IPAddress)
if req.GetFileMeta() == nil {
return nil, status.Error(codes.InvalidArgument, "invalid request")
}

contents, err := fs.getFileContents(req, gi.IPAddress)
if err != nil {
return nil, err
}

return &pb.GetFileResponse{
Contents: &pb.FileContents{
Contents: contents,
},
}, nil
}

// GetFileStream is called by the agent when it needs to download a file in chunks for a ConfigApplyRequest.
// The deployment object used to get the files is already LOCKED when this function is called,
// before the ConfigApply transaction is started.
func (fs *fileService) GetFileStream(
req *pb.GetFileRequest,
server grpc.ServerStreamingServer[pb.FileDataChunk],
) error {
gi, ok := grpcContext.GrpcInfoFromContext(server.Context())
if !ok {
return agentgrpc.ErrStatusInvalidConnection
}

if req.GetFileMeta() == nil || req.GetMessageMeta() == nil {
return status.Error(codes.InvalidArgument, "invalid request")
}

contents, err := fs.getFileContents(req, gi.IPAddress)
if err != nil {
return err
}

Check warning on line 99 in internal/mode/static/nginx/agent/file.go

View check run for this annotation

Codecov / codecov/patch

internal/mode/static/nginx/agent/file.go#L98-L99

Added lines #L98 - L99 were not covered by tests

size := req.GetFileMeta().GetSize()
var sizeUint32 uint32
if size > math.MaxUint32 {
return status.Error(codes.Internal, "file size is too large and cannot be converted to uint32")
}

Check warning on line 105 in internal/mode/static/nginx/agent/file.go

View check run for this annotation

Codecov / codecov/patch

internal/mode/static/nginx/agent/file.go#L104-L105

Added lines #L104 - L105 were not covered by tests
sizeUint32 = uint32(size) //nolint:gosec // validation check performed on previous line
hash := req.GetFileMeta().GetHash()

fs.logger.V(1).Info("Sending chunked file to agent", "file", req.GetFileMeta().GetName())

if err := files.SendChunkedFile(
req.GetMessageMeta(),
pb.FileDataChunk_Header{
Header: &pb.FileDataChunkHeader{
ChunkSize: defaultChunkSize,
Chunks: calculateChunks(sizeUint32, defaultChunkSize),
FileMeta: &pb.FileMeta{
Name: req.GetFileMeta().GetName(),
Hash: hash,
Permissions: req.GetFileMeta().GetPermissions(),
Size: size,
},
},
},
bytes.NewReader(contents),
server,
); err != nil {
return status.Error(codes.Aborted, err.Error())
}

Check warning on line 129 in internal/mode/static/nginx/agent/file.go

View check run for this annotation

Codecov / codecov/patch

internal/mode/static/nginx/agent/file.go#L128-L129

Added lines #L128 - L129 were not covered by tests

return nil
}

func (fs *fileService) getFileContents(req *pb.GetFileRequest, connKey string) ([]byte, error) {
conn := fs.connTracker.GetConnection(connKey)
if conn.PodName == "" {
return nil, status.Errorf(codes.NotFound, "connection not found")
}
Expand All @@ -69,43 +142,47 @@
return nil, status.Errorf(codes.NotFound, "deployment not found in store")
}

contents := deployment.GetFile(filename, hash)
filename := req.GetFileMeta().GetName()
contents := deployment.GetFile(filename, req.GetFileMeta().GetHash())
if len(contents) == 0 {
return nil, status.Errorf(codes.NotFound, "file not found")
}

fs.logger.V(1).Info("Getting file for agent", "file", filename)

return &pb.GetFileResponse{
Contents: &pb.FileContents{
Contents: contents,
},
}, nil
return contents, nil
}

func calculateChunks(fileSize uint32, chunkSize uint32) uint32 {
remainder, divide := fileSize%chunkSize, fileSize/chunkSize
if remainder > 0 {
return divide + 1
}
// if fileSize is divisible by chunkSize without remainder
// then we don't need the extra chunk for the remainder
return divide

Check warning on line 163 in internal/mode/static/nginx/agent/file.go

View check run for this annotation

Codecov / codecov/patch

internal/mode/static/nginx/agent/file.go#L163

Added line #L163 was not covered by tests
}

// GetOverview gets the overview of files for a particular configuration version of an instance.
// At the moment it doesn't appear to be used by the agent.
func (fs *fileService) GetOverview(
_ context.Context,
_ *pb.GetOverviewRequest,
) (*pb.GetOverviewResponse, error) {
func (*fileService) GetOverview(context.Context, *pb.GetOverviewRequest) (*pb.GetOverviewResponse, error) {
return &pb.GetOverviewResponse{}, nil
}

// UpdateOverview is called by agent on startup and whenever any files change on the instance.
// Since directly changing nginx configuration on the instance is not supported, this is a no-op for NGF.
func (fs *fileService) UpdateOverview(
_ context.Context,
_ *pb.UpdateOverviewRequest,
) (*pb.UpdateOverviewResponse, error) {
func (*fileService) UpdateOverview(context.Context, *pb.UpdateOverviewRequest) (*pb.UpdateOverviewResponse, error) {
return &pb.UpdateOverviewResponse{}, nil
}

// UpdateFile is called by agent whenever any files change on the instance.
// Since directly changing nginx configuration on the instance is not supported, this is a no-op for NGF.
func (fs *fileService) UpdateFile(
_ context.Context,
_ *pb.UpdateFileRequest,
) (*pb.UpdateFileResponse, error) {
func (*fileService) UpdateFile(context.Context, *pb.UpdateFileRequest) (*pb.UpdateFileResponse, error) {
return &pb.UpdateFileResponse{}, nil
}

// UpdateFileStream is called by agent whenever any files change on the instance.
// Since directly changing nginx configuration on the instance is not supported, this is a no-op for NGF.
func (*fileService) UpdateFileStream(grpc.ClientStreamingServer[pb.FileDataChunk, pb.UpdateFileResponse]) error {
return nil
}
Loading
Loading