From 3b61e6971e3e3d33e11caac78c2ee189089abdb8 Mon Sep 17 00:00:00 2001 From: Saylor Berman Date: Tue, 13 May 2025 14:40:05 -0600 Subject: [PATCH] Support sending chunked files to agent Problem: If nginx.conf files are too large, they can't be sent over the existing gRPC stream to agent. Solution: Agent has added an API and helper function to send files in chunks if over a certain size limit. Our controller will implement this API for agent to call when in this condition. --- build/Dockerfile.nginx | 2 +- build/Dockerfile.nginxplus | 2 +- go.mod | 2 +- go.sum | 4 +- internal/mode/static/nginx/agent/command.go | 6 +- internal/mode/static/nginx/agent/file.go | 121 +++++++++-- internal/mode/static/nginx/agent/file_test.go | 203 +++++++++++++++++- .../mode/static/nginx/config/generator.go | 4 + .../static/nginx/config/generator_test.go | 1 + .../mode/static/nginx/config/main_config.go | 5 + 10 files changed, 310 insertions(+), 40 deletions(-) diff --git a/build/Dockerfile.nginx b/build/Dockerfile.nginx index 3d5dc24241..8d22987895 100644 --- a/build/Dockerfile.nginx +++ b/build/Dockerfile.nginx @@ -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 diff --git a/build/Dockerfile.nginxplus b/build/Dockerfile.nginxplus index 2c7d7452aa..84ee8993cd 100644 --- a/build/Dockerfile.nginxplus +++ b/build/Dockerfile.nginxplus @@ -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 diff --git a/go.mod b/go.mod index 9215baaf31..349a10a03f 100644 --- a/go.mod +++ b/go.mod @@ -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 diff --git a/go.sum b/go.sum index 58dbc0d4bd..4cb6a4da10 100644 --- a/go.sum +++ b/go.sum @@ -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= diff --git a/internal/mode/static/nginx/agent/command.go b/internal/mode/static/nginx/agent/command.go index 8f694e581d..a8b2ba849d 100644 --- a/internal/mode/static/nginx/agent/command.go +++ b/internal/mode/static/nginx/agent/command.go @@ -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 } diff --git a/internal/mode/static/nginx/agent/file.go b/internal/mode/static/nginx/agent/file.go index fa604bc16b..17fac0a9ed 100644 --- a/internal/mode/static/nginx/agent/file.go +++ b/internal/mode/static/nginx/agent/file.go @@ -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" @@ -13,6 +16,8 @@ import ( 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 { @@ -51,15 +56,83 @@ func (fs *fileService) GetFile( 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 + } + + 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") + } + 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()) + } + + 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") } @@ -69,43 +142,47 @@ func (fs *fileService) GetFile( 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 } // 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 +} diff --git a/internal/mode/static/nginx/agent/file_test.go b/internal/mode/static/nginx/agent/file_test.go index 1e683eb214..22f8f4d964 100644 --- a/internal/mode/static/nginx/agent/file_test.go +++ b/internal/mode/static/nginx/agent/file_test.go @@ -7,6 +7,7 @@ import ( "github.com/go-logr/logr" pb "github.com/nginx/agent/v3/api/grpc/mpi/v1" . "github.com/onsi/gomega" + "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" "k8s.io/apimachinery/pkg/types" @@ -16,6 +17,24 @@ import ( agentgrpcfakes "github.com/nginx/nginx-gateway-fabric/internal/mode/static/nginx/agent/grpc/grpcfakes" ) +type mockServerStreamingServer struct { + grpc.ServerStream + ctx context.Context + sentChunks []*pb.FileDataChunk +} + +func (m *mockServerStreamingServer) Send(chunk *pb.FileDataChunk) error { + m.sentChunks = append(m.sentChunks, chunk) + + return nil +} + +func (m *mockServerStreamingServer) Context() context.Context { return m.ctx } + +func newMockServerStreamingServer(ctx context.Context) *mockServerStreamingServer { + return &mockServerStreamingServer{ctx: ctx} +} + func TestGetFile(t *testing.T) { t.Parallel() g := NewWithT(t) @@ -31,7 +50,7 @@ func TestGetFile(t *testing.T) { connTracker.GetConnectionReturns(conn) depStore := NewDeploymentStore(connTracker) - dep := depStore.GetOrStore(context.Background(), deploymentName, nil) + dep := depStore.GetOrStore(t.Context(), deploymentName, nil) fileMeta := &pb.FileMeta{ Name: "test.conf", @@ -48,7 +67,7 @@ func TestGetFile(t *testing.T) { fs := newFileService(logr.Discard(), depStore, connTracker) - ctx := grpcContext.NewGrpcContext(context.Background(), grpcContext.GrpcInfo{ + ctx := grpcContext.NewGrpcContext(t.Context(), grpcContext.GrpcInfo{ IPAddress: "127.0.0.1", }) @@ -77,12 +96,44 @@ func TestGetFile_InvalidConnection(t *testing.T) { }, } - resp, err := fs.GetFile(context.Background(), req) + resp, err := fs.GetFile(t.Context(), req) g.Expect(err).To(Equal(agentgrpc.ErrStatusInvalidConnection)) g.Expect(resp).To(BeNil()) } +func TestGetFile_InvalidRequest(t *testing.T) { + t.Parallel() + g := NewWithT(t) + + deploymentName := types.NamespacedName{Name: "nginx-deployment", Namespace: "default"} + connTracker := &agentgrpcfakes.FakeConnectionsTracker{} + conn := agentgrpc.Connection{ + PodName: "nginx-pod", + InstanceID: "12345", + Parent: deploymentName, + } + connTracker.GetConnectionReturns(conn) + + depStore := NewDeploymentStore(connTracker) + _ = depStore.GetOrStore(t.Context(), deploymentName, nil) + + fs := newFileService(logr.Discard(), depStore, connTracker) + + ctx := grpcContext.NewGrpcContext(t.Context(), grpcContext.GrpcInfo{ + IPAddress: "127.0.0.1", + }) + + req := &pb.GetFileRequest{ + FileMeta: nil, + } + + resp, err := fs.GetFile(ctx, req) + + g.Expect(err).To(Equal(status.Error(codes.InvalidArgument, "invalid request"))) + g.Expect(resp).To(BeNil()) +} + func TestGetFile_ConnectionNotFound(t *testing.T) { t.Parallel() g := NewWithT(t) @@ -96,7 +147,7 @@ func TestGetFile_ConnectionNotFound(t *testing.T) { }, } - ctx := grpcContext.NewGrpcContext(context.Background(), grpcContext.GrpcInfo{ + ctx := grpcContext.NewGrpcContext(t.Context(), grpcContext.GrpcInfo{ IPAddress: "127.0.0.1", }) @@ -129,7 +180,7 @@ func TestGetFile_DeploymentNotFound(t *testing.T) { }, } - ctx := grpcContext.NewGrpcContext(context.Background(), grpcContext.GrpcInfo{ + ctx := grpcContext.NewGrpcContext(t.Context(), grpcContext.GrpcInfo{ IPAddress: "127.0.0.1", }) @@ -154,7 +205,7 @@ func TestGetFile_FileNotFound(t *testing.T) { connTracker.GetConnectionReturns(conn) depStore := NewDeploymentStore(connTracker) - depStore.GetOrStore(context.Background(), deploymentName, nil) + depStore.GetOrStore(t.Context(), deploymentName, nil) fs := newFileService(logr.Discard(), depStore, connTracker) @@ -165,7 +216,7 @@ func TestGetFile_FileNotFound(t *testing.T) { }, } - ctx := grpcContext.NewGrpcContext(context.Background(), grpcContext.GrpcInfo{ + ctx := grpcContext.NewGrpcContext(t.Context(), grpcContext.GrpcInfo{ IPAddress: "127.0.0.1", }) @@ -175,12 +226,136 @@ func TestGetFile_FileNotFound(t *testing.T) { g.Expect(resp).To(BeNil()) } +func TestGetFileStream(t *testing.T) { + t.Parallel() + g := NewWithT(t) + + deploymentName := types.NamespacedName{Name: "nginx-deployment", Namespace: "default"} + + connTracker := &agentgrpcfakes.FakeConnectionsTracker{} + conn := agentgrpc.Connection{ + PodName: "nginx-pod", + InstanceID: "12345", + Parent: deploymentName, + } + connTracker.GetConnectionReturns(conn) + + depStore := NewDeploymentStore(connTracker) + dep := depStore.GetOrStore(t.Context(), deploymentName, nil) + + // Create a file larger than defaultChunkSize to ensure multiple chunks are sent + fileContent := make([]byte, defaultChunkSize+100) + for i := range fileContent { + fileContent[i] = byte(i % 256) + } + fileMeta := &pb.FileMeta{ + Name: "bigfile.conf", + Hash: "big-hash", + Size: int64(len(fileContent)), + } + + dep.files = []File{ + { + Meta: fileMeta, + Contents: fileContent, + }, + } + + fs := newFileService(logr.Discard(), depStore, connTracker) + + ctx := grpcContext.NewGrpcContext(t.Context(), grpcContext.GrpcInfo{ + IPAddress: "127.0.0.1", + }) + + req := &pb.GetFileRequest{ + FileMeta: fileMeta, + MessageMeta: &pb.MessageMeta{}, + } + + server := newMockServerStreamingServer(ctx) + + err := fs.GetFileStream(req, server) + g.Expect(err).ToNot(HaveOccurred()) + g.Expect(len(server.sentChunks)).To(BeNumerically(">", 1)) + g.Expect(server.sentChunks[0].GetHeader()).ToNot(BeNil()) + + var received []byte + for _, c := range server.sentChunks { + if c.GetContent() != nil { + received = append(received, c.GetContent().Data...) + } + } + g.Expect(received).To(Equal(fileContent)) +} + +func TestGetFileStream_InvalidConnection(t *testing.T) { + t.Parallel() + g := NewWithT(t) + + fs := newFileService(logr.Discard(), nil, nil) + + req := &pb.GetFileRequest{ + FileMeta: &pb.FileMeta{Name: "test.conf", Hash: "some-hash"}, + MessageMeta: &pb.MessageMeta{}, + } + + server := newMockServerStreamingServer(t.Context()) + + err := fs.GetFileStream(req, server) + g.Expect(err).To(Equal(agentgrpc.ErrStatusInvalidConnection)) +} + +func TestGetFileStream_InvalidRequest(t *testing.T) { + t.Parallel() + g := NewWithT(t) + + deploymentName := types.NamespacedName{Name: "nginx-deployment", Namespace: "default"} + connTracker := &agentgrpcfakes.FakeConnectionsTracker{} + conn := agentgrpc.Connection{ + PodName: "nginx-pod", + InstanceID: "12345", + Parent: deploymentName, + } + connTracker.GetConnectionReturns(conn) + + depStore := NewDeploymentStore(connTracker) + _ = depStore.GetOrStore(t.Context(), deploymentName, nil) + + fs := newFileService(logr.Discard(), depStore, connTracker) + + ctx := grpcContext.NewGrpcContext(t.Context(), grpcContext.GrpcInfo{ + IPAddress: "127.0.0.1", + }) + + // no filemeta + req := &pb.GetFileRequest{ + FileMeta: nil, + MessageMeta: &pb.MessageMeta{}, + } + + server := newMockServerStreamingServer(ctx) + + err := fs.GetFileStream(req, server) + g.Expect(err).To(Equal(status.Error(codes.InvalidArgument, "invalid request"))) + g.Expect(server.sentChunks).To(BeEmpty()) + + // no messagemeta + req = &pb.GetFileRequest{ + FileMeta: &pb.FileMeta{Name: "test.conf", Hash: "some-hash"}, + MessageMeta: nil, + } + + err = fs.GetFileStream(req, server) + g.Expect(err).To(Equal(status.Error(codes.InvalidArgument, "invalid request"))) + g.Expect(server.sentChunks).To(BeEmpty()) +} + func TestGetOverview(t *testing.T) { t.Parallel() g := NewWithT(t) fs := newFileService(logr.Discard(), nil, nil) - resp, err := fs.GetOverview(context.Background(), &pb.GetOverviewRequest{}) + resp, err := fs.GetOverview(t.Context(), &pb.GetOverviewRequest{}) g.Expect(err).ToNot(HaveOccurred()) g.Expect(resp).To(Equal(&pb.GetOverviewResponse{})) @@ -191,7 +366,7 @@ func TestUpdateOverview(t *testing.T) { g := NewWithT(t) fs := newFileService(logr.Discard(), nil, nil) - resp, err := fs.UpdateOverview(context.Background(), &pb.UpdateOverviewRequest{}) + resp, err := fs.UpdateOverview(t.Context(), &pb.UpdateOverviewRequest{}) g.Expect(err).ToNot(HaveOccurred()) g.Expect(resp).To(Equal(&pb.UpdateOverviewResponse{})) @@ -202,8 +377,16 @@ func TestUpdateFile(t *testing.T) { g := NewWithT(t) fs := newFileService(logr.Discard(), nil, nil) - resp, err := fs.UpdateFile(context.Background(), &pb.UpdateFileRequest{}) + resp, err := fs.UpdateFile(t.Context(), &pb.UpdateFileRequest{}) g.Expect(err).ToNot(HaveOccurred()) g.Expect(resp).To(Equal(&pb.UpdateFileResponse{})) } + +func TestUpdateFileStream(t *testing.T) { + t.Parallel() + g := NewWithT(t) + + fs := newFileService(logr.Discard(), nil, nil) + g.Expect(fs.UpdateFileStream(nil)).To(Succeed()) +} diff --git a/internal/mode/static/nginx/config/generator.go b/internal/mode/static/nginx/config/generator.go index 5e92544c2d..6b40b6ac06 100644 --- a/internal/mode/static/nginx/config/generator.go +++ b/internal/mode/static/nginx/config/generator.go @@ -143,6 +143,7 @@ func (g GeneratorImpl) GenerateDeploymentContext(depCtx dataplane.DeploymentCont Name: mainIncludesFolder + "/deployment_ctx.json", Hash: filesHelper.GenerateHash(depCtxBytes), Permissions: file.RegularFileMode, + Size: int64(len(depCtxBytes)), }, Contents: depCtxBytes, } @@ -178,6 +179,7 @@ func (g GeneratorImpl) executeConfigTemplates( Name: fp, Hash: filesHelper.GenerateHash(bytes), Permissions: file.RegularFileMode, + Size: int64(len(bytes)), }, Contents: bytes, }) @@ -218,6 +220,7 @@ func generatePEM(id dataplane.SSLKeyPairID, cert []byte, key []byte) agent.File Name: generatePEMFileName(id), Hash: filesHelper.GenerateHash(c), Permissions: file.SecretFileMode, + Size: int64(len(c)), }, Contents: c, } @@ -233,6 +236,7 @@ func generateCertBundle(id dataplane.CertBundleID, cert []byte) agent.File { Name: generateCertBundleFileName(id), Hash: filesHelper.GenerateHash(cert), Permissions: file.SecretFileMode, + Size: int64(len(cert)), }, Contents: cert, } diff --git a/internal/mode/static/nginx/config/generator_test.go b/internal/mode/static/nginx/config/generator_test.go index 9e0fe140fa..51b73361c7 100644 --- a/internal/mode/static/nginx/config/generator_test.go +++ b/internal/mode/static/nginx/config/generator_test.go @@ -261,6 +261,7 @@ func TestGenerate(t *testing.T) { Name: "/etc/nginx/secrets/test-keypair.pem", Hash: filesHelper.GenerateHash([]byte("test-cert\ntest-key")), Permissions: file.SecretFileMode, + Size: int64(len([]byte("test-cert\ntest-key"))), }, Contents: []byte("test-cert\ntest-key"), })) diff --git a/internal/mode/static/nginx/config/main_config.go b/internal/mode/static/nginx/config/main_config.go index edb837d2bc..f6710bc587 100644 --- a/internal/mode/static/nginx/config/main_config.go +++ b/internal/mode/static/nginx/config/main_config.go @@ -69,6 +69,7 @@ func (g GeneratorImpl) generateMgmtFiles(conf dataplane.Configuration) []agent.F Name: secretsFolder + "/license.jwt", Hash: filesHelper.GenerateHash(tokenContent), Permissions: file.SecretFileMode, + Size: int64(len(tokenContent)), }, Contents: tokenContent, } @@ -87,6 +88,7 @@ func (g GeneratorImpl) generateMgmtFiles(conf dataplane.Configuration) []agent.F Name: secretsFolder + "/mgmt-ca.crt", Hash: filesHelper.GenerateHash(content), Permissions: file.SecretFileMode, + Size: int64(len(content)), }, Contents: content, } @@ -100,6 +102,7 @@ func (g GeneratorImpl) generateMgmtFiles(conf dataplane.Configuration) []agent.F Name: secretsFolder + "/mgmt-tls.crt", Hash: filesHelper.GenerateHash(content), Permissions: file.SecretFileMode, + Size: int64(len(content)), }, Contents: content, } @@ -113,6 +116,7 @@ func (g GeneratorImpl) generateMgmtFiles(conf dataplane.Configuration) []agent.F Name: secretsFolder + "/mgmt-tls.key", Hash: filesHelper.GenerateHash(content), Permissions: file.SecretFileMode, + Size: int64(len(content)), }, Contents: content, } @@ -133,6 +137,7 @@ func (g GeneratorImpl) generateMgmtFiles(conf dataplane.Configuration) []agent.F Name: mgmtIncludesFile, Hash: filesHelper.GenerateHash(mgmtContents), Permissions: file.RegularFileMode, + Size: int64(len(mgmtContents)), }, Contents: mgmtContents, }