Get Started With Operations
This feature was introduced in v2.
For more information read the Crossplane feature lifecycle.
This guide shows how to use Crossplane Operations to automate day-two
operational tasks. You create an Operation that checks SSL certificate
expiry for a website.
Crossplane calls this Operations. Operations run function pipelines to perform tasks that don’t fit the typical resource creation pattern - like certificate monitoring, rolling upgrades, or scheduled maintenance.
An Operation looks like this:
1apiVersion: ops.crossplane.io/v1alpha1
2kind: Operation
3metadata:
4 name: check-cert-expiry
5spec:
6 mode: Pipeline
7 pipeline:
8 - step: check-certificate
9 functionRef:
10 name: crossplane-contrib-function-python
11 input:
12 apiVersion: python.fn.crossplane.io/v1beta1
13 kind: Script
14 script: |
15 import ssl
16 import socket
17 from datetime import datetime
18
19 from crossplane.function import request, response
20
21 def operate(req, rsp):
22 hostname = "google.com"
23 port = 443
24
25 # Get SSL certificate info
26 context = ssl.create_default_context()
27 with socket.create_connection((hostname, port)) as sock:
28 with context.wrap_socket(sock, server_hostname=hostname) as ssock:
29 cert = ssock.getpeercert()
30
31 # Parse expiration date
32 expiry_date = datetime.strptime(cert['notAfter'], '%b %d %H:%M:%S %Y %Z')
33 days_until_expiry = (expiry_date - datetime.now()).days
34
35 # Return results in operation output
36 response.set_output(rsp, {
37 "hostname": hostname,
38 "certificateExpires": cert['notAfter'],
39 "daysUntilExpiry": days_until_expiry,
40 "status": "warning" if days_until_expiry < 30 else "ok"
41 })
The Operation runs once to completion, like a Kubernetes Job.
When you create the Operation, Crossplane runs the function pipeline. The
function checks SSL certificate expiry for google.com and returns the results
in the operation’s output.
This basic example shows the concept. In the walkthrough below, you create
a more realistic Operation that reads Kubernetes Ingress resources and
annotates them with certificate expiry information for monitoring tools.
Prerequisites
This guide requires:
- A Kubernetes cluster with at least 2 GB of RAM
- The Crossplane v2 preview installed on the Kubernetes cluster with Operations enabled
Create an operation
Follow these steps to create your first Operation:
- Create a sample Ingress for certificate checking
- Install the function you want to use for the operation
- Create the Operation that checks the
Ingress - Check the Operation as it runs
Create a sample Ingress
Create an Ingress that references a real hostname but doesn’t route actual
traffic:
1apiVersion: networking.k8s.io/v1
2kind: Ingress
3metadata:
4 name: example-app
5 namespace: default
6spec:
7 rules:
8 - host: google.com
9 http:
10 paths:
11 - path: /
12 pathType: Prefix
13 backend:
14 service:
15 name: nonexistent-service
16 port:
17 number: 80
Save as ingress.yaml and apply it:
1kubectl apply -f ingress.yaml
Grant Ingress permissions
Operations need permission to access and change Ingresses. Create a ClusterRole
that grants Crossplane access to Ingresses:
1apiVersion: rbac.authorization.k8s.io/v1
2kind: ClusterRole
3metadata:
4 name: operations-ingress-access
5 labels:
6 rbac.crossplane.io/aggregate-to-crossplane: "true"
7rules:
8- apiGroups: ["networking.k8s.io"]
9 resources: ["ingresses"]
10 verbs: ["get", "list", "watch", "patch", "update"]
Save as ingress-rbac.yaml and apply it:
1kubectl apply -f ingress-rbac.yaml
Install the function
Operations use operation functions to implement their logic. Use the Python function, which supports both composition and operations.
Create this function to install Python support:
1apiVersion: pkg.crossplane.io/v1
2kind: Function
3metadata:
4 name: crossplane-contrib-function-python
5spec:
6 package: xpkg.crossplane.io/crossplane-contrib/function-python:v0.2.0
Save the function as function.yaml and apply it:
1kubectl apply -f function.yaml
Check that Crossplane installed the function:
1kubectl get -f function.yaml
2NAME INSTALLED HEALTHY PACKAGE AGE
3crossplane-contrib-function-python True True xpkg.crossplane.io/crossplane-contrib/function-python:v0.2.0 12s
Create the operation
Create this Operation that monitors the Ingress certificate:
1apiVersion: ops.crossplane.io/v1alpha1
2kind: Operation
3metadata:
4 name: ingress-cert-monitor
5spec:
6 mode: Pipeline
7 pipeline:
8 - step: check-ingress-certificate
9 functionRef:
10 name: crossplane-contrib-function-python
11 requirements:
12 requiredResources:
13 - requirementName: ingress
14 apiVersion: networking.k8s.io/v1
15 kind: Ingress
16 name: example-app
17 namespace: default
18 input:
19 apiVersion: python.fn.crossplane.io/v1beta1
20 kind: Script
21 script: |
22 import ssl
23 import socket
24 from datetime import datetime
25
26 from crossplane.function import request, response
27
28 def operate(req, rsp):
29 # Get the Ingress resource
30 ingress = request.get_required_resource(req, "ingress")
31 if not ingress:
32 response.set_output(rsp, {"error": "No ingress resource found"})
33 return
34
35 # Extract hostname from Ingress rules
36 hostname = ingress["spec"]["rules"][0]["host"]
37 port = 443
38
39 # Get SSL certificate info
40 context = ssl.create_default_context()
41 with socket.create_connection((hostname, port)) as sock:
42 with context.wrap_socket(sock, server_hostname=hostname) as ssock:
43 cert = ssock.getpeercert()
44
45 # Parse expiration date
46 expiry_date = datetime.strptime(cert['notAfter'], '%b %d %H:%M:%S %Y %Z')
47 days_until_expiry = (expiry_date - datetime.now()).days
48
49 # Add warning if certificate expires soon
50 if days_until_expiry < 30:
51 response.warning(rsp, f"Certificate for {hostname} expires in {days_until_expiry} days")
52
53 # Annotate the Ingress with certificate expiry info
54 rsp.desired.resources["ingress"].resource.update({
55 "apiVersion": "networking.k8s.io/v1",
56 "kind": "Ingress",
57 "metadata": {
58 "name": ingress["metadata"]["name"],
59 "namespace": ingress["metadata"]["namespace"],
60 "annotations": {
61 "cert-monitor.crossplane.io/expires": cert['notAfter'],
62 "cert-monitor.crossplane.io/days-until-expiry": str(days_until_expiry),
63 "cert-monitor.crossplane.io/status": "warning" if days_until_expiry < 30 else "ok"
64 }
65 }
66 })
67
68 # Return results in operation output for monitoring
69 response.set_output(rsp, {
70 "ingressName": ingress["metadata"]["name"],
71 "hostname": hostname,
72 "certificateExpires": cert['notAfter'],
73 "daysUntilExpiry": days_until_expiry,
74 "status": "warning" if days_until_expiry < 30 else "ok"
75 })
Save the operation as operation.yaml and apply it:
1kubectl apply -f operation.yaml
Check the operation
Check that the Operation runs successfully:
Operations show SUCCEEDED=True when they complete successfully.Check the Operation’s detailed status:
1kubectl describe operation ingress-cert-monitor
2# ... metadata ...
3Status:
4 Conditions:
5 Last Transition Time: 2024-01-15T10:30:15Z
6 Reason: PipelineSuccess
7 Status: True
8 Type: Succeeded
9 Last Transition Time: 2024-01-15T10:30:15Z
10 Reason: ValidPipeline
11 Status: True
12 Type: ValidPipeline
13 Pipeline:
14 Output:
15 Certificate Expires: Sep 29 08:34:02 2025 GMT
16 Days Until Expiry: 54
17 Hostname: google.com
18 Ingress Name: example-app
19 Status: ok
20 Step: check-ingress-certificate
status.pipeline field shows the output returned by each function step.
Use this field for tracking what the operation accomplished.Check that the Operation annotated the Ingress with certificate information:
1kubectl get ingress example-app -o yaml
2apiVersion: networking.k8s.io/v1
3kind: Ingress
4metadata:
5 annotations:
6 cert-monitor.crossplane.io/days-until-expiry: "54"
7 cert-monitor.crossplane.io/expires: Sep 29 08:34:02 2025 GMT
8 cert-monitor.crossplane.io/status: ok
9 name: example-app
10 namespace: default
11spec:
12 # ... ingress spec ...
Operations can both read and change existing Kubernetes
resources. The Operation annotated the Ingress with certificate expiry
information that other tools can use for monitoring and alerting.Clean up
Delete the resources you created:
1kubectl delete -f operation.yaml
2kubectl delete -f ingress.yaml
3kubectl delete -f ingress-rbac.yaml
4kubectl delete -f function.yaml
Next steps
Operations are powerful building blocks for operational workflows. Learn more
about:
Operationconcepts - CoreOperationfeatures and best practicesCronOperation- Schedule operations to run automaticallyWatchOperation- Trigger operations when resources change
Explore the complete Operations documentation for advanced features and examples.