consolidateS3Objects merges multiple S3 BucketObject/BucketObjectv2 DecodedResources that share the same region, bucket, and storage volume type into a single "S3 Objects (xN)" entry. Each object otherwise produces its own "Storage" line with the same 25 GB-Mo default usage, duplicating the bucket's
(results []resources.DecodedResource)
| 97 | // its own "Storage" line with the same 25 GB-Mo default usage, duplicating |
| 98 | // the bucket's own Storage line and overstating the estimate. |
| 99 | func consolidateS3Objects(results []resources.DecodedResource) []resources.DecodedResource { |
| 100 | type group struct { |
| 101 | indices []int |
| 102 | names []string |
| 103 | } |
| 104 | groups := make(map[string]*group) |
| 105 | var order []string |
| 106 | |
| 107 | for i, d := range results { |
| 108 | if !s3ObjectTypes[d.RawType] { |
| 109 | continue |
| 110 | } |
| 111 | key := d.Region + "|" + d.Props["bucket"] + "|" + d.Props["volumeType"] |
| 112 | g, ok := groups[key] |
| 113 | if !ok { |
| 114 | g = &group{} |
| 115 | groups[key] = g |
| 116 | order = append(order, key) |
| 117 | } |
| 118 | g.indices = append(g.indices, i) |
| 119 | g.names = append(g.names, d.Name) |
| 120 | } |
| 121 | |
| 122 | const maxNames = 5 |
| 123 | replace := make(map[int]resources.DecodedResource) |
| 124 | remove := make(map[int]bool) |
| 125 | |
| 126 | for _, key := range order { |
| 127 | g := groups[key] |
| 128 | if len(g.indices) < 2 { |
| 129 | continue |
| 130 | } |
| 131 | |
| 132 | nameList := strings.Join(g.names[:min(len(g.names), maxNames)], ", ") |
| 133 | if len(g.names) > maxNames { |
| 134 | nameList += fmt.Sprintf(", ...and %d more", len(g.names)-maxNames) |
| 135 | } |
| 136 | |
| 137 | first := g.indices[0] |
| 138 | consolidated := results[first] |
| 139 | consolidated.Name = fmt.Sprintf("S3 Objects (x%d)", len(g.indices)) |
| 140 | |
| 141 | props := make(map[string]string, len(consolidated.Props)+2) |
| 142 | for k, v := range consolidated.Props { |
| 143 | props[k] = v |
| 144 | } |
| 145 | props["objectCount"] = strconv.Itoa(len(g.indices)) |
| 146 | props["objects"] = nameList |
| 147 | consolidated.Props = props |
| 148 | |
| 149 | replace[first] = consolidated |
| 150 | for _, idx := range g.indices[1:] { |
| 151 | remove[idx] = true |
| 152 | } |
| 153 | } |
| 154 | |
| 155 | if len(replace) == 0 { |
| 156 | return results |
no test coverage detected