diff --git a/Makefile b/Makefile index f2c0bb40a..296163ac3 100644 --- a/Makefile +++ b/Makefile @@ -43,6 +43,8 @@ PROTO_DIR := proto BINARY_NAME := nginx-agent PROJECT_DIR = cmd/agent PROJECT_FILE = main.go +COLLECTOR_PATH ?= /etc/nginx-agent/opentelemetry-collector-agent.yaml +MANIFEST_DIR ?= /var/lib/nginx-agent DIRS = $(BUILD_DIR) $(TEST_BUILD_DIR) $(BUILD_DIR)/$(DOCS_DIR) $(BUILD_DIR)/$(DOCS_DIR)/$(PROTO_DIR) $(shell mkdir -p $(DIRS)) @@ -181,7 +183,7 @@ run: build ## Run code dev: ## Run agent executable @echo "🚀 Running App" - $(GORUN) -ldflags=$(DEBUG_LDFLAGS) $(PROJECT_DIR)/$(PROJECT_FILE) + NGINX_AGENT_COLLECTOR_CONFIG_PATH=$(COLLECTOR_PATH) NGINX_AGENT_MANIFEST_DIR=$(MANIFEST_DIR) $(GORUN) -ldflags=$(DEBUG_LDFLAGS) $(PROJECT_DIR)/$(PROJECT_FILE) race-condition-dev: ## Run agent executable with race condition detection @echo "🏎️ Running app with race condition detection enabled" diff --git a/internal/config/config.go b/internal/config/config.go index 63dd0c87c..85cdc6a71 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -124,6 +124,7 @@ func ResolveConfig() (*Config, error) { Watchers: resolveWatchers(), Features: viperInstance.GetStringSlice(FeaturesKey), Labels: resolveLabels(), + ManifestDir: viperInstance.GetString(ManifestDirPathKey), } checkCollectorConfiguration(collector, config) @@ -231,7 +232,11 @@ func registerFlags() { "The path to output log messages to. "+ "If the default path doesn't exist, log messages are output to stdout/stderr.", ) - + fs.String( + ManifestDirPathKey, + DefManifestDir, + "Specifies the path to the directory containing the manifest files", + ) fs.Duration( NginxReloadMonitoringPeriodKey, DefNginxReloadMonitoringPeriod, diff --git a/internal/config/defaults.go b/internal/config/defaults.go index cc1212edc..ddeee7a3b 100644 --- a/internal/config/defaults.go +++ b/internal/config/defaults.go @@ -74,6 +74,9 @@ const ( DefCollectorExtensionsHealthTLSCAPath = "" DefCollectorExtensionsHealthTLSSkipVerify = false DefCollectorExtensionsHealthTLServerNameKey = "" + + // File defaults + DefManifestDir = "/var/lib/nginx-agent" ) func DefaultFeatures() []string { diff --git a/internal/config/flags.go b/internal/config/flags.go index 7c977f1ac..50fb461e5 100644 --- a/internal/config/flags.go +++ b/internal/config/flags.go @@ -23,6 +23,7 @@ const ( InstanceWatcherMonitoringFrequencyKey = "watchers_instance_watcher_monitoring_frequency" InstanceHealthWatcherMonitoringFrequencyKey = "watchers_instance_health_watcher_monitoring_frequency" FileWatcherKey = "watchers_file_watcher" + ManifestDirPathKey = "manifest_dir" ) var ( diff --git a/internal/config/types.go b/internal/config/types.go index ed4f77c31..8017987f1 100644 --- a/internal/config/types.go +++ b/internal/config/types.go @@ -42,6 +42,7 @@ type ( Version string `yaml:"-"` Path string `yaml:"-"` UUID string `yaml:"-"` + ManifestDir string `yaml:"-"` AllowedDirectories []string `yaml:"allowed_directories" mapstructure:"allowed_directories"` Features []string `yaml:"features" mapstructure:"features"` } diff --git a/internal/file/file_manager_service.go b/internal/file/file_manager_service.go index 4836b6fc8..acbab1f29 100644 --- a/internal/file/file_manager_service.go +++ b/internal/file/file_manager_service.go @@ -48,11 +48,6 @@ const ( filePerm = 0o600 ) -var ( - manifestDirPath = "/var/lib/nginx-agent" - manifestFilePath = manifestDirPath + "/manifest.json" -) - type ( fileOperator interface { Write(ctx context.Context, fileContent []byte, file *mpi.FileMeta) error @@ -98,6 +93,7 @@ type FileManagerService struct { // map of the files currently on disk, used to determine the file action during config apply currentFilesOnDisk map[string]*mpi.File // key is file path previousManifestFiles map[string]*model.ManifestFile + manifestFilePath string filesMutex sync.RWMutex } @@ -113,6 +109,7 @@ func NewFileManagerService(fileServiceClient mpi.FileServiceClient, agentConfig rollbackFileContents: make(map[string][]byte), currentFilesOnDisk: make(map[string]*mpi.File), previousManifestFiles: make(map[string]*model.ManifestFile), + manifestFilePath: agentConfig.ManifestDir + "/manifest.json", isConnected: isConnected, } } @@ -851,12 +848,12 @@ func (fms *FileManagerService) writeManifestFile(updatedFiles map[string]*model. } // 0755 allows read/execute for all, write for owner - if err = os.MkdirAll(manifestDirPath, dirPerm); err != nil { - return fmt.Errorf("unable to create directory %s: %w", manifestDirPath, err) + if err = os.MkdirAll(fms.agentConfig.ManifestDir, dirPerm); err != nil { + return fmt.Errorf("unable to create directory %s: %w", fms.agentConfig.ManifestDir, err) } // 0600 ensures only root can read/write - newFile, err := os.OpenFile(manifestFilePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, filePerm) + newFile, err := os.OpenFile(fms.manifestFilePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, filePerm) if err != nil { return fmt.Errorf("failed to read manifest file: %w", err) } @@ -875,11 +872,11 @@ func (fms *FileManagerService) writeManifestFile(updatedFiles map[string]*model. } func (fms *FileManagerService) manifestFile() (map[string]*model.ManifestFile, map[string]*mpi.File, error) { - if _, err := os.Stat(manifestFilePath); err != nil { + if _, err := os.Stat(fms.manifestFilePath); err != nil { return nil, nil, err } - file, err := os.ReadFile(manifestFilePath) + file, err := os.ReadFile(fms.manifestFilePath) if err != nil { return nil, nil, fmt.Errorf("failed to read manifest file: %w", err) } diff --git a/internal/file/file_manager_service_test.go b/internal/file/file_manager_service_test.go index b6a07d6f7..aa139810d 100644 --- a/internal/file/file_manager_service_test.go +++ b/internal/file/file_manager_service_test.go @@ -179,8 +179,8 @@ func TestFileManagerService_ConfigApply_Add(t *testing.T) { overview := protos.FileOverview(filePath, fileHash) - manifestDirPath = tempDir - manifestFilePath = manifestDirPath + "/manifest.json" + manifestDirPath := tempDir + manifestFilePath := manifestDirPath + "/manifest.json" helpers.CreateFileWithErrorCheck(t, manifestDirPath, "manifest.json") fakeFileServiceClient := &v1fakes.FakeFileServiceClient{} @@ -194,7 +194,10 @@ func TestFileManagerService_ConfigApply_Add(t *testing.T) { }, nil) agentConfig := types.AgentConfig() agentConfig.AllowedDirectories = []string{tempDir} + fileManagerService := NewFileManagerService(fakeFileServiceClient, agentConfig) + fileManagerService.agentConfig.ManifestDir = manifestDirPath + fileManagerService.manifestFilePath = manifestFilePath request := protos.CreateConfigApplyRequest(overview) writeStatus, err := fileManagerService.ConfigApply(ctx, request) @@ -218,10 +221,6 @@ func TestFileManagerService_ConfigApply_Add_LargeFile(t *testing.T) { overview := protos.FileOverviewLargeFile(filePath, fileHash) - manifestDirPath = tempDir - manifestFilePath = manifestDirPath + "/manifest.json" - helpers.CreateFileWithErrorCheck(t, manifestDirPath, "manifest.json") - fakeFileServiceClient := &v1fakes.FakeFileServiceClient{} fakeFileServiceClient.GetOverviewReturns(&mpi.GetOverviewResponse{ Overview: overview, @@ -237,10 +236,15 @@ func TestFileManagerService_ConfigApply_Add_LargeFile(t *testing.T) { fakeServerStreamingClient.chunks[uint32(i)] = []byte{fileContent[i]} } + manifestDirPath := tempDir + manifestFilePath := manifestDirPath + "/manifest.json" + fakeFileServiceClient.GetFileStreamReturns(fakeServerStreamingClient, nil) agentConfig := types.AgentConfig() agentConfig.AllowedDirectories = []string{tempDir} fileManagerService := NewFileManagerService(fakeFileServiceClient, agentConfig) + fileManagerService.agentConfig.ManifestDir = manifestDirPath + fileManagerService.manifestFilePath = manifestFilePath request := protos.CreateConfigApplyRequest(overview) writeStatus, err := fileManagerService.ConfigApply(ctx, request) @@ -279,8 +283,8 @@ func TestFileManagerService_ConfigApply_Update(t *testing.T) { }, } - manifestDirPath = tempDir - manifestFilePath = manifestDirPath + "/manifest.json" + manifestDirPath := tempDir + manifestFilePath := manifestDirPath + "/manifest.json" helpers.CreateFileWithErrorCheck(t, manifestDirPath, "manifest.json") overview := protos.FileOverview(tempFile.Name(), fileHash) @@ -296,12 +300,14 @@ func TestFileManagerService_ConfigApply_Update(t *testing.T) { }, nil) agentConfig := types.AgentConfig() agentConfig.AllowedDirectories = []string{tempDir} + fileManagerService := NewFileManagerService(fakeFileServiceClient, agentConfig) + fileManagerService.agentConfig.ManifestDir = manifestDirPath + fileManagerService.manifestFilePath = manifestFilePath err := fileManagerService.UpdateCurrentFilesOnDisk(ctx, filesOnDisk, false) require.NoError(t, err) request := protos.CreateConfigApplyRequest(overview) - writeStatus, err := fileManagerService.ConfigApply(ctx, request) require.NoError(t, err) assert.Equal(t, model.OK, writeStatus) @@ -336,14 +342,17 @@ func TestFileManagerService_ConfigApply_Delete(t *testing.T) { }, } - manifestDirPath = tempDir - manifestFilePath = manifestDirPath + "/manifest.json" + manifestDirPath := tempDir + manifestFilePath := manifestDirPath + "/manifest.json" helpers.CreateFileWithErrorCheck(t, manifestDirPath, "manifest.json") fakeFileServiceClient := &v1fakes.FakeFileServiceClient{} agentConfig := types.AgentConfig() agentConfig.AllowedDirectories = []string{tempDir} + fileManagerService := NewFileManagerService(fakeFileServiceClient, agentConfig) + fileManagerService.agentConfig.ManifestDir = manifestDirPath + fileManagerService.manifestFilePath = manifestFilePath err := fileManagerService.UpdateCurrentFilesOnDisk(ctx, filesOnDisk, false) require.NoError(t, err) @@ -462,8 +471,8 @@ func TestFileManagerService_Rollback(t *testing.T) { _, writeErr = updateFile.Write(newFileContent) require.NoError(t, writeErr) - manifestDirPath = tempDir - manifestFilePath = manifestDirPath + "/manifest.json" + manifestDirPath := tempDir + manifestFilePath := manifestDirPath + "/manifest.json" helpers.CreateFileWithErrorCheck(t, manifestDirPath, "manifest.json") filesCache := map[string]*model.FileCache{ @@ -529,6 +538,8 @@ func TestFileManagerService_Rollback(t *testing.T) { fileManagerService := NewFileManagerService(fakeFileServiceClient, types.AgentConfig()) fileManagerService.rollbackFileContents = fileContentCache fileManagerService.fileActions = filesCache + fileManagerService.agentConfig.ManifestDir = manifestDirPath + fileManagerService.manifestFilePath = manifestFilePath err := fileManagerService.Rollback(ctx, instanceID) require.NoError(t, err) @@ -690,11 +701,14 @@ func TestFileManagerService_DetermineFileActions(t *testing.T) { // Delete manifest file if it already exists manifestFile := CreateTestManifestFile(t, tempDir, test.currentFiles) defer manifestFile.Close() - manifestDirPath = tempDir - manifestFilePath = manifestFile.Name() + manifestDirPath := tempDir + manifestFilePath := manifestFile.Name() fakeFileServiceClient := &v1fakes.FakeFileServiceClient{} fileManagerService := NewFileManagerService(fakeFileServiceClient, types.AgentConfig()) + fileManagerService.agentConfig.ManifestDir = manifestDirPath + fileManagerService.manifestFilePath = manifestFilePath + require.NoError(tt, err) diff, contents, fileActionErr := fileManagerService.DetermineFileActions(test.currentFiles,