Skip to content

Commit 53a68c3

Browse files
authored
Recreate configs only if base files changed (#1234)
1 parent ca5a4c9 commit 53a68c3

File tree

2 files changed

+105
-77
lines changed

2 files changed

+105
-77
lines changed

cmd/thin_entrypoint/main.go

+87-65
Original file line numberDiff line numberDiff line change
@@ -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:
140139
current-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

241253
const 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

523545
func 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

Comments
 (0)