feat: added working rendering with plugins
This commit is contained in:
parent
fbdaf218eb
commit
1ebea8cb73
7 changed files with 139 additions and 81 deletions
|
|
@ -112,8 +112,12 @@ var downloadCmd = cobra.Command{
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
var downloadProfileCmd = &cobra.Command{}
|
var downloadProfileCmd = &cobra.Command{
|
||||||
var downloadPluginCmd = &cobra.Command{}
|
Use: "profile",
|
||||||
|
}
|
||||||
|
var downloadPluginCmd = &cobra.Command{
|
||||||
|
Use: "plugin",
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
downloadCmd.Flags().String("host", "http://localhost:5050", "Set the makeshift remote host (can be set with MAKESHIFT_HOST)")
|
downloadCmd.Flags().String("host", "http://localhost:5050", "Set the makeshift remote host (can be set with MAKESHIFT_HOST)")
|
||||||
|
|
@ -122,5 +126,7 @@ func init() {
|
||||||
downloadCmd.Flags().StringSlice("profiles", []string{}, "Set the profile to use to populate data store")
|
downloadCmd.Flags().StringSlice("profiles", []string{}, "Set the profile to use to populate data store")
|
||||||
downloadCmd.Flags().StringSlice("plugins", []string{}, "Set the plugins to run before downloading files")
|
downloadCmd.Flags().StringSlice("plugins", []string{}, "Set the plugins to run before downloading files")
|
||||||
|
|
||||||
|
downloadCmd.AddCommand(downloadProfileCmd, downloadPluginCmd)
|
||||||
|
|
||||||
rootCmd.AddCommand(&downloadCmd)
|
rootCmd.AddCommand(&downloadCmd)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package makeshift
|
||||||
|
|
||||||
import "git.towk2.me/towk/makeshift/pkg/storage"
|
import "git.towk2.me/towk/makeshift/pkg/storage"
|
||||||
|
|
||||||
|
type ProfileMap map[string]*Profile
|
||||||
type Profile struct {
|
type Profile struct {
|
||||||
ID string `json:"id"` // profile ID
|
ID string `json:"id"` // profile ID
|
||||||
Description string `json:"description,omitempty"` // profile description
|
Description string `json:"description,omitempty"` // profile description
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
configurator "git.towk2.me/towk/makeshift/pkg"
|
makeshift "git.towk2.me/towk/makeshift/pkg"
|
||||||
"git.towk2.me/towk/makeshift/pkg/storage"
|
"git.towk2.me/towk/makeshift/pkg/storage"
|
||||||
"github.com/nikolalohinski/gonja/v2"
|
"github.com/nikolalohinski/gonja/v2"
|
||||||
"github.com/nikolalohinski/gonja/v2/exec"
|
"github.com/nikolalohinski/gonja/v2/exec"
|
||||||
|
|
@ -17,13 +17,15 @@ type Jinja2 struct{}
|
||||||
func (p *Jinja2) Name() string { return "jinja2" }
|
func (p *Jinja2) Name() string { return "jinja2" }
|
||||||
func (p *Jinja2) Version() string { return "v0.0.1-alpha" }
|
func (p *Jinja2) Version() string { return "v0.0.1-alpha" }
|
||||||
func (p *Jinja2) Description() string { return "Renders Jinja 2 templates" }
|
func (p *Jinja2) Description() string { return "Renders Jinja 2 templates" }
|
||||||
func (p *Jinja2) Metadata() configurator.Metadata {
|
func (p *Jinja2) Metadata() makeshift.Metadata {
|
||||||
return configurator.Metadata{
|
return makeshift.Metadata{
|
||||||
"author.name": "David J. Allen",
|
"author": map[string]any{
|
||||||
"author.email": "davidallendj@gmail.com",
|
"name": "David J. Allen",
|
||||||
"author.links": []string{
|
"email": "davidallendj@gmail.com",
|
||||||
"https://github.com/davidallendj",
|
"links": []string{
|
||||||
"https://git.towk2.me/towk",
|
"https://github.com/davidallendj",
|
||||||
|
"https://git.towk2.me/towk",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -34,25 +36,32 @@ func (p *Jinja2) Init() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Jinja2) Run(data storage.KVStore, args []string) error {
|
func (p *Jinja2) Run(store storage.KVStore, args []string) error {
|
||||||
// render the files using Jinja 2 from args
|
// render the files using Jinja 2 from args
|
||||||
var (
|
var (
|
||||||
rendered []string
|
mappings struct {
|
||||||
|
Data map[string]any `json:"data"`
|
||||||
|
}
|
||||||
context *exec.Context
|
context *exec.Context
|
||||||
template *exec.Template
|
template *exec.Template
|
||||||
mappings map[string]any
|
profiles any // makeshift.ProfileMap
|
||||||
input any // must be a byte array
|
input any // []byte
|
||||||
output bytes.Buffer
|
output bytes.Buffer
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
log.Debug().
|
log.Debug().
|
||||||
Str("plugin", p.Name()).
|
Str("plugin", p.Name()).
|
||||||
Any("data", data).
|
Any("store", store).
|
||||||
// Bytes("input", input.([]byte)).
|
Strs("args", args).
|
||||||
Int("arg_count", len(args)).
|
Int("arg_count", len(args)).
|
||||||
Msg("Run()")
|
Msg("(jinja2) Run()")
|
||||||
|
|
||||||
input, err = data.Get("file")
|
profiles, err = store.Get("profiles")
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("(jinja2) failed to get profiles: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
input, err = store.Get("file")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("(jinja2) failed to get input data: %v", err)
|
return fmt.Errorf("(jinja2) failed to get input data: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -63,35 +72,56 @@ func (p *Jinja2) Run(data storage.KVStore, args []string) error {
|
||||||
return fmt.Errorf("(jinja2) failed to get template from args: %v", err)
|
return fmt.Errorf("(jinja2) failed to get template from args: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// get mappings from shared data
|
// get mappings from shared data (optional)
|
||||||
shared, err := data.Get("shared")
|
shared, err := store.Get("shared")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("(jinja2) failed to get data from store: %v", err)
|
log.Warn().Err(err).Msg("(jinja2) could not retrieve shared data")
|
||||||
|
} else {
|
||||||
|
err = json.Unmarshal(shared.([]byte), &mappings)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("(jinja2) failed to unmarshal mappings from shared data: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = json.Unmarshal(shared.([]byte), &mappings)
|
var ps = make(map[string]any)
|
||||||
if err != nil {
|
for profileID, profile := range profiles.(makeshift.ProfileMap) {
|
||||||
return fmt.Errorf("(jinja2) failed to unmarshal mappings from shared data: %v", err)
|
ps[profileID] = map[string]any{
|
||||||
|
"id": profile.ID,
|
||||||
|
"description": profile.Description,
|
||||||
|
"data": profile.Data,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data.Set("mappings", mappings)
|
// inject profiles and plugin-specific mapping
|
||||||
|
mappings.Data = map[string]any{
|
||||||
|
"makeshift": map[string]any{
|
||||||
|
"profiles": ps,
|
||||||
|
"plugin": map[string]any{
|
||||||
|
"name": p.Name(),
|
||||||
|
"version": p.Version(),
|
||||||
|
"description": p.Description(),
|
||||||
|
"metadata": p.Metadata(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debug().Any("mappings", mappings).Send()
|
||||||
|
|
||||||
// use the provided data in the store to render templates
|
// use the provided data in the store to render templates
|
||||||
// NOTE: this may be changed to specifically use "shared" data instead
|
// NOTE: this may be changed to specifically use "shared" data instead
|
||||||
context = exec.NewContext(data.GetData().(map[string]any))
|
context = exec.NewContext(mappings.Data)
|
||||||
if err = template.Execute(&output, context); err != nil { // Prints: Hello Bob!
|
if err = template.Execute(&output, context); err != nil { // Prints: Hello Bob!
|
||||||
return fmt.Errorf("(jinja2) failed to render template: %v", err)
|
return fmt.Errorf("(jinja2) failed to render template: %v", err)
|
||||||
}
|
}
|
||||||
rendered = append(rendered, output.String())
|
|
||||||
|
|
||||||
// write render templates to data store output
|
// write render templates to data store output
|
||||||
data.Set("out", rendered)
|
store.Set("out", output.String())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Jinja2) Cleanup() error {
|
func (p *Jinja2) Cleanup() error {
|
||||||
// nothing to clean up
|
// nothing to clean up
|
||||||
log.Debug().Str("plugin", p.Name()).Msg("jinja2.Cleanup()")
|
log.Debug().Str("plugin", p.Name()).Msg("(jinja2) Cleanup()")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -82,21 +82,23 @@ func (p *SmdClient) Version() string { return "v0.0.1-alpha" }
|
||||||
func (p *SmdClient) Description() string { return "Fetchs data from SMD and writes to store" }
|
func (p *SmdClient) Description() string { return "Fetchs data from SMD and writes to store" }
|
||||||
func (p *SmdClient) Metadata() makeshift.Metadata {
|
func (p *SmdClient) Metadata() makeshift.Metadata {
|
||||||
return makeshift.Metadata{
|
return makeshift.Metadata{
|
||||||
"author.name": "David J. Allen",
|
"author": map[string]any{
|
||||||
"author.email": "davidallendj@gmail.com",
|
"name": "David J. Allen",
|
||||||
"author.links": []string{
|
"email": "davidallendj@gmail.com",
|
||||||
"https://github.com/davidallendj",
|
"links": []string{
|
||||||
"https://git.towk2.me/towk",
|
"https://github.com/davidallendj",
|
||||||
|
"https://git.towk2.me/towk",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *SmdClient) Init() error {
|
func (p *SmdClient) Init() error {
|
||||||
log.Debug().Str("plugin", p.Name()).Msg("smd.Init()")
|
log.Debug().Str("plugin", p.Name()).Msg("(smd) Init()")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *SmdClient) Run(data storage.KVStore, args []string) error {
|
func (p *SmdClient) Run(store storage.KVStore, args []string) error {
|
||||||
// set all the defaults for variables
|
// set all the defaults for variables
|
||||||
var (
|
var (
|
||||||
client SmdClient
|
client SmdClient
|
||||||
|
|
@ -104,6 +106,13 @@ func (p *SmdClient) Run(data storage.KVStore, args []string) error {
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
|
|
||||||
|
log.Debug().
|
||||||
|
Str("plugin", p.Name()).
|
||||||
|
Strs("args", args).
|
||||||
|
Int("arg_count", len(args)).
|
||||||
|
Any("store", store).
|
||||||
|
Msg("(smd) Run()")
|
||||||
|
|
||||||
// if we have a client, try making the request for the ethernet interfaces
|
// if we have a client, try making the request for the ethernet interfaces
|
||||||
err = client.FetchEthernetInterfaces()
|
err = client.FetchEthernetInterfaces()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -124,14 +133,14 @@ func (p *SmdClient) Run(data storage.KVStore, args []string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("(smd) failed to marshal SMD client: %v")
|
return fmt.Errorf("(smd) failed to marshal SMD client: %v")
|
||||||
}
|
}
|
||||||
data.Set("shared", bytes)
|
store.Set("shared", bytes)
|
||||||
|
|
||||||
// apply template substitutions and return output as byte array
|
// apply template substitutions and return output as byte array
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *SmdClient) Cleanup() error {
|
func (p *SmdClient) Cleanup() error {
|
||||||
log.Debug().Str("plugin", p.Name()).Msg("smd.Init()")
|
log.Debug().Str("plugin", p.Name()).Msg("(smd) Init()")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,10 +20,20 @@ const (
|
||||||
<html>
|
<html>
|
||||||
<body>
|
<body>
|
||||||
<p>
|
<p>
|
||||||
|
Plugin Information:
|
||||||
|
Name: {{ makeshift.plugin.name }}
|
||||||
|
Version: {{ makeshift.plugin.version }}
|
||||||
|
Description: {{ makeshift.plugin.description }}
|
||||||
|
Metadata: {{ makeshift.plugin.metadata }}
|
||||||
|
|
||||||
|
Profile Information:
|
||||||
|
ID: {{ makeshift.profiles.default.id }}
|
||||||
|
Description: {{ makeshift.profiles.default.description }}
|
||||||
|
|
||||||
# setup environment variables</br>
|
# setup environment variables</br>
|
||||||
export MAKESHIFT_HOST={{ makeshift.host }}</br>
|
export MAKESHIFT_HOST={{ makeshift.profiles.default.data.host }}</br>
|
||||||
export MAKESHIFT_PATH={{ makeshift.path }}</br>
|
export MAKESHIFT_PATH={{ makeshift.profiles.default.data.path }}</br>
|
||||||
export MAKESHIFT_SERVER_ROOT={{ makeshift.server.root }}</br>
|
export MAKESHIFT_SERVER_ROOT={{ makeshift.profiles.default.data.server_root }}</br>
|
||||||
</br>
|
</br>
|
||||||
# start the service</br>
|
# start the service</br>
|
||||||
makeshift serve --root $HOME/apps/makeshift/server --init</br>
|
makeshift serve --root $HOME/apps/makeshift/server --init</br>
|
||||||
|
|
@ -53,13 +63,9 @@ const (
|
||||||
"id": "default",
|
"id": "default",
|
||||||
"description": "Makeshift default profile",
|
"description": "Makeshift default profile",
|
||||||
"data": {
|
"data": {
|
||||||
"makeshift": {
|
"host": "localhost",
|
||||||
"host": "localhost",
|
"path": "/test",
|
||||||
"path": "/test",
|
"server_root": "./test"
|
||||||
"server": {
|
|
||||||
"root": "/test"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
|
||||||
|
|
@ -20,8 +20,8 @@ func (s *Service) Download() http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
var (
|
var (
|
||||||
path = s.PathForData() + strings.TrimPrefix(r.URL.Path, "/download")
|
path = s.PathForData() + strings.TrimPrefix(r.URL.Path, "/download")
|
||||||
pluginNames = r.URL.Query()["plugins"]
|
pluginNames = strings.Split(r.URL.Query().Get("plugins"), ",")
|
||||||
profileIDs = r.URL.Query()["profiles"]
|
profileIDs = strings.Split(r.URL.Query().Get("profiles"), ",")
|
||||||
|
|
||||||
fileInfo os.FileInfo
|
fileInfo os.FileInfo
|
||||||
out *os.File
|
out *os.File
|
||||||
|
|
@ -126,38 +126,42 @@ func (s *Service) Download() http.HandlerFunc {
|
||||||
log.Error().Errs("errs", errs).Msg("errors occurred loading plugins")
|
log.Error().Errs("errs", errs).Msg("errors occurred loading plugins")
|
||||||
errs = []error{}
|
errs = []error{}
|
||||||
}
|
}
|
||||||
|
if len(hooks) > 0 {
|
||||||
|
|
||||||
// run pre-hooks to modify the contents of the file before archiving
|
// run pre-hooks to modify the contents of the file before archiving
|
||||||
log.Debug().Int("hook_count", len(hooks)).Msg("running hooks")
|
log.Debug().Int("hook_count", len(hooks)).Msg("running hooks")
|
||||||
for _, hook := range hooks {
|
for _, hook := range hooks {
|
||||||
log.Debug().Any("hook", map[string]any{
|
log.Debug().Any("hook", map[string]any{
|
||||||
"data": hook.Data,
|
"store": hook.Data,
|
||||||
"args": hook.Args,
|
"args": hook.Args,
|
||||||
"plugin": map[string]string{
|
"plugin": map[string]string{
|
||||||
"name": hook.Plugin.Name(),
|
"name": hook.Plugin.Name(),
|
||||||
"description": hook.Plugin.Description(),
|
"description": hook.Plugin.Description(),
|
||||||
"version": hook.Plugin.Version(),
|
"version": hook.Plugin.Version(),
|
||||||
},
|
},
|
||||||
}).Send()
|
}).Send()
|
||||||
err = hook.Run()
|
err = hook.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Str("plugin", hook.Plugin.Name()).Msg("failed to run plugin")
|
log.Error().Err(err).Str("plugin", hook.Plugin.Name()).Msg("failed to run plugin")
|
||||||
continue
|
continue
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// take the contents from the last hook and update files
|
||||||
|
var (
|
||||||
|
hook = hooks[len(hooks)-1]
|
||||||
|
data any
|
||||||
|
)
|
||||||
|
data, err = hook.Data.Get("out")
|
||||||
|
if err != nil {
|
||||||
|
s.writeErrorResponse(w, fmt.Sprintf("failed to get data from hook: %v", err), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
w.Write([]byte(data.(string)))
|
||||||
|
} else {
|
||||||
|
w.Write(contents)
|
||||||
}
|
}
|
||||||
|
|
||||||
// take the contents from the last hook and update files
|
|
||||||
var (
|
|
||||||
hook = hooks[len(hooks)-1]
|
|
||||||
data any
|
|
||||||
)
|
|
||||||
data, err = hook.Data.Get("out")
|
|
||||||
if err != nil {
|
|
||||||
s.writeErrorResponse(w, fmt.Sprintf("failed to get data from hook: %v", err), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
w.Write([]byte(data.(string)))
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
s.writeErrorResponse(w, err.Error(), http.StatusBadRequest)
|
s.writeErrorResponse(w, err.Error(), http.StatusBadRequest)
|
||||||
|
|
@ -228,6 +232,7 @@ func (s *Service) GetStatus(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
func (s *Service) loadProfiles(profileIDs []string, store storage.KVStore, errs []error) []error {
|
func (s *Service) loadProfiles(profileIDs []string, store storage.KVStore, errs []error) []error {
|
||||||
// load data from profiles into the data store
|
// load data from profiles into the data store
|
||||||
|
var profiles = make(makeshift.ProfileMap, len(profileIDs))
|
||||||
for i, profileID := range profileIDs {
|
for i, profileID := range profileIDs {
|
||||||
var (
|
var (
|
||||||
profilePath = s.PathForProfileWithID(profileID)
|
profilePath = s.PathForProfileWithID(profileID)
|
||||||
|
|
@ -251,8 +256,9 @@ func (s *Service) loadProfiles(profileIDs []string, store storage.KVStore, errs
|
||||||
errs = append(errs, err)
|
errs = append(errs, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
store.Set(profileID, profile)
|
profiles[profileID] = profile
|
||||||
}
|
}
|
||||||
|
store.Set("profiles", profiles)
|
||||||
|
|
||||||
return errs
|
return errs
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ package storage
|
||||||
import "fmt"
|
import "fmt"
|
||||||
|
|
||||||
type MemoryStorage struct {
|
type MemoryStorage struct {
|
||||||
Data map[string]any
|
Data map[string]any `json:"data"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ms *MemoryStorage) Init() error {
|
func (ms *MemoryStorage) Init() error {
|
||||||
|
|
@ -20,7 +20,7 @@ func (ms *MemoryStorage) Get(k string) (any, error) {
|
||||||
if ok {
|
if ok {
|
||||||
return v, nil
|
return v, nil
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("value does not exist")
|
return nil, fmt.Errorf("value '%s' does not exist", k)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ms *MemoryStorage) Set(k string, v any) error {
|
func (ms *MemoryStorage) Set(k string, v any) error {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue