diff --git a/cmd/agent/executor_agent_service.go b/cmd/agent/executor_agent_service.go index f15b681f..2f6b07c4 100644 --- a/cmd/agent/executor_agent_service.go +++ b/cmd/agent/executor_agent_service.go @@ -103,7 +103,10 @@ func NewExecutorAgentService(cfg *config.ExecutorAgentServiceConfig, actionsChan func (e *ExecutorAgentService) readCloudProviderAccounts() ([]credentials.AccountConfig, error) { accounts, err := credentials.ReadCloudAccounts(e.cfg.Credentials.CredentialsFile) if err != nil { - return nil, err + if len(accounts) == 0 { + return nil, err + } + e.logger.Warn("Some accounts were skipped due to invalid credentials", zap.Error(err)) } return accounts, nil diff --git a/cmd/scanner/scanner.go b/cmd/scanner/scanner.go index ea268a6c..48d4e57f 100644 --- a/cmd/scanner/scanner.go +++ b/cmd/scanner/scanner.go @@ -100,7 +100,10 @@ func init() { func (s *Scanner) loadAccounts() error { accountConfigs, err := credentials.ReadCloudAccounts(s.cfg.CredentialsFile) if err != nil { - return fmt.Errorf("failed to read cloud accounts: %w", err) + if len(accountConfigs) == 0 { + return fmt.Errorf("failed to read cloud accounts: %w", err) + } + s.logger.Warn("Some accounts were skipped due to invalid credentials", zap.Error(err)) } for _, ac := range accountConfigs { diff --git a/internal/credentials/cloud_credentials.go b/internal/credentials/cloud_credentials.go index 12bc3a5d..c65c0be8 100644 --- a/internal/credentials/cloud_credentials.go +++ b/internal/credentials/cloud_credentials.go @@ -1,10 +1,17 @@ package credentials import ( + "errors" + "fmt" + "github.com/RHEcosystemAppEng/cluster-iq/internal/inventory" ini "gopkg.in/ini.v1" ) +var ( + ErrMissingCredentials = errors.New("missing credentials") +) + type AccountConfig struct { ID string Name string @@ -26,17 +33,26 @@ func ReadCloudAccounts(credsFile string) ([]AccountConfig, error) { cfg.DeleteSection(ini.DefaultSection) var accounts []AccountConfig + var skipped []error for _, section := range cfg.Sections() { + user := section.Key("user").String() + key := section.Key("key").String() + + if user == "" || key == "" { + skipped = append(skipped, fmt.Errorf("%w: account %q has empty user or key", ErrMissingCredentials, section.Name())) + continue + } + account := AccountConfig{ ID: section.Name(), - Name: section.Key("name").MustString(section.Name()), // If `name` is empty, the id is used as replacement + Name: section.Key("name").MustString(section.Name()), Provider: inventory.GetProvider(section.Key("provider").String()), - User: section.Key("user").String(), - Key: section.Key("key").String(), + User: user, + Key: key, BillingEnabled: section.Key("billing_enabled").MustBool(), } accounts = append(accounts, account) } - return accounts, nil + return accounts, errors.Join(skipped...) } diff --git a/internal/credentials/cloud_credentials_test.go b/internal/credentials/cloud_credentials_test.go index 002dc840..84ff3249 100644 --- a/internal/credentials/cloud_credentials_test.go +++ b/internal/credentials/cloud_credentials_test.go @@ -77,3 +77,67 @@ func testReadCloudAccounts_EmptyFile(t *testing.T) { assert.NoError(t, err) assert.Len(t, accounts, 0) } + +func TestReadCloudAccounts_MissingUser(t *testing.T) { + content := ` +[acc-1] +name = No User Account +provider = aws +key = secret +` + tmpDir := t.TempDir() + file := filepath.Join(tmpDir, "creds.ini") + err := os.WriteFile(file, []byte(content), 0600) + assert.NoError(t, err) + + accounts, err := ReadCloudAccounts(file) + + assert.Error(t, err) + assert.ErrorIs(t, err, ErrMissingCredentials) + assert.Len(t, accounts, 0) +} + +func TestReadCloudAccounts_MissingKey(t *testing.T) { + content := ` +[acc-1] +name = No Key Account +provider = aws +user = admin +` + tmpDir := t.TempDir() + file := filepath.Join(tmpDir, "creds.ini") + err := os.WriteFile(file, []byte(content), 0600) + assert.NoError(t, err) + + accounts, err := ReadCloudAccounts(file) + + assert.Error(t, err) + assert.ErrorIs(t, err, ErrMissingCredentials) + assert.Len(t, accounts, 0) +} + +func TestReadCloudAccounts_MixedValidAndInvalid(t *testing.T) { + content := ` +[valid-acc] +name = Valid Account +provider = aws +user = admin +key = secret + +[invalid-acc] +name = Invalid Account +provider = aws +user = admin +` + tmpDir := t.TempDir() + file := filepath.Join(tmpDir, "creds.ini") + err := os.WriteFile(file, []byte(content), 0600) + assert.NoError(t, err) + + accounts, err := ReadCloudAccounts(file) + + assert.Error(t, err) + assert.ErrorIs(t, err, ErrMissingCredentials) + assert.Len(t, accounts, 1) + assert.Equal(t, "valid-acc", accounts[0].ID) +}