in agent/pluginmanager/installeds.go [44:125]
func loadInstalledPlugins(isPreInstalled bool) (*InstalledPlugins, error) {
var boltPath string
var err error
if isPreInstalled {
boltPath, err = getPreInstalledPluginsBoltPath()
if err != nil {
return nil, err
}
} else {
boltPath, err = getInstalledPluginsBoltPath()
if err != nil {
return nil, err
}
}
// 1. Just use the new BoltDB file if existed, but NEVER AUTO-CREATE IT if
// not existed
boltdb, err := bolt.Open(boltPath, os.FileMode(0o0640), &bolt.Options{
OpenFile: func(name string, flag int, perm os.FileMode) (*os.File, error) {
return os.OpenFile(name, flag & ^os.O_CREATE, perm)
},
})
if err == nil {
return &InstalledPlugins{
boltdb: boltdb,
}, nil
}
if !errors.Is(err, os.ErrNotExist) {
return nil, err
}
// 2. Just use the new BoltDB file when old JSON file does not exist
jsonPath, err := getInstalledPluginsJSONPath()
if err != nil {
return nil, err
}
jsonFile, err := os.OpenFile(jsonPath, os.O_RDONLY, 0)
if err != nil {
// Resolved: Simply use BoltDB database file on error encountered when
// opening installed_plugins JSON database file. Just log the error and
// let it go then.
log.GetLogger().WithError(err).Warningln("Failed to open obsolete installed_plugins JSON database file")
return _loadInstalledPluginsBolt(boltPath)
}
// 3. Now migrate data from old existed JSON file to the new BoltDB file,
// which MUST be created EXCLUSIVELY BY CURRENT PROCESS
installedPluginInfoBytes, err := _loadEachInstalledPluginJsonAsBytes(jsonFile)
if err != nil {
// Resolved: Simply use BoltDB database file on error encountered when
// reading and parsing installed_plugins JSON database file. Empty file
// is also unacceptable.
log.GetLogger().WithError(err).Warningln("Failed to read obsolete installed_plugins JSON database file")
return _loadInstalledPluginsBolt(boltPath)
}
boltdb, err = bolt.Open(boltPath, os.FileMode(0o0640), &bolt.Options{
OpenFile: func(name string, flag int, perm os.FileMode) (*os.File, error) {
return os.OpenFile(name, flag|os.O_EXCL, perm)
},
})
if err != nil {
if errors.Is(err, os.ErrExist) {
// !!!RACE CONDITION HERE!!!
// Existed installed_plugins.db BoltDB file means another process
// (e.g., agent or yet another acs-plugin-manager) is doing or has
// done the migration. Simply fallback to general opening procedure.
return _loadInstalledPluginsBolt(boltPath)
} else {
return nil, err
}
}
if err := _insertInstalledPluginInfoBytes(boltdb, installedPluginInfoBytes); err != nil {
_ = boltdb.Close()
return nil, err
}
return &InstalledPlugins{
boltdb: boltdb,
}, nil
}