Skip to content

Commit b7f6c67

Browse files
authored
feat: fix skip-acls on apply and add tests (#57)
1 parent 1e47feb commit b7f6c67

File tree

14 files changed

+248
-16
lines changed

14 files changed

+248
-16
lines changed

docs/quick-start.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,11 +89,16 @@ Plan: 1 to create, 0 to update, 0 to delete.
8989

9090
In most cases, you will want to output the plan to a file which can then be passed to the apply command. Plan files are `JSON` files. This can be done by running:
9191

92-
9392
```bash
9493
kafka-gitops plan -o plan.json
9594
```
9695

96+
If running against a Kafka cluster with no authorizer configured or if you simply want to only manage topics, you can ignore ACLs completely. This can be done by running:
97+
98+
```bash
99+
kafka-gitops --skip-acls plan
100+
```
101+
97102
## Apply
98103

99104
To execute a plan against the cluster, we use the apply command.

src/main/java/com/devshawn/kafka/gitops/MainCommand.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public class MainCommand implements Callable<Integer> {
3030
@Option(names = {"--no-delete"}, description = "Disable the ability to delete resources.")
3131
private boolean deleteDisabled = false;
3232

33-
@Option(names = {"--skip-acls"}, description = "Do not take ACL into account in the plan file.")
33+
@Option(names = {"--skip-acls"}, description = "Do not take ACLs into account during plans or applies.")
3434
private boolean skipAcls = false;
3535

3636
@Option(names = {"-h", "--help"}, usageHelp = true, description = "Display this help message.")

src/main/java/com/devshawn/kafka/gitops/StateManager.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ public DesiredStateFile getAndValidateStateFile() {
7979
public DesiredPlan plan() {
8080
DesiredPlan desiredPlan = generatePlan();
8181
planManager.writePlanToFile(desiredPlan);
82-
planManager.validatePlanHasChanges(desiredPlan, managerConfig.isDeleteDisabled());
82+
planManager.validatePlanHasChanges(desiredPlan, managerConfig.isDeleteDisabled(), managerConfig.isSkipAclsDisabled());
8383
return desiredPlan;
8484
}
8585

@@ -99,10 +99,12 @@ public DesiredPlan apply() {
9999
desiredPlan = generatePlan();
100100
}
101101

102-
planManager.validatePlanHasChanges(desiredPlan, managerConfig.isDeleteDisabled());
102+
planManager.validatePlanHasChanges(desiredPlan, managerConfig.isDeleteDisabled(), managerConfig.isSkipAclsDisabled());
103103

104104
applyManager.applyTopics(desiredPlan);
105-
applyManager.applyAcls(desiredPlan);
105+
if (!managerConfig.isSkipAclsDisabled()) {
106+
applyManager.applyAcls(desiredPlan);
107+
}
106108

107109
return desiredPlan;
108110
}

src/main/java/com/devshawn/kafka/gitops/cli/ApplyCommand.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public Integer call() {
3434
ParserService parserService = new ParserService(parent.getFile());
3535
StateManager stateManager = new StateManager(generateStateManagerConfig(), parserService);
3636
DesiredPlan desiredPlan = stateManager.apply();
37-
LogUtil.printApplyOverview(PlanUtil.getOverview(desiredPlan, parent.isDeleteDisabled()));
37+
LogUtil.printApplyOverview(PlanUtil.getOverview(desiredPlan, parent.isDeleteDisabled(), parent.areAclsDisabled()));
3838
return 0;
3939
} catch (PlanIsUpToDateException ex) {
4040
LogUtil.printNoChangesMessage();

src/main/java/com/devshawn/kafka/gitops/cli/PlanCommand.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public Integer call() {
3636
ParserService parserService = new ParserService(parent.getFile());
3737
StateManager stateManager = new StateManager(generateStateManagerConfig(), parserService);
3838
DesiredPlan desiredPlan = stateManager.plan();
39-
LogUtil.printPlan(desiredPlan, parent.isDeleteDisabled());
39+
LogUtil.printPlan(desiredPlan, parent.isDeleteDisabled(), parent.areAclsDisabled());
4040
return 0;
4141
} catch (PlanIsUpToDateException ex) {
4242
LogUtil.printNoChangesMessage();

src/main/java/com/devshawn/kafka/gitops/manager/PlanManager.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,8 +173,8 @@ public void planAcls(DesiredState desiredState, DesiredPlan.Builder desiredPlan)
173173
});
174174
}
175175

176-
public void validatePlanHasChanges(DesiredPlan desiredPlan, boolean deleteDisabled) {
177-
PlanOverview planOverview = PlanUtil.getOverview(desiredPlan, deleteDisabled);
176+
public void validatePlanHasChanges(DesiredPlan desiredPlan, boolean deleteDisabled, boolean skipAclsDisabled) {
177+
PlanOverview planOverview = PlanUtil.getOverview(desiredPlan, deleteDisabled, skipAclsDisabled);
178178
if (planOverview.getAdd() == 0 && planOverview.getUpdate() == 0 && planOverview.getRemove() == 0) {
179179
throw new PlanIsUpToDateException();
180180
}

src/main/java/com/devshawn/kafka/gitops/util/LogUtil.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@
1414

1515
public class LogUtil {
1616

17-
public static void printPlan(DesiredPlan desiredPlan, boolean deleteDisabled) {
18-
PlanOverview planOverview = PlanUtil.getOverview(desiredPlan, deleteDisabled);
17+
public static void printPlan(DesiredPlan desiredPlan, boolean deleteDisabled, boolean skipAclsDisabled) {
18+
PlanOverview planOverview = PlanUtil.getOverview(desiredPlan, deleteDisabled, skipAclsDisabled);
1919

2020
printLegend(planOverview);
2121

@@ -25,7 +25,7 @@ public static void printPlan(DesiredPlan desiredPlan, boolean deleteDisabled) {
2525
printAclOverview(desiredPlan, deleteDisabled);
2626
desiredPlan.getAclPlans().forEach(LogUtil::printAclPlan);
2727

28-
printOverview(desiredPlan, deleteDisabled);
28+
printOverview(desiredPlan, deleteDisabled, skipAclsDisabled);
2929
}
3030

3131
public static void printValidationResult(String message, boolean success) {
@@ -131,8 +131,8 @@ public static void printPostApply() {
131131
* Helpers
132132
*/
133133

134-
private static void printOverview(DesiredPlan desiredPlan, boolean deleteDisabled) {
135-
PlanOverview planOverview = PlanUtil.getOverview(desiredPlan, deleteDisabled);
134+
private static void printOverview(DesiredPlan desiredPlan, boolean deleteDisabled, boolean skipAclsDisabled) {
135+
PlanOverview planOverview = PlanUtil.getOverview(desiredPlan, deleteDisabled, skipAclsDisabled);
136136
System.out.println(String.format("%s: %s, %s, %s.", bold("Plan"), toCreate(planOverview.getAdd()),
137137
toUpdate(planOverview.getUpdate()), toDelete(planOverview.getRemove())));
138138
}

src/main/java/com/devshawn/kafka/gitops/util/PlanUtil.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,12 @@
99

1010
public class PlanUtil {
1111

12-
public static PlanOverview getOverview(DesiredPlan desiredPlan, boolean deleteDisabled) {
12+
public static PlanOverview getOverview(DesiredPlan desiredPlan, boolean deleteDisabled, boolean skipAclsDisabled) {
1313
EnumMap<PlanAction, Long> map = getPlanActionMap();
1414
desiredPlan.getTopicPlans().forEach(it -> addToMap(map, it.getAction(), deleteDisabled));
15-
desiredPlan.getAclPlans().forEach(it -> addToMap(map, it.getAction(), deleteDisabled));
15+
if(!skipAclsDisabled) {
16+
desiredPlan.getAclPlans().forEach(it -> addToMap(map, it.getAction(), deleteDisabled));
17+
}
1618
return buildPlanOverview(map);
1719
}
1820

src/test/groovy/com/devshawn/kafka/gitops/ApplyCommandIntegrationSpec.groovy

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,31 @@ class ApplyCommandIntegrationSpec extends Specification {
6262
]
6363
}
6464

65+
void 'test skip-acls flag'() {
66+
setup:
67+
ByteArrayOutputStream out = new ByteArrayOutputStream()
68+
PrintStream oldOut = System.out
69+
System.setOut(new PrintStream(out))
70+
String file = TestUtils.getResourceFilePath("plans/${planFile}-plan.json")
71+
MainCommand mainCommand = new MainCommand()
72+
CommandLine cmd = new CommandLine(mainCommand)
73+
74+
when:
75+
int exitCode = cmd.execute("-f", file, "--skip-acls", "apply", "-p", file)
76+
77+
then:
78+
exitCode == 0
79+
out.toString() == TestUtils.getResourceFileContent("plans/${planFile}-apply-output.txt")
80+
81+
cleanup:
82+
System.setOut(oldOut)
83+
84+
where:
85+
planFile << [
86+
"skip-acls-apply"
87+
]
88+
}
89+
6590
void 'test various valid applies with seed - #planFile #deleteDisabled'() {
6691
setup:
6792
TestUtils.seedCluster()

src/test/groovy/com/devshawn/kafka/gitops/PlanCommandIntegrationSpec.groovy

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,32 @@ class PlanCommandIntegrationSpec extends Specification {
7171
]
7272
}
7373

74+
void 'test skip-acls flag'() {
75+
setup:
76+
String planOutputFile = "/tmp/plan.json"
77+
String file = TestUtils.getResourceFilePath("plans/${planName}.yaml")
78+
MainCommand mainCommand = new MainCommand()
79+
CommandLine cmd = new CommandLine(mainCommand)
80+
81+
when:
82+
int exitCode = cmd.execute("-f", file, "--skip-acls", "plan", "-o", planOutputFile)
83+
84+
then:
85+
exitCode == 0
86+
87+
when:
88+
String actualPlan = TestUtils.getFileContent(planOutputFile)
89+
String expectedPlan = TestUtils.getResourceFileContent("plans/${planName}-plan.json")
90+
91+
then:
92+
JSONAssert.assertEquals(expectedPlan, actualPlan, true)
93+
94+
where:
95+
planName << [
96+
"skip-acls"
97+
]
98+
}
99+
74100
void 'test various valid plans with seed - #planName'() {
75101
setup:
76102
TestUtils.cleanUpCluster()
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
Executing apply...
2+
3+
Applying: [CREATE]
4+
5+
+ [TOPIC] MY_TOPIC
6+
+ partitions: 6
7+
+ replication: 1
8+
9+
10+
Successfully applied.
11+
12+
Applying: [CREATE]
13+
14+
+ [TOPIC] another.topic.0
15+
+ partitions: 1
16+
+ replication: 1
17+
+ configs:
18+
+ cleanup.policy: compact
19+
+ segment.bytes: 100000
20+
21+
22+
Successfully applied.
23+
24+
[SUCCESS] Apply complete! Resources: 2 created, 0 updated, 0 deleted.
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
{
2+
"topicPlans": [
3+
{
4+
"name": "MY_TOPIC",
5+
"action": "ADD",
6+
"topicDetails": {
7+
"partitions": 6,
8+
"replication": 1,
9+
"configs": {}
10+
},
11+
"topicConfigPlans": []
12+
},
13+
{
14+
"name": "another.topic.0",
15+
"action": "ADD",
16+
"topicDetails": {
17+
"partitions": 1,
18+
"replication": 1,
19+
"configs": {
20+
"cleanup.policy": "compact",
21+
"segment.bytes": "100000"
22+
}
23+
},
24+
"topicConfigPlans": []
25+
}
26+
],
27+
"aclPlans": [
28+
{
29+
"name": "test-service-0",
30+
"aclDetails": {
31+
"name": "another.topic.0",
32+
"type": "TOPIC",
33+
"pattern": "LITERAL",
34+
"principal": "User:test",
35+
"host": "*",
36+
"operation": "WRITE",
37+
"permission": "ALLOW"
38+
},
39+
"action": "ADD"
40+
},
41+
{
42+
"name": "test-service-1",
43+
"aclDetails": {
44+
"name": "MY_TOPIC",
45+
"type": "TOPIC",
46+
"pattern": "LITERAL",
47+
"principal": "User:test",
48+
"host": "*",
49+
"operation": "READ",
50+
"permission": "ALLOW"
51+
},
52+
"action": "ADD"
53+
},
54+
{
55+
"name": "test-service-2",
56+
"aclDetails": {
57+
"name": "test-service",
58+
"type": "GROUP",
59+
"pattern": "LITERAL",
60+
"principal": "User:test",
61+
"host": "*",
62+
"operation": "READ",
63+
"permission": "ALLOW"
64+
},
65+
"action": "ADD"
66+
},
67+
{
68+
"name": "my-other-service-0",
69+
"aclDetails": {
70+
"name": "another.topic.0",
71+
"type": "TOPIC",
72+
"pattern": "LITERAL",
73+
"principal": "User:test",
74+
"host": "*",
75+
"operation": "READ",
76+
"permission": "ALLOW"
77+
},
78+
"action": "ADD"
79+
},
80+
{
81+
"name": "my-other-service-1",
82+
"aclDetails": {
83+
"name": "my-other-service",
84+
"type": "GROUP",
85+
"pattern": "LITERAL",
86+
"principal": "User:test",
87+
"host": "*",
88+
"operation": "READ",
89+
"permission": "ALLOW"
90+
},
91+
"action": "ADD"
92+
}
93+
]
94+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
{
2+
"topicPlans": [
3+
{
4+
"name": "MY_TOPIC",
5+
"action": "ADD",
6+
"topicDetails": {
7+
"partitions": 6,
8+
"replication": 1,
9+
"configs": {}
10+
},
11+
"topicConfigPlans": []
12+
},
13+
{
14+
"name": "another.topic.0",
15+
"action": "ADD",
16+
"topicDetails": {
17+
"partitions": 1,
18+
"replication": 1,
19+
"configs": {
20+
"cleanup.policy": "compact",
21+
"segment.bytes": "100000"
22+
}
23+
},
24+
"topicConfigPlans": []
25+
}
26+
],
27+
"aclPlans": []
28+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
topics:
2+
MY_TOPIC:
3+
partitions: 6
4+
replication: 1
5+
6+
another.topic.0:
7+
partitions: 1
8+
replication: 1
9+
configs:
10+
cleanup.policy: compact
11+
segment.bytes: 100000
12+
13+
services:
14+
test-service:
15+
type: application
16+
principal: User:test
17+
produces:
18+
- another.topic.0
19+
consumes:
20+
- MY_TOPIC
21+
22+
my-other-service:
23+
type: application
24+
principal: User:test
25+
consumes:
26+
- another.topic.0

0 commit comments

Comments
 (0)