server/config: consolidate ConfigManager start and fsnotify watching

Simplify setup by moving the post-creation operations like
GenerateConfig() and PersistMultusConfig() into a new Start() function
that also begins watching the configuration directory. This better
encapsulates the manager functionality in the object.

We can also get rid of the done channel passed to the config
manager and just use the existing WaitGroup to determine when to
exit the daemon main().

Signed-off-by: Dan Williams <dcbw@redhat.com>
This commit is contained in:
Dan Williams 2023-09-12 21:07:20 -05:00
parent 4ade85669b
commit 8539a476fd
3 changed files with 48 additions and 46 deletions

View File

@ -57,8 +57,6 @@ func main() {
os.Exit(4)
}
configWatcherDoneChannel := make(chan struct{})
multusConfigFile := ""
ctx := context.Background()
ctx, cancel := context.WithCancel(ctx)
@ -111,29 +109,6 @@ func main() {
_ = logging.Errorf("failed to create the configuration manager for the primary CNI plugin: %v", err)
os.Exit(2)
}
if multusConf.OverrideNetworkName {
if err := configManager.OverrideNetworkName(); err != nil {
_ = logging.Errorf("could not override the network name: %v", err)
}
}
generatedMultusConfig, err := configManager.GenerateConfig()
if err != nil {
_ = logging.Errorf("failed to generated the multus configuration: %v", err)
}
logging.Verbosef("Generated MultusCNI config: %s", generatedMultusConfig)
multusConfigFile, err = configManager.PersistMultusConfig(generatedMultusConfig)
if err != nil {
_ = logging.Errorf("failed to persist the multus configuration: %v", err)
}
go func(ctx context.Context, doneChannel chan<- struct{}) {
if err := configManager.MonitorPluginConfiguration(ctx, doneChannel); err != nil {
_ = logging.Errorf("error watching file: %v", err)
}
}(ctx, configWatcherDoneChannel)
} else {
if err := copyUserProvidedConfig(multusConf.MultusConfigFile, multusConf.CniConfigDir); err != nil {
logging.Errorf("failed to copy the user provided configuration %s: %v", multusConf.MultusConfigFile, err)
@ -151,14 +126,10 @@ func main() {
var wg sync.WaitGroup
if configManager != nil {
wg.Add(1)
go func() {
<-configWatcherDoneChannel
logging.Verbosef("ConfigWatcher done")
logging.Verbosef("Delete old config @ %v", multusConfigFile)
os.Remove(multusConfigFile)
wg.Done()
}()
if err := configManager.Start(ctx, &wg); err != nil {
_ = logging.Errorf("failed to start config manager: %v", err)
os.Exit(3)
}
}
wg.Wait()

View File

@ -20,6 +20,7 @@ import (
"fmt"
"os"
"path/filepath"
"sync"
"github.com/fsnotify/fsnotify"
@ -123,9 +124,43 @@ func newManager(config MultusConf, defaultCNIPluginName string) (*Manager, error
return nil, fmt.Errorf("failed to load the primary CNI configuration as a multus delegate with error '%v'", err)
}
if config.OverrideNetworkName {
if err := configManager.OverrideNetworkName(); err != nil {
return nil, logging.Errorf("could not override the network name: %v", err)
}
}
return configManager, nil
}
// Start generates an updated Multus config, writes it, and begins watching
// the config directory and readiness indicator files for changes
func (m *Manager) Start(ctx context.Context, wg *sync.WaitGroup) error {
generatedMultusConfig, err := m.GenerateConfig()
if err != nil {
return logging.Errorf("failed to generated the multus configuration: %v", err)
}
logging.Verbosef("Generated MultusCNI config: %s", generatedMultusConfig)
multusConfigFile, err := m.PersistMultusConfig(generatedMultusConfig)
if err != nil {
return logging.Errorf("failed to persist the multus configuration: %v", err)
}
wg.Add(1)
go func() {
defer wg.Done()
if err := m.MonitorPluginConfiguration(ctx); err != nil {
_ = logging.Errorf("error watching file: %v", err)
}
logging.Verbosef("ConfigWatcher done")
logging.Verbosef("Delete old config @ %v", multusConfigFile)
os.Remove(multusConfigFile)
}()
return nil
}
func (m *Manager) loadPrimaryCNIConfigFromFile() error {
primaryCNIConfigData, err := primaryCNIData(m.primaryCNIConfigPath)
if err != nil {
@ -175,7 +210,7 @@ func (m *Manager) GenerateConfig() (string, error) {
// MonitorPluginConfiguration monitors the configuration file pointed
// to by the primaryCNIPluginName attribute, and re-generates the multus
// configuration whenever the primary CNI config is updated.
func (m *Manager) MonitorPluginConfiguration(ctx context.Context, done chan<- struct{}) error {
func (m *Manager) MonitorPluginConfiguration(ctx context.Context) error {
logging.Verbosef("started to watch file %s", m.primaryCNIConfigPath)
for {
@ -215,7 +250,6 @@ func (m *Manager) MonitorPluginConfiguration(ctx context.Context, done chan<- st
case <-ctx.Done():
logging.Verbosef("Stopped monitoring, closing channel ...")
_ = m.configWatcher.Close()
close(done)
return nil
}
}

View File

@ -19,6 +19,7 @@ import (
"encoding/json"
"fmt"
"os"
"sync"
"time"
. "github.com/onsi/ginkgo/v2"
@ -42,6 +43,7 @@ var _ = Describe("Configuration Manager", func() {
var configManager *Manager
var multusConfigDir string
var defaultCniConfig string
var wg *sync.WaitGroup
BeforeEach(func() {
var err error
@ -67,9 +69,12 @@ var _ = Describe("Configuration Manager", func() {
configManager, err = NewManager(*multusConf)
Expect(err).NotTo(HaveOccurred())
wg = &sync.WaitGroup{}
})
AfterEach(func() {
wg.Wait()
Expect(os.RemoveAll(multusConfigDir)).To(Succeed())
})
@ -102,15 +107,10 @@ var _ = Describe("Configuration Manager", func() {
config, err := configManager.GenerateConfig()
Expect(err).NotTo(HaveOccurred())
_, err = configManager.PersistMultusConfig(config)
Expect(err).NotTo(HaveOccurred())
ctx, cancel := context.WithCancel(context.Background())
configWatcherDoneChannel := make(chan struct{})
go func(ctx context.Context, doneChannel chan struct{}) {
err := configManager.MonitorPluginConfiguration(ctx, doneChannel)
Expect(err).NotTo(HaveOccurred())
}(ctx, configWatcherDoneChannel)
defer cancel()
err = configManager.Start(ctx, wg)
Expect(err).NotTo(HaveOccurred())
updatedCNIConfig := `
{
@ -129,9 +129,6 @@ var _ = Describe("Configuration Manager", func() {
file, err := os.ReadFile(configManager.multusConfigFilePath)
Expect(err).NotTo(HaveOccurred())
Expect(string(file)).To(Equal(config))
// stop groutine
cancel()
})
When("the user requests the name of the multus configuration to be overridden", func() {