Skip to content

Commit 6cd6067

Browse files
committed
Add example for provider specific functions
1 parent 8a922a5 commit 6cd6067

File tree

6 files changed

+311
-1
lines changed

6 files changed

+311
-1
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
# limitations under the License.
1414

1515
CMDS_DIR=example
16-
CMDS=hello-populator
16+
CMDS ?= hello-populator
1717
all: build
1818

1919
include release-tools/build.make

example/provider-populator/Dockerfile

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
FROM gcr.io/distroless/static:latest
2+
LABEL maintainers="Kubernetes Authors"
3+
LABEL description="provider populator"
4+
ARG binary=./provider-populator
5+
6+
COPY ${binary} provider-populator
7+
ENTRYPOINT ["/provider-populator"]

example/provider-populator/README.md

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
2+
# Provider Populator Example
3+
4+
This example demonstrates an extremely simple provider specific populator implementation.
5+
6+
## How To
7+
8+
Install kubernetes 1.33 or later
9+
10+
Install the CRD:
11+
12+
`kubectl apply -f crd.yaml`
13+
14+
Install the controller:
15+
16+
`kubectl apply -f deploy.yaml`
17+
18+
Create a CR:
19+
20+
```
21+
kubectl create -f - << EOF
22+
apiVersion: provider.example.com/v1alpha1
23+
kind: Provider
24+
metadata:
25+
name: provider1
26+
spec:
27+
dataSourceName: example-source
28+
EOF
29+
```
30+
31+
Create a PVC:
32+
33+
```
34+
kubectl create -f - << EOF
35+
apiVersion: v1
36+
kind: PersistentVolumeClaim
37+
metadata:
38+
name: pvc1
39+
spec:
40+
accessModes:
41+
- ReadWriteOnce
42+
resources:
43+
requests:
44+
storage: 10Mi
45+
dataSourceRef:
46+
apiGroup: provider.example.com
47+
kind: Provider
48+
name: provider1
49+
EOF
50+
```
51+
52+
Get the logs from the pod to verify that controller starts:
53+
54+
`kubectl get pod -n provider`
55+
56+
```
57+
NAME READY STATUS RESTARTS AGE
58+
provider-populator-7f6c786fb5-q2vsq 1/1 Running 0 11s
59+
```
60+
61+
`kubectl logs provider-populator-7f6c786fb5-q2vsq -n provider`
62+
63+
```
64+
I0331 08:06:03.602113 1 controller.go:236] Starting populator controller for Provider.provider.example.com
65+
W0331 08:06:03.604038 1 client_config.go:667] Neither --kubeconfig nor --master was specified. Using the inClusterConfig. This might not work.
66+
I0331 08:06:03.606450 1 metrics.go:109] Metrics path successfully registered at /metrics
67+
I0331 08:06:03.606920 1 metrics.go:121] Metrics http server successfully started on :8080, /metrics
68+
```
69+
70+
### To build the image from code:
71+
72+
`make all CMDS=provider-populator`
73+
74+
Make sure you have a repo you can push to, and set the variable
75+
76+
`YOUR_REPO=...`
77+
78+
Push the image to your repo:
79+
80+
```
81+
docker tag provider-populator:latest ${YOUR_REPO}/provider-populator:latest
82+
docker push ${YOUR_REPO}/provider-populator:latest
83+
```
84+
85+
To use the image, update deploy.yaml before installing the controller.

example/provider-populator/crd.yaml

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
apiVersion: apiextensions.k8s.io/v1
2+
kind: CustomResourceDefinition
3+
metadata:
4+
name: providers.provider.example.com
5+
spec:
6+
group: provider.example.com
7+
names:
8+
kind: Provider
9+
listKind: ProviderList
10+
plural: providers
11+
singular: provider
12+
scope: Namespaced
13+
versions:
14+
- name: v1alpha1
15+
schema:
16+
openAPIV3Schema:
17+
description: Provider is a specification for a Provider resource
18+
properties:
19+
spec:
20+
description: ProviderSpec is the spec for a Provider resource
21+
properties:
22+
dataSourceName:
23+
type: string
24+
# Add provider specific data source properties
25+
type: object
26+
required:
27+
- spec
28+
type: object
29+
served: true
30+
storage: true
31+
status:
32+
acceptedNames:
33+
kind: ""
34+
plural: ""
35+
conditions: []
36+
storedVersions: []
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
apiVersion: v1
2+
kind: Namespace
3+
metadata:
4+
name: provider
5+
---
6+
apiVersion: v1
7+
kind: ServiceAccount
8+
metadata:
9+
name: provider-account
10+
namespace: provider
11+
---
12+
kind: ClusterRole
13+
apiVersion: rbac.authorization.k8s.io/v1
14+
metadata:
15+
name: provider-role
16+
rules:
17+
- apiGroups: [""]
18+
resources: [persistentvolumes]
19+
verbs: [get, list, watch, patch]
20+
- apiGroups: [""]
21+
resources: [persistentvolumeclaims]
22+
verbs: [get, list, watch, patch, create, delete]
23+
- apiGroups: [""]
24+
resources: [pods]
25+
verbs: [get, list, watch, create, delete]
26+
- apiGroups: [""]
27+
resources: [events]
28+
verbs: [create]
29+
- apiGroups: [storage.k8s.io]
30+
resources: [storageclasses]
31+
verbs: [get, list, watch]
32+
33+
- apiGroups: [provider.example.com]
34+
resources: [providers]
35+
verbs: [get, list, watch]
36+
# (Alpha) Access to referencegrants is only needed when the CSI driver
37+
# has the CrossNamespaceVolumeDataSource controller capability.
38+
# In that case, lib-volume-populator requires "get", "list", "watch"
39+
# permissions for "referencegrants" on "gateway.networking.k8s.io".
40+
#- apiGroups: ["gateway.networking.k8s.io"]
41+
# resources: ["referencegrants"]
42+
# verbs: ["get", "list", "watch"]
43+
---
44+
kind: ClusterRoleBinding
45+
apiVersion: rbac.authorization.k8s.io/v1
46+
metadata:
47+
name: provider-binding
48+
subjects:
49+
- kind: ServiceAccount
50+
name: provider-account
51+
namespace: provider
52+
roleRef:
53+
kind: ClusterRole
54+
name: provider-role
55+
apiGroup: rbac.authorization.k8s.io
56+
---
57+
kind: Deployment
58+
apiVersion: apps/v1
59+
metadata:
60+
name: provider-populator
61+
namespace: provider
62+
spec:
63+
selector:
64+
matchLabels:
65+
app: provider
66+
template:
67+
metadata:
68+
labels:
69+
app: provider
70+
spec:
71+
serviceAccount: provider-account
72+
containers:
73+
- name: provider
74+
image: gcr.io/dannawang-gke-dev/provider-populator:v1.0.1
75+
imagePullPolicy: IfNotPresent
76+
args:
77+
- --mode=controller
78+
- --http-endpoint=:8080
79+
ports:
80+
- containerPort: 8080
81+
name: http-endpoint
82+
protocol: TCP
83+
---
84+
kind: VolumePopulator
85+
apiVersion: populator.storage.k8s.io/v1beta1
86+
metadata:
87+
name: provider-populator
88+
sourceKind:
89+
group: provider.example.com
90+
kind: provider

example/provider-populator/main.go

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"flag"
6+
7+
populatorMachinery "github.com/kubernetes-csi/lib-volume-populator/populator-machinery"
8+
"k8s.io/apimachinery/pkg/runtime/schema"
9+
10+
"k8s.io/klog/v2"
11+
)
12+
13+
const (
14+
groupName = "provider.example.com"
15+
kind = "Provider"
16+
apiVersion = "v1alpha1"
17+
resource = "providers"
18+
prefix = "provider.example.com"
19+
)
20+
21+
var (
22+
namespace = flag.String("namespace", "provider-populator", "Namespace to deploy controller")
23+
mode = flag.String("mode", "controller", "Mode to run the application in, supported values is controller")
24+
kubeconfigPath = flag.String("kubeconfig-path", "", "kubeconfig path")
25+
httpEndpoint = flag.String("http-endpoint", "", "The TCP network address where the HTTP server for diagnostics, including metrics and leader election health check, will listen (example: `:8080`). The default is empty string.")
26+
metricsPath = flag.String("metrics-path", "/metrics", "The HTTP path where prometheus metrics will be exposed. Default is `/metrics`.")
27+
28+
groupKind = schema.GroupKind{
29+
Group: groupName,
30+
Kind: kind,
31+
}
32+
versionResource = schema.GroupVersionResource{
33+
Group: groupKind.Group,
34+
Version: apiVersion,
35+
Resource: resource,
36+
}
37+
)
38+
39+
func main() {
40+
klog.InitFlags(nil)
41+
flag.Parse()
42+
43+
switch *mode {
44+
case "controller":
45+
klog.Infof("Run provider-populator controller")
46+
pfcfg := &populatorMachinery.ProviderFunctionConfig{
47+
PopulateFn: populateFn,
48+
PopulateCompleteFn: populateCompleteFn,
49+
PopulateCleanupFn: populateCleanupFn,
50+
}
51+
52+
vpcfg := &populatorMachinery.VolumePopulatorConfig{
53+
MasterURL: "",
54+
Kubeconfig: *kubeconfigPath,
55+
HttpEndpoint: *httpEndpoint,
56+
MetricsPath: *metricsPath,
57+
Namespace: *namespace,
58+
Prefix: prefix,
59+
Gk: groupKind,
60+
Gvr: versionResource,
61+
ProviderFunctionConfig: pfcfg,
62+
CrossNamespace: false,
63+
}
64+
65+
populatorMachinery.RunControllerWithConfig(*vpcfg)
66+
default:
67+
klog.Infof("Mode %s is not supported", *mode)
68+
}
69+
}
70+
71+
func populateFn(ctx context.Context, params populatorMachinery.PopulatorParams) error {
72+
// Implement the provider-specific logic to initiate volume population.
73+
// This may involve calling cloud-native APIs or creating temporary Kubernetes resources
74+
// such as Pods or Jobs for data transfer.
75+
klog.Infof("Run populateFn")
76+
return nil
77+
}
78+
79+
func populateCompleteFn(ctx context.Context, params populatorMachinery.PopulatorParams) (bool, error) {
80+
// Implement the provider-specific logic to determine the status of volume population.
81+
// This may involve calling cloud-native APIs or checking the completion status of
82+
// temporary Kubernetes resources like Pods or Jobs.
83+
klog.Infof("Run populateCompleteFn")
84+
return true, nil
85+
}
86+
87+
func populateCleanupFn(ctx context.Context, params populatorMachinery.PopulatorParams) error {
88+
// Implement the provider-specific logic to clean up any temporary resources
89+
// that were created during the volume population process.
90+
klog.Infof("Run populateCleanupFn")
91+
return nil
92+
}

0 commit comments

Comments
 (0)