@@ -115,7 +115,7 @@ func (c *CertSyncController) sync(ctx context.Context, syncCtx factory.SyncConte
115115
116116 contentDir := getConfigMapDir (c .destinationDir , cm .Name )
117117
118- data := map [string ]string {}
118+ data := make ( map [string ]string , len ( configMap . Data ))
119119 for filename := range configMap .Data {
120120 fullFilename := filepath .Join (contentDir , filename )
121121
@@ -152,27 +152,7 @@ func (c *CertSyncController) sync(ctx context.Context, syncCtx factory.SyncConte
152152 continue
153153 }
154154
155- klog .Infof ("Creating directory %q ..." , contentDir )
156- if err := os .MkdirAll (contentDir , 0755 ); err != nil && ! os .IsExist (err ) {
157- c .eventRecorder .Warningf ("CertificateUpdateFailed" , "Failed creating directory for configmap: %s/%s: %v" , configMap .Namespace , configMap .Name , err )
158- errors = append (errors , err )
159- continue
160- }
161- for filename , content := range configMap .Data {
162- fullFilename := filepath .Join (contentDir , filename )
163- // if the existing is the same, do nothing
164- if reflect .DeepEqual (data [fullFilename ], content ) {
165- continue
166- }
167-
168- klog .Infof ("Writing configmap manifest %q ..." , fullFilename )
169- if err := staticpod .WriteFileAtomic ([]byte (content ), 0644 , fullFilename ); err != nil {
170- c .eventRecorder .Warningf ("CertificateUpdateFailed" , "Failed writing file for configmap: %s/%s: %v" , configMap .Namespace , configMap .Name , err )
171- errors = append (errors , err )
172- continue
173- }
174- }
175- c .eventRecorder .Eventf ("CertificateUpdated" , "Wrote updated configmap: %s/%s" , configMap .Namespace , configMap .Name )
155+ errors = append (errors , writeFiles (& realFS , c .eventRecorder , configMap .Namespace , configMap .Name , "configmap" , contentDir , data , 0644 )... )
176156 }
177157
178158 klog .Infof ("Syncing secrets: %v" , c .secrets )
@@ -220,7 +200,7 @@ func (c *CertSyncController) sync(ctx context.Context, syncCtx factory.SyncConte
220200
221201 contentDir := getSecretDir (c .destinationDir , s .Name )
222202
223- data := map [string ][]byte {}
203+ data := make ( map [string ][]byte , len ( secret . Data ))
224204 for filename := range secret .Data {
225205 fullFilename := filepath .Join (contentDir , filename )
226206
@@ -257,29 +237,80 @@ func (c *CertSyncController) sync(ctx context.Context, syncCtx factory.SyncConte
257237 continue
258238 }
259239
260- klog .Infof ("Creating directory %q ..." , contentDir )
261- if err := os .MkdirAll (contentDir , 0755 ); err != nil && ! os .IsExist (err ) {
262- c .eventRecorder .Warningf ("CertificateUpdateFailed" , "Failed creating directory for secret: %s/%s: %v" , secret .Namespace , secret .Name , err )
240+ errors = append (errors , writeFiles (& realFS , c .eventRecorder , secret .Namespace , secret .Name , "secret" , contentDir , data , 0600 )... )
241+ }
242+
243+ return utilerrors .NewAggregate (errors )
244+ }
245+
246+ type fileSystem struct {
247+ MkdirAll func (path string , perm os.FileMode ) error
248+ MkdirTemp func (dir , pattern string ) (string , error )
249+ RemoveAll func (path string ) error
250+ WriteFile func (name string , data []byte , perm os.FileMode ) error
251+ SwapDirectoriesAtomic func (dirA , dirB string ) error
252+ }
253+
254+ var realFS = fileSystem {
255+ MkdirAll : os .MkdirAll ,
256+ MkdirTemp : os .MkdirTemp ,
257+ RemoveAll : os .RemoveAll ,
258+ WriteFile : os .WriteFile ,
259+ SwapDirectoriesAtomic : staticpod .SwapDirectoriesAtomic ,
260+ }
261+
262+ func writeFiles [C string | []byte ](
263+ fs * fileSystem , eventRecorder events.Recorder ,
264+ objectNamespace , objectName , kind string ,
265+ contentDir string , files map [string ]C , filePerm os.FileMode ,
266+ ) []error {
267+ var errors []error
268+
269+ // We are going to atomically swap the new data directory for the old one.
270+ // In case the target directory does not exist, create it so that the directory not existing is not a special case.
271+ klog .Infof ("Ensuring directory %q exists ..." , contentDir )
272+ if err := fs .MkdirAll (contentDir , 0755 ); err != nil && ! os .IsExist (err ) {
273+ eventRecorder .Warningf ("CertificateUpdateFailed" ,
274+ "Failed creating content directory for %s: %s/%s: %v" , kind , objectNamespace , objectName , err )
275+ errors = append (errors , err )
276+ return errors
277+ }
278+
279+ // Create a tmp source directory to be swapped.
280+ srcDir , err := fs .MkdirTemp (filepath .Dir (contentDir ), filepath .Base (contentDir )+ "-*" )
281+ if err != nil {
282+ eventRecorder .Warningf ("CertificateUpdateFailed" ,
283+ "Failed to create source %s directory for %s/%s: %v" , kind , objectNamespace , objectName , err )
284+ errors = append (errors , err )
285+ return errors
286+ }
287+ defer fs .RemoveAll (srcDir )
288+
289+ // Populate the tmp directory with files.
290+ for filename , content := range files {
291+ fullFilename := filepath .Join (srcDir , filename )
292+ klog .Infof ("Writing %s manifest %q ..." , kind , fullFilename )
293+
294+ if err := fs .WriteFile (fullFilename , []byte (content ), filePerm ); err != nil {
295+ eventRecorder .Warningf ("CertificateUpdateFailed" ,
296+ "Failed writing file for %s: %s/%s: %v" , kind , objectNamespace , objectName , err )
263297 errors = append (errors , err )
264298 continue
265299 }
266- for filename , content := range secret .Data {
267- // TODO fix permissions
268- fullFilename := filepath .Join (contentDir , filename )
269- // if the existing is the same, do nothing
270- if reflect .DeepEqual (data [fullFilename ], content ) {
271- continue
272- }
300+ }
301+ if len (errors ) > 0 {
302+ return errors
303+ }
273304
274- klog .Infof ("Writing secret manifest %q ..." , fullFilename )
275- if err := staticpod .WriteFileAtomic (content , 0600 , fullFilename ); err != nil {
276- c .eventRecorder .Warningf ("CertificateUpdateFailed" , "Failed writing file for secret: %s/%s: %v" , secret .Namespace , secret .Name , err )
277- errors = append (errors , err )
278- continue
279- }
280- }
281- c .eventRecorder .Eventf ("CertificateUpdated" , "Wrote updated secret: %s/%s" , secret .Namespace , secret .Name )
305+ // Swap directories atomically.
306+ if err := fs .SwapDirectoriesAtomic (contentDir , srcDir ); err != nil {
307+ eventRecorder .Warningf ("CertificateUpdateFailed" ,
308+ "Failed to enable new %s directory for %s/%s: %v" , kind , objectNamespace , objectName , err )
309+ errors = append (errors , err )
310+ return errors
282311 }
283312
284- return utilerrors .NewAggregate (errors )
313+ eventRecorder .Eventf ("CertificateUpdated" ,
314+ "Wrote updated %s: %s/%s" , kind , objectNamespace , objectName )
315+ return nil
285316}
0 commit comments