Skip to content

Commit f35d2da

Browse files
committed
feat(backingimage): backing image clone and encryption support
ref: longhorn/longhorn 7051 Signed-off-by: Jack Lin <[email protected]>
1 parent a13e767 commit f35d2da

28 files changed

+543
-63
lines changed

api/backingimage.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ func (s *Server) BackingImageCreate(rw http.ResponseWriter, req *http.Request) e
5252
return err
5353
}
5454

55-
bi, err := s.m.CreateBackingImage(input.Name, input.ExpectedChecksum, input.SourceType, input.Parameters, input.MinNumberOfCopies, input.NodeSelector, input.DiskSelector)
55+
bi, err := s.m.CreateBackingImage(input.Name, input.ExpectedChecksum, input.SourceType, input.Parameters, input.MinNumberOfCopies, input.NodeSelector, input.DiskSelector, input.Secret, input.SecretNamespace)
5656
if err != nil {
5757
return errors.Wrapf(err, "failed to create backing image %v from source type %v with parameters %+v", input.Name, input.SourceType, input.Parameters)
5858
}

api/backupbackingimage.go

+7-1
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,14 @@ func (s *Server) BackupBackingImageDelete(w http.ResponseWriter, req *http.Reque
4040
}
4141

4242
func (s *Server) BackupBackingImageRestore(w http.ResponseWriter, req *http.Request) error {
43+
var input BackingImageRestoreInput
44+
apiContext := api.GetApiContext(req)
45+
if err := apiContext.Read(&input); err != nil {
46+
return err
47+
}
48+
4349
backupBackingImageName := mux.Vars(req)["name"]
44-
if err := s.m.RestoreBackupBackingImage(backupBackingImageName); err != nil {
50+
if err := s.m.RestoreBackupBackingImage(backupBackingImageName, input.Secret, input.SecretNamespace); err != nil {
4551
return errors.Wrapf(err, "failed to restore backup backing image '%s'", backupBackingImageName)
4652
}
4753
return nil

api/model.go

+15-1
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,9 @@ type BackingImage struct {
271271
Size int64 `json:"size"`
272272
CurrentChecksum string `json:"currentChecksum"`
273273

274+
Secret string `json:"secret"`
275+
SecretNamespace string `json:"secretNamespace"`
276+
274277
DeletionTimestamp string `json:"deletionTimestamp"`
275278
}
276279

@@ -282,6 +285,11 @@ type UpdateMinNumberOfCopiesInput struct {
282285
MinNumberOfCopies int `json:"minNumberOfCopies"`
283286
}
284287

288+
type BackingImageRestoreInput struct {
289+
Secret string `json:"secret"`
290+
SecretNamespace string `json:"secretNamespace"`
291+
}
292+
285293
type AttachInput struct {
286294
HostID string `json:"hostId"`
287295
DisableFrontend bool `json:"disableFrontend"`
@@ -676,6 +684,7 @@ func NewSchema() *client.Schemas {
676684
schemas.AddType("backingImageDiskFileStatus", longhorn.BackingImageDiskFileStatus{})
677685
schemas.AddType("backingImageCleanupInput", BackingImageCleanupInput{})
678686
schemas.AddType("updateMinNumberOfCopiesInput", UpdateMinNumberOfCopiesInput{})
687+
schemas.AddType("backingImageRestoreInput", BackingImageRestoreInput{})
679688

680689
attachmentSchema(schemas.AddType("attachment", Attachment{}))
681690
volumeAttachmentSchema(schemas.AddType("volumeAttachment", VolumeAttachment{}))
@@ -810,7 +819,9 @@ func backupBackingImageSchema(backupBackingImage *client.Schema) {
810819
backupBackingImage.ResourceMethods = []string{"GET", "DELETE"}
811820

812821
backupBackingImage.ResourceActions = map[string]client.Action{
813-
"backupBackingImageRestore": {},
822+
"backupBackingImageRestore": {
823+
Input: "backingImageRestoreInput",
824+
},
814825
}
815826
}
816827

@@ -2018,6 +2029,9 @@ func toBackingImageResource(bi *longhorn.BackingImage, apiContext *api.ApiContex
20182029
Size: bi.Status.Size,
20192030
CurrentChecksum: bi.Status.Checksum,
20202031

2032+
Secret: bi.Spec.Secret,
2033+
SecretNamespace: bi.Spec.SecretNamespace,
2034+
20212035
DeletionTimestamp: deletionTimestamp,
20222036
}
20232037
res.Actions = map[string]string{

client/generated_backing_image.go

+4
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ type BackingImage struct {
2525

2626
Parameters map[string]string `json:"parameters,omitempty" yaml:"parameters,omitempty"`
2727

28+
Secret string `json:"secret,omitempty" yaml:"secret,omitempty"`
29+
30+
SecretNamespace string `json:"secretNamespace,omitempty" yaml:"secretNamespace,omitempty"`
31+
2832
Size int64 `json:"size,omitempty" yaml:"size,omitempty"`
2933

3034
SourceType string `json:"sourceType,omitempty" yaml:"source_type,omitempty"`
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package client
2+
3+
const (
4+
BACKING_IMAGE_RESTORE_INPUT_TYPE = "backingImageRestoreInput"
5+
)
6+
7+
type BackingImageRestoreInput struct {
8+
Resource `yaml:"-"`
9+
10+
Secret string `json:"secret,omitempty" yaml:"secret,omitempty"`
11+
12+
SecretNamespace string `json:"secretNamespace,omitempty" yaml:"secret_namespace,omitempty"`
13+
}
14+
15+
type BackingImageRestoreInputCollection struct {
16+
Collection
17+
Data []BackingImageRestoreInput `json:"data,omitempty"`
18+
client *BackingImageRestoreInputClient
19+
}
20+
21+
type BackingImageRestoreInputClient struct {
22+
rancherClient *RancherClient
23+
}
24+
25+
type BackingImageRestoreInputOperations interface {
26+
List(opts *ListOpts) (*BackingImageRestoreInputCollection, error)
27+
Create(opts *BackingImageRestoreInput) (*BackingImageRestoreInput, error)
28+
Update(existing *BackingImageRestoreInput, updates interface{}) (*BackingImageRestoreInput, error)
29+
ById(id string) (*BackingImageRestoreInput, error)
30+
Delete(container *BackingImageRestoreInput) error
31+
}
32+
33+
func newBackingImageRestoreInputClient(rancherClient *RancherClient) *BackingImageRestoreInputClient {
34+
return &BackingImageRestoreInputClient{
35+
rancherClient: rancherClient,
36+
}
37+
}
38+
39+
func (c *BackingImageRestoreInputClient) Create(container *BackingImageRestoreInput) (*BackingImageRestoreInput, error) {
40+
resp := &BackingImageRestoreInput{}
41+
err := c.rancherClient.doCreate(BACKING_IMAGE_RESTORE_INPUT_TYPE, container, resp)
42+
return resp, err
43+
}
44+
45+
func (c *BackingImageRestoreInputClient) Update(existing *BackingImageRestoreInput, updates interface{}) (*BackingImageRestoreInput, error) {
46+
resp := &BackingImageRestoreInput{}
47+
err := c.rancherClient.doUpdate(BACKING_IMAGE_RESTORE_INPUT_TYPE, &existing.Resource, updates, resp)
48+
return resp, err
49+
}
50+
51+
func (c *BackingImageRestoreInputClient) List(opts *ListOpts) (*BackingImageRestoreInputCollection, error) {
52+
resp := &BackingImageRestoreInputCollection{}
53+
err := c.rancherClient.doList(BACKING_IMAGE_RESTORE_INPUT_TYPE, opts, resp)
54+
resp.client = c
55+
return resp, err
56+
}
57+
58+
func (cc *BackingImageRestoreInputCollection) Next() (*BackingImageRestoreInputCollection, error) {
59+
if cc != nil && cc.Pagination != nil && cc.Pagination.Next != "" {
60+
resp := &BackingImageRestoreInputCollection{}
61+
err := cc.client.rancherClient.doNext(cc.Pagination.Next, resp)
62+
resp.client = cc.client
63+
return resp, err
64+
}
65+
return nil, nil
66+
}
67+
68+
func (c *BackingImageRestoreInputClient) ById(id string) (*BackingImageRestoreInput, error) {
69+
resp := &BackingImageRestoreInput{}
70+
err := c.rancherClient.doById(BACKING_IMAGE_RESTORE_INPUT_TYPE, id, resp)
71+
if apiError, ok := err.(*ApiError); ok {
72+
if apiError.StatusCode == 404 {
73+
return nil, nil
74+
}
75+
}
76+
return resp, err
77+
}
78+
79+
func (c *BackingImageRestoreInputClient) Delete(container *BackingImageRestoreInput) error {
80+
return c.rancherClient.doResourceDelete(BACKING_IMAGE_RESTORE_INPUT_TYPE, &container.Resource)
81+
}

client/generated_client.go

+2
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ type RancherClient struct {
5757
InstanceManager InstanceManagerOperations
5858
BackingImageDiskFileStatus BackingImageDiskFileStatusOperations
5959
BackingImageCleanupInput BackingImageCleanupInputOperations
60+
BackingImageRestoreInput BackingImageRestoreInputOperations
6061
UpdateMinNumberOfCopiesInput UpdateMinNumberOfCopiesInputOperations
6162
Attachment AttachmentOperations
6263
VolumeAttachment VolumeAttachmentOperations
@@ -140,6 +141,7 @@ func constructClient(rancherBaseClient *RancherBaseClientImpl) *RancherClient {
140141
client.BackingImageDiskFileStatus = newBackingImageDiskFileStatusClient(client)
141142
client.BackingImageCleanupInput = newBackingImageCleanupInputClient(client)
142143
client.UpdateMinNumberOfCopiesInput = newUpdateMinNumberOfCopiesInputClient(client)
144+
client.BackingImageRestoreInput = newBackingImageRestoreInputClient(client)
143145
client.Attachment = newAttachmentClient(client)
144146
client.VolumeAttachment = newVolumeAttachmentClient(client)
145147
client.Volume = newVolumeClient(client)

controller/backing_image_controller.go

+32
Original file line numberDiff line numberDiff line change
@@ -527,6 +527,15 @@ func (bic *BackingImageController) handleBackingImageDataSource(bi *longhorn.Bac
527527
if err != nil {
528528
return err
529529
}
530+
531+
// For clone, we choose the same node and disk as the source backing image
532+
if bi.Spec.SourceType == longhorn.BackingImageDataSourceTypeClone {
533+
readyNode, readyDiskName, err = bic.findReadyNodeAndDiskForClone(bi)
534+
if err != nil {
535+
return nil
536+
}
537+
}
538+
530539
foundReadyDisk = true
531540
readyNodeID = readyNode.Name
532541
readyDiskUUID = readyNode.Status.DiskStatus[readyDiskName].DiskUUID
@@ -658,6 +667,15 @@ func (bic *BackingImageController) handleBackingImageDataSource(bi *longhorn.Bac
658667
if err != nil {
659668
return err
660669
}
670+
671+
// For clone, we choose the same node and disk as the source backing image
672+
if bi.Spec.SourceType == longhorn.BackingImageDataSourceTypeClone {
673+
readyNode, readyDiskName, err = bic.findReadyNodeAndDiskForClone(bi)
674+
if err != nil {
675+
return nil
676+
}
677+
}
678+
661679
bids.Spec.NodeID = readyNode.Name
662680
bids.Spec.DiskUUID = readyNode.Status.DiskStatus[readyDiskName].DiskUUID
663681
bids.Spec.DiskPath = readyNode.Spec.Disks[readyDiskName].Path
@@ -1034,3 +1052,17 @@ func (bic *BackingImageController) enqueueBackingImageForReplica(obj interface{}
10341052
func (bic *BackingImageController) isResponsibleFor(bi *longhorn.BackingImage) bool {
10351053
return isControllerResponsibleFor(bic.controllerID, bic.ds, bi.Name, "", bi.Status.OwnerID)
10361054
}
1055+
1056+
// For cloning, we choose the same node and disk as the source backing image
1057+
func (bic *BackingImageController) findReadyNodeAndDiskForClone(bi *longhorn.BackingImage) (*longhorn.Node, string, error) {
1058+
sourceBackingImageName := bi.Spec.SourceParameters[longhorn.DataSourceTypeCloneParameterBackingImage]
1059+
sourceBackingImage, err := bic.ds.GetBackingImageRO(sourceBackingImageName)
1060+
if err != nil {
1061+
return nil, "", fmt.Errorf("failed to get source backing image %v during cloning", sourceBackingImageName)
1062+
}
1063+
readyNode, readyDiskName, err := bic.ds.GetOneBackingImageReadyNodeDisk(sourceBackingImage)
1064+
if err != nil {
1065+
return nil, "", fmt.Errorf("failed to find one ready source backing image %v during cloning", sourceBackingImageName)
1066+
}
1067+
return readyNode, readyDiskName, nil
1068+
}

controller/backing_image_data_source_controller.go

+80-3
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,17 @@ func (c *BackingImageDataSourceController) syncBackingImage(bids *longhorn.Backi
405405
}
406406
}
407407

408+
// Only copy the secret to spec if it is to encrypt other backing image
409+
// because we use spec secret to check if it is encrypted.
410+
if isEncryptionRequire(bi) {
411+
if bi.Spec.SourceParameters[longhorn.DataSourceTypeCloneParameterSecret] != "" {
412+
bi.Spec.Secret = bi.Spec.SourceParameters[longhorn.DataSourceTypeCloneParameterSecret]
413+
}
414+
if bi.Spec.SourceParameters[longhorn.DataSourceTypeCloneParameterSecretNamespace] != "" {
415+
bi.Spec.SecretNamespace = bi.Spec.SourceParameters[longhorn.DataSourceTypeCloneParameterSecretNamespace]
416+
}
417+
}
418+
408419
return nil
409420
}
410421

@@ -669,7 +680,11 @@ func (c *BackingImageDataSourceController) generateBackingImageDataSourcePodMani
669680
"--source-type", string(bids.Spec.SourceType),
670681
}
671682

672-
if err := c.prepareRunningParameters(bids); err != nil {
683+
bids.Status.RunningParameters = bids.Spec.Parameters
684+
if err := c.prepareRunningParametersForClone(bids); err != nil {
685+
return nil, err
686+
}
687+
if err := c.prepareRunningParametersForExport(bids); err != nil {
673688
return nil, err
674689
}
675690
for key, value := range bids.Status.RunningParameters {
@@ -679,6 +694,21 @@ func (c *BackingImageDataSourceController) generateBackingImageDataSourcePodMani
679694
cmd = append(cmd, "--checksum", bids.Spec.Checksum)
680695
}
681696

697+
if bids.Spec.SourceType == longhorn.BackingImageDataSourceTypeClone && secretExists(bids) {
698+
699+
credential, err := c.ds.GetEncryptionSecret(
700+
bids.Spec.Parameters[longhorn.DataSourceTypeCloneParameterSecretNamespace],
701+
bids.Spec.Parameters[longhorn.DataSourceTypeCloneParameterSecret],
702+
)
703+
if err != nil {
704+
return nil, err
705+
}
706+
707+
for key, value := range credential {
708+
cmd = append(cmd, "--credential", fmt.Sprintf("%s=%s", key, value))
709+
}
710+
}
711+
682712
if bids.Spec.SourceType == longhorn.BackingImageDataSourceTypeRestore {
683713
var credential map[string]string
684714
backupTarget, err := c.ds.GetBackupTargetRO(types.DefaultBackupTargetName)
@@ -745,6 +775,14 @@ func (c *BackingImageDataSourceController) generateBackingImageDataSourcePodMani
745775
Name: "disk-path",
746776
MountPath: bimtypes.DiskPathInContainer,
747777
},
778+
{
779+
Name: "host-dev",
780+
MountPath: "/dev",
781+
},
782+
{
783+
Name: "host-proc",
784+
MountPath: "/host/proc", // we use this to enter the host namespace
785+
},
748786
},
749787
Env: []corev1.EnvVar{
750788
{
@@ -770,6 +808,22 @@ func (c *BackingImageDataSourceController) generateBackingImageDataSourcePodMani
770808
},
771809
},
772810
},
811+
{
812+
Name: "host-dev",
813+
VolumeSource: corev1.VolumeSource{
814+
HostPath: &corev1.HostPathVolumeSource{
815+
Path: "/dev",
816+
},
817+
},
818+
},
819+
{
820+
Name: "host-proc",
821+
VolumeSource: corev1.VolumeSource{
822+
HostPath: &corev1.HostPathVolumeSource{
823+
Path: "/proc",
824+
},
825+
},
826+
},
773827
},
774828
NodeName: bids.Spec.NodeID,
775829
RestartPolicy: corev1.RestartPolicyNever,
@@ -802,8 +856,21 @@ func (c *BackingImageDataSourceController) generateBackingImageDataSourcePodMani
802856
return podSpec, nil
803857
}
804858

805-
func (c *BackingImageDataSourceController) prepareRunningParameters(bids *longhorn.BackingImageDataSource) error {
806-
bids.Status.RunningParameters = bids.Spec.Parameters
859+
func (c *BackingImageDataSourceController) prepareRunningParametersForClone(bids *longhorn.BackingImageDataSource) error {
860+
if bids.Spec.SourceType != longhorn.BackingImageDataSourceTypeClone {
861+
return nil
862+
}
863+
864+
sourceBackingImageName := bids.Spec.Parameters[longhorn.DataSourceTypeCloneParameterBackingImage]
865+
sourceBackingImage, err := c.ds.GetBackingImageRO(sourceBackingImageName)
866+
if err != nil {
867+
return err
868+
}
869+
bids.Status.RunningParameters[longhorn.DataSourceTypeCloneParameterBackingImageUUID] = sourceBackingImage.Status.UUID
870+
return nil
871+
}
872+
873+
func (c *BackingImageDataSourceController) prepareRunningParametersForExport(bids *longhorn.BackingImageDataSource) error {
807874
if bids.Spec.SourceType != longhorn.BackingImageDataSourceTypeExportFromVolume {
808875
return nil
809876
}
@@ -1173,3 +1240,13 @@ func (m *BackingImageDataSourceMonitor) sync() {
11731240
func (c *BackingImageDataSourceController) isResponsibleFor(bids *longhorn.BackingImageDataSource) bool {
11741241
return isControllerResponsibleFor(c.controllerID, c.ds, bids.Name, bids.Spec.NodeID, bids.Status.OwnerID)
11751242
}
1243+
1244+
func isEncryptionRequire(bi *longhorn.BackingImage) bool {
1245+
encryptionType := bimtypes.EncryptionType(bi.Spec.SourceParameters[longhorn.DataSourceTypeCloneParameterEncryption])
1246+
return bi.Spec.SourceType == longhorn.BackingImageDataSourceTypeClone && encryptionType == bimtypes.EncryptionTypeEncrypt
1247+
}
1248+
1249+
func secretExists(bids *longhorn.BackingImageDataSource) bool {
1250+
return bids.Spec.Parameters[longhorn.DataSourceTypeCloneParameterSecretNamespace] != "" &&
1251+
bids.Spec.Parameters[longhorn.DataSourceTypeCloneParameterSecret] != ""
1252+
}

controller/share_manager_controller.go

+7-8
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ import (
2525
clientset "k8s.io/client-go/kubernetes"
2626
v1core "k8s.io/client-go/kubernetes/typed/core/v1"
2727

28-
"github.com/longhorn/longhorn-manager/csi"
2928
"github.com/longhorn/longhorn-manager/csi/crypto"
3029
"github.com/longhorn/longhorn-manager/datastore"
3130
"github.com/longhorn/longhorn-manager/engineapi"
@@ -906,16 +905,16 @@ func (c *ShareManagerController) createShareManagerPod(sm *longhorn.ShareManager
906905
return nil, err
907906
}
908907

909-
cryptoKey = string(secret.Data[csi.CryptoKeyValue])
908+
cryptoKey = string(secret.Data[types.CryptoKeyValue])
910909
if len(cryptoKey) == 0 {
911-
return nil, fmt.Errorf("missing %v in secret for encrypted RWX volume %v", csi.CryptoKeyValue, volume.Name)
910+
return nil, fmt.Errorf("missing %v in secret for encrypted RWX volume %v", types.CryptoKeyValue, volume.Name)
912911
}
913912
cryptoParams = crypto.NewEncryptParams(
914-
string(secret.Data[csi.CryptoKeyProvider]),
915-
string(secret.Data[csi.CryptoKeyCipher]),
916-
string(secret.Data[csi.CryptoKeyHash]),
917-
string(secret.Data[csi.CryptoKeySize]),
918-
string(secret.Data[csi.CryptoPBKDF]))
913+
string(secret.Data[types.CryptoKeyProvider]),
914+
string(secret.Data[types.CryptoKeyCipher]),
915+
string(secret.Data[types.CryptoKeyHash]),
916+
string(secret.Data[types.CryptoKeySize]),
917+
string(secret.Data[types.CryptoPBKDF]))
919918
}
920919

921920
manifest := c.createPodManifest(sm, annotations, tolerations, affinity, imagePullPolicy, nil, registrySecret,

0 commit comments

Comments
 (0)