-
Notifications
You must be signed in to change notification settings - Fork 1.8k
/
pvchandler.go
110 lines (95 loc) · 4.7 KB
/
pvchandler.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
/*
Copyright 2020 The Tekton Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package volumeclaim
import (
"context"
"crypto/sha256"
"fmt"
"github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1"
"go.uber.org/zap"
corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
errorutils "k8s.io/apimachinery/pkg/util/errors"
clientset "k8s.io/client-go/kubernetes"
)
const (
// ReasonCouldntCreateWorkspacePVC indicates that a Pipeline expects a workspace from a
// volumeClaimTemplate but couldn't create a claim.
ReasonCouldntCreateWorkspacePVC = "CouldntCreateWorkspacePVC"
)
// PvcHandler is used to create PVCs for workspaces
type PvcHandler interface {
CreatePersistentVolumeClaimsForWorkspaces(ctx context.Context, wb []v1beta1.WorkspaceBinding, ownerReference metav1.OwnerReference, namespace string) error
}
type defaultPVCHandler struct {
clientset clientset.Interface
logger *zap.SugaredLogger
}
// NewPVCHandler returns a new defaultPVCHandler
func NewPVCHandler(clientset clientset.Interface, logger *zap.SugaredLogger) PvcHandler {
return &defaultPVCHandler{clientset, logger}
}
// CreatePersistentVolumeClaimsForWorkspaces checks if a PVC named <claim-name>-<workspace-name>-<owner-name> exists;
// where claim-name is provided by the user in the volumeClaimTemplate, and owner-name is the name of the
// resource with the volumeClaimTemplate declared, a PipelineRun or TaskRun. If the PVC did not exist, a new PVC
// with that name is created with the provided OwnerReference.
func (c *defaultPVCHandler) CreatePersistentVolumeClaimsForWorkspaces(ctx context.Context, wb []v1beta1.WorkspaceBinding, ownerReference metav1.OwnerReference, namespace string) error {
var errs []error
for _, claim := range getPersistentVolumeClaims(wb, ownerReference, namespace) {
_, err := c.clientset.CoreV1().PersistentVolumeClaims(claim.Namespace).Get(ctx, claim.Name, metav1.GetOptions{})
switch {
case apierrors.IsNotFound(err):
_, err := c.clientset.CoreV1().PersistentVolumeClaims(claim.Namespace).Create(ctx, claim, metav1.CreateOptions{})
if err != nil {
errs = append(errs, fmt.Errorf("failed to create PVC %s: %s", claim.Name, err))
}
if err == nil || !apierrors.IsAlreadyExists(err) {
c.logger.Infof("Created PersistentVolumeClaim %s in namespace %s", claim.Name, claim.Namespace)
}
case err != nil:
errs = append(errs, fmt.Errorf("failed to retrieve PVC %s: %s", claim.Name, err))
}
}
return errorutils.NewAggregate(errs)
}
func getPersistentVolumeClaims(workspaceBindings []v1beta1.WorkspaceBinding, ownerReference metav1.OwnerReference, namespace string) map[string]*corev1.PersistentVolumeClaim {
claims := make(map[string]*corev1.PersistentVolumeClaim)
for _, workspaceBinding := range workspaceBindings {
if workspaceBinding.VolumeClaimTemplate == nil {
continue
}
claim := workspaceBinding.VolumeClaimTemplate.DeepCopy()
claim.Name = GetPersistentVolumeClaimName(workspaceBinding.VolumeClaimTemplate, workspaceBinding, ownerReference)
claim.Namespace = namespace
claim.OwnerReferences = []metav1.OwnerReference{ownerReference}
claims[workspaceBinding.Name] = claim
}
return claims
}
// GetPersistentVolumeClaimName gets the name of PersistentVolumeClaim for a Workspace and PipelineRun or TaskRun. claim
// must be a PersistentVolumeClaim from a volumeClaimTemplate. The returned name must be consistent given the same
// workspaceBinding name and ownerReference UID - because it is first used for creating a PVC and later,
// possibly several TaskRuns to lookup the PVC to mount.
// We use ownerReference UID over ownerReference name to distinguish runs with the same name.
func GetPersistentVolumeClaimName(claim *corev1.PersistentVolumeClaim, wb v1beta1.WorkspaceBinding, owner metav1.OwnerReference) string {
if claim.Name == "" {
return fmt.Sprintf("%s-%s", "pvc", getPersistentVolumeClaimIdentity(wb.Name, string(owner.UID)))
}
return fmt.Sprintf("%s-%s", claim.Name, getPersistentVolumeClaimIdentity(wb.Name, string(owner.UID)))
}
func getPersistentVolumeClaimIdentity(workspaceName, ownerName string) string {
hashBytes := sha256.Sum256([]byte(workspaceName + ownerName))
hashString := fmt.Sprintf("%x", hashBytes)
return hashString[:10]
}