Skip to content

Commit a6b6e52

Browse files
committed
start of file plugins
1 parent e07bf64 commit a6b6e52

13 files changed

+1402
-871
lines changed

internal/file/file_manager_service.go

Lines changed: 72 additions & 504 deletions
Large diffs are not rendered by default.

internal/file/file_manager_service_test.go

Lines changed: 0 additions & 141 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import (
1111
"fmt"
1212
"os"
1313
"path/filepath"
14-
"sync/atomic"
1514
"testing"
1615

1716
"github.com/nginx/agent/v3/internal/model"
@@ -28,146 +27,6 @@ import (
2827
"github.com/stretchr/testify/require"
2928
)
3029

31-
func TestFileManagerService_UpdateOverview(t *testing.T) {
32-
ctx := context.Background()
33-
34-
filePath := filepath.Join(t.TempDir(), "nginx.conf")
35-
fileMeta := protos.FileMeta(filePath, "")
36-
37-
fileContent := []byte("location /test {\n return 200 \"Test location\\n\";\n}")
38-
fileHash := files.GenerateHash(fileContent)
39-
40-
fileWriteErr := os.WriteFile(filePath, fileContent, 0o600)
41-
require.NoError(t, fileWriteErr)
42-
43-
overview := protos.FileOverview(filePath, fileHash)
44-
45-
fakeFileServiceClient := &v1fakes.FakeFileServiceClient{}
46-
fakeFileServiceClient.UpdateOverviewReturnsOnCall(0, &mpi.UpdateOverviewResponse{
47-
Overview: overview,
48-
}, nil)
49-
50-
fakeFileServiceClient.UpdateOverviewReturnsOnCall(1, &mpi.UpdateOverviewResponse{}, nil)
51-
52-
fakeFileServiceClient.UpdateFileReturns(&mpi.UpdateFileResponse{}, nil)
53-
54-
fileManagerService := NewFileManagerService(fakeFileServiceClient, types.AgentConfig())
55-
fileManagerService.SetIsConnected(true)
56-
57-
err := fileManagerService.UpdateOverview(ctx, "123", []*mpi.File{
58-
{
59-
FileMeta: fileMeta,
60-
},
61-
}, 0)
62-
63-
require.NoError(t, err)
64-
assert.Equal(t, 2, fakeFileServiceClient.UpdateOverviewCallCount())
65-
}
66-
67-
func TestFileManagerService_UpdateOverview_MaxIterations(t *testing.T) {
68-
ctx := context.Background()
69-
70-
filePath := filepath.Join(t.TempDir(), "nginx.conf")
71-
fileMeta := protos.FileMeta(filePath, "")
72-
73-
fileContent := []byte("location /test {\n return 200 \"Test location\\n\";\n}")
74-
fileHash := files.GenerateHash(fileContent)
75-
76-
fileWriteErr := os.WriteFile(filePath, fileContent, 0o600)
77-
require.NoError(t, fileWriteErr)
78-
79-
overview := protos.FileOverview(filePath, fileHash)
80-
81-
fakeFileServiceClient := &v1fakes.FakeFileServiceClient{}
82-
83-
// do 5 iterations
84-
for i := 0; i <= 5; i++ {
85-
fakeFileServiceClient.UpdateOverviewReturnsOnCall(i, &mpi.UpdateOverviewResponse{
86-
Overview: overview,
87-
}, nil)
88-
}
89-
90-
fakeFileServiceClient.UpdateFileReturns(&mpi.UpdateFileResponse{}, nil)
91-
92-
fileManagerService := NewFileManagerService(fakeFileServiceClient, types.AgentConfig())
93-
fileManagerService.SetIsConnected(true)
94-
95-
err := fileManagerService.UpdateOverview(ctx, "123", []*mpi.File{
96-
{
97-
FileMeta: fileMeta,
98-
},
99-
}, 0)
100-
101-
require.Error(t, err)
102-
assert.Equal(t, "too many UpdateOverview attempts", err.Error())
103-
}
104-
105-
func TestFileManagerService_UpdateFile(t *testing.T) {
106-
tests := []struct {
107-
name string
108-
isCert bool
109-
}{
110-
{
111-
name: "non-cert",
112-
isCert: false,
113-
},
114-
{
115-
name: "cert",
116-
isCert: true,
117-
},
118-
}
119-
120-
tempDir := os.TempDir()
121-
122-
for _, test := range tests {
123-
ctx := context.Background()
124-
125-
testFile := helpers.CreateFileWithErrorCheck(t, tempDir, "nginx.conf")
126-
127-
var fileMeta *mpi.FileMeta
128-
if test.isCert {
129-
fileMeta = protos.CertMeta(testFile.Name(), "")
130-
} else {
131-
fileMeta = protos.FileMeta(testFile.Name(), "")
132-
}
133-
134-
fakeFileServiceClient := &v1fakes.FakeFileServiceClient{}
135-
fileManagerService := NewFileManagerService(fakeFileServiceClient, types.AgentConfig())
136-
fileManagerService.SetIsConnected(true)
137-
138-
err := fileManagerService.UpdateFile(ctx, "123", &mpi.File{FileMeta: fileMeta})
139-
140-
require.NoError(t, err)
141-
assert.Equal(t, 1, fakeFileServiceClient.UpdateFileCallCount())
142-
143-
helpers.RemoveFileWithErrorCheck(t, testFile.Name())
144-
}
145-
}
146-
147-
func TestFileManagerService_UpdateFile_LargeFile(t *testing.T) {
148-
ctx := context.Background()
149-
tempDir := os.TempDir()
150-
151-
testFile := helpers.CreateFileWithErrorCheck(t, tempDir, "nginx.conf")
152-
writeFileError := os.WriteFile(testFile.Name(), []byte("#test content"), 0o600)
153-
require.NoError(t, writeFileError)
154-
fileMeta := protos.FileMetaLargeFile(testFile.Name(), "")
155-
156-
fakeFileServiceClient := &v1fakes.FakeFileServiceClient{}
157-
fakeClientStreamingClient := &FakeClientStreamingClient{sendCount: atomic.Int32{}}
158-
fakeFileServiceClient.UpdateFileStreamReturns(fakeClientStreamingClient, nil)
159-
fileManagerService := NewFileManagerService(fakeFileServiceClient, types.AgentConfig())
160-
fileManagerService.SetIsConnected(true)
161-
162-
err := fileManagerService.UpdateFile(ctx, "123", &mpi.File{FileMeta: fileMeta})
163-
164-
require.NoError(t, err)
165-
assert.Equal(t, 0, fakeFileServiceClient.UpdateFileCallCount())
166-
assert.Equal(t, 14, int(fakeClientStreamingClient.sendCount.Load()))
167-
168-
helpers.RemoveFileWithErrorCheck(t, testFile.Name())
169-
}
170-
17130
func TestFileManagerService_ConfigApply_Add(t *testing.T) {
17231
ctx := context.Background()
17332
tempDir := t.TempDir()

internal/file/file_operator.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,15 @@ package file
88
import (
99
"bufio"
1010
"context"
11+
"encoding/json"
1112
"fmt"
1213
"io"
1314
"log/slog"
1415
"os"
1516
"path"
1617

18+
"github.com/nginx/agent/v3/internal/model"
19+
1720
"google.golang.org/grpc"
1821

1922
"github.com/nginx/agent/v3/pkg/files"
@@ -140,3 +143,35 @@ func (fo *FileOperator) ReadChunk(
140143

141144
return chunk, err
142145
}
146+
147+
func (fo *FileOperator) WriteManifestFile(updatedFiles map[string]*model.ManifestFile, manifestDir,
148+
manifestPath string,
149+
) (writeError error) {
150+
manifestJSON, err := json.MarshalIndent(updatedFiles, "", " ")
151+
if err != nil {
152+
return fmt.Errorf("unable to marshal manifest file json: %w", err)
153+
}
154+
155+
// 0755 allows read/execute for all, write for owner
156+
if err = os.MkdirAll(manifestDir, dirPerm); err != nil {
157+
return fmt.Errorf("unable to create directory %s: %w", manifestDir, err)
158+
}
159+
160+
// 0600 ensures only root can read/write
161+
newFile, err := os.OpenFile(manifestPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, filePerm)
162+
if err != nil {
163+
return fmt.Errorf("failed to read manifest file: %w", err)
164+
}
165+
defer func() {
166+
if closeErr := newFile.Close(); closeErr != nil {
167+
writeError = closeErr
168+
}
169+
}()
170+
171+
_, err = newFile.Write(manifestJSON)
172+
if err != nil {
173+
return fmt.Errorf("failed to write manifest file: %w", err)
174+
}
175+
176+
return writeError
177+
}

internal/file/file_plugin.go

Lines changed: 3 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ package file
77

88
import (
99
"context"
10-
"fmt"
1110
"log/slog"
1211

1312
"github.com/nginx/agent/v3/pkg/files"
@@ -319,27 +318,10 @@ func (fp *FilePlugin) handleNginxConfigUpdate(ctx context.Context, msg *bus.Mess
319318
return
320319
}
321320

322-
updateError := fp.fileManagerService.UpdateCurrentFilesOnDisk(
323-
ctx,
324-
files.ConvertToMapOfFiles(nginxConfigContext.Files),
325-
true,
326-
)
327-
if updateError != nil {
328-
slog.ErrorContext(ctx, "Unable to update current files on disk", "error", updateError)
329-
}
330-
331-
slog.InfoContext(ctx, "Updating overview after nginx config update")
332-
err := fp.fileManagerService.UpdateOverview(ctx, nginxConfigContext.InstanceID, nginxConfigContext.Files, 0)
333-
if err != nil {
334-
slog.ErrorContext(
335-
ctx,
336-
"Failed to update file overview",
337-
"instance_id", nginxConfigContext.InstanceID,
338-
"error", err,
339-
)
340-
}
321+
fp.fileManagerService.ConfigUpdate(ctx, nginxConfigContext)
341322
}
342323

324+
// nolint: dupl
343325
func (fp *FilePlugin) handleConfigUploadRequest(ctx context.Context, msg *bus.Message) {
344326
slog.DebugContext(ctx, "File plugin received config upload request message")
345327
managementPlaneRequest, ok := msg.Data.(*mpi.ManagementPlaneRequest)
@@ -357,36 +339,7 @@ func (fp *FilePlugin) handleConfigUploadRequest(ctx context.Context, msg *bus.Me
357339

358340
correlationID := logger.CorrelationID(ctx)
359341

360-
var updatingFilesError error
361-
362-
for _, file := range configUploadRequest.GetOverview().GetFiles() {
363-
err := fp.fileManagerService.UpdateFile(
364-
ctx,
365-
configUploadRequest.GetOverview().GetConfigVersion().GetInstanceId(),
366-
file,
367-
)
368-
if err != nil {
369-
slog.ErrorContext(
370-
ctx,
371-
"Failed to update file",
372-
"instance_id", configUploadRequest.GetOverview().GetConfigVersion().GetInstanceId(),
373-
"file_name", file.GetFileMeta().GetName(),
374-
"error", err,
375-
)
376-
377-
response := fp.createDataPlaneResponse(correlationID, mpi.CommandResponse_COMMAND_STATUS_ERROR,
378-
fmt.Sprintf("Failed to update file %s", file.GetFileMeta().GetName()),
379-
configUploadRequest.GetOverview().GetConfigVersion().GetInstanceId(),
380-
err.Error(),
381-
)
382-
383-
updatingFilesError = err
384-
385-
fp.messagePipe.Process(ctx, &bus.Message{Topic: bus.DataPlaneResponseTopic, Data: response})
386-
387-
break
388-
}
389-
}
342+
updatingFilesError := fp.fileManagerService.ConfigUpload(ctx, configUploadRequest)
390343

391344
response := &mpi.DataPlaneResponse{
392345
MessageMeta: &mpi.MessageMeta{

internal/file/file_plugin_test.go

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ func TestFilePlugin_Subscriptions(t *testing.T) {
6363
)
6464
}
6565

66+
// nolint: dupl
6667
func TestFilePlugin_Process_NginxConfigUpdateTopic(t *testing.T) {
6768
ctx := context.Background()
6869

@@ -224,6 +225,7 @@ func TestFilePlugin_Process_ConfigApplyRequestTopic(t *testing.T) {
224225
}
225226
}
226227

228+
// nolint: dupl
227229
func TestFilePlugin_Process_ConfigUploadRequestTopic(t *testing.T) {
228230
ctx := context.Background()
229231

@@ -322,29 +324,20 @@ func TestFilePlugin_Process_ConfigUploadRequestTopic_Failure(t *testing.T) {
322324

323325
assert.Eventually(
324326
t,
325-
func() bool { return len(messagePipe.Messages()) == 2 },
327+
func() bool { return len(messagePipe.Messages()) == 1 },
326328
2*time.Second,
327329
10*time.Millisecond,
328330
)
329331

330332
assert.Equal(t, 0, fakeFileServiceClient.UpdateFileCallCount())
331333

332334
messages := messagePipe.Messages()
333-
assert.Len(t, messages, 2)
335+
assert.Len(t, messages, 1)
336+
334337
assert.Equal(t, bus.DataPlaneResponseTopic, messages[0].Topic)
335338

336339
dataPlaneResponse, ok := messages[0].Data.(*mpi.DataPlaneResponse)
337340
assert.True(t, ok)
338-
assert.Equal(
339-
t,
340-
mpi.CommandResponse_COMMAND_STATUS_ERROR,
341-
dataPlaneResponse.GetCommandResponse().GetStatus(),
342-
)
343-
344-
assert.Equal(t, bus.DataPlaneResponseTopic, messages[1].Topic)
345-
346-
dataPlaneResponse, ok = messages[1].Data.(*mpi.DataPlaneResponse)
347-
assert.True(t, ok)
348341
assert.Equal(
349342
t,
350343
mpi.CommandResponse_COMMAND_STATUS_FAILURE,

0 commit comments

Comments
 (0)