func loadInstalledPlugins()

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
}