From 7d91198abd73e164dd42366bc1028bbb176cc0a3 Mon Sep 17 00:00:00 2001 From: Christophe Varoqui Date: Fri, 23 Jan 2026 15:29:36 +0100 Subject: [PATCH 1/3] Don't call the api from "om node| config doc" Let ox use the api, but om has all the keywords builtin, so no need to require a working daemon to serve them. --- core/commoncmd/node_config_doc.go | 2 +- core/doc/main.go | 115 ++++++++++++++++++ core/om/kind_all.go | 3 +- core/om/kind_ccfg.go | 7 +- core/om/kind_cfg.go | 7 +- core/om/kind_nscfg.go | 3 +- core/om/kind_sec.go | 7 +- core/om/kind_svc.go | 3 +- core/om/kind_usr.go | 7 +- core/om/kind_vol.go | 3 +- core/om/node.go | 3 +- core/omcmd/node_config_doc.go | 83 +++++++++++++ core/omcmd/object_config_doc.go | 88 ++++++++++++++ daemon/daemonapi/get_node_config_keywords.go | 19 +-- .../daemonapi/get_object_config_keywords.go | 14 ++- 15 files changed, 338 insertions(+), 26 deletions(-) create mode 100644 core/doc/main.go create mode 100644 core/omcmd/node_config_doc.go create mode 100644 core/omcmd/object_config_doc.go diff --git a/core/commoncmd/node_config_doc.go b/core/commoncmd/node_config_doc.go index d67451579..588eda45d 100644 --- a/core/commoncmd/node_config_doc.go +++ b/core/commoncmd/node_config_doc.go @@ -28,7 +28,7 @@ func NewCmdNodeConfigDoc() *cobra.Command { var options CmdNodeConfigDoc cmd := &cobra.Command{ Use: "doc", - Short: "print the documentation of the selected keywords", + Short: "print the keyword documentation", RunE: func(cmd *cobra.Command, args []string) error { return options.Run() }, diff --git a/core/doc/main.go b/core/doc/main.go new file mode 100644 index 000000000..cb6366f6d --- /dev/null +++ b/core/doc/main.go @@ -0,0 +1,115 @@ +package doc + +import ( + "fmt" + "strings" + + "github.com/opensvc/om3/v3/core/keywords" + "github.com/opensvc/om3/v3/core/naming" + "github.com/opensvc/om3/v3/core/xconfig" + "github.com/opensvc/om3/v3/daemon/api" + "github.com/opensvc/om3/v3/util/key" +) + +type ( + ConfigProvider interface { + Config() *xconfig.T + } + errBadRequest struct { + text string + } +) + +var ( + ErrBadRequest errBadRequest +) + +func (err errBadRequest) Error() string { + return err.text +} + +func newErrBadRequest(text string) errBadRequest { + return errBadRequest{text: text} +} + +func FilterKeywordStore(store keywords.Store, driver, section, option *string, path naming.Path, getConfigProvider func() (ConfigProvider, error)) (keywords.Store, error) { + var err error + switch { + case driver == nil && section == nil && option == nil: + case driver != nil && section != nil && option == nil: + return nil, newErrBadRequest("driver and section filters are mutually exclusive") + case driver != nil && section == nil && option == nil: + l := keywords.ParseIndex(*driver) + store, err = store.DriverKeywords(l[0], l[1], path.Kind) + if err != nil { + return nil, err + } + case driver == nil && section != nil && option == nil: + o, err := getConfigProvider() + if err != nil { + return nil, err + } + sectionType := o.Config().GetString(key.New(*section, "type")) + drvGroup, _, _ := strings.Cut(*section, "#") + store, err = store.DriverKeywords(drvGroup, sectionType, path.Kind) + if err != nil { + return nil, fmt.Errorf("%s.%s: %s", drvGroup, sectionType, err) + } + case driver == nil && section != nil && option != nil: + o, err := getConfigProvider() + if err != nil { + return nil, err + } + sectionType := o.Config().GetString(key.New(*section, "type")) + k := key.New(*section, *option) + kw := o.Config().Referrer.KeywordLookup(k, sectionType) + if kw.IsZero() { + store = []keywords.Keyword{} + } else { + store = []keywords.Keyword{kw} + } + } + return store, nil +} + +func ConvertKeywordStore(store keywords.Store) api.KeywordDefinitionItems { + l := make(api.KeywordDefinitionItems, 0) + for _, kw := range store { + item := api.KeywordDefinitionItem{ + Option: kw.Option, + Section: kw.Section, + Converter: kw.Converter, + Default: kw.Default, + DefaultOption: kw.DefaultOption, + DefaultText: kw.DefaultText, + Text: kw.Text, + Example: kw.Example, + Deprecated: kw.Deprecated, + Provisioning: kw.Provisioning, + Scopable: kw.Scopable, + Required: kw.Required, + Inherit: kw.Inherit.String(), + Aliases: append([]string{}, kw.Aliases...), + Candidates: append([]string{}, kw.Candidates...), + Types: append([]string{}, kw.Types...), + } + + for _, d := range kw.Depends { + item.Depends = append(item.Depends, d.String()) + } + + for _, k := range kw.Kind { + switch v := k.(type) { + case string: + item.Kind = append(item.Kind, v) + case fmt.Stringer: + item.Kind = append(item.Kind, v.String()) + default: + item.Kind = append(item.Kind, fmt.Sprintf("%v", v)) + } + } + + l = append(l, item) + } + return l +} diff --git a/core/om/kind_all.go b/core/om/kind_all.go index 51bcdbaf5..833130c87 100644 --- a/core/om/kind_all.go +++ b/core/om/kind_all.go @@ -2,6 +2,7 @@ package om import ( "github.com/opensvc/om3/v3/core/commoncmd" + "github.com/opensvc/om3/v3/core/omcmd" "github.com/opensvc/om3/v3/util/hostname" ) @@ -126,7 +127,7 @@ func init() { newCmdObjectResourceList(kind), ) cmdObjectConfig.AddCommand( - commoncmd.NewCmdObjectConfigDoc(kind), + omcmd.NewCmdObjectConfigDoc(kind), newCmdObjectConfigEdit(kind), newCmdObjectConfigEval(kind), newCmdObjectConfigGet(kind), diff --git a/core/om/kind_ccfg.go b/core/om/kind_ccfg.go index 67585e382..8ac375cc7 100644 --- a/core/om/kind_ccfg.go +++ b/core/om/kind_ccfg.go @@ -1,6 +1,9 @@ package om -import "github.com/opensvc/om3/v3/core/commoncmd" +import ( + "github.com/opensvc/om3/v3/core/commoncmd" + "github.com/opensvc/om3/v3/core/omcmd" +) func init() { kind := "ccfg" @@ -45,7 +48,7 @@ func init() { newCmdObjectUnset(kind), ) cmdObjectConfig.AddCommand( - commoncmd.NewCmdObjectConfigDoc(kind), + omcmd.NewCmdObjectConfigDoc(kind), newCmdObjectConfigEdit(kind), newCmdObjectConfigEval(kind), newCmdObjectConfigGet(kind), diff --git a/core/om/kind_cfg.go b/core/om/kind_cfg.go index 38164e1a5..e64e3a12f 100644 --- a/core/om/kind_cfg.go +++ b/core/om/kind_cfg.go @@ -1,6 +1,9 @@ package om -import "github.com/opensvc/om3/v3/core/commoncmd" +import ( + "github.com/opensvc/om3/v3/core/commoncmd" + "github.com/opensvc/om3/v3/core/omcmd" +) func init() { kind := "cfg" @@ -49,7 +52,7 @@ func init() { newCmdObjectUnset(kind), ) cmdObjectConfig.AddCommand( - commoncmd.NewCmdObjectConfigDoc(kind), + omcmd.NewCmdObjectConfigDoc(kind), newCmdObjectConfigEdit(kind), newCmdObjectConfigEval(kind), newCmdObjectConfigGet(kind), diff --git a/core/om/kind_nscfg.go b/core/om/kind_nscfg.go index de1b2682f..813deabb4 100644 --- a/core/om/kind_nscfg.go +++ b/core/om/kind_nscfg.go @@ -4,6 +4,7 @@ import ( "github.com/spf13/cobra" "github.com/opensvc/om3/v3/core/commoncmd" + "github.com/opensvc/om3/v3/core/omcmd" ) func init() { @@ -41,7 +42,7 @@ func init() { ) cmdObjectConfig.AddCommand( - commoncmd.NewCmdObjectConfigDoc(kind), + omcmd.NewCmdObjectConfigDoc(kind), newCmdObjectConfigEdit(kind), newCmdObjectConfigEval(kind), newCmdObjectConfigGet(kind), diff --git a/core/om/kind_sec.go b/core/om/kind_sec.go index 19ab82d76..8374dadd0 100644 --- a/core/om/kind_sec.go +++ b/core/om/kind_sec.go @@ -1,6 +1,9 @@ package om -import "github.com/opensvc/om3/v3/core/commoncmd" +import ( + "github.com/opensvc/om3/v3/core/commoncmd" + "github.com/opensvc/om3/v3/core/omcmd" +) func init() { kind := "sec" @@ -59,7 +62,7 @@ func init() { newCmdObjectCertificatePKCS(kind), ) cmdObjectConfig.AddCommand( - commoncmd.NewCmdObjectConfigDoc(kind), + omcmd.NewCmdObjectConfigDoc(kind), newCmdObjectConfigEdit(kind), newCmdObjectConfigEval(kind), newCmdObjectConfigGet(kind), diff --git a/core/om/kind_svc.go b/core/om/kind_svc.go index 0254097d5..68c5f266c 100644 --- a/core/om/kind_svc.go +++ b/core/om/kind_svc.go @@ -2,6 +2,7 @@ package om import ( "github.com/opensvc/om3/v3/core/commoncmd" + "github.com/opensvc/om3/v3/core/omcmd" "github.com/opensvc/om3/v3/util/hostname" ) @@ -87,7 +88,7 @@ func init() { newCmdObjectUnset(kind), ) cmdObjectConfig.AddCommand( - commoncmd.NewCmdObjectConfigDoc(kind), + omcmd.NewCmdObjectConfigDoc(kind), newCmdObjectConfigEdit(kind), newCmdObjectConfigEval(kind), newCmdObjectConfigGet(kind), diff --git a/core/om/kind_usr.go b/core/om/kind_usr.go index 26ab2ff18..6049d13d5 100644 --- a/core/om/kind_usr.go +++ b/core/om/kind_usr.go @@ -1,6 +1,9 @@ package om -import "github.com/opensvc/om3/v3/core/commoncmd" +import ( + "github.com/opensvc/om3/v3/core/commoncmd" + "github.com/opensvc/om3/v3/core/omcmd" +) func init() { kind := "usr" @@ -57,7 +60,7 @@ func init() { newCmdObjectCertificatePKCS(kind), ) cmdObjectConfig.AddCommand( - commoncmd.NewCmdObjectConfigDoc(kind), + omcmd.NewCmdObjectConfigDoc(kind), newCmdObjectConfigEdit(kind), newCmdObjectConfigEval(kind), newCmdObjectConfigGet(kind), diff --git a/core/om/kind_vol.go b/core/om/kind_vol.go index afb7624ad..77aa81a88 100644 --- a/core/om/kind_vol.go +++ b/core/om/kind_vol.go @@ -2,6 +2,7 @@ package om import ( "github.com/opensvc/om3/v3/core/commoncmd" + "github.com/opensvc/om3/v3/core/omcmd" "github.com/opensvc/om3/v3/util/hostname" ) @@ -88,7 +89,7 @@ func init() { newCmdObjectCollectorTagShow(kind), ) cmdObjectConfig.AddCommand( - commoncmd.NewCmdObjectConfigDoc(kind), + omcmd.NewCmdObjectConfigDoc(kind), newCmdObjectConfigEdit(kind), newCmdObjectConfigEval(kind), newCmdObjectConfigGet(kind), diff --git a/core/om/node.go b/core/om/node.go index ce2596efe..767168000 100644 --- a/core/om/node.go +++ b/core/om/node.go @@ -4,6 +4,7 @@ import ( "github.com/spf13/cobra" "github.com/opensvc/om3/v3/core/commoncmd" + "github.com/opensvc/om3/v3/core/omcmd" ) var ( @@ -173,7 +174,7 @@ func init() { newCmdNodeVersion(), ) cmdNodeConfig.AddCommand( - commoncmd.NewCmdNodeConfigDoc(), + omcmd.NewCmdNodeConfigDoc(), newCmdNodeConfigEdit(), newCmdNodeConfigEval(), newCmdNodeConfigGet(), diff --git a/core/omcmd/node_config_doc.go b/core/omcmd/node_config_doc.go new file mode 100644 index 000000000..d5082c900 --- /dev/null +++ b/core/omcmd/node_config_doc.go @@ -0,0 +1,83 @@ +package omcmd + +import ( + "os" + + "github.com/spf13/cobra" + + "github.com/opensvc/om3/v3/core/commoncmd" + "github.com/opensvc/om3/v3/core/doc" + "github.com/opensvc/om3/v3/core/keywords" + "github.com/opensvc/om3/v3/core/naming" + "github.com/opensvc/om3/v3/core/object" + "github.com/opensvc/om3/v3/core/output" + "github.com/opensvc/om3/v3/core/rawconfig" +) + +type ( + CmdNodeConfigDoc struct { + Color string + Output string + Keyword string + Driver string + Depth int + } +) + +func NewCmdNodeConfigDoc() *cobra.Command { + var options CmdNodeConfigDoc + cmd := &cobra.Command{ + Use: "doc", + Short: "print the keyword documentation", + RunE: func(cmd *cobra.Command, args []string) error { + return options.Run() + }, + } + flags := cmd.Flags() + commoncmd.FlagColor(flags, &options.Color) + commoncmd.FlagOutput(flags, &options.Output) + commoncmd.FlagKeyword(flags, &options.Keyword) + commoncmd.FlagDriver(flags, &options.Driver) + commoncmd.FlagDepth(flags, &options.Depth) + return cmd +} + +func (t *CmdNodeConfigDoc) Run() error { + var path naming.Path + var driver, section, option *string + if t.Driver != "" { + driver = &t.Driver + } + if t.Keyword != "" { + index := keywords.ParseIndex(t.Keyword) + section = &index[0] + option = &index[1] + } + store := object.NodeKeywordStore + store, err := doc.FilterKeywordStore(store, driver, section, option, path, func() (doc.ConfigProvider, error) { + var ( + i any + err error + ) + i, err = object.NewNode(object.WithVolatile(true)) + if err != nil { + return nil, err + } + return i.(doc.ConfigProvider), nil + }) + if err != nil { + return err + } + items := doc.ConvertKeywordStore(store) + output.Renderer{ + HumanRenderer: func() string { + commoncmd.Doc(os.Stdout, items, path.Kind, t.Driver, t.Keyword, t.Depth) + return "" + }, + Output: t.Output, + Color: t.Color, + Data: items, + Colorize: rawconfig.Colorize, + }.Print() + return nil +} diff --git a/core/omcmd/object_config_doc.go b/core/omcmd/object_config_doc.go new file mode 100644 index 000000000..203d086b9 --- /dev/null +++ b/core/omcmd/object_config_doc.go @@ -0,0 +1,88 @@ +package omcmd + +import ( + "os" + + "github.com/spf13/cobra" + + "github.com/opensvc/om3/v3/core/commoncmd" + "github.com/opensvc/om3/v3/core/doc" + "github.com/opensvc/om3/v3/core/keywords" + "github.com/opensvc/om3/v3/core/naming" + "github.com/opensvc/om3/v3/core/object" + "github.com/opensvc/om3/v3/core/output" + "github.com/opensvc/om3/v3/core/rawconfig" +) + +type ( + CmdObjectConfigDoc struct { + OptsGlobal + Color string + Output string + Keyword string + Driver string + Depth int + } +) + +func NewCmdObjectConfigDoc(kind string) *cobra.Command { + var options CmdObjectConfigDoc + cmd := &cobra.Command{ + Use: "doc", + Short: "print the keyword documentation", + RunE: func(cmd *cobra.Command, args []string) error { + return options.Run(kind) + }, + } + flags := cmd.Flags() + commoncmd.FlagObjectSelector(flags, &options.ObjectSelector) + commoncmd.FlagColor(flags, &options.Color) + commoncmd.FlagOutput(flags, &options.Output) + commoncmd.FlagKeyword(flags, &options.Keyword) + commoncmd.FlagDriver(flags, &options.Driver) + commoncmd.FlagDepth(flags, &options.Depth) + return cmd +} + +func (t *CmdObjectConfigDoc) Run(kind string) error { + path, err := naming.ParsePath(t.ObjectSelector) + if err != nil { + path, _ = naming.ParsePath("ns1/" + kind + "/obj1") + } + var driver, section, option *string + if t.Driver != "" { + driver = &t.Driver + } + if t.Keyword != "" { + index := keywords.ParseIndex(t.Keyword) + section = &index[0] + option = &index[1] + } + store := object.KeywordStoreWithDrivers(path.Kind) + store, err = doc.FilterKeywordStore(store, driver, section, option, path, func() (doc.ConfigProvider, error) { + var ( + i any + err error + ) + i, err = object.NewConfigurer(path, object.WithVolatile(true)) + if err != nil { + return nil, err + } + return i.(doc.ConfigProvider), nil + }) + if err != nil { + return err + } + items := doc.ConvertKeywordStore(store) + output.Renderer{ + HumanRenderer: func() string { + commoncmd.Doc(os.Stdout, items, path.Kind, t.Driver, t.Keyword, t.Depth) + return "" + }, + Output: t.Output, + Color: t.Color, + Data: items, + Colorize: rawconfig.Colorize, + }.Print() + return nil +} diff --git a/daemon/daemonapi/get_node_config_keywords.go b/daemon/daemonapi/get_node_config_keywords.go index 9f3eb2264..ff82aa13e 100644 --- a/daemon/daemonapi/get_node_config_keywords.go +++ b/daemon/daemonapi/get_node_config_keywords.go @@ -1,23 +1,22 @@ package daemonapi import ( + "errors" "net/http" "github.com/labstack/echo/v4" + "github.com/opensvc/om3/v3/core/doc" "github.com/opensvc/om3/v3/core/naming" "github.com/opensvc/om3/v3/core/object" "github.com/opensvc/om3/v3/daemon/api" ) func (a *DaemonAPI) GetNodeConfigKeywords(ctx echo.Context, nodename string, params api.GetNodeConfigKeywordsParams) error { - var ( - err error - status int - ) + var err error store := object.NodeKeywordStore path := naming.Path{} - store, status, err = filterKeywordStore(ctx, store, params.Driver, params.Section, params.Option, path, func() (configProvider, error) { + store, err = doc.FilterKeywordStore(store, params.Driver, params.Section, params.Option, path, func() (doc.ConfigProvider, error) { var ( err error i any @@ -26,14 +25,18 @@ func (a *DaemonAPI) GetNodeConfigKeywords(ctx echo.Context, nodename string, par if err != nil { return nil, err } - return i.(configProvider), nil + return i.(doc.ConfigProvider), nil }) - if err != nil { + if errors.Is(err, doc.ErrBadRequest) { + status := http.StatusBadRequest + return JSONProblemf(ctx, status, http.StatusText(status), "%s", err) + } else if err != nil { + status := http.StatusInternalServerError return JSONProblemf(ctx, status, http.StatusText(status), "%s", err) } r := api.KeywordDefinitionList{ Kind: "KeywordDefinitionList", - Items: convertKeywordStore(store), + Items: doc.ConvertKeywordStore(store), } return ctx.JSON(http.StatusOK, r) } diff --git a/daemon/daemonapi/get_object_config_keywords.go b/daemon/daemonapi/get_object_config_keywords.go index d638bf6be..7843a7a91 100644 --- a/daemon/daemonapi/get_object_config_keywords.go +++ b/daemon/daemonapi/get_object_config_keywords.go @@ -1,10 +1,12 @@ package daemonapi import ( + "errors" "net/http" "github.com/labstack/echo/v4" + "github.com/opensvc/om3/v3/core/doc" "github.com/opensvc/om3/v3/core/naming" "github.com/opensvc/om3/v3/core/object" "github.com/opensvc/om3/v3/core/xconfig" @@ -28,7 +30,7 @@ func (a *DaemonAPI) GetObjectConfigKeywords(ctx echo.Context, namespace string, Namespace: namespace, Kind: kind, } - store, status, err = filterKeywordStore(ctx, store, params.Driver, params.Section, params.Option, path, func() (configProvider, error) { + store, err = doc.FilterKeywordStore(store, params.Driver, params.Section, params.Option, path, func() (doc.ConfigProvider, error) { var ( i any err error @@ -37,14 +39,18 @@ func (a *DaemonAPI) GetObjectConfigKeywords(ctx echo.Context, namespace string, if err != nil { return nil, err } - return i.(configProvider), nil + return i.(doc.ConfigProvider), nil }) - if err != nil { + if errors.As(err, doc.ErrBadRequest) { + status = http.StatusBadRequest + return JSONProblemf(ctx, status, http.StatusText(status), "%s", err) + } else if err != nil { + status := http.StatusInternalServerError return JSONProblemf(ctx, status, http.StatusText(status), "%s", err) } r := api.KeywordDefinitionList{ Kind: "KeywordDefinitionList", - Items: convertKeywordStore(store), + Items: doc.ConvertKeywordStore(store), } return ctx.JSON(http.StatusOK, r) } From b33fd56447834e92ed02a35d964dcb16c239a902 Mon Sep 17 00:00:00 2001 From: Christophe Varoqui Date: Fri, 23 Jan 2026 15:53:10 +0100 Subject: [PATCH 2/3] Support "om node| config doc --driver app.fork --kw start" The --driver plus --kw flags was not implemented, and the whole driver kw store was printed. The patch add a Store.ByOption(string) filtering func to support this new feature. --- core/doc/main.go | 23 ++++++++----------- core/keywords/keywords.go | 9 ++++++++ .../daemonapi/get_object_config_keywords.go | 2 +- 3 files changed, 20 insertions(+), 14 deletions(-) diff --git a/core/doc/main.go b/core/doc/main.go index cb6366f6d..6b4a5569c 100644 --- a/core/doc/main.go +++ b/core/doc/main.go @@ -1,6 +1,7 @@ package doc import ( + "errors" "fmt" "strings" @@ -15,35 +16,31 @@ type ( ConfigProvider interface { Config() *xconfig.T } - errBadRequest struct { - text string - } ) var ( - ErrBadRequest errBadRequest + ErrBadRequest = errors.New("driver and section filters are mutually exclusive") ) -func (err errBadRequest) Error() string { - return err.text -} - -func newErrBadRequest(text string) errBadRequest { - return errBadRequest{text: text} -} - func FilterKeywordStore(store keywords.Store, driver, section, option *string, path naming.Path, getConfigProvider func() (ConfigProvider, error)) (keywords.Store, error) { var err error switch { case driver == nil && section == nil && option == nil: case driver != nil && section != nil && option == nil: - return nil, newErrBadRequest("driver and section filters are mutually exclusive") + return nil, ErrBadRequest case driver != nil && section == nil && option == nil: l := keywords.ParseIndex(*driver) store, err = store.DriverKeywords(l[0], l[1], path.Kind) if err != nil { return nil, err } + case driver != nil && option != nil: + l := keywords.ParseIndex(*driver) + store, err = store.DriverKeywords(l[0], l[1], path.Kind) + if *option == "" && section != nil { + return store.ByOption(*section), nil + } + return store.ByOption(*option), nil case driver == nil && section != nil && option == nil: o, err := getConfigProvider() if err != nil { diff --git a/core/keywords/keywords.go b/core/keywords/keywords.go index 66a17a51e..dcd66f790 100644 --- a/core/keywords/keywords.go +++ b/core/keywords/keywords.go @@ -189,6 +189,15 @@ func (t Store) Swap(i, j int) { t[i], t[j] = t[j], t[i] } +func (t Store) ByOption(option string) Store { + for _, kw := range t { + if kw.Option == option { + return Store{kw} + } + } + return Store{} +} + func (t Store) Lookup(k key.T, kind naming.Kind, sectionType string) Keyword { driverGroup := strings.Split(k.Section, "#")[0] baseOption := k.BaseOption() diff --git a/daemon/daemonapi/get_object_config_keywords.go b/daemon/daemonapi/get_object_config_keywords.go index 7843a7a91..68aa9759e 100644 --- a/daemon/daemonapi/get_object_config_keywords.go +++ b/daemon/daemonapi/get_object_config_keywords.go @@ -41,7 +41,7 @@ func (a *DaemonAPI) GetObjectConfigKeywords(ctx echo.Context, namespace string, } return i.(doc.ConfigProvider), nil }) - if errors.As(err, doc.ErrBadRequest) { + if errors.Is(err, doc.ErrBadRequest) { status = http.StatusBadRequest return JSONProblemf(ctx, status, http.StatusText(status), "%s", err) } else if err != nil { From d511a1b3b9b02d74098d7e22f772cbbe888e2fbf Mon Sep 17 00:00:00 2001 From: Christophe Varoqui Date: Sat, 24 Jan 2026 09:14:18 +0100 Subject: [PATCH 3/3] Remove daemon/daemonapi/lib_config_keywords.go Convert its last caller (daemon/daemonapi/get_cluster_config_keywords) to use the doc pkg instead. The "om cluster config doc" had already switched to the "doc" pkg. --- .../daemonapi/get_cluster_config_keywords.go | 19 ++-- daemon/daemonapi/lib_config_keywords.go | 96 ------------------- 2 files changed, 11 insertions(+), 104 deletions(-) delete mode 100644 daemon/daemonapi/lib_config_keywords.go diff --git a/daemon/daemonapi/get_cluster_config_keywords.go b/daemon/daemonapi/get_cluster_config_keywords.go index 68e039d19..edae8cf44 100644 --- a/daemon/daemonapi/get_cluster_config_keywords.go +++ b/daemon/daemonapi/get_cluster_config_keywords.go @@ -1,22 +1,21 @@ package daemonapi import ( + "errors" "net/http" "github.com/labstack/echo/v4" + "github.com/opensvc/om3/v3/core/doc" "github.com/opensvc/om3/v3/core/naming" "github.com/opensvc/om3/v3/core/object" "github.com/opensvc/om3/v3/daemon/api" ) func (a *DaemonAPI) GetClusterConfigKeywords(ctx echo.Context, params api.GetClusterConfigKeywordsParams) error { - var ( - err error - status int - ) + var err error store := object.KeywordStoreWithDrivers(naming.KindCcfg) - store, status, err = filterKeywordStore(ctx, store, params.Driver, params.Section, params.Option, naming.Cluster, func() (configProvider, error) { + store, err = doc.FilterKeywordStore(store, params.Driver, params.Section, params.Option, naming.Cluster, func() (doc.ConfigProvider, error) { var ( i any err error @@ -25,14 +24,18 @@ func (a *DaemonAPI) GetClusterConfigKeywords(ctx echo.Context, params api.GetClu if err != nil { return nil, err } - return i.(configProvider), nil + return i.(doc.ConfigProvider), nil }) - if err != nil { + if errors.Is(err, doc.ErrBadRequest) { + status := http.StatusBadRequest + return JSONProblemf(ctx, status, http.StatusText(status), "%s", err) + } else if err != nil { + status := http.StatusInternalServerError return JSONProblemf(ctx, status, http.StatusText(status), "%s", err) } r := api.KeywordDefinitionList{ Kind: "KeywordDefinitionList", - Items: convertKeywordStore(store), + Items: doc.ConvertKeywordStore(store), } return ctx.JSON(http.StatusOK, r) } diff --git a/daemon/daemonapi/lib_config_keywords.go b/daemon/daemonapi/lib_config_keywords.go deleted file mode 100644 index 66819eb63..000000000 --- a/daemon/daemonapi/lib_config_keywords.go +++ /dev/null @@ -1,96 +0,0 @@ -package daemonapi - -import ( - "fmt" - "net/http" - "strings" - - "github.com/labstack/echo/v4" - - "github.com/opensvc/om3/v3/core/keywords" - "github.com/opensvc/om3/v3/core/naming" - "github.com/opensvc/om3/v3/daemon/api" - "github.com/opensvc/om3/v3/util/key" -) - -func filterKeywordStore(ctx echo.Context, store keywords.Store, driver, section, option *string, path naming.Path, getConfigProvider func() (configProvider, error)) (keywords.Store, int, error) { - var err error - switch { - case driver == nil && section == nil && option == nil: - case driver != nil && section != nil && option == nil: - return nil, http.StatusBadRequest, fmt.Errorf("driver and section filters are mutually exclusive") - case driver != nil && section == nil && option == nil: - l := keywords.ParseIndex(*driver) - store, err = store.DriverKeywords(l[0], l[1], path.Kind) - if err != nil { - return nil, http.StatusInternalServerError, err - } - case driver == nil && section != nil && option == nil: - o, err := getConfigProvider() - if err != nil { - return nil, http.StatusInternalServerError, err - } - sectionType := o.Config().GetString(key.New(*section, "type")) - drvGroup, _, _ := strings.Cut(*section, "#") - store, err = store.DriverKeywords(drvGroup, sectionType, path.Kind) - if err != nil { - return nil, http.StatusInternalServerError, fmt.Errorf("%s.%s: %s", drvGroup, sectionType, err) - } - case driver == nil && section != nil && option != nil: - o, err := getConfigProvider() - if err != nil { - return nil, http.StatusInternalServerError, err - } - sectionType := o.Config().GetString(key.New(*section, "type")) - k := key.New(*section, *option) - kw := o.Config().Referrer.KeywordLookup(k, sectionType) - if kw.IsZero() { - store = []keywords.Keyword{} - } else { - store = []keywords.Keyword{kw} - } - } - return store, http.StatusOK, nil -} - -func convertKeywordStore(store keywords.Store) api.KeywordDefinitionItems { - l := make(api.KeywordDefinitionItems, 0) - for _, kw := range store { - item := api.KeywordDefinitionItem{ - Option: kw.Option, - Section: kw.Section, - Converter: kw.Converter, - Default: kw.Default, - DefaultOption: kw.DefaultOption, - DefaultText: kw.DefaultText, - Text: kw.Text, - Example: kw.Example, - Deprecated: kw.Deprecated, - Provisioning: kw.Provisioning, - Scopable: kw.Scopable, - Required: kw.Required, - Inherit: kw.Inherit.String(), - Aliases: append([]string{}, kw.Aliases...), - Candidates: append([]string{}, kw.Candidates...), - Types: append([]string{}, kw.Types...), - } - - for _, d := range kw.Depends { - item.Depends = append(item.Depends, d.String()) - } - - for _, k := range kw.Kind { - switch v := k.(type) { - case string: - item.Kind = append(item.Kind, v) - case fmt.Stringer: - item.Kind = append(item.Kind, v.String()) - default: - item.Kind = append(item.Kind, fmt.Sprintf("%v", v)) - } - } - - l = append(l, item) - } - return l -}