func (m *Module) hasChild(name string) bool {
	_, ok := m.children[name]
	return ok
}
hasChild checks if the module has a child with the given name.
package config
import (
	"reflect"
	"sigs.k8s.io/yaml"
	"strings"
)
const (
	MainModule = "main"
)
type GetConfigFn func() interface{}
type NotifyFn func(Event, Source) error
type Event string
const (
	UpdateEvent = "update"
	RevertEvent = "rollback"
)
type Source string
const (
	ConfigFile Source = "configuration file"
	ConfigExternal Source = "external configuration"
	ConfigBackup Source = "backed up configuration"
)
type Module struct {
	path        string              
	description string              
	help        string              
	ptr         interface{}         
	parent      *Module             
	name        string              
	children    map[string]*Module  
	getdefault  GetConfigFn         
	notifiers   []NotifyFn          
	noValidate  bool                
}
var main = &Module{
	path:     MainModule,
	name:     MainModule,
	children: make(map[string]*Module),
}
func GetConfig() (Data, error) {
	return main.getconfig()
}
func SetConfig(cfg map[string]string) error {
	data, err := DataFromStringMap(cfg)
	if err != nil {
		return configError("failed to update configuration: %v", err)
	}
	return setconfig(data, ConfigExternal)
}
func SetConfigFromFile(path string) error {
	data, err := DataFromFile(path)
	if err != nil {
		return configError("failed to apply configuration from file: %v", err)
	}
	return setconfig(data, ConfigFile)
}
func GetModule(path string) *Module {
	return lookup(path)
}
func (m *Module) AddNotify(fn NotifyFn) error {
	return WithNotify(fn).apply(m)
}
func Register(path, description string, ptr interface{}, getfn GetConfigFn, opts ...Option) *Module {
	m := lookup(path)
	if !m.isImplicit() {
		log.Fatal("module %s: conflicting module with same path already declared (%s)",
			path, m.description)
	}
	m.setDescription(description)
	m.ptr = ptr
	m.getdefault = getfn
	m.check()
	foreign := m.notifiers
	m.notifiers = nil
	for _, opt := range opts {
		opt.apply(m)
	}
	m.notifiers = append(m.notifiers, foreign...)
	return m
}
func setconfig(data Data, source Source) error {
	snapshot, err := main.getconfig()
	if err != nil {
		return configError("pre-update configuration snapshot failed: %v", err)
	}
	log.Info("validating configuration...")
	err = main.validate(data)
	if err != nil {
		return err
	}
	log.Info("applying configuration...")
	err = main.configure(data, false)
	if err != nil {
		revertconfig(snapshot, false)
		return err
	}
	log.Info("activating configuration...")
	err = main.notify(UpdateEvent, source)
	if err != nil {
		log.Error("configuration rejected: %v", err)
		revertconfig(snapshot, true)
		return err
	}
	return nil
}
func revertconfig(snapshot Data, notify bool) {
	err := main.configure(snapshot, true)
	if err != nil {
		log.Error("failed to revert configuration: %v", err)
	}
	if !notify {
		return
	}
	err = main.notify(RevertEvent, ConfigBackup)
	if err != nil {
		log.Error("reverted configuration rejected: %v", err)
	}
}
func (m *Module) getconfig() (Data, error) {
	var mcfg, ccfg Data
	var err error
	if m.isImplicit() {
		mcfg = make(Data)
	} else {
		mcfg, err = DataFromObject(m.ptr)
		if err != nil {
			return nil, configError("module %s: failed to get confguration: %v",
				m.path, err)
		}
	}
	for name, child := range m.children {
		ccfg, err = child.getconfig()
		if err != nil {
			return nil, configError("module %s: failed to get child configuration for %s: %v",
				m.path, child.path, err)
		}
		mcfg[name] = ccfg
	}
	return mcfg, nil
}
func (m *Module) isImplicit() bool {
	return m.description == ""
}