-
Notifications
You must be signed in to change notification settings - Fork 61
/
snapshots.go
129 lines (100 loc) · 3.45 KB
/
snapshots.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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
package kubernetes
import (
"context"
k8upv1 "github.com/k8up-io/k8up/v2/api/v1"
"github.com/k8up-io/k8up/v2/restic/dto"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
)
// SyncSnapshotList will take a k8upv1.SnapshotList and apply them to the k8s cluster.
// It will remove any snapshots on the cluster that are not present in the list.
func SyncSnapshotList(ctx context.Context, list []dto.Snapshot, namespace, repository string) error {
newList := filterAndConvert(list, namespace, repository)
oldList := &k8upv1.SnapshotList{}
kube, err := NewTypedClient()
if err != nil {
return err
}
err = kube.List(ctx, oldList, &client.ListOptions{Namespace: namespace})
if err != nil {
return err
}
oldList = filterByRepo(oldList, repository)
err = createNewSnapshots(ctx, newList, oldList, kube)
if err != nil {
return err
}
return deleteOldSnapshots(ctx, newList, oldList, kube)
}
// createNewSnapshots is a wrapper for the diff function to correctly pass the right order and function
func createNewSnapshots(ctx context.Context, newList, oldList *k8upv1.SnapshotList, kube client.Client) error {
return diff(newList, oldList, func(snap k8upv1.Snapshot) error {
return kube.Create(ctx, &snap)
})
}
// deleteOldSnapshots is a wrapper for the diff function to correctly pass the right order and function
func deleteOldSnapshots(ctx context.Context, newList, oldList *k8upv1.SnapshotList, kube client.Client) error {
return diff(oldList, newList, func(snap k8upv1.Snapshot) error {
return kube.Delete(ctx, &snap)
})
}
// diff will execute a given function for each element that is in a but not b
// it assumes that both lists belong to the same namespace and repository
func diff(a, b *k8upv1.SnapshotList, diffFunc func(snap k8upv1.Snapshot) error) error {
snapMap := listToMap(b)
for _, snapshot := range a.Items {
// Avoid pointer bug
snapshot := &snapshot
if _, ok := snapMap[*snapshot.Spec.ID]; !ok {
err := diffFunc(*snapshot)
if err != nil {
return err
}
}
}
return nil
}
func listToMap(list *k8upv1.SnapshotList) map[string]bool {
finalMap := map[string]bool{}
for _, snap := range list.Items {
finalMap[*snap.Spec.ID] = true
}
return finalMap
}
// filterAndConvert removes snapshots that don't belong to the same namespace
// and it converts them to the k8up snapshot CR.
func filterAndConvert(list []dto.Snapshot, namespace, repository string) *k8upv1.SnapshotList {
finalList := &k8upv1.SnapshotList{Items: []k8upv1.Snapshot{}}
for _, snapshot := range list {
// Avoid pointer bug
snapshot := snapshot
// we don't want snapshots that belong to another namespace in here.
if snapshot.Hostname != namespace {
continue
}
finalList.Items = append(finalList.Items, k8upv1.Snapshot{
ObjectMeta: metav1.ObjectMeta{
Name: snapshot.ID[:8],
Namespace: namespace,
},
Spec: k8upv1.SnapshotSpec{
ID: &snapshot.ID,
Date: &metav1.Time{Time: snapshot.Time},
Paths: &snapshot.Paths,
Repository: &repository,
},
})
}
return finalList
}
// filterByRepo will filter the list according to the given repository.
func filterByRepo(list *k8upv1.SnapshotList, repo string) *k8upv1.SnapshotList {
filteredList := &k8upv1.SnapshotList{Items: []k8upv1.Snapshot{}}
for _, snap := range list.Items {
snap := snap
if *snap.Spec.Repository == repo {
filteredList.Items = append(filteredList.Items, snap)
}
}
return filteredList
}