Skip to content

Commit 1d5969a

Browse files
authored
DENA-671: refactor: extracted test cases from func & split them into multiple scenarios (#26)
* refactor: extracted test cases from func & split them into multiple scenarios * DENA-671: Compacted topics validations (#27)
1 parent 608b8d2 commit 1d5969a

File tree

3 files changed

+561
-330
lines changed

3 files changed

+561
-330
lines changed

rules/msk_topic_config.go

Lines changed: 88 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -74,16 +74,12 @@ func (r *MSKTopicConfigRule) validateTopicConfig(runner tflint.Runner, topic *hc
7474
return err
7575
}
7676

77-
configAttr, hasConfig := topic.Body.Attributes["config"]
78-
if !hasConfig {
79-
err := runner.EmitIssue(
80-
r,
81-
"missing config attribute: the topic configuration must be specified in a config attribute",
82-
topic.DefRange,
83-
)
84-
if err != nil {
85-
return fmt.Errorf("emitting issue: missing config block: %w", err)
86-
}
77+
configAttr, err := r.validateAndGetConfigAttr(runner, topic)
78+
if err != nil {
79+
return err
80+
}
81+
82+
if configAttr == nil {
8783
return nil
8884
}
8985

@@ -97,21 +93,61 @@ func (r *MSKTopicConfigRule) validateTopicConfig(runner tflint.Runner, topic *hc
9793
return err
9894
}
9995

100-
cleanupPolicy, err := r.getAndValidateCleanupPolicy(runner, configAttr, configKeyToPairMap)
96+
if err = r.validateCleanupPolicyConfig(runner, configAttr, configKeyToPairMap); err != nil {
97+
return err
98+
}
99+
return nil
100+
}
101+
102+
func (r *MSKTopicConfigRule) validateCleanupPolicyConfig(
103+
runner tflint.Runner,
104+
configAttr *hclext.Attribute,
105+
configKeyToPairMap map[string]hcl.KeyValuePair,
106+
) error {
107+
cleanupPolicy, err := r.getAndValidateCleanupPolicyValue(runner, configAttr, configKeyToPairMap)
101108
if err != nil {
102109
return err
103110
}
111+
104112
switch cleanupPolicy {
105113
case cleanupPolicyDelete:
106114
if err := r.validateRetentionForDeletePolicy(runner, configAttr, configKeyToPairMap); err != nil {
107115
return err
108116
}
109117
case cleanupPolicyCompact:
110-
// todo: validate no retention & remote storage for compact
118+
reason := "compacted topic"
119+
if err := r.validateTieredStorageDisabled(runner, configKeyToPairMap, reason); err != nil {
120+
return err
121+
}
122+
if err := r.validateLocalRetentionNotDefined(runner, configKeyToPairMap, reason); err != nil {
123+
return err
124+
}
125+
if err := r.validateRetentionTimeNotDefined(runner, configKeyToPairMap, reason); err != nil {
126+
return err
127+
}
111128
}
112129
return nil
113130
}
114131

132+
func (r *MSKTopicConfigRule) validateAndGetConfigAttr(
133+
runner tflint.Runner,
134+
topic *hclext.Block,
135+
) (*hclext.Attribute, error) {
136+
configAttr, hasConfig := topic.Body.Attributes["config"]
137+
if !hasConfig {
138+
err := runner.EmitIssue(
139+
r,
140+
"missing config attribute: the topic configuration must be specified in a config attribute",
141+
topic.DefRange,
142+
)
143+
if err != nil {
144+
return nil, fmt.Errorf("emitting issue: missing config block: %w", err)
145+
}
146+
return nil, nil
147+
}
148+
return configAttr, nil
149+
}
150+
115151
func constructConfigKeyToPairMap(configAttr *hclext.Attribute) (map[string]hcl.KeyValuePair, error) {
116152
configExpr, ok := configAttr.Expr.(*hclsyntax.ObjectConsExpr)
117153
if !ok {
@@ -258,7 +294,7 @@ var (
258294
cleanupPolicyValidValues = []string{cleanupPolicyDelete, cleanupPolicyCompact}
259295
)
260296

261-
func (r *MSKTopicConfigRule) getAndValidateCleanupPolicy(
297+
func (r *MSKTopicConfigRule) getAndValidateCleanupPolicyValue(
262298
runner tflint.Runner,
263299
config *hclext.Attribute,
264300
configKeyToPairMap map[string]hcl.KeyValuePair,
@@ -349,11 +385,12 @@ func (r *MSKTopicConfigRule) validateRetentionForDeletePolicy(
349385
return err
350386
}
351387
} else {
352-
if err := r.validateTieredStorageNotEnabled(runner, configKeyToPairMap); err != nil {
388+
reason := fmt.Sprintf("less than %d days retention", tieredStorageThresholdInDays)
389+
if err := r.validateTieredStorageDisabled(runner, configKeyToPairMap, reason); err != nil {
353390
return err
354391
}
355392

356-
if err := r.validateLocalRetentionNotDefined(runner, configKeyToPairMap); err != nil {
393+
if err := r.validateLocalRetentionNotDefined(runner, configKeyToPairMap, reason); err != nil {
357394
return err
358395
}
359396
}
@@ -413,16 +450,17 @@ func (r *MSKTopicConfigRule) validateLocalRetentionDefined(
413450
func (r *MSKTopicConfigRule) validateLocalRetentionNotDefined(
414451
runner tflint.Runner,
415452
configKeyToPairMap map[string]hcl.KeyValuePair,
453+
reason string,
416454
) error {
417455
localRetTimePair, hasLocalRetTimeAttr := configKeyToPairMap[localRetentionTimeAttr]
418456
if !hasLocalRetTimeAttr {
419457
return nil
420458
}
421459

422460
msg := fmt.Sprintf(
423-
"defining %s is misleading when tiered storage is disabled due to less than %d days retention: removing it...",
461+
"defining %s is misleading when tiered storage is disabled due to %s: removing it...",
424462
localRetentionTimeAttr,
425-
tieredStorageThresholdInDays,
463+
reason,
426464
)
427465
err := runner.EmitIssueWithFix(r, msg, localRetTimePair.Value.Range(),
428466
func(f tflint.Fixer) error {
@@ -490,9 +528,10 @@ func (r *MSKTopicConfigRule) validateTieredStorageEnabled(
490528
return nil
491529
}
492530

493-
func (r *MSKTopicConfigRule) validateTieredStorageNotEnabled(
531+
func (r *MSKTopicConfigRule) validateTieredStorageDisabled(
494532
runner tflint.Runner,
495533
configKeyToPairMap map[string]hcl.KeyValuePair,
534+
reason string,
496535
) error {
497536
tieredStoragePair, hasTieredStorageAttr := configKeyToPairMap[tieredStorageEnableAttr]
498537

@@ -511,8 +550,8 @@ func (r *MSKTopicConfigRule) validateTieredStorageNotEnabled(
511550
}
512551

513552
msg := fmt.Sprintf(
514-
"tiered storage is not supported for less than %d days retention: disabling it...",
515-
tieredStorageThresholdInDays,
553+
"tiered storage is not supported for %s: disabling it...",
554+
reason,
516555
)
517556
err := runner.EmitIssueWithFix(r, msg, tieredStoragePair.Value.Range(),
518557
func(f tflint.Fixer) error {
@@ -573,3 +612,32 @@ func (r *MSKTopicConfigRule) getAndValidateRetentionTime(
573612
}
574613
return &retTimeIntVal, nil
575614
}
615+
616+
func (r *MSKTopicConfigRule) validateRetentionTimeNotDefined(
617+
runner tflint.Runner,
618+
configKeyToPairMap map[string]hcl.KeyValuePair,
619+
reason string,
620+
) error {
621+
retTimePair, hasRetTime := configKeyToPairMap[retentionTimeAttr]
622+
if !hasRetTime {
623+
return nil
624+
}
625+
msg := fmt.Sprintf("defining %s is misleading for %s: removing it...", retentionTimeAttr, reason)
626+
keyRange := retTimePair.Key.Range()
627+
628+
err := runner.EmitIssueWithFix(r, msg, keyRange,
629+
func(f tflint.Fixer) error {
630+
return f.Remove(
631+
hcl.Range{
632+
Filename: keyRange.Filename,
633+
Start: keyRange.Start,
634+
End: retTimePair.Value.Range().End,
635+
},
636+
)
637+
},
638+
)
639+
if err != nil {
640+
return fmt.Errorf("emitting issue: retention time defined for compacted topic: %w", err)
641+
}
642+
return nil
643+
}

rules/msk_topic_config.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ When cleanup policy is 'delete':
1313
- for a retention period less than 3 days, tiered storage must be disabled and the local.retention.ms parameter must not be defined.
1414
See the [AWS docs](https://docs.aws.amazon.com/msk/latest/developerguide/msk-tiered-storage.html#msk-tiered-storage-constraints).
1515

16+
When cleanup policy is 'compact':
17+
- 'retention.ms' must not be specified in the config as it is misleading. It doesn't apply to compacted topics. See [definition](https://docs.confluent.io/platform/current/installation/configuration/topic-configs.html#retention-ms)
18+
- tiered storage must not be enabled as it is not supported for compacted topics. See [limitations](https://docs.aws.amazon.com/msk/latest/developerguide/msk-tiered-storage.html#msk-tiered-storage-constraints).
19+
1620
## Example
1721

1822
### Good example
@@ -42,6 +46,16 @@ resource "kafka_topic" "good topic" {
4246
"retention.ms" = "86400000"
4347
}
4448
}
49+
50+
# Good compacted topic
51+
resource "kafka_topic" "good topic" {
52+
name = "good_topic"
53+
replication_factor = 3
54+
config = {
55+
"cleanup.policy" = "compact"
56+
"compression.type" = "zstd"
57+
}
58+
}
4559
```
4660

4761
### Bad examples
@@ -88,6 +102,17 @@ resource "kafka_topic" "topic_with_more_than_3_days_retention" {
88102
"compression.type" = "zstd"
89103
}
90104
}
105+
106+
# compacted topic with tiered storage enabled
107+
resource "kafka_topic" "topic_compacted_with_tiered_storage" {
108+
name = "topic_compacted_with_tiered_storage"
109+
replication_factor = 3
110+
config = {
111+
"remote.storage.enable" = "true"
112+
"cleanup.policy" = "compact"
113+
"compression.type" = "zstd"
114+
}
115+
}
91116
```
92117

93118
## How To Fix

0 commit comments

Comments
 (0)