@@ -21,7 +21,6 @@ import (
2121 b64 "encoding/base64"
2222 "encoding/json"
2323 "fmt"
24- "io"
2524 "os"
2625 "path/filepath"
2726 "strings"
@@ -140,23 +139,56 @@ contexts:
140139current-context: multus-context
141140`
142141
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 )
147145 }
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 )
150182 }
151183
152184 // create multus.d directory
153185 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 )
155187 }
156188
157189 // create multus cni conf directory
158190 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 )
160192 }
161193
162194 // get Kubernetes service protocol/host/port
@@ -173,69 +205,49 @@ func (o *Options) createKubeConfig(currentFileHash []byte) ([]byte, error) {
173205 tlsConfig = "insecure-skip-tls-verify: true"
174206 } else {
175207 // 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- }
180208 caFileB64 := bytes .ReplaceAll ([]byte (b64 .StdEncoding .EncodeToString (caFileByte )), []byte ("\n " ), []byte ("" ))
181209 tlsConfig = fmt .Sprintf ("certificate-authority-data: %s" , string (caFileB64 ))
182210 }
183211
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-
189212 // create kubeconfig by template and replace it by atomic
190213 tempKubeConfigFile := fmt .Sprintf ("%s/multus.d/multus.kubeconfig.new" , o .CNIConfDir )
191214 multusKubeConfig := fmt .Sprintf ("%s/multus.d/multus.kubeconfig" , o .CNIConfDir )
192215 fp , err := os .OpenFile (tempKubeConfigFile , os .O_RDWR | os .O_CREATE | os .O_TRUNC , 0600 )
193216 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 )
195218 }
196219
197220 templateKubeconfig , err := template .New ("kubeconfig" ).Parse (kubeConfigTemplate )
198221 if err != nil {
199- return nil , fmt .Errorf ("template parse error: %v" , err )
222+ return nil , nil , fmt .Errorf ("template parse error: %v" , err )
200223 }
201224 templateData := map [string ]string {
202225 "KubeConfigHost" : fmt .Sprintf ("%s://[%s]:%s" , kubeProtocol , kubeHost , kubePort ),
203226 "KubeServerTLS" : tlsConfig ,
204227 "KubeServiceAccountToken" : string (saTokenByte ),
205228 }
206229
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 )
214233 }
215234
216235 if err := fp .Sync (); err != nil {
217236 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 )
219238 }
220239 if err := fp .Close (); err != nil {
221240 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 )
230242 }
231243
232244 // replace file with tempfile
233245 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 )
235247 }
236248
237249 fmt .Printf ("kubeconfig is created in %s\n " , multusKubeConfig )
238- return newFileHash , nil
250+ return caHash , saTokenHash , nil
239251}
240252
241253const multusConflistTemplate = `{
@@ -298,11 +310,11 @@ const multusConfTemplate = `{
298310}
299311`
300312
301- func (o * Options ) createMultusConfig () (string , error ) {
313+ func (o * Options ) createMultusConfig (prevMasterConfigFileHash [] byte ) (string , [] byte , error ) {
302314 // find master file from MultusAutoconfigDir
303315 files , err := libcni .ConfFiles (o .MultusAutoconfigDir , []string {".conf" , ".conflist" })
304316 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 )
306318 }
307319
308320 masterConfigPath := ""
@@ -313,22 +325,32 @@ func (o *Options) createMultusConfig() (string, error) {
313325 }
314326 }
315327 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 )
317329 }
318330
319- masterConfigBytes , err := os . ReadFile (masterConfigPath )
331+ masterConfigBytes , masterConfigFileHash , err := getFileAndHash (masterConfigPath )
320332 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 " )
322343 }
344+
323345 masterConfig := map [string ]interface {}{}
324346 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 )
326348 }
327349
328350 // check CNIVersion
329351 masterCNIVersionElem , ok := masterConfig ["cniVersion" ]
330352 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 )
332354 }
333355
334356 if o .ForceCNIVersion {
@@ -337,7 +359,7 @@ func (o *Options) createMultusConfig() (string, error) {
337359 } else {
338360 masterCNIVersion := masterCNIVersionElem .(string )
339361 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 )
341363 }
342364 o .CNIVersion = masterCNIVersion
343365 }
@@ -348,7 +370,7 @@ func (o *Options) createMultusConfig() (string, error) {
348370 if o .OverrideNetworkName {
349371 masterPluginNetworkElem , ok := masterConfig ["name" ]
350372 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 )
352374 }
353375
354376 masterPluginNetworkName = masterPluginNetworkElem .(string )
@@ -362,7 +384,7 @@ func (o *Options) createMultusConfig() (string, error) {
362384 if isMasterConfList {
363385 masterPluginsElem , ok := masterConfig ["plugins" ]
364386 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 )
366388 }
367389 masterPlugins := masterPluginsElem .([]interface {})
368390 for _ , v := range masterPlugins {
@@ -389,7 +411,7 @@ func (o *Options) createMultusConfig() (string, error) {
389411 if len (masterCapabilities ) != 0 {
390412 capabilitiesByte , err := json .Marshal (masterCapabilities )
391413 if err != nil {
392- return "" , fmt .Errorf ("cannot get capabilities map: %v" , err )
414+ return "" , nil , fmt .Errorf ("cannot get capabilities map: %v" , err )
393415 }
394416 nestedCapabilitiesConf = fmt .Sprintf ("\n \" capabilities\" : %s," , string (capabilitiesByte ))
395417 }
@@ -421,7 +443,7 @@ func (o *Options) createMultusConfig() (string, error) {
421443 case "" :
422444 // no logLevel config, skipped
423445 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 )
425447 }
426448
427449 // check MultusLogFile
@@ -451,28 +473,28 @@ func (o *Options) createMultusConfig() (string, error) {
451473 // fill .MasterPluginJSON
452474 masterPluginByte , err := json .Marshal (masterConfig )
453475 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 )
455477 }
456478
457479 // generate multus config
458480 tempFileName := fmt .Sprintf ("%s/00-multus.conf.new" , o .CNIConfDir )
459481 fp , err := os .OpenFile (tempFileName , os .O_WRONLY | os .O_CREATE , 0600 )
460482 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 )
462484 }
463485
464486 // use conflist template if cniVersionConfig == "1.0.0"
465487 multusConfFilePath := fmt .Sprintf ("%s/00-multus.conf" , o .CNIConfDir )
466488 templateMultusConfig , err := template .New ("multusCNIConfig" ).Parse (multusConfTemplate )
467489 if err != nil {
468- return "" , fmt .Errorf ("template parse error: %v" , err )
490+ return "" , nil , fmt .Errorf ("template parse error: %v" , err )
469491 }
470492
471493 if o .CNIVersion == "1.0.0" { //Check 1.0.0 or above!
472494 multusConfFilePath = fmt .Sprintf ("%s/00-multus.conflist" , o .CNIConfDir )
473495 templateMultusConfig , err = template .New ("multusCNIConfig" ).Parse (multusConflistTemplate )
474496 if err != nil {
475- return "" , fmt .Errorf ("template parse error: %v" , err )
497+ return "" , nil , fmt .Errorf ("template parse error: %v" , err )
476498 }
477499 }
478500
@@ -492,32 +514,32 @@ func (o *Options) createMultusConfig() (string, error) {
492514 "MasterPluginJSON" : string (masterPluginByte ),
493515 }
494516 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 )
496518 }
497519
498520 if err := fp .Sync (); err != nil {
499521 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 )
501523 }
502524 if err := fp .Close (); err != nil {
503525 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 )
505527 }
506528
507529 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 )
509531 }
510532
511533 if o .RenameConfFile {
512534 //masterConfigPath
513535 renamedMasterConfigPath := fmt .Sprintf ("%s.old" , masterConfigPath )
514536 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 )
516538 }
517539 fmt .Printf ("Original master file moved to %q\n " , renamedMasterConfigPath )
518540 }
519541
520- return masterConfigPath , nil
542+ return masterConfigPath , masterConfigFileHash , nil
521543}
522544
523545func main () {
@@ -546,7 +568,7 @@ func main() {
546568 }
547569 }
548570
549- var kubeConfigHash []byte
571+ var masterConfigHash , caHash , saTokenHash []byte
550572 var masterConfigFilePath string
551573 // copy user specified multus conf to CNI conf directory
552574 if opt .MultusConfFile != "auto" {
@@ -558,13 +580,13 @@ func main() {
558580 }
559581 fmt .Printf ("multus config file %s is copied.\n " , opt .MultusConfFile )
560582 } else { // auto generate multus config
561- kubeConfigHash , err = opt .createKubeConfig (nil )
583+ caHash , saTokenHash , err = opt .createKubeConfig (nil , nil )
562584 if err != nil {
563585 fmt .Fprintf (os .Stderr , "failed to create multus kubeconfig: %v\n " , err )
564586 return
565587 }
566588 fmt .Printf ("kubeconfig file is created.\n " )
567- masterConfigFilePath , err = opt .createMultusConfig ()
589+ masterConfigFilePath , masterConfigHash , err = opt .createMultusConfig (nil )
568590 if err != nil {
569591 fmt .Fprintf (os .Stderr , "failed to create multus config: %v\n " , err )
570592 return
@@ -576,7 +598,7 @@ func main() {
576598 fmt .Printf ("Entering watch loop...\n " )
577599 for {
578600 // 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 )
580602 if err != nil {
581603 fmt .Fprintf (os .Stderr , "failed to update multus kubeconfig: %v\n " , err )
582604 return
@@ -598,7 +620,7 @@ func main() {
598620 }
599621 }
600622 }
601- masterConfigFilePath , err = opt .createMultusConfig ()
623+ masterConfigFilePath , masterConfigHash , err = opt .createMultusConfig (masterConfigHash )
602624 if err != nil {
603625 fmt .Fprintf (os .Stderr , "failed to create multus config: %v\n " , err )
604626 return
0 commit comments