@@ -2,24 +2,22 @@ package manager
2
2
3
3
import (
4
4
"context"
5
- kerr "k8s.io/apimachinery/pkg/api/errors"
5
+ "path/filepath"
6
+
7
+ "stash.appscode.dev/apimachinery/apis/stash/v1beta1"
8
+ "stash.appscode.dev/manifest-backup/pkg/sanitizers"
9
+
6
10
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
7
11
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
8
12
"k8s.io/apimachinery/pkg/runtime/schema"
9
- "k8s.io/apimachinery/pkg/runtime/serializer"
10
13
"k8s.io/apimachinery/pkg/types"
11
14
"k8s.io/client-go/discovery"
12
15
"k8s.io/client-go/dynamic"
13
- "k8s.io/client-go/kubernetes/scheme"
14
16
"k8s.io/client-go/rest"
15
17
"k8s.io/client-go/restmapper"
16
- "path/filepath"
17
- "stash.appscode.dev/apimachinery/apis/stash/v1beta1"
18
- "stash.appscode.dev/manifest-backup/pkg/manager/sanitizers"
19
18
)
20
19
21
20
type applicationBackupManager struct {
22
- disc discovery.DiscoveryInterface
23
21
di dynamic.Interface
24
22
namespace string
25
23
storage Writer
@@ -45,175 +43,129 @@ func newApplicationBackupManager(opt BackupOptions) BackupManager {
45
43
}
46
44
47
45
func (opt applicationBackupManager ) Dump () error {
48
- var err error
49
- opt .config .QPS = 1e6
50
- opt .config .Burst = 1e6
51
- if err := rest .SetKubernetesDefaults (opt .config ); err != nil {
52
- return err
53
- }
54
- opt .config .NegotiatedSerializer = serializer.WithoutConversionCodecFactory {CodecFactory : scheme .Codecs }
55
- if opt .config .UserAgent == "" {
56
- opt .config .UserAgent = rest .DefaultKubernetesUserAgent ()
57
- }
58
-
59
- opt .disc , err = discovery .NewDiscoveryClientForConfig (opt .config )
60
- if err != nil {
61
- return err
62
- }
63
-
64
- opt .di , err = dynamic .NewForConfig (opt .config )
65
- if err != nil {
66
- return err
67
- }
68
-
69
- gv , err := schema .ParseGroupVersion (opt .target .APIVersion )
70
- if err != nil {
71
- return err
72
- }
73
- gvk := gv .WithKind (opt .target .Kind )
74
-
75
- apiResources , err := restmapper .GetAPIGroupResources (opt .disc )
46
+ gvr , err := opt .getRootObjectGVR ()
76
47
if err != nil {
77
- return err
48
+ return nil
78
49
}
79
- mapper := restmapper .NewDiscoveryRESTMapper (apiResources )
80
- mapping , err := mapper .RESTMapping (schema.GroupKind {Group : gvk .Group , Kind : gvk .Kind }, gvk .Version )
50
+ rootObj , err := opt .getRootObject (* gvr )
81
51
if err != nil {
82
52
return err
83
53
}
84
- ri := opt .di .Resource (mapping .Resource ).Namespace (opt .namespace )
85
54
86
- rootObj , err := ri .Get (context .TODO (), opt .target .Name , metav1.GetOptions {})
87
- if err != nil {
88
- return err
55
+ rTree := treeBuilder {
56
+ resourceTree : make (map [types.UID ][]resourceRef ),
89
57
}
90
-
91
- resourceTree := make (map [types.UID ][]resourceRef )
92
58
rootUID := types .UID ("root" )
93
- resourceTree [rootUID ] = []resourceRef {
59
+ rTree . resourceTree [rootUID ] = []resourceRef {
94
60
{
95
- gvr : mapping . Resource ,
61
+ gvr : * gvr ,
96
62
name : rootObj .GetName (),
97
63
namespace : rootObj .GetNamespace (),
64
+ kind : rootObj .GetKind (),
98
65
},
99
66
}
100
67
101
68
if opt .includeDependants {
102
- err := opt .generateDependencyTree (resourceTree )
69
+ err := opt .generateDependencyTree (& rTree )
103
70
if err != nil {
104
71
return err
105
72
}
106
73
}
107
- return opt .dumpResourceTree (resourceTree , rootUID )
74
+ return opt .dumpResourceTree (rTree . resourceTree , rootUID , opt . dataDir )
108
75
}
109
76
110
- type resourceRef struct {
111
- gvr schema.GroupVersionResource
112
- name string
113
- namespace string
114
- }
77
+ func (opt * applicationBackupManager ) getRootObjectGVR () (* schema.GroupVersionResource , error ) {
78
+ disc , err := discovery .NewDiscoveryClientForConfig (opt .config )
79
+ if err != nil {
80
+ return nil , err
81
+ }
82
+ apiResources , err := restmapper .GetAPIGroupResources (disc )
83
+ if err != nil {
84
+ return nil , err
85
+ }
115
86
116
- func (opt * applicationBackupManager ) generateDependencyTree (resourceTree map [types.UID ][]resourceRef ) error {
117
- resList , err := opt .disc .ServerPreferredResources ()
87
+ gv , err := schema .ParseGroupVersion (opt .target .APIVersion )
118
88
if err != nil {
119
- return err
89
+ return nil , err
120
90
}
91
+ gvk := gv .WithKind (opt .target .Kind )
121
92
122
- for _ , group := range resList {
123
- err := opt .traverseGroup (resourceTree , group )
124
- if err != nil {
125
- return err
126
- }
93
+ mapper := restmapper .NewDiscoveryRESTMapper (apiResources )
94
+ mapping , err := mapper .RESTMapping (schema.GroupKind {Group : gvk .Group , Kind : gvk .Kind }, gvk .Version )
95
+ if err != nil {
96
+ return nil , err
127
97
}
128
- return nil
98
+ return & mapping . Resource , nil
129
99
}
130
100
131
- func (opt * applicationBackupManager ) traverseGroup (resourceTree map [types.UID ][]resourceRef , group * metav1.APIResourceList ) error {
132
- gv , err := schema .ParseGroupVersion (group .GroupVersion )
101
+ func (opt * applicationBackupManager ) getRootObject (gvr schema.GroupVersionResource ) (* unstructured.Unstructured , error ) {
102
+ var err error
103
+ opt .di , err = dynamic .NewForConfig (opt .config )
133
104
if err != nil {
134
- return err
105
+ return nil , err
135
106
}
107
+ ri := opt .di .Resource (gvr ).Namespace (opt .namespace )
108
+ return ri .Get (context .TODO (), opt .target .Name , metav1.GetOptions {})
109
+ }
136
110
137
- for _ , res := range group .APIResources {
138
- if isSubResource (res .Name ) || ! hasGetListVerbs (res .Verbs ) {
139
- continue
140
- }
141
- // don't process non-namespaced resources when target is a namespace
142
- if ! res .Namespaced && opt .namespace != "" {
143
- continue
144
- }
145
-
146
- err := opt .traverseResourceInstances (resourceTree , gv .WithResource (res .Name ))
147
- if err != nil {
148
- return err
149
- }
111
+ func (opt * applicationBackupManager ) generateDependencyTree (tb * treeBuilder ) error {
112
+ rp := resourceProcessor {
113
+ config : opt .config ,
114
+ namespace : opt .namespace ,
115
+ selector : opt .selector ,
116
+ itemProcessor : tb ,
150
117
}
151
- return nil
118
+ return rp . processAPIResources ()
152
119
}
153
120
154
- func (opt * applicationBackupManager ) traverseResourceInstances (resourceTree map [types.UID ][]resourceRef , gvr schema.GroupVersionResource ) error {
155
- var next string
156
- for {
157
- var ri dynamic.ResourceInterface
158
- if opt .namespace != "" {
159
- ri = opt .di .Resource (gvr ).Namespace (opt .namespace )
160
- } else {
161
- ri = opt .di .Resource (gvr )
162
- }
163
-
164
- resp , err := ri .List (context .TODO (), metav1.ListOptions {
165
- Limit : 250 ,
166
- Continue : next ,
167
- LabelSelector : opt .selector ,
168
- })
169
- if err != nil {
170
- if ! kerr .IsNotFound (err ) {
171
- return err
172
- }
173
- return nil
174
- }
175
-
176
- opt .processItems (resourceTree , resp .Items , gvr )
121
+ type resourceRef struct {
122
+ gvr schema.GroupVersionResource
123
+ name string
124
+ namespace string
125
+ kind string
126
+ }
177
127
178
- next = resp .GetContinue ()
179
- if next == "" {
180
- break
181
- }
182
- }
183
- return nil
128
+ type treeBuilder struct {
129
+ resourceTree map [types.UID ][]resourceRef
184
130
}
185
131
186
- func (opt * applicationBackupManager ) processItems ( resourceTree map [types. UID ][] resourceRef , items []unstructured.Unstructured , gvr schema.GroupVersionResource ) {
132
+ func (opt treeBuilder ) Process ( items []unstructured.Unstructured , gvr schema.GroupVersionResource ) error {
187
133
for _ , r := range items {
188
134
ownerRefs := r .GetOwnerReferences ()
189
135
for i := range ownerRefs {
190
- if _ , ok := resourceTree [ownerRefs [i ].UID ]; ! ok {
191
- resourceTree [ownerRefs [i ].UID ] = make ([]resourceRef , 0 )
136
+ if _ , ok := opt . resourceTree [ownerRefs [i ].UID ]; ! ok {
137
+ opt . resourceTree [ownerRefs [i ].UID ] = make ([]resourceRef , 0 )
192
138
}
193
- resourceTree [ownerRefs [i ].UID ] = append (resourceTree [ownerRefs [i ].UID ], resourceRef {
139
+ opt . resourceTree [ownerRefs [i ].UID ] = append (opt . resourceTree [ownerRefs [i ].UID ], resourceRef {
194
140
gvr : gvr ,
195
141
name : r .GetName (),
196
142
namespace : r .GetNamespace (),
143
+ kind : r .GetKind (),
197
144
})
198
145
}
199
146
}
147
+ return nil
200
148
}
201
149
202
- func (opt * applicationBackupManager ) dumpResourceTree (resourceTree map [types.UID ][]resourceRef , rootUID types.UID ) error {
150
+ func (opt * applicationBackupManager ) dumpResourceTree (resourceTree map [types.UID ][]resourceRef , rootUID types.UID , prefix string ) error {
203
151
for _ , r := range resourceTree [rootUID ] {
204
- childUID , err := opt .dumpItem (r )
152
+ childUID , err := opt .dumpItem (r , prefix )
205
153
if err != nil {
206
154
return err
207
155
}
208
- err = opt .dumpResourceTree (resourceTree , childUID )
156
+ childPrefix := prefix
157
+ if rootUID != "root" {
158
+ childPrefix = filepath .Join (prefix , r .kind , r .name )
159
+ }
160
+ err = opt .dumpResourceTree (resourceTree , childUID , childPrefix )
209
161
if err != nil {
210
162
return err
211
163
}
212
164
}
213
165
return nil
214
166
}
215
167
216
- func (opt * applicationBackupManager ) dumpItem (r resourceRef ) (types.UID , error ) {
168
+ func (opt * applicationBackupManager ) dumpItem (r resourceRef , prefix string ) (types.UID , error ) {
217
169
var ri dynamic.ResourceInterface
218
170
if r .namespace != "" {
219
171
ri = opt .di .Resource (r .gvr ).Namespace (r .namespace )
@@ -237,16 +189,15 @@ func (opt *applicationBackupManager) dumpItem(r resourceRef) (types.UID, error)
237
189
delete (data , "status" )
238
190
}
239
191
240
- fileName := getFileName (obj , true , opt . dataDir )
192
+ fileName := opt . getFileName (obj , prefix )
241
193
return uid , storeItem (fileName , data , opt .storage )
242
194
}
243
195
244
- func getFileName (r * unstructured.Unstructured , isNamespaced bool , dataDir string ) string {
245
- prefix := ""
246
- if isNamespaced {
247
- prefix = filepath .Join (dataDir , "namespaces" , r .GetNamespace ())
248
- } else {
249
- prefix = filepath .Join (dataDir , "global" )
196
+ func (opt * applicationBackupManager ) getFileName (r * unstructured.Unstructured , prefix string ) string {
197
+ if opt .target .Kind == r .GetKind () &&
198
+ opt .target .Name == r .GetName () &&
199
+ opt .namespace == r .GetNamespace () {
200
+ return filepath .Join (prefix , r .GetName ()) + ".yaml"
250
201
}
251
- return filepath .Join (prefix , r .GetKind (), r .GetName ()) + ".yaml"
202
+ return filepath .Join (prefix , r .GetKind (), r .GetName (), r . GetName () ) + ".yaml"
252
203
}
0 commit comments