Skip to content

Commit b6d6ee8

Browse files
committed
🧹 Improve discovery filters parsing in the AWS provider.
Signed-off-by: Vasil Sirakov <sirakov97@gmail.com>
1 parent 4a5a0aa commit b6d6ee8

File tree

4 files changed

+282
-123
lines changed

4 files changed

+282
-123
lines changed

providers/aws/connection/connection.go

Lines changed: 1 addition & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@ import (
1111
"maps"
1212
"net/http"
1313
"slices"
14-
"strconv"
15-
"strings"
1614

1715
"github.com/aws/aws-sdk-go-v2/aws"
1816
"github.com/aws/aws-sdk-go-v2/config"
@@ -65,7 +63,6 @@ func NewAwsConnection(id uint32, asset *inventory.Asset, conf *inventory.Config)
6563
// check flags for connection options
6664
c := &AwsConnection{
6765
awsConfigOptions: []func(*config.LoadOptions) error{},
68-
Filters: EmptyDiscoveryFilters(),
6966
}
7067

7168
// merge the options to make sure we don't miss anything
@@ -100,9 +97,7 @@ func NewAwsConnection(id uint32, asset *inventory.Asset, conf *inventory.Config)
10097
c.opts.profile = asset.Options["profile"]
10198
c.opts.scope = asset.Options["scope"]
10299
c.opts.options = asset.Options
103-
if conf.Discover != nil {
104-
c.Filters = parseOptsToFilters(conf.Discover.Filter)
105-
}
100+
c.Filters = DiscoveryFiltersFromOpts(conf.Discover.GetFilter())
106101
return c, nil
107102
}
108103

@@ -147,51 +142,6 @@ func (p *AwsConnection) AccountId() string {
147142
return p.accountId
148143
}
149144

150-
func parseOptsToFilters(opts map[string]string) DiscoveryFilters {
151-
d := EmptyDiscoveryFilters()
152-
for k, v := range opts {
153-
switch {
154-
case k == "regions":
155-
d.General.Regions = append(d.General.Regions, strings.Split(v, ",")...)
156-
case k == "exclude:regions":
157-
d.General.ExcludeRegions = append(d.General.ExcludeRegions, strings.Split(v, ",")...)
158-
case strings.HasPrefix(k, "tag:"):
159-
d.General.Tags[strings.TrimPrefix(k, "tag:")] = v
160-
case strings.HasPrefix(k, "exclude:tag:"):
161-
d.General.ExcludeTags[strings.TrimPrefix(k, "exclude:tag:")] = v
162-
case k == "ec2:instance-ids":
163-
d.Ec2.InstanceIds = append(d.Ec2.InstanceIds, strings.Split(v, ",")...)
164-
case k == "ec2:exclude:instance-ids":
165-
d.Ec2.ExcludeInstanceIds = append(d.Ec2.ExcludeInstanceIds, strings.Split(v, ",")...)
166-
// tag filters were moved to GeneralDiscoveryFilters, ec2 opts are kept for backward compatibility
167-
case strings.HasPrefix(k, "ec2:tag:"):
168-
d.General.Tags[strings.TrimPrefix(k, "ec2:tag:")] = v
169-
case strings.HasPrefix(k, "ec2:exclude:tag:"):
170-
d.General.ExcludeTags[strings.TrimPrefix(k, "ec2:exclude:tag:")] = v
171-
case k == "ecr:tags":
172-
d.Ecr.Tags = append(d.Ecr.Tags, strings.Split(v, ",")...)
173-
case k == "ecr:exclude:tags":
174-
d.Ecr.ExcludeTags = append(d.Ecr.ExcludeTags, strings.Split(v, ",")...)
175-
case k == "ecs:only-running-containers":
176-
parsed, err := strconv.ParseBool(v)
177-
if err == nil {
178-
d.Ecs.OnlyRunningContainers = parsed
179-
}
180-
case k == "ecs:discover-instances":
181-
parsed, err := strconv.ParseBool(v)
182-
if err == nil {
183-
d.Ecs.DiscoverInstances = parsed
184-
}
185-
case k == "ecs:discover-images":
186-
parsed, err := strconv.ParseBool(v)
187-
if err == nil {
188-
d.Ecs.DiscoverImages = parsed
189-
}
190-
}
191-
}
192-
return d
193-
}
194-
195145
func parseFlagsForConnectionOptions(m map[string]string, creds []*vault.Credential) []ConnectionOption {
196146
o := make([]ConnectionOption, 0)
197147
if apiEndpoint, ok := m["endpoint-url"]; ok {

providers/aws/connection/connection_test.go

Lines changed: 0 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -16,71 +16,6 @@ func TestNewAwsConnection(t *testing.T) {
1616
require.NotNil(t, conn)
1717
}
1818

19-
func TestParseOptsToFilters(t *testing.T) {
20-
t.Run("all opts are mapped to discovery filters correctly", func(t *testing.T) {
21-
opts := map[string]string{
22-
// DiscoveryFilters.Regions
23-
"regions": "us-east-1,us-west-1,eu-west-1",
24-
// DiscoveryFilters.ExcludeRegions
25-
"exclude:regions": "us-east-2,us-west-2,eu-west-2",
26-
// Ec2DiscoveryFilters.InstanceIds
27-
"ec2:instance-ids": "iid-1,iid-2",
28-
// Ec2DiscoveryFilters.ExcludeInstanceIds
29-
"ec2:exclude:instance-ids": "iid-1,iid-2",
30-
// GeneralDiscoveryFilters.Tags
31-
"tag:key1": "val1",
32-
"tag:key2": "val2",
33-
// GeneralDiscoveryFilters.ExcludeTags
34-
"exclude:tag:key1": "val1,val2",
35-
"exclude:tag:key2": "val3",
36-
// EcrDiscoveryFilters.Tags
37-
"ecr:tags": "tag1,tag2",
38-
// EcrDiscoveryFilters.ExcludeTags
39-
"ecr:exclude:tags": "tag1,tag2",
40-
// EcsDiscoveryFilters
41-
"ecs:only-running-containers": "true",
42-
"ecs:discover-images": "T",
43-
"ecs:discover-instances": "false",
44-
}
45-
expected := DiscoveryFilters{
46-
General: GeneralDiscoveryFilters{
47-
Regions: []string{"us-east-1", "us-west-1", "eu-west-1"},
48-
ExcludeRegions: []string{"us-east-2", "us-west-2", "eu-west-2"},
49-
Tags: map[string]string{
50-
"key1": "val1",
51-
"key2": "val2",
52-
},
53-
ExcludeTags: map[string]string{
54-
"key1": "val1,val2",
55-
"key2": "val3",
56-
},
57-
},
58-
Ec2: Ec2DiscoveryFilters{
59-
InstanceIds: []string{"iid-1", "iid-2"},
60-
ExcludeInstanceIds: []string{"iid-1", "iid-2"},
61-
},
62-
Ecs: EcsDiscoveryFilters{
63-
OnlyRunningContainers: true,
64-
DiscoverImages: true,
65-
DiscoverInstances: false,
66-
},
67-
Ecr: EcrDiscoveryFilters{
68-
Tags: []string{"tag1", "tag2"},
69-
ExcludeTags: []string{"tag1", "tag2"},
70-
},
71-
}
72-
73-
actual := parseOptsToFilters(opts)
74-
require.Equal(t, expected, actual)
75-
})
76-
77-
t.Run("empty opts are mapped to discovery filters correctly", func(t *testing.T) {
78-
expected := EmptyDiscoveryFilters()
79-
actual := parseOptsToFilters(map[string]string{})
80-
require.Equal(t, expected, actual)
81-
})
82-
}
83-
8419
func TestGetRegionsFromRegionalTable(t *testing.T) {
8520
t.Run("Successful region extraction and deduplication", func(t *testing.T) {
8621
regions, err := getRegionsFromRegionalTable()

providers/aws/connection/filters.go

Lines changed: 92 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package connection
66
import (
77
"fmt"
88
"slices"
9+
"strconv"
910
"strings"
1011

1112
"github.com/aws/aws-sdk-go-v2/aws"
@@ -19,14 +20,43 @@ type DiscoveryFilters struct {
1920
General GeneralDiscoveryFilters
2021
}
2122

22-
// ensure all underlying reference types aren't `nil`
23-
func EmptyDiscoveryFilters() DiscoveryFilters {
24-
return DiscoveryFilters{
25-
General: GeneralDiscoveryFilters{Regions: []string{}, ExcludeRegions: []string{}, Tags: map[string]string{}, ExcludeTags: map[string]string{}},
26-
Ec2: Ec2DiscoveryFilters{InstanceIds: []string{}, ExcludeInstanceIds: []string{}},
27-
Ecr: EcrDiscoveryFilters{Tags: []string{}, ExcludeTags: []string{}},
28-
Ecs: EcsDiscoveryFilters{},
23+
func DiscoveryFiltersFromOpts(opts map[string]string) DiscoveryFilters {
24+
d := DiscoveryFilters{
25+
General: GeneralDiscoveryFilters{
26+
Regions: parseCsvSliceOpt(opts, "regions"),
27+
ExcludeRegions: parseCsvSliceOpt(opts, "exclude:regions"),
28+
Tags: parseMapOpt(opts, "tag:"),
29+
ExcludeTags: parseMapOpt(opts, "exclude:tag:"),
30+
},
31+
Ec2: Ec2DiscoveryFilters{
32+
InstanceIds: parseCsvSliceOpt(opts, "ec2:instance-ids"),
33+
ExcludeInstanceIds: parseCsvSliceOpt(opts, "ec2:exclude:instance-ids"),
34+
},
35+
Ecr: EcrDiscoveryFilters{
36+
Tags: parseCsvSliceOpt(opts, "ecr:tags"),
37+
ExcludeTags: parseCsvSliceOpt(opts, "ecr:exclude:tags"),
38+
},
39+
Ecs: EcsDiscoveryFilters{
40+
OnlyRunningContainers: parseBoolOpt(opts, "ecs:only-running-containers", false),
41+
DiscoverInstances: parseBoolOpt(opts, "ecs:discover-instances", false),
42+
DiscoverImages: parseBoolOpt(opts, "ecs:discover-images", false),
43+
},
2944
}
45+
46+
// TODO: backward compatibility, remove in future versions
47+
ec2Tags := parseMapOpt(opts, "ec2:tag:")
48+
ec2ExcludeTags := parseMapOpt(opts, "ec2:exclude:tag:")
49+
for k, v := range ec2Tags {
50+
if _, exists := d.General.Tags[k]; !exists {
51+
d.General.Tags[k] = v
52+
}
53+
}
54+
for k, v := range ec2ExcludeTags {
55+
if _, exists := d.General.ExcludeTags[k]; !exists {
56+
d.General.ExcludeTags[k] = v
57+
}
58+
}
59+
return d
3060
}
3161

3262
type GeneralDiscoveryFilters struct {
@@ -107,3 +137,58 @@ type EcsDiscoveryFilters struct {
107137
DiscoverImages bool
108138
DiscoverInstances bool
109139
}
140+
141+
// Given a key-value pair that matches a key, return the boolean value of the key.
142+
// If the key is not found or the value cannot be parsed as a boolean, return the default value.
143+
// Example: key = "ecs:only-running-containers", opts = {"ecs:only-running-containers": "true"}
144+
// Returns: true
145+
func parseBoolOpt(opts map[string]string, key string, defaultVal bool) bool {
146+
for k, v := range opts {
147+
if k == key {
148+
parsed, err := strconv.ParseBool(v)
149+
if err == nil {
150+
return parsed
151+
}
152+
}
153+
}
154+
return defaultVal
155+
}
156+
157+
// Given a map of options and a key prefix, return a map of key-value pairs
158+
// where the keys start with the given prefix, with the prefix removed.
159+
// Example:
160+
// keyPrefix = "tag:"
161+
// opts = {"tag:env": "prod", "tag:role": "web"}
162+
// returns {"env": "prod", "role": "web"}
163+
func parseMapOpt(opts map[string]string, keyPrefix string) map[string]string {
164+
res := map[string]string{}
165+
for k, v := range opts {
166+
if k == "" || v == "" {
167+
continue
168+
}
169+
if !strings.HasPrefix(k, keyPrefix) {
170+
continue
171+
}
172+
res[strings.TrimPrefix(k, keyPrefix)] = v
173+
}
174+
return res
175+
}
176+
177+
// Given a map of options and a key, return a slice of strings
178+
// where the key matches the given key. The value is split by commas.
179+
// Example:
180+
// key = "regions"
181+
// opts = {"regions": "us-east-1,us-west-2"}
182+
// returns []string{"us-east-1", "us-west-2"}
183+
func parseCsvSliceOpt(opts map[string]string, key string) []string {
184+
res := []string{}
185+
for k, v := range opts {
186+
if k == "" || v == "" {
187+
continue
188+
}
189+
if k == key {
190+
res = append(res, strings.Split(v, ",")...)
191+
}
192+
}
193+
return res
194+
}

0 commit comments

Comments
 (0)