Skip to content

Commit

Permalink
feat: Make policy loop with io.kubewarden.policy.echo.loop annot
Browse files Browse the repository at this point in the history
Add a new `Operation::Loop`, that corresponds to
`io.kubewarden.policy.echo.loop` annotation.

When this annotation is present, the policy will loop indifinetly.
This is helpful for testing purposes.

Signed-off-by: Víctor Cuadrado Juan <[email protected]>
  • Loading branch information
viccuad committed Jul 31, 2024
1 parent c839521 commit 33743fa
Show file tree
Hide file tree
Showing 3 changed files with 193 additions and 9 deletions.
20 changes: 11 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,14 @@ will contain the JSON representation of the the `AdmissionReview`.

These are the annotations being watched:

* `io.kubewarden.policy.echo.create`: rejects creation of objects with this annotations
* `io.kubewarden.policy.echo.updates`: rejects changes to objects with this annotations
* `io.kubewarden.policy.echo.delete`: rejects deletions of objects with this annotations
* `io.kubewarden.policy.echo.connect`: rejects CONNECT operations to objects with this annotations
- `io.kubewarden.policy.echo.create`: rejects creation of objects with this annotations
- `io.kubewarden.policy.echo.updates`: rejects changes to objects with this annotations
- `io.kubewarden.policy.echo.delete`: rejects deletions of objects with this annotations
- `io.kubewarden.policy.echo.connect`: rejects CONNECT operations to objects with this annotations
- `io.kubewarden.policy.echo.loop`: the policy loops. This will result in a
rejection as the policy-server timeout is reached and it fails-closed.

We will cover these in depth inside of the *"examples"* section.
We will cover these in depth inside of the _"examples"_ section.

## Settings

Expand Down Expand Up @@ -95,10 +97,10 @@ spec:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
```
Attempting to create this object will fail because the `echo` policy rejects
Expand Down
16 changes: 16 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ enum Operation {
Update,
Delete,
Connect,
Loop,
}

impl Operation {
Expand All @@ -26,6 +27,8 @@ impl Operation {
.expect("delete jmespath should not fail"),
Operation::Connect => jmespath::compile("request.object.metadata.annotations")
.expect("connect jmespath should not fail"),
Operation::Loop => jmespath::compile("request.object.metadata.annotations")
.expect("connect jmespath should not fail"),
}
}

Expand All @@ -35,6 +38,7 @@ impl Operation {
Operation::Update => "io.kubewarden.policy.echo.update",
Operation::Delete => "io.kubewarden.policy.echo.delete",
Operation::Connect => "io.kubewarden.policy.echo.connect",
Operation::Loop => "io.kubewarden.policy.echo.loop",
}
}
}
Expand All @@ -48,6 +52,7 @@ impl TryFrom<&String> for Operation {
"UPDATE" => Ok(Operation::Update),
"DELETE" => Ok(Operation::Delete),
"CONNECT" => Ok(Operation::Connect),
"LOOP" => Ok(Operation::Loop),
_ => Err(format!("unknown type of operation: {value}")),
}
}
Expand All @@ -74,6 +79,11 @@ fn validate(payload: &[u8]) -> CallResult {
.ok_or_else(|| anyhow!("jmespath didn't return a string"))?,
)?;

if matches!(operation, Operation::Loop) {
#[allow(clippy::empty_loop)]
loop {}
}

// Search the data with the compiled expression
let result = operation.annotation_expr().search(data.clone())?;
if result.is_object() {
Expand Down Expand Up @@ -115,6 +125,12 @@ mod tests {
expected_validation_result: true,
settings: Settings {},
},
Testcase {
name: String::from("loop"),
fixture_file: String::from("test_data/create_loop.json"),
expected_validation_result: true,
settings: Settings {},
},
];

for tc in &test_cases {
Expand Down
166 changes: 166 additions & 0 deletions test_data/create_loop.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
{
"dryRun": false,
"kind": {
"group": "apps",
"kind": "Deployment",
"version": "v1"
},
"name": "nginx",
"namespace": "default",
"object": {
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": {
"annotations": {
"io.kubewarden.policy.echo.loop": "true",
"kubectl.kubernetes.io/last-applied-configuration": "{\"apiVersion\":\"apps/v1\",\"kind\":\"Deployment\",\"metadata\":{\"annotations\":{\"io.kubewarden.policy.echo.create\":\"true\"},\"name\":\"nginx\",\"namespace\":\"default\"},\"spec\":{\"replicas\":0,\"selector\":{\"matchLabels\":{\"app\":\"nginx\"}},\"template\":{\"metadata\":{\"labels\":{\"app\":\"nginx\"}},\"spec\":{\"containers\":[{\"image\":\"nginx:latest\",\"name\":\"nginx\",\"ports\":[{\"containerPort\":80}]}]}}}}\n"
},
"creationTimestamp": "2022-06-22T13:23:21Z",
"generation": 1,
"managedFields": [
{
"apiVersion": "apps/v1",
"fieldsType": "FieldsV1",
"fieldsV1": {
"f:metadata": {
"f:annotations": {
".": {},
"f:io.kubewarden.policy.echo.create": {},
"f:kubectl.kubernetes.io/last-applied-configuration": {}
}
},
"f:spec": {
"f:progressDeadlineSeconds": {},
"f:replicas": {},
"f:revisionHistoryLimit": {},
"f:selector": {},
"f:strategy": {
"f:rollingUpdate": {
".": {},
"f:maxSurge": {},
"f:maxUnavailable": {}
},
"f:type": {}
},
"f:template": {
"f:metadata": {
"f:labels": {
".": {},
"f:app": {}
}
},
"f:spec": {
"f:containers": {
"k:{\"name\":\"nginx\"}": {
".": {},
"f:image": {},
"f:imagePullPolicy": {},
"f:name": {},
"f:ports": {
".": {},
"k:{\"containerPort\":80,\"protocol\":\"TCP\"}": {
".": {},
"f:containerPort": {},
"f:protocol": {}
}
},
"f:resources": {},
"f:terminationMessagePath": {},
"f:terminationMessagePolicy": {}
}
},
"f:dnsPolicy": {},
"f:restartPolicy": {},
"f:schedulerName": {},
"f:securityContext": {},
"f:terminationGracePeriodSeconds": {}
}
}
}
},
"manager": "kubectl-client-side-apply",
"operation": "Update",
"time": "2022-06-22T13:23:21Z"
}
],
"name": "nginx",
"namespace": "default",
"uid": "5be2582c-c8fb-4318-8d47-6df8a24affc7"
},
"spec": {
"progressDeadlineSeconds": 600,
"replicas": 0,
"revisionHistoryLimit": 10,
"selector": {
"matchLabels": {
"app": "nginx"
}
},
"strategy": {
"rollingUpdate": {
"maxSurge": "25%",
"maxUnavailable": "25%"
},
"type": "RollingUpdate"
},
"template": {
"metadata": {
"creationTimestamp": null,
"labels": {
"app": "nginx"
}
},
"spec": {
"containers": [
{
"image": "nginx:latest",
"imagePullPolicy": "Always",
"name": "nginx",
"ports": [
{
"containerPort": 80,
"protocol": "TCP"
}
],
"resources": {},
"terminationMessagePath": "/dev/termination-log",
"terminationMessagePolicy": "File"
}
],
"dnsPolicy": "ClusterFirst",
"restartPolicy": "Always",
"schedulerName": "default-scheduler",
"securityContext": {},
"terminationGracePeriodSeconds": 30
}
}
},
"status": {}
},
"operation": "CREATE",
"options": {
"apiVersion": "meta.k8s.io/v1",
"fieldManager": "kubectl-client-side-apply",
"kind": "CreateOptions"
},
"requestKind": {
"group": "apps",
"kind": "Deployment",
"version": "v1"
},
"requestResource": {
"group": "apps",
"resource": "deployments",
"version": "v1"
},
"resource": {
"group": "apps",
"resource": "deployments",
"version": "v1"
},
"uid": "307362f8-ffb1-481a-9ce7-7e6192fbc699",
"userInfo": {
"groups": ["system:masters", "system:authenticated"],
"username": "minikube-user"
}
}

0 comments on commit 33743fa

Please sign in to comment.