Skip to content

Commit 81193c7

Browse files
authored
Merge pull request #56 from barney-s/pvc
Add support for volumeClaimTemplates
2 parents e32bf7f + dc840bb commit 81193c7

File tree

7 files changed

+204
-3
lines changed

7 files changed

+204
-3
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ build:
1212
KIND_CLUSTER=agent-sandbox
1313

1414
.PHONY: deploy-kind
15-
deploy-kind:
15+
deploy-kind: all
1616
kind get clusters | grep ${KIND_CLUSTER} || kind create cluster --name ${KIND_CLUSTER}
1717
./dev/tools/push-images --image-prefix=kind.local/ --kind-cluster-name=${KIND_CLUSTER}
1818
./dev/tools/deploy-to-kube --image-prefix=kind.local/

api/v1alpha1/sandbox_types.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,17 @@ type PodTemplate struct {
5858
ObjectMeta PodMetadata `json:"metadata" protobuf:"bytes,3,opt,name=metadata"`
5959
}
6060

61+
type PersistentVolumeClaimTemplate struct {
62+
// Metadata is the Pod's metadata. Only labels and annotations are used.
63+
// +kubebuilder:pruning:PreserveUnknownFields
64+
// +kubebuilder:validation:Optional
65+
ObjectMeta metav1.ObjectMeta `json:"metadata" protobuf:"bytes,3,opt,name=metadata"`
66+
67+
// Spec is the Pod's spec
68+
// +kubebuilder:validation:Required
69+
Spec corev1.PersistentVolumeClaimSpec `json:"spec" protobuf:"bytes,3,opt,name=spec"`
70+
}
71+
6172
// SandboxSpec defines the desired state of Sandbox
6273
type SandboxSpec struct {
6374
// The following markers will use OpenAPI v3 schema to validate the value
@@ -66,6 +77,12 @@ type SandboxSpec struct {
6677
// PodTemplate describes the pod spec that will be used to create an agent sandbox.
6778
// +kubebuilder:validation:Required
6879
PodTemplate PodTemplate `json:"podTemplate" protobuf:"bytes,3,opt,name=podTemplate"`
80+
81+
// VolumeClaimTemplates is a list of claims that the sandbox pod is allowed to reference.
82+
// Every claim in this list must have at least one matching access mode with a provisioner volume.
83+
// +optional
84+
// +kubebuilder:validation:Optional
85+
VolumeClaimTemplates []PersistentVolumeClaimTemplate `json:"volumeClaimTemplates,omitempty" protobuf:"bytes,4,rep,name=volumeClaimTemplates"`
6986
}
7087

7188
// SandboxStatus defines the observed state of Sandbox.

api/v1alpha1/zz_generated.deepcopy.go

Lines changed: 24 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

controllers/sandbox_controller.go

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ type SandboxReconciler struct {
6464

6565
//+kubebuilder:rbac:groups=core,resources=pods,verbs=get;list;watch;create;update;patch;delete
6666
//+kubebuilder:rbac:groups=core,resources=services,verbs=get;list;watch;create;update;patch;delete
67+
//+kubebuilder:rbac:groups=core,resources=persistentvolumeclaims,verbs=get;list;watch;create;update;patch;delete
6768

6869
// Reconcile is part of the main kubernetes reconciliation loop which aims to
6970
// move the current state of the cluster closer to the desired state.
@@ -98,9 +99,13 @@ func (r *SandboxReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct
9899

99100
var allErrors error
100101

102+
// Reconcile PVCs
103+
err := r.reconcilePVCs(ctx, sandbox)
104+
allErrors = errors.Join(allErrors, err)
105+
101106
// Reconcile Pod
102107
pod, err := r.reconcilePod(ctx, sandbox, nameHash)
103-
allErrors = errors.Join(err)
108+
allErrors = errors.Join(allErrors, err)
104109

105110
// Reconcile Service
106111
svc, err := r.reconcileService(ctx, sandbox, nameHash)
@@ -271,14 +276,27 @@ func (r *SandboxReconciler) reconcilePod(ctx context.Context, sandbox *sandboxv1
271276
annotations[k] = v
272277
}
273278

279+
mutatedSpec := sandbox.Spec.PodTemplate.Spec.DeepCopy()
280+
281+
for _, pvcTemplate := range sandbox.Spec.VolumeClaimTemplates {
282+
pvcName := pvcTemplate.ObjectMeta.Name + "-" + sandbox.Name
283+
mutatedSpec.Volumes = append(mutatedSpec.Volumes, corev1.Volume{
284+
Name: pvcTemplate.ObjectMeta.Name,
285+
VolumeSource: corev1.VolumeSource{
286+
PersistentVolumeClaim: &corev1.PersistentVolumeClaimVolumeSource{
287+
ClaimName: pvcName,
288+
},
289+
},
290+
})
291+
}
274292
pod = &corev1.Pod{
275293
ObjectMeta: metav1.ObjectMeta{
276294
Name: sandbox.Name,
277295
Namespace: sandbox.Namespace,
278296
Labels: labels,
279297
Annotations: annotations,
280298
},
281-
Spec: sandbox.Spec.PodTemplate.Spec,
299+
Spec: *mutatedSpec,
282300
}
283301
pod.SetGroupVersionKind(corev1.SchemeGroupVersion.WithKind("Pod"))
284302
if err := ctrl.SetControllerReference(sandbox, pod, r.Scheme); err != nil {
@@ -292,6 +310,38 @@ func (r *SandboxReconciler) reconcilePod(ctx context.Context, sandbox *sandboxv1
292310
return pod, nil
293311
}
294312

313+
func (r *SandboxReconciler) reconcilePVCs(ctx context.Context, sandbox *sandboxv1alpha1.Sandbox) error {
314+
log := log.FromContext(ctx)
315+
for _, pvcTemplate := range sandbox.Spec.VolumeClaimTemplates {
316+
pvc := &corev1.PersistentVolumeClaim{}
317+
pvcName := pvcTemplate.ObjectMeta.Name + "-" + sandbox.Name
318+
err := r.Get(ctx, types.NamespacedName{Name: pvcName, Namespace: sandbox.Namespace}, pvc)
319+
if err != nil {
320+
if k8serrors.IsNotFound(err) {
321+
log.Info("Creating a new PVC", "PVC.Namespace", sandbox.Namespace, "PVC.Name", pvcName)
322+
pvc = &corev1.PersistentVolumeClaim{
323+
ObjectMeta: metav1.ObjectMeta{
324+
Name: pvcName,
325+
Namespace: sandbox.Namespace,
326+
},
327+
Spec: pvcTemplate.Spec,
328+
}
329+
if err := ctrl.SetControllerReference(sandbox, pvc, r.Scheme); err != nil {
330+
return fmt.Errorf("SetControllerReference for PVC failed: %w", err)
331+
}
332+
if err := r.Create(ctx, pvc, client.FieldOwner("sandbox-controller")); err != nil {
333+
log.Error(err, "Failed to create PVC", "PVC.Namespace", sandbox.Namespace, "PVC.Name", pvcName)
334+
return err
335+
}
336+
} else {
337+
log.Error(err, "Failed to get PVC")
338+
return fmt.Errorf("PVC Get Failed: %w", err)
339+
}
340+
}
341+
}
342+
return nil
343+
}
344+
295345
// SetupWithManager sets up the controller with the Manager.
296346
func (r *SandboxReconciler) SetupWithManager(mgr ctrl.Manager) error {
297347
labelSelectorPredicate, err := predicate.LabelSelectorPredicate(metav1.LabelSelector{

examples/sandbox.yaml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,14 @@ spec:
1414
- name: my-container
1515
image: busybox
1616
command: ["/bin/sh", "-c", "sleep 3600"]
17+
volumeMounts:
18+
- name: my-pvc
19+
mountPath: /my-data
20+
volumeClaimTemplates:
21+
- metadata:
22+
name: my-pvc
23+
spec:
24+
accessModes: [ "ReadWriteOnce" ]
25+
resources:
26+
requests:
27+
storage: 1Gi

k8s/crds/agents.x-k8s.io_sandboxes.yaml

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3814,6 +3814,104 @@ spec:
38143814
required:
38153815
- spec
38163816
type: object
3817+
volumeClaimTemplates:
3818+
items:
3819+
properties:
3820+
metadata:
3821+
type: object
3822+
x-kubernetes-preserve-unknown-fields: true
3823+
spec:
3824+
properties:
3825+
accessModes:
3826+
items:
3827+
type: string
3828+
type: array
3829+
x-kubernetes-list-type: atomic
3830+
dataSource:
3831+
properties:
3832+
apiGroup:
3833+
type: string
3834+
kind:
3835+
type: string
3836+
name:
3837+
type: string
3838+
required:
3839+
- kind
3840+
- name
3841+
type: object
3842+
x-kubernetes-map-type: atomic
3843+
dataSourceRef:
3844+
properties:
3845+
apiGroup:
3846+
type: string
3847+
kind:
3848+
type: string
3849+
name:
3850+
type: string
3851+
namespace:
3852+
type: string
3853+
required:
3854+
- kind
3855+
- name
3856+
type: object
3857+
resources:
3858+
properties:
3859+
limits:
3860+
additionalProperties:
3861+
anyOf:
3862+
- type: integer
3863+
- type: string
3864+
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
3865+
x-kubernetes-int-or-string: true
3866+
type: object
3867+
requests:
3868+
additionalProperties:
3869+
anyOf:
3870+
- type: integer
3871+
- type: string
3872+
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
3873+
x-kubernetes-int-or-string: true
3874+
type: object
3875+
type: object
3876+
selector:
3877+
properties:
3878+
matchExpressions:
3879+
items:
3880+
properties:
3881+
key:
3882+
type: string
3883+
operator:
3884+
type: string
3885+
values:
3886+
items:
3887+
type: string
3888+
type: array
3889+
x-kubernetes-list-type: atomic
3890+
required:
3891+
- key
3892+
- operator
3893+
type: object
3894+
type: array
3895+
x-kubernetes-list-type: atomic
3896+
matchLabels:
3897+
additionalProperties:
3898+
type: string
3899+
type: object
3900+
type: object
3901+
x-kubernetes-map-type: atomic
3902+
storageClassName:
3903+
type: string
3904+
volumeAttributesClassName:
3905+
type: string
3906+
volumeMode:
3907+
type: string
3908+
volumeName:
3909+
type: string
3910+
type: object
3911+
required:
3912+
- spec
3913+
type: object
3914+
type: array
38173915
required:
38183916
- podTemplate
38193917
type: object

k8s/rbac.generated.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ rules:
77
- apiGroups:
88
- ""
99
resources:
10+
- persistentvolumeclaims
1011
- pods
1112
- services
1213
verbs:

0 commit comments

Comments
 (0)