@@ -21,7 +21,6 @@ import (
21
21
b64 "encoding/base64"
22
22
"encoding/json"
23
23
"fmt"
24
- "io"
25
24
"os"
26
25
"path/filepath"
27
26
"strings"
@@ -140,23 +139,56 @@ contexts:
140
139
current-context: multus-context
141
140
`
142
141
143
- func (o * Options ) createKubeConfig (currentFileHash []byte ) ([]byte , error ) {
144
- // check file exists
145
- if _ , err := os .Stat (serviceAccountTokenFile ); err != nil {
146
- return nil , fmt .Errorf ("service account token is not found: %v" , err )
142
+ func getFileAndHash (filepath string ) ([]byte , []byte , error ) {
143
+ if _ , err := os .Stat (filepath ); err != nil {
144
+ return nil , nil , fmt .Errorf ("file %s not found: %v" , filepath , err )
147
145
}
148
- if _ , err := os .Stat (serviceAccountCAFile ); err != nil {
149
- return nil , fmt .Errorf ("service account ca is not found: %v" , err )
146
+ content , err := os .ReadFile (filepath )
147
+ if err != nil {
148
+ return nil , nil , fmt .Errorf ("cannot read %s file: %v" , filepath , err )
149
+ }
150
+
151
+ hash := sha256 .New ()
152
+ hash .Write (content )
153
+ return content , hash .Sum (nil ), nil
154
+ }
155
+
156
+ func (o * Options ) createKubeConfig (prevCAHash , prevSATokenHash []byte ) ([]byte , []byte , error ) {
157
+ caFileByte , caHash , err := getFileAndHash (serviceAccountCAFile )
158
+ if err != nil {
159
+ return nil , nil , err
160
+ }
161
+ saTokenByte , saTokenHash , err := getFileAndHash (serviceAccountTokenFile )
162
+ if err != nil {
163
+ return nil , nil , err
164
+ }
165
+
166
+ caUnchanged := prevCAHash != nil && bytes .Equal (prevCAHash , caHash )
167
+ saUnchanged := prevSATokenHash != nil && bytes .Equal (prevSATokenHash , saTokenHash )
168
+
169
+ if o .SkipTLSVerify {
170
+ if saUnchanged {
171
+ return caHash , saTokenHash , nil
172
+ }
173
+ } else {
174
+ if caUnchanged && saUnchanged {
175
+ return caHash , saTokenHash , nil
176
+ }
177
+ }
178
+
179
+ if prevSATokenHash != nil {
180
+ // don't log "recreating" on first function execution
181
+ fmt .Printf ("CA (%v) or SA token (%v) changed - recreating kubeconfig\n " , ! caUnchanged , ! saUnchanged )
150
182
}
151
183
152
184
// create multus.d directory
153
185
if err := os .MkdirAll (fmt .Sprintf ("%s/multus.d" , o .CNIConfDir ), 0755 ); err != nil {
154
- return nil , fmt .Errorf ("cannot create multus.d directory: %v" , err )
186
+ return nil , nil , fmt .Errorf ("cannot create multus.d directory: %v" , err )
155
187
}
156
188
157
189
// create multus cni conf directory
158
190
if err := os .MkdirAll (o .MultusCNIConfDir , 0755 ); err != nil {
159
- return nil , fmt .Errorf ("cannot create multus-cni-conf-dir(%s) directory: %v" , o .MultusCNIConfDir , err )
191
+ return nil , nil , fmt .Errorf ("cannot create multus-cni-conf-dir(%s) directory: %v" , o .MultusCNIConfDir , err )
160
192
}
161
193
162
194
// get Kubernetes service protocol/host/port
@@ -173,69 +205,49 @@ func (o *Options) createKubeConfig(currentFileHash []byte) ([]byte, error) {
173
205
tlsConfig = "insecure-skip-tls-verify: true"
174
206
} else {
175
207
// create tlsConfig by service account CA file
176
- caFileByte , err := os .ReadFile (serviceAccountCAFile )
177
- if err != nil {
178
- return nil , fmt .Errorf ("cannot read service account ca file: %v" , err )
179
- }
180
208
caFileB64 := bytes .ReplaceAll ([]byte (b64 .StdEncoding .EncodeToString (caFileByte )), []byte ("\n " ), []byte ("" ))
181
209
tlsConfig = fmt .Sprintf ("certificate-authority-data: %s" , string (caFileB64 ))
182
210
}
183
211
184
- saTokenByte , err := os .ReadFile (serviceAccountTokenFile )
185
- if err != nil {
186
- return nil , fmt .Errorf ("cannot read service account token file: %v" , err )
187
- }
188
-
189
212
// create kubeconfig by template and replace it by atomic
190
213
tempKubeConfigFile := fmt .Sprintf ("%s/multus.d/multus.kubeconfig.new" , o .CNIConfDir )
191
214
multusKubeConfig := fmt .Sprintf ("%s/multus.d/multus.kubeconfig" , o .CNIConfDir )
192
215
fp , err := os .OpenFile (tempKubeConfigFile , os .O_RDWR | os .O_CREATE | os .O_TRUNC , 0600 )
193
216
if err != nil {
194
- return nil , fmt .Errorf ("cannot create kubeconfig temp file: %v" , err )
217
+ return nil , nil , fmt .Errorf ("cannot create kubeconfig temp file: %v" , err )
195
218
}
196
219
197
220
templateKubeconfig , err := template .New ("kubeconfig" ).Parse (kubeConfigTemplate )
198
221
if err != nil {
199
- return nil , fmt .Errorf ("template parse error: %v" , err )
222
+ return nil , nil , fmt .Errorf ("template parse error: %v" , err )
200
223
}
201
224
templateData := map [string ]string {
202
225
"KubeConfigHost" : fmt .Sprintf ("%s://[%s]:%s" , kubeProtocol , kubeHost , kubePort ),
203
226
"KubeServerTLS" : tlsConfig ,
204
227
"KubeServiceAccountToken" : string (saTokenByte ),
205
228
}
206
229
207
- // Prepare
208
- hash := sha256 .New ()
209
- writer := io .MultiWriter (hash , fp )
210
-
211
- // genearate kubeconfig from template
212
- if err = templateKubeconfig .Execute (writer , templateData ); err != nil {
213
- return nil , fmt .Errorf ("cannot create kubeconfig: %v" , err )
230
+ // generate kubeconfig from template
231
+ if err = templateKubeconfig .Execute (fp , templateData ); err != nil {
232
+ return nil , nil , fmt .Errorf ("cannot create kubeconfig: %v" , err )
214
233
}
215
234
216
235
if err := fp .Sync (); err != nil {
217
236
os .Remove (fp .Name ())
218
- return nil , fmt .Errorf ("cannot flush kubeconfig temp file: %v" , err )
237
+ return nil , nil , fmt .Errorf ("cannot flush kubeconfig temp file: %v" , err )
219
238
}
220
239
if err := fp .Close (); err != nil {
221
240
os .Remove (fp .Name ())
222
- return nil , fmt .Errorf ("cannot close kubeconfig temp file: %v" , err )
223
- }
224
-
225
- newFileHash := hash .Sum (nil )
226
- if currentFileHash != nil && bytes .Compare (newFileHash , currentFileHash ) == 0 {
227
- fmt .Printf ("kubeconfig is same, not copy\n " )
228
- os .Remove (fp .Name ())
229
- return currentFileHash , nil
241
+ return nil , nil , fmt .Errorf ("cannot close kubeconfig temp file: %v" , err )
230
242
}
231
243
232
244
// replace file with tempfile
233
245
if err := os .Rename (tempKubeConfigFile , multusKubeConfig ); err != nil {
234
- return nil , fmt .Errorf ("cannot replace %q with temp file %q: %v" , multusKubeConfig , tempKubeConfigFile , err )
246
+ return nil , nil , fmt .Errorf ("cannot replace %q with temp file %q: %v" , multusKubeConfig , tempKubeConfigFile , err )
235
247
}
236
248
237
249
fmt .Printf ("kubeconfig is created in %s\n " , multusKubeConfig )
238
- return newFileHash , nil
250
+ return caHash , saTokenHash , nil
239
251
}
240
252
241
253
const multusConflistTemplate = `{
@@ -298,11 +310,11 @@ const multusConfTemplate = `{
298
310
}
299
311
`
300
312
301
- func (o * Options ) createMultusConfig () (string , error ) {
313
+ func (o * Options ) createMultusConfig (prevMasterConfigFileHash [] byte ) (string , [] byte , error ) {
302
314
// find master file from MultusAutoconfigDir
303
315
files , err := libcni .ConfFiles (o .MultusAutoconfigDir , []string {".conf" , ".conflist" })
304
316
if err != nil {
305
- return "" , fmt .Errorf ("cannot find master CNI config in %q: %v" , o .MultusAutoconfigDir , err )
317
+ return "" , nil , fmt .Errorf ("cannot find master CNI config in %q: %v" , o .MultusAutoconfigDir , err )
306
318
}
307
319
308
320
masterConfigPath := ""
@@ -313,22 +325,32 @@ func (o *Options) createMultusConfig() (string, error) {
313
325
}
314
326
}
315
327
if masterConfigPath == "" {
316
- return "" , fmt .Errorf ("cannot find valid master CNI config in %q" , o .MultusAutoconfigDir )
328
+ return "" , nil , fmt .Errorf ("cannot find valid master CNI config in %q" , o .MultusAutoconfigDir )
317
329
}
318
330
319
- masterConfigBytes , err := os . ReadFile (masterConfigPath )
331
+ masterConfigBytes , masterConfigFileHash , err := getFileAndHash (masterConfigPath )
320
332
if err != nil {
321
- return "" , fmt .Errorf ("cannot read master CNI config file %q: %v" , masterConfigPath , err )
333
+ return "" , nil , err
334
+ }
335
+
336
+ if prevMasterConfigFileHash != nil && bytes .Equal (prevMasterConfigFileHash , masterConfigFileHash ) {
337
+ return masterConfigPath , masterConfigFileHash , nil
338
+ }
339
+
340
+ if prevMasterConfigFileHash != nil {
341
+ // don't log "recreating" on first function execution
342
+ fmt .Printf ("master config changed - recreating multus config\n " )
322
343
}
344
+
323
345
masterConfig := map [string ]interface {}{}
324
346
if err = json .Unmarshal (masterConfigBytes , & masterConfig ); err != nil {
325
- return "" , fmt .Errorf ("cannot read master CNI config json: %v" , err )
347
+ return "" , nil , fmt .Errorf ("cannot read master CNI config json: %v" , err )
326
348
}
327
349
328
350
// check CNIVersion
329
351
masterCNIVersionElem , ok := masterConfig ["cniVersion" ]
330
352
if ! ok {
331
- return "" , fmt .Errorf ("cannot get cniVersion in master CNI config file %q: %v" , masterConfigPath , err )
353
+ return "" , nil , fmt .Errorf ("cannot get cniVersion in master CNI config file %q: %v" , masterConfigPath , err )
332
354
}
333
355
334
356
if o .ForceCNIVersion {
@@ -337,7 +359,7 @@ func (o *Options) createMultusConfig() (string, error) {
337
359
} else {
338
360
masterCNIVersion := masterCNIVersionElem .(string )
339
361
if o .CNIVersion != "" && masterCNIVersion != o .CNIVersion {
340
- return "" , fmt .Errorf ("Multus cni version is %q while master plugin cni version is %q" , o .CNIVersion , masterCNIVersion )
362
+ return "" , nil , fmt .Errorf ("Multus cni version is %q while master plugin cni version is %q" , o .CNIVersion , masterCNIVersion )
341
363
}
342
364
o .CNIVersion = masterCNIVersion
343
365
}
@@ -348,7 +370,7 @@ func (o *Options) createMultusConfig() (string, error) {
348
370
if o .OverrideNetworkName {
349
371
masterPluginNetworkElem , ok := masterConfig ["name" ]
350
372
if ! ok {
351
- return "" , fmt .Errorf ("cannot get name in master CNI config file %q: %v" , masterConfigPath , err )
373
+ return "" , nil , fmt .Errorf ("cannot get name in master CNI config file %q: %v" , masterConfigPath , err )
352
374
}
353
375
354
376
masterPluginNetworkName = masterPluginNetworkElem .(string )
@@ -362,7 +384,7 @@ func (o *Options) createMultusConfig() (string, error) {
362
384
if isMasterConfList {
363
385
masterPluginsElem , ok := masterConfig ["plugins" ]
364
386
if ! ok {
365
- return "" , fmt .Errorf ("cannot get 'plugins' field in master CNI config file %q: %v" , masterConfigPath , err )
387
+ return "" , nil , fmt .Errorf ("cannot get 'plugins' field in master CNI config file %q: %v" , masterConfigPath , err )
366
388
}
367
389
masterPlugins := masterPluginsElem .([]interface {})
368
390
for _ , v := range masterPlugins {
@@ -389,7 +411,7 @@ func (o *Options) createMultusConfig() (string, error) {
389
411
if len (masterCapabilities ) != 0 {
390
412
capabilitiesByte , err := json .Marshal (masterCapabilities )
391
413
if err != nil {
392
- return "" , fmt .Errorf ("cannot get capabilities map: %v" , err )
414
+ return "" , nil , fmt .Errorf ("cannot get capabilities map: %v" , err )
393
415
}
394
416
nestedCapabilitiesConf = fmt .Sprintf ("\n \" capabilities\" : %s," , string (capabilitiesByte ))
395
417
}
@@ -421,7 +443,7 @@ func (o *Options) createMultusConfig() (string, error) {
421
443
case "" :
422
444
// no logLevel config, skipped
423
445
default :
424
- return "" , fmt .Errorf ("Log levels should be one of: debug/verbose/error/panic, did not understand: %q" , o .MultusLogLevel )
446
+ return "" , nil , fmt .Errorf ("Log levels should be one of: debug/verbose/error/panic, did not understand: %q" , o .MultusLogLevel )
425
447
}
426
448
427
449
// check MultusLogFile
@@ -451,28 +473,28 @@ func (o *Options) createMultusConfig() (string, error) {
451
473
// fill .MasterPluginJSON
452
474
masterPluginByte , err := json .Marshal (masterConfig )
453
475
if err != nil {
454
- return "" , fmt .Errorf ("cannot encode master CNI config: %v" , err )
476
+ return "" , nil , fmt .Errorf ("cannot encode master CNI config: %v" , err )
455
477
}
456
478
457
479
// generate multus config
458
480
tempFileName := fmt .Sprintf ("%s/00-multus.conf.new" , o .CNIConfDir )
459
481
fp , err := os .OpenFile (tempFileName , os .O_WRONLY | os .O_CREATE , 0600 )
460
482
if err != nil {
461
- return "" , fmt .Errorf ("cannot create multus cni temp file: %v" , err )
483
+ return "" , nil , fmt .Errorf ("cannot create multus cni temp file: %v" , err )
462
484
}
463
485
464
486
// use conflist template if cniVersionConfig == "1.0.0"
465
487
multusConfFilePath := fmt .Sprintf ("%s/00-multus.conf" , o .CNIConfDir )
466
488
templateMultusConfig , err := template .New ("multusCNIConfig" ).Parse (multusConfTemplate )
467
489
if err != nil {
468
- return "" , fmt .Errorf ("template parse error: %v" , err )
490
+ return "" , nil , fmt .Errorf ("template parse error: %v" , err )
469
491
}
470
492
471
493
if o .CNIVersion == "1.0.0" { //Check 1.0.0 or above!
472
494
multusConfFilePath = fmt .Sprintf ("%s/00-multus.conflist" , o .CNIConfDir )
473
495
templateMultusConfig , err = template .New ("multusCNIConfig" ).Parse (multusConflistTemplate )
474
496
if err != nil {
475
- return "" , fmt .Errorf ("template parse error: %v" , err )
497
+ return "" , nil , fmt .Errorf ("template parse error: %v" , err )
476
498
}
477
499
}
478
500
@@ -492,32 +514,32 @@ func (o *Options) createMultusConfig() (string, error) {
492
514
"MasterPluginJSON" : string (masterPluginByte ),
493
515
}
494
516
if err = templateMultusConfig .Execute (fp , templateData ); err != nil {
495
- return "" , fmt .Errorf ("cannot create multus cni config: %v" , err )
517
+ return "" , nil , fmt .Errorf ("cannot create multus cni config: %v" , err )
496
518
}
497
519
498
520
if err := fp .Sync (); err != nil {
499
521
os .Remove (tempFileName )
500
- return "" , fmt .Errorf ("cannot flush multus cni config: %v" , err )
522
+ return "" , nil , fmt .Errorf ("cannot flush multus cni config: %v" , err )
501
523
}
502
524
if err := fp .Close (); err != nil {
503
525
os .Remove (tempFileName )
504
- return "" , fmt .Errorf ("cannot close multus cni config: %v" , err )
526
+ return "" , nil , fmt .Errorf ("cannot close multus cni config: %v" , err )
505
527
}
506
528
507
529
if err := os .Rename (tempFileName , multusConfFilePath ); err != nil {
508
- return "" , fmt .Errorf ("cannot replace %q with temp file %q: %v" , multusConfFilePath , tempFileName , err )
530
+ return "" , nil , fmt .Errorf ("cannot replace %q with temp file %q: %v" , multusConfFilePath , tempFileName , err )
509
531
}
510
532
511
533
if o .RenameConfFile {
512
534
//masterConfigPath
513
535
renamedMasterConfigPath := fmt .Sprintf ("%s.old" , masterConfigPath )
514
536
if err := os .Rename (masterConfigPath , renamedMasterConfigPath ); err != nil {
515
- return "" , fmt .Errorf ("cannot move original master file to %q" , renamedMasterConfigPath )
537
+ return "" , nil , fmt .Errorf ("cannot move original master file to %q" , renamedMasterConfigPath )
516
538
}
517
539
fmt .Printf ("Original master file moved to %q\n " , renamedMasterConfigPath )
518
540
}
519
541
520
- return masterConfigPath , nil
542
+ return masterConfigPath , masterConfigFileHash , nil
521
543
}
522
544
523
545
func main () {
@@ -546,7 +568,7 @@ func main() {
546
568
}
547
569
}
548
570
549
- var kubeConfigHash []byte
571
+ var masterConfigHash , caHash , saTokenHash []byte
550
572
var masterConfigFilePath string
551
573
// copy user specified multus conf to CNI conf directory
552
574
if opt .MultusConfFile != "auto" {
@@ -558,13 +580,13 @@ func main() {
558
580
}
559
581
fmt .Printf ("multus config file %s is copied.\n " , opt .MultusConfFile )
560
582
} else { // auto generate multus config
561
- kubeConfigHash , err = opt .createKubeConfig (nil )
583
+ caHash , saTokenHash , err = opt .createKubeConfig (nil , nil )
562
584
if err != nil {
563
585
fmt .Fprintf (os .Stderr , "failed to create multus kubeconfig: %v\n " , err )
564
586
return
565
587
}
566
588
fmt .Printf ("kubeconfig file is created.\n " )
567
- masterConfigFilePath , err = opt .createMultusConfig ()
589
+ masterConfigFilePath , masterConfigHash , err = opt .createMultusConfig (nil )
568
590
if err != nil {
569
591
fmt .Fprintf (os .Stderr , "failed to create multus config: %v\n " , err )
570
592
return
@@ -576,7 +598,7 @@ func main() {
576
598
fmt .Printf ("Entering watch loop...\n " )
577
599
for {
578
600
// Check kubeconfig and update if different (i.e. service account updated)
579
- kubeConfigHash , err = opt .createKubeConfig (kubeConfigHash )
601
+ caHash , saTokenHash , err = opt .createKubeConfig (caHash , saTokenHash )
580
602
if err != nil {
581
603
fmt .Fprintf (os .Stderr , "failed to update multus kubeconfig: %v\n " , err )
582
604
return
@@ -598,7 +620,7 @@ func main() {
598
620
}
599
621
}
600
622
}
601
- masterConfigFilePath , err = opt .createMultusConfig ()
623
+ masterConfigFilePath , masterConfigHash , err = opt .createMultusConfig (masterConfigHash )
602
624
if err != nil {
603
625
fmt .Fprintf (os .Stderr , "failed to create multus config: %v\n " , err )
604
626
return
0 commit comments