Skip to content

Commit

Permalink
Add Volume Project setting to support the scenario describe in issue #92
Browse files Browse the repository at this point in the history


Signed-off-by: Xun Jiang <[email protected]>
  • Loading branch information
Xun Jiang committed Jul 25, 2023
1 parent 817c494 commit 7bb0d37
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 4 deletions.
3 changes: 2 additions & 1 deletion examples/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# Examples

- [Restore snapshots from GCP across projects](./gcp-projects.md)
- [Backup at project A, and restore at project B](./backup_at_a_restore_at_b.md)
- [Velero at project A, backup and restore at other projects](./velero_at_a_br_at_other.md)
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Restore snapshots from GCP across projects
# Backup at project A, and restore at project B

These steps are heavily inspired by the [gcp documentation](https://cloud.google.com/compute/docs/images/sharing-images-across-projects).

Expand Down
48 changes: 48 additions & 0 deletions examples/velero_at_a_br_at_other.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Velero at project A, backup and restore at other projects

This scenario is introduced in [issue 4806](https://github.com/vmware-tanzu/velero/issues/4806).

Assume the following...

- Project A [project-a]: The project where the Velero's service account is located, and the Velero service account is granted to have enough permission to do backup and restore in the other projects.
- Project B [project-b]: The GCP project we want to restore TO.
- Project C [project-c]: The GCP project we want to restore FROM.

## Set up Velero with permission in projects
* In **project-a**
* Create "Velero Server" IAM role **role-a** with required role permissions.
* Create ServiceAccount **sa-a**.
* Assign **sa-a** with **role-a**.
* Assign **sa-a** with **role-b**.
* Assign **sa-a** with **role-c**.
* Create a bucket **bucket-a**.
* Assign [sa-a] "Storage Object Admin" permissions to [bucket-a]

* In **project-b**
* Add the ServiceAccount **sa-a** into project **project-b** according to [Granting service accounts access to your projects](https://cloud.google.com/marketplace/docs/grant-service-account-access).
* Create ServiceAccount **sa-b**.
* Create "Velero Server" IAM role **role-b** with required role permissions.
* Assign **sa-b** with **role-b**.

* In **project-c**
* Add the ServiceAccount **sa-a** into project **project-c** according to [Granting service accounts access to your projects](https://cloud.google.com/marketplace/docs/grant-service-account-access).
* Create ServiceAccount **sa-c**.
* Create "Velero Server" IAM role **role-c** with required role permissions.
* Assign **sa-c** with **role-c**.

## Backup at project C
* In **project-c**
* Install Velero on the k8s cluster in this project with configs
* SecretFile: **sa-a**
* SnapshotLocation: project=**project-a** and volumeProject=**project-c**
* Bucket: **bucket-a**
* Create Velero backup with the PVC snapshots desired: **backup-c**

## Restore at project B
* In **project-b**
* NOTE: Make sure to disable any scheduled backups.
* Install Velero on the k8s cluster in this project with configurations
* SecretFile: **sa-a**
* SnapshotLocation: project=**project-a** and volumeProject=**project-b**
* Bucket: **bucket-a**
* Create Velero restore **restore-b** from backup **backup-c**
9 changes: 7 additions & 2 deletions velero-plugin-for-gcp/volume_snapshotter.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ const (
zoneSeparator = "__"
projectKey = "project"
snapshotLocationKey = "snapshotLocation"
volumeProjectKey = "volumeProject"
)

var pdCSIDriver = map[string]bool{
Expand All @@ -65,7 +66,8 @@ func newVolumeSnapshotter(logger logrus.FieldLogger) *VolumeSnapshotter {
}

func (b *VolumeSnapshotter) Init(config map[string]string) error {
if err := veleroplugin.ValidateVolumeSnapshotterConfigKeys(config, snapshotLocationKey, projectKey, credentialsFileConfigKey); err != nil {
if err := veleroplugin.ValidateVolumeSnapshotterConfigKeys(config,
snapshotLocationKey, projectKey, credentialsFileConfigKey, volumeProjectKey); err != nil {
return err
}

Expand Down Expand Up @@ -102,7 +104,10 @@ func (b *VolumeSnapshotter) Init(config map[string]string) error {

b.snapshotLocation = config[snapshotLocationKey]

b.volumeProject = creds.ProjectID
b.volumeProject = config[volumeProjectKey]
if b.volumeProject == "" {
b.volumeProject = creds.ProjectID
}

// get snapshot project from 'project' config key if specified,
// otherwise from the credentials file
Expand Down
67 changes: 67 additions & 0 deletions velero-plugin-for-gcp/volume_snapshotter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package main

import (
"encoding/json"
"os"
"strings"
"testing"

Expand Down Expand Up @@ -397,3 +398,69 @@ func TestRegionHelpers(t *testing.T) {
})
}
}

func TestInit(t *testing.T) {
credential_file_name := "./credential_file"
default_credential_file_name := "./default_credential"
os.Setenv("GOOGLE_APPLICATION_CREDENTIALS", default_credential_file_name)
credential_content := `{"type": "service_account","project_id": "project-a","private_key_id":"id","private_key":"key","client_email":"[email protected]","client_id":"id","auth_uri":"uri","token_uri":"uri","auth_provider_x509_cert_url":"url","client_x509_cert_url":"url"}`
f, err := os.Create(credential_file_name)
require.NoError(t, err)
_, err = f.Write([]byte(credential_content))
require.NoError(t, err)

f, err = os.Create(default_credential_file_name)
require.NoError(t, err)
_, err = f.Write([]byte(credential_content))
require.NoError(t, err)

tests := []struct {
name string
config map[string]string
expectedVolumeSnapshotter VolumeSnapshotter
}{
{
name: "Init with Credential files.",
config: map[string]string{
"project": "project-a",
"credentialsFile": credential_file_name,
"snapshotLocation": "default",
"volumeProject": "project-b",
},
expectedVolumeSnapshotter: VolumeSnapshotter{
snapshotLocation: "default",
volumeProject: "project-b",
snapshotProject: "project-a",
},
},
{
name: "Init without Credential files.",
config: map[string]string{
"project": "project-a",
"snapshotLocation": "default",
"volumeProject": "project-b",
},
expectedVolumeSnapshotter: VolumeSnapshotter{
snapshotLocation: "default",
volumeProject: "project-b",
snapshotProject: "project-a",
},
},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
volumeSnapshotter := newVolumeSnapshotter(logrus.StandardLogger())
err := volumeSnapshotter.Init(test.config)
require.NoError(t, err)
require.Equal(t, test.expectedVolumeSnapshotter.snapshotLocation, volumeSnapshotter.snapshotLocation)
require.Equal(t, test.expectedVolumeSnapshotter.volumeProject, volumeSnapshotter.volumeProject)
require.Equal(t, test.expectedVolumeSnapshotter.snapshotProject, volumeSnapshotter.snapshotProject)
})
}

err = os.Remove(credential_file_name)
require.NoError(t, err)
err = os.Remove(default_credential_file_name)
require.NoError(t, err)
}

0 comments on commit 7bb0d37

Please sign in to comment.