engine, gapi, lang, lib: Plumb through new local API

This is a new API that is similar in spirit and plumbing to the World
API, but it intended for all local machine operations and will likely
only ever have one implementation.
This commit is contained in:
James Shubin
2023-12-01 15:18:12 -05:00
parent 12ffac1f06
commit 9d47b6843f
11 changed files with 97 additions and 0 deletions

View File

@@ -28,6 +28,7 @@ import (
"github.com/purpleidea/mgmt/converger" "github.com/purpleidea/mgmt/converger"
"github.com/purpleidea/mgmt/engine" "github.com/purpleidea/mgmt/engine"
"github.com/purpleidea/mgmt/engine/local"
engineUtil "github.com/purpleidea/mgmt/engine/util" engineUtil "github.com/purpleidea/mgmt/engine/util"
"github.com/purpleidea/mgmt/pgraph" "github.com/purpleidea/mgmt/pgraph"
"github.com/purpleidea/mgmt/util/errwrap" "github.com/purpleidea/mgmt/util/errwrap"
@@ -47,6 +48,7 @@ type Engine struct {
Hostname string Hostname string
Converger *converger.Coordinator Converger *converger.Coordinator
Local *local.API
World engine.World World engine.World
// Prefix is a unique directory prefix which can be used. It should be // Prefix is a unique directory prefix which can be used. It should be
@@ -224,6 +226,7 @@ func (obj *Engine) Commit() error {
Hostname: obj.Hostname, Hostname: obj.Hostname,
//Converger: obj.Converger, //Converger: obj.Converger,
Local: obj.Local,
World: obj.World, World: obj.World,
Prefix: statePrefix, Prefix: statePrefix,

View File

@@ -25,6 +25,7 @@ import (
"github.com/purpleidea/mgmt/converger" "github.com/purpleidea/mgmt/converger"
"github.com/purpleidea/mgmt/engine" "github.com/purpleidea/mgmt/engine"
"github.com/purpleidea/mgmt/engine/local"
engineUtil "github.com/purpleidea/mgmt/engine/util" engineUtil "github.com/purpleidea/mgmt/engine/util"
"github.com/purpleidea/mgmt/pgraph" "github.com/purpleidea/mgmt/pgraph"
"github.com/purpleidea/mgmt/util/errwrap" "github.com/purpleidea/mgmt/util/errwrap"
@@ -46,6 +47,7 @@ type State struct {
//Converger *converger.Coordinator //Converger *converger.Coordinator
Local *local.API
World engine.World World engine.World
// Prefix is a unique directory prefix which can be used. It should be // Prefix is a unique directory prefix which can be used. It should be
@@ -239,6 +241,7 @@ func (obj *State) Init() error {
return graph, nil // we return in a func so it's fresh! return graph, nil // we return in a func so it's fresh!
}, },
Local: obj.Local,
World: obj.World, World: obj.World,
VarDir: obj.varDir, VarDir: obj.varDir,

36
engine/local/local.go Normal file
View File

@@ -0,0 +1,36 @@
// Mgmt
// Copyright (C) 2013-2023+ James Shubin and the project contributors
// Written by James Shubin <james@shubin.ca> and the project contributors
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
// Package local contains functions and interfaces that are shared between
// functions and resources. It's similar to the "world" functionality, except
// that it only involves local operations that stay within a single machine or
// local mgmt instance.
package local
import (
"context"
)
// API implements the base handle for all the methods in this package. If we
// were going to have more than one implementation for all of these, then this
// would be an interface instead, and different packages would implement it.
// Since this is not the expectation for the local API, it's all self-contained.
type API struct {
Prefix string
Debug bool
Logf func(format string, v ...interface{})
}

View File

@@ -22,6 +22,7 @@ import (
"encoding/gob" "encoding/gob"
"fmt" "fmt"
"github.com/purpleidea/mgmt/engine/local"
"github.com/purpleidea/mgmt/pgraph" "github.com/purpleidea/mgmt/pgraph"
"github.com/purpleidea/mgmt/util/errwrap" "github.com/purpleidea/mgmt/util/errwrap"
@@ -135,6 +136,11 @@ type Init struct {
// TODO: GraphQuery offers an interface to query the resource graph. // TODO: GraphQuery offers an interface to query the resource graph.
// Local has a bunch of methods and properties which are useful for
// operations on the local machine and for communication between
// functions and resources.
Local *local.API
// World provides a connection to the outside world. This is most often // World provides a connection to the outside world. This is most often
// used for communicating with the distributed database. // used for communicating with the distributed database.
World World World World

View File

@@ -23,6 +23,7 @@ import (
"fmt" "fmt"
"github.com/purpleidea/mgmt/engine" "github.com/purpleidea/mgmt/engine"
"github.com/purpleidea/mgmt/engine/local"
"github.com/purpleidea/mgmt/pgraph" "github.com/purpleidea/mgmt/pgraph"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
@@ -72,6 +73,7 @@ type Data struct {
Program string // name of the originating program Program string // name of the originating program
Version string // version of the originating program Version string // version of the originating program
Hostname string // uuid for the host, required for GAPI Hostname string // uuid for the host, required for GAPI
Local *local.API
World engine.World World engine.World
Noop bool Noop bool
NoStreamWatch bool NoStreamWatch bool

View File

@@ -29,6 +29,7 @@ import (
"time" "time"
"github.com/purpleidea/mgmt/engine" "github.com/purpleidea/mgmt/engine"
"github.com/purpleidea/mgmt/engine/local"
"github.com/purpleidea/mgmt/lang/funcs/structs" "github.com/purpleidea/mgmt/lang/funcs/structs"
"github.com/purpleidea/mgmt/lang/interfaces" "github.com/purpleidea/mgmt/lang/interfaces"
"github.com/purpleidea/mgmt/lang/types" "github.com/purpleidea/mgmt/lang/types"
@@ -44,6 +45,7 @@ type Engine struct {
Name string Name string
Hostname string Hostname string
Local *local.API
World engine.World World engine.World
Debug bool Debug bool
@@ -289,6 +291,7 @@ func (obj *Engine) addVertex(f interfaces.Func) error {
Input: node.input, Input: node.input,
Output: node.output, Output: node.output,
Txn: node.txn, Txn: node.txn,
Local: obj.Local,
World: obj.World, World: obj.World,
Debug: obj.Debug, Debug: obj.Debug,
Logf: func(format string, v ...interface{}) { Logf: func(format string, v ...interface{}) {

View File

@@ -259,6 +259,7 @@ func (obj *GAPI) Cli(cliInfo *gapi.CliInfo) (*gapi.Deploy, error) {
LexParser: parser.LexParse, LexParser: parser.LexParse,
Downloader: downloader, Downloader: downloader,
StrInterpolater: interpolate.StrInterpolate, StrInterpolater: interpolate.StrInterpolate,
//Local: obj.Local, // TODO: do we need this?
//World: obj.World, // TODO: do we need this? //World: obj.World, // TODO: do we need this?
Prefix: prefix, Prefix: prefix,
@@ -467,6 +468,7 @@ func (obj *GAPI) LangInit() error {
Input: input, Input: input,
Hostname: obj.data.Hostname, Hostname: obj.data.Hostname,
Local: obj.data.Local,
World: obj.data.World, World: obj.data.World,
Debug: obj.data.Debug, Debug: obj.data.Debug,
Logf: func(format string, v ...interface{}) { Logf: func(format string, v ...interface{}) {
@@ -747,6 +749,7 @@ func (obj *GAPI) Get(getInfo *gapi.GetInfo) error {
LexParser: parser.LexParse, LexParser: parser.LexParse,
Downloader: downloader, Downloader: downloader,
StrInterpolater: interpolate.StrInterpolate, StrInterpolater: interpolate.StrInterpolate,
//Local: obj.Local, // TODO: do we need this?
//World: obj.World, // TODO: do we need this? //World: obj.World, // TODO: do we need this?
Prefix: prefix, Prefix: prefix,

View File

@@ -23,6 +23,7 @@ import (
"strings" "strings"
"github.com/purpleidea/mgmt/engine" "github.com/purpleidea/mgmt/engine"
"github.com/purpleidea/mgmt/engine/local"
"github.com/purpleidea/mgmt/lang/types" "github.com/purpleidea/mgmt/lang/types"
"github.com/purpleidea/mgmt/pgraph" "github.com/purpleidea/mgmt/pgraph"
) )
@@ -61,6 +62,8 @@ type Init struct {
Txn Txn Txn Txn
// TODO: should we pass in a *Scope here for functions like template() ? // TODO: should we pass in a *Scope here for functions like template() ?
Local *local.API
World engine.World World engine.World
Debug bool Debug bool

View File

@@ -36,6 +36,7 @@ import (
"github.com/purpleidea/mgmt/engine" "github.com/purpleidea/mgmt/engine"
"github.com/purpleidea/mgmt/engine/graph" "github.com/purpleidea/mgmt/engine/graph"
"github.com/purpleidea/mgmt/engine/graph/autoedge" "github.com/purpleidea/mgmt/engine/graph/autoedge"
"github.com/purpleidea/mgmt/engine/local"
engineUtil "github.com/purpleidea/mgmt/engine/util" engineUtil "github.com/purpleidea/mgmt/engine/util"
"github.com/purpleidea/mgmt/etcd" "github.com/purpleidea/mgmt/etcd"
"github.com/purpleidea/mgmt/lang/ast" "github.com/purpleidea/mgmt/lang/ast"
@@ -717,6 +718,15 @@ func TestAstFunc2(t *testing.T) {
afs := &afero.Afero{Fs: mmFs} // wrap so that we're implementing ioutil afs := &afero.Afero{Fs: mmFs} // wrap so that we're implementing ioutil
fs := &util.Fs{Afero: afs} fs := &util.Fs{Afero: afs}
// implementation of the Local API (we only expect just this single one)
localAPI := &local.API{
Prefix: fmt.Sprintf("%s/", filepath.Join(tmpdir, "local")),
Debug: testing.Verbose(), // set via the -test.v flag to `go test`
Logf: func(format string, v ...interface{}) {
logf("local: api: "+format, v...)
},
}
// implementation of the World API (alternatives can be substituted in) // implementation of the World API (alternatives can be substituted in)
world := &etcd.World{ world := &etcd.World{
//Hostname: hostname, //Hostname: hostname,
@@ -1011,6 +1021,7 @@ func TestAstFunc2(t *testing.T) {
funcs := &dage.Engine{ funcs := &dage.Engine{
Name: "test", Name: "test",
Hostname: "", // NOTE: empty b/c not used Hostname: "", // NOTE: empty b/c not used
Local: localAPI, // used partially in some tests
World: world, // used partially in some tests World: world, // used partially in some tests
//Prefix: fmt.Sprintf("%s/", filepath.Join(tmpdir, "funcs")), //Prefix: fmt.Sprintf("%s/", filepath.Join(tmpdir, "funcs")),
Debug: testing.Verbose(), // set via the -test.v flag to `go test` Debug: testing.Verbose(), // set via the -test.v flag to `go test`
@@ -1479,6 +1490,15 @@ func TestAstFunc3(t *testing.T) {
afs := &afero.Afero{Fs: mmFs} // wrap so that we're implementing ioutil afs := &afero.Afero{Fs: mmFs} // wrap so that we're implementing ioutil
fs := &util.Fs{Afero: afs} fs := &util.Fs{Afero: afs}
// implementation of the Local API (we only expect just this single one)
localAPI := &local.API{
Prefix: fmt.Sprintf("%s/", filepath.Join(tmpdir, "local")),
Debug: testing.Verbose(), // set via the -test.v flag to `go test`
Logf: func(format string, v ...interface{}) {
logf("local: api: "+format, v...)
},
}
// implementation of the World API (alternatives can be substituted in) // implementation of the World API (alternatives can be substituted in)
world := &etcd.World{ world := &etcd.World{
//Hostname: hostname, //Hostname: hostname,
@@ -1773,6 +1793,7 @@ func TestAstFunc3(t *testing.T) {
funcs := &dage.Engine{ funcs := &dage.Engine{
Name: "test", Name: "test",
Hostname: "", // NOTE: empty b/c not used Hostname: "", // NOTE: empty b/c not used
Local: localAPI, // used partially in some tests
World: world, // used partially in some tests World: world, // used partially in some tests
//Prefix: fmt.Sprintf("%s/", filepath.Join(tmpdir, "funcs")), //Prefix: fmt.Sprintf("%s/", filepath.Join(tmpdir, "funcs")),
Debug: testing.Verbose(), // set via the -test.v flag to `go test` Debug: testing.Verbose(), // set via the -test.v flag to `go test`
@@ -2004,6 +2025,7 @@ func TestAstFunc3(t *testing.T) {
//Version: obj.Version, //Version: obj.Version,
Hostname: "localhost", Hostname: "localhost",
Converger: converger, Converger: converger,
Local: localAPI,
World: world, World: world,
Prefix: fmt.Sprintf("%s/", filepath.Join(tmpdir, "engine")), Prefix: fmt.Sprintf("%s/", filepath.Join(tmpdir, "engine")),
Debug: testing.Verbose(), Debug: testing.Verbose(),

View File

@@ -26,6 +26,7 @@ import (
"sync" "sync"
"github.com/purpleidea/mgmt/engine" "github.com/purpleidea/mgmt/engine"
"github.com/purpleidea/mgmt/engine/local"
"github.com/purpleidea/mgmt/lang/ast" "github.com/purpleidea/mgmt/lang/ast"
_ "github.com/purpleidea/mgmt/lang/funcs/core" // import so the funcs register _ "github.com/purpleidea/mgmt/lang/funcs/core" // import so the funcs register
"github.com/purpleidea/mgmt/lang/funcs/dage" "github.com/purpleidea/mgmt/lang/funcs/dage"
@@ -57,6 +58,7 @@ type Lang struct {
Input string Input string
Hostname string Hostname string
Local *local.API
World engine.World World engine.World
Prefix string Prefix string
Debug bool Debug bool
@@ -139,6 +141,7 @@ func (obj *Lang) Init() error {
LexParser: parser.LexParse, LexParser: parser.LexParse,
Downloader: nil, // XXX: is this used here? Downloader: nil, // XXX: is this used here?
StrInterpolater: interpolate.StrInterpolate, StrInterpolater: interpolate.StrInterpolate,
//Local: obj.Local, // TODO: do we need this?
//World: obj.World, // TODO: do we need this? //World: obj.World, // TODO: do we need this?
Prefix: obj.Prefix, Prefix: obj.Prefix,
@@ -237,6 +240,7 @@ func (obj *Lang) Init() error {
obj.funcs = &dage.Engine{ obj.funcs = &dage.Engine{
Name: "lang", // TODO: arbitrary name for now Name: "lang", // TODO: arbitrary name for now
Hostname: obj.Hostname, Hostname: obj.Hostname,
Local: obj.Local,
World: obj.World, World: obj.World,
//Prefix: fmt.Sprintf("%s/", path.Join(obj.Prefix, "funcs")), //Prefix: fmt.Sprintf("%s/", path.Join(obj.Prefix, "funcs")),
Debug: obj.Debug, Debug: obj.Debug,

View File

@@ -36,6 +36,7 @@ import (
"github.com/purpleidea/mgmt/engine" "github.com/purpleidea/mgmt/engine"
"github.com/purpleidea/mgmt/engine/graph" "github.com/purpleidea/mgmt/engine/graph"
"github.com/purpleidea/mgmt/engine/graph/autogroup" "github.com/purpleidea/mgmt/engine/graph/autogroup"
"github.com/purpleidea/mgmt/engine/local"
_ "github.com/purpleidea/mgmt/engine/resources" // let register's run _ "github.com/purpleidea/mgmt/engine/resources" // let register's run
"github.com/purpleidea/mgmt/etcd" "github.com/purpleidea/mgmt/etcd"
"github.com/purpleidea/mgmt/etcd/chooser" "github.com/purpleidea/mgmt/etcd/chooser"
@@ -475,6 +476,15 @@ func (obj *Main) Run() error {
} }
}() }()
// implementation of the Local API (we only expect just this single one)
localAPI := &local.API{
Prefix: fmt.Sprintf("%s/", path.Join(prefix, "local")),
Debug: obj.Flags.Debug,
Logf: func(format string, v ...interface{}) {
log.Printf("local: api: "+format, v...)
},
}
// implementation of the World API (alternatives can be substituted in) // implementation of the World API (alternatives can be substituted in)
world := &etcd.World{ world := &etcd.World{
Hostname: hostname, Hostname: hostname,
@@ -493,6 +503,7 @@ func (obj *Main) Run() error {
Version: obj.Version, Version: obj.Version,
Hostname: hostname, Hostname: hostname,
Converger: converger, Converger: converger,
Local: localAPI,
World: world, World: world,
Prefix: fmt.Sprintf("%s/", path.Join(prefix, "engine")), Prefix: fmt.Sprintf("%s/", path.Join(prefix, "engine")),
//Prometheus: prom, // TODO: implement this via a general Status API //Prometheus: prom, // TODO: implement this via a general Status API
@@ -582,6 +593,7 @@ func (obj *Main) Run() error {
Program: obj.Program, Program: obj.Program,
Version: obj.Version, Version: obj.Version,
Hostname: hostname, Hostname: hostname,
Local: localAPI,
World: world, World: world,
Noop: mainDeploy.Noop, Noop: mainDeploy.Noop,
// FIXME: should the below flags come from the deploy struct? // FIXME: should the below flags come from the deploy struct?