Compare commits

..

No commits in common. "fbed466c3d349619f99f8b9ff9a38f450c1e2235" and "0349ecaf349f06e6452e8e353ff95f2d8e858a15" have entirely different histories.

17 changed files with 230 additions and 471 deletions

View file

@ -36,13 +36,13 @@ container-testing: binaries
plugins: $(plugin_binaries)
# how to make each plugin
lib/%.so: pkg/plugins/%/*.go
lib/%.so: pkg/generator/plugins/%/*.go
mkdir -p lib
go build -buildmode=plugin -o $@ $<
docs:
go doc git.towk2.me/towk/makeshift/cmd
go doc git.towk2.me/towk/makeshift/pkg/${prog}
go doc github.com/OpenCHAMI/cmd
go doc github.com/OpenCHAMI/pkg/${prog}
# remove executable and all built plugins
.PHONY: clean

View file

@ -209,5 +209,4 @@ There are some features still missing that will be added later.
5. Optionally build plugins directly into the main driver
6. Protected routes that require authentication
7. Configuration file for persistent runs
8. `Dockerfile` and `docker-compose.yml` files to build containers
9. Including certs with requests
8. `Dockerfile` and `docker-compose.yml` files

0
bin/.gitkeep Normal file
View file

View file

@ -1,26 +0,0 @@
#!/usr/bin bash
function compile_default_plugins() {
makeshift_exe=./makeshift
go_exe=go
# make sure go build tools are installed
if command -v $go_exe >/dev/null 2>&1; then
# make sure that MAKESHIFT_ROOT is set
if [[ ! -v MAKESHIFT_ROOT ]]; then
# Compile the default external plugins
go build
$makeshift_exe compile pkg/plugins/jinja2/jinja2.go -o $MAKESHIFT_ROOT/plugins/jinja2.go
$makeshift_exe compile pkg/plugins/smd/smd.go -o $MAKESHIFT_ROOT/plugins/smd.so
$makeshift_exe compile pkg/plugins/userdata/userdata.go -o $MAKESHIFT_ROOT/plugins/userdata.go
else
echo "requires MAKESHIFT_ROOT to be set"
fi
else
echo "Go build tools must be installed"
fi
}
compile_default_plugins

View file

@ -1,123 +0,0 @@
package cmd
import (
"fmt"
"net/http"
"git.towk2.me/towk/makeshift/pkg/client"
"github.com/rs/zerolog/log"
"github.com/spf13/cobra"
)
var deleteCmd = &cobra.Command{
Use: "delete",
Example: `
# set up environment
export MAKESHIFT_HOST=http://localhost:5050
export MAKESHIFT_PATH=test
# delete a file or directory (cannot delete root)
makeshift delete -p help.txt
makeshift delete --host http://localhost:5555 --path templates
`,
Short: "Delete files and directories",
PersistentPreRun: func(cmd *cobra.Command, args []string) {
setenv(cmd, "host", "MAKESHIFT_HOST")
setenv(cmd, "path", "MAKESHIFT_PATH")
},
Run: func(cmd *cobra.Command, args []string) {
var (
host, _ = cmd.Flags().GetString("host")
paths, _ = cmd.Flags().GetStringSlice("path")
c = client.New(host)
res *http.Response
query string
err error
)
for _, path := range paths {
if path == "" {
log.Warn().Msg("skipping empty path")
continue
}
query = fmt.Sprintf("/delete/%s?", path)
res, _, err = c.MakeRequest(client.HTTPEnvelope{
Path: query,
Method: http.MethodDelete,
})
handleResponseError(res, host, query, err)
}
},
}
var deleteProfilesCmd = &cobra.Command{
Use: "profiles",
Example: `
# delete profile(s) by its ID
makeshift delete profiles kubernetes slurm compute
`,
Args: cobra.MinimumNArgs(1),
Short: "Delete profile(s)",
Run: func(cmd *cobra.Command, args []string) {
var (
host, _ = cmd.Flags().GetString("host")
c = client.New(host)
res *http.Response
query string
err error
)
for _, profileID := range args {
if profileID == "default" {
log.Warn().Msg("cannot delete the default profile")
continue
}
query = fmt.Sprintf("/profiles/%s", profileID)
res, _, err = c.MakeRequest(client.HTTPEnvelope{
Path: query,
Method: http.MethodDelete,
})
handleResponseError(res, host, query, err)
}
},
}
var deletePluginsCmd = &cobra.Command{
Use: "plugins",
Example: `
# delete plugin(s) by name
makeshift delete plugins weather slurm user
`,
Args: cobra.MinimumNArgs(1),
Short: "Delete plugin(s)",
Run: func(cmd *cobra.Command, args []string) {
var (
host, _ = cmd.Flags().GetString("host")
c = client.New(host)
res *http.Response
query string
err error
)
for _, pluginName := range args {
query = fmt.Sprintf("/plugins/%s", pluginName)
res, _, err = c.MakeRequest(client.HTTPEnvelope{
Path: query,
Method: http.MethodDelete,
})
handleResponseError(res, host, query, err)
}
},
}
func init() {
deleteCmd.PersistentFlags().String("host", "http://localhost:5050", "Set the makeshift server host (can be set with MAKESHIFT_HOST)")
deleteCmd.Flags().StringSliceP("path", "p", []string{}, "Set the paths to delete files and directories")
deleteCmd.AddCommand(deleteProfilesCmd, deletePluginsCmd)
rootCmd.AddCommand(deleteCmd)
}

View file

@ -81,10 +81,10 @@ var listPluginsCmd = &cobra.Command{
Run: func(cmd *cobra.Command, args []string) {
var (
host, _ = cmd.Flags().GetString("host")
path, _ = cmd.Flags().GetString("path")
c = client.New(host)
res *http.Response
query string
plugins []string
body []byte
err error
@ -96,7 +96,24 @@ var listPluginsCmd = &cobra.Command{
Path: "/plugins",
Method: http.MethodGet,
})
handleResponseError(res, host, "/plugins", err)
if err != nil {
log.Error().Err(err).
Str("host", host).
Str("path", path).
Msg("failed to make request")
os.Exit(1)
}
if res.StatusCode != http.StatusOK {
log.Error().
Any("status", map[string]any{
"code": res.StatusCode,
"message": res.Status,
}).
Str("host", host).
Str("path", path).
Msg("response returned bad status")
os.Exit(1)
}
err = json.Unmarshal(body, &plugins)
if err != nil {
log.Error().Err(err).
@ -106,12 +123,28 @@ var listPluginsCmd = &cobra.Command{
} else {
for _, pluginName := range args {
// make request to /list endpoint
query = fmt.Sprintf("/plugins/%s/info", pluginName)
res, body, err = c.MakeRequest(client.HTTPEnvelope{
Path: query,
Path: fmt.Sprintf("/plugins/%s/info", pluginName),
Method: http.MethodGet,
})
handleResponseError(res, host, query, err)
if err != nil {
log.Error().Err(err).
Str("host", host).
Str("path", path).
Msg("failed to make request")
os.Exit(1)
}
if res.StatusCode != http.StatusOK {
log.Error().
Any("status", map[string]any{
"code": res.StatusCode,
"message": res.Status,
}).
Str("host", host).
Str("path", path).
Msg("response returned bad status")
os.Exit(1)
}
plugins = append(plugins, string(body))
}
@ -126,12 +159,12 @@ var listProfilesCmd = &cobra.Command{
Run: func(cmd *cobra.Command, args []string) {
var (
host, _ = cmd.Flags().GetString("host")
path, _ = cmd.Flags().GetString("path")
c = client.New(host)
res *http.Response
profiles []makeshift.Profile
body []byte
query string
err error
)
@ -141,7 +174,24 @@ var listProfilesCmd = &cobra.Command{
Path: "/profiles",
Method: http.MethodGet,
})
handleResponseError(res, host, "/profiles", err)
if err != nil {
log.Error().Err(err).
Str("host", host).
Str("path", path).
Msg("failed to make request")
os.Exit(1)
}
if res.StatusCode != http.StatusOK {
log.Error().
Any("status", map[string]any{
"code": res.StatusCode,
"message": res.Status,
}).
Str("host", host).
Str("path", path).
Msg("response returned bad status")
os.Exit(1)
}
err = json.Unmarshal(body, &profiles)
if err != nil {
@ -152,12 +202,28 @@ var listProfilesCmd = &cobra.Command{
} else {
for _, profileID := range args {
// make request to /list endpoint
query = fmt.Sprintf("/profiles/%s", profileID)
res, body, err = c.MakeRequest(client.HTTPEnvelope{
Path: fmt.Sprintf(query),
Path: fmt.Sprintf("/profiles/%s", profileID),
Method: http.MethodGet,
})
handleResponseError(res, host, query, err)
if err != nil {
log.Error().Err(err).
Str("host", host).
Str("path", path).
Msg("failed to make request")
os.Exit(1)
}
if res.StatusCode != http.StatusOK {
log.Error().
Any("status", map[string]any{
"code": res.StatusCode,
"message": res.Status,
}).
Str("host", host).
Str("path", path).
Msg("response returned bad status")
os.Exit(1)
}
var profile makeshift.Profile
err = json.Unmarshal(body, &profile)
if err != nil {

View file

@ -178,8 +178,8 @@ var pluginsInfoCmd = &cobra.Command{
}
func init() {
pluginsCompileCmd.Flags().StringP("output", "o", "", "Set the path to save compiled plugin (matches source type, i.e. uses files or directory)")
pluginsInfoCmd.Flags().String("host", "http://localhost:5050", "Set the makeshift remote host (can be set with MAKESHIFT_HOST)")
pluginsCompileCmd.PersistentFlags().StringP("output", "o", "", "Set the path to save compiled plugin")
pluginsInfoCmd.PersistentFlags().String("host", "http://localhost:5050", "Set the makeshift remote host (can be set with MAKESHIFT_HOST)")
pluginsCmd.AddCommand(pluginsCompileCmd, pluginsInspectCmd, pluginsInfoCmd)
rootCmd.AddCommand(pluginsCmd)

View file

@ -2,7 +2,6 @@ package cmd
import (
"fmt"
"net/http"
"os"
logger "git.towk2.me/towk/makeshift/pkg/log"
@ -79,16 +78,6 @@ func setenv(cmd *cobra.Command, varname string, envvar string) {
}
}
func setenvp(cmd *cobra.Command, varname string, envvar string) {
if cmd.Flags().Changed(varname) {
return
}
val := os.Getenv(envvar)
if val != "" {
cmd.PersistentFlags().Set(varname, val)
}
}
func initLogger() {
// initialize the logger
logfile, _ := rootCmd.PersistentFlags().GetString("log-file")
@ -98,23 +87,3 @@ func initLogger() {
os.Exit(1)
}
}
func handleResponseError(res *http.Response, host, query string, err error) {
if err != nil {
log.Error().Err(err).
Str("host", host).
Str("query", query).
Msg("failed to make request")
os.Exit(1)
}
if res.StatusCode != http.StatusOK {
log.Error().
Any("status", map[string]any{
"code": res.StatusCode,
"message": res.Status,
}).
Str("host", host).
Msg("response returned bad status")
os.Exit(1)
}
}

View file

@ -5,16 +5,14 @@ import "github.com/spf13/cobra"
var runCmd = &cobra.Command{
Use: "run",
Example: `
NOTE: This command is not implemented yet!
# set up environment
export MAKESHIFT_HOST=http://localhost:5050
export MAKESHIFT_PATH=help.txt
export MAKESHIFT_ROOT=/opt/makeshift
export MAKESHIFT_ROOT=./test
# run locally similar to 'download'
makeshift run --plugins jinja2 --profiles default
makeshift run --root $HOME/apps/makeshift -p help.txt --plugins jinja2 --profiles default
makeshift run --root ./test -p help.txt --plugins jinja2 --profiles default
`,
Args: cobra.NoArgs,
Short: "Run locally with plugins and profiles",

View file

@ -4,127 +4,72 @@ import (
"bufio"
"encoding/json"
"fmt"
"net/http"
"os"
"strings"
"git.towk2.me/towk/makeshift/internal/format"
makeshift "git.towk2.me/towk/makeshift/pkg"
"git.towk2.me/towk/makeshift/pkg/client"
"github.com/rs/zerolog/log"
"github.com/spf13/cobra"
)
var (
inputFormat format.DataFormat = format.JSON
dataArgs []string
)
var uploadCmd = &cobra.Command{
Use: "upload",
Example: `
# upload a single file in root directory
makeshift upload -d @compute-base.yaml
# upload a single file
makeshift upload -d @compute-base.yaml -t file
# upload a single file with contents without specify type
makeshift upload -d '{"name": "John Smith", "email": "john.smith@example.com"}'
# upload a directory
makeshift upload -d @setup/
makeshift upload -d @setup/ -t directory
# upload an archive (extracted and saved on server)
makeshift upload -d @setup.tar.gz -t archive
# upload a new profile with a specific path (used to set remote location)
makeshift upload profile -d @kubernetes.json -p nodes/kubernetes.json
makeshift upload profile -d @slurm.json -@compute.json -p nodes
`,
Short: "Upload files and directories",
PersistentPreRun: func(cmd *cobra.Command, args []string) {
setenv(cmd, "host", "MAKESHIFT_HOST")
setenv(cmd, "path", "MAKESHIFT_PATH")
},
Run: func(cmd *cobra.Command, args []string) {
var (
dataArgs, _ = cmd.Flags().GetStringArray("data")
inputData = processFiles(dataArgs)
useDirectoryPath = len(inputData) > 1
)
for path, contents := range inputData {
log.Info().Str("path", path).Int("size", len(contents)).Send()
if useDirectoryPath {
} else {
// make one request be host positional argument (restricted to 1 for now)
var inputData []map[string]any
temp := append(handleArgs(args), processDataArgs(dataArgs)...)
for _, data := range temp {
if data != nil {
inputData = append(inputData, data)
}
}
},
}
var uploadProfilesCmd = &cobra.Command{
Use: "profile [profileID]",
var uploadProfileCmd = &cobra.Command{
Use: "profile",
Example: `
# upload a new profile
makeshift upload profile -d @compute.json
# upload a new profile with a specific path (used for lookup)
# upload a new profile with a specific name (used for lookups)
makeshift upload profile -d @kubernetes.json -n k8s
`,
Args: cobra.NoArgs,
Args: cobra.ExactArgs(1),
Short: "Upload a new profile",
Run: func(cmd *cobra.Command, args []string) {
// make one request be host positional argument (restricted to 1 for now)
var (
// inputData []map[string]any = append(handleArgs(args), processDataArgs(dataArgs)...)
host, _ = cmd.Flags().GetString("host")
dataArgs, _ = cmd.Flags().GetStringArray("data")
profiles = processProfiles(dataArgs)
c = client.New(host)
res *http.Response
query string
body []byte
err error
)
for _, profile := range profiles {
if profile == nil {
continue
var inputData []map[string]any
temp := append(handleArgs(args), processDataArgs(dataArgs)...)
for _, data := range temp {
if data != nil {
inputData = append(inputData, data)
}
}
body, err = json.Marshal(profile)
if err != nil {
log.Error().Err(err).Msg("failed to marshal profile")
continue
}
// send data to server
query = fmt.Sprintf("/profiles/%s", profile.ID)
res, body, err = c.MakeRequest(client.HTTPEnvelope{
Path: query,
Method: http.MethodPost,
Body: body,
})
if err != nil {
log.Error().Err(err).
Str("host", host).
Str("query", query).
Msg("failed to make request")
os.Exit(1)
}
if res.StatusCode != http.StatusOK {
log.Error().
Any("status", map[string]any{
"code": res.StatusCode,
"message": res.Status,
}).
Str("host", host).
Msg("response returned bad status")
os.Exit(1)
}
}
},
}
var uploadPluginsCmd = &cobra.Command{
var uploadPluginCmd = &cobra.Command{
Use: "plugin",
Example: `
# upload a new plugin
@ -137,12 +82,8 @@ var uploadPluginsCmd = &cobra.Command{
Short: "Upload a new plugin",
Run: func(cmd *cobra.Command, args []string) {
// make one request be host positional argument (restricted to 1 for now)
// temp := append(handleArgs(args), processDataArgs(dataArgs)...)
var (
inputData []*makeshift.Profile
dataArgs, _ = cmd.PersistentFlags().GetStringArray("data")
)
temp := processProfiles(dataArgs)
var inputData []map[string]any
temp := append(handleArgs(args), processDataArgs(dataArgs)...)
for _, data := range temp {
if data != nil {
inputData = append(inputData, data)
@ -152,62 +93,27 @@ var uploadPluginsCmd = &cobra.Command{
}
func init() {
uploadCmd.PersistentFlags().String("host", "http://localhost:5050", "Set the makeshift remote host (can be set with MAKESHIFT_HOST)")
uploadCmd.PersistentFlags().StringArrayP("data", "d", []string{}, "Set the data to send to specified host (prepend @ for files)")
uploadCmd.Flags().StringP("path", "p", ".", "Set the path to list files (can be set with MAKESHIFT_PATH)")
uploadProfileCmd.Flags().VarP(&inputFormat, "format", "F", "Set the input format for profile")
uploadProfilesCmd.Flags().VarP(&inputFormat, "format", "F", "Set the input format for profile")
uploadCmd.AddCommand(uploadProfilesCmd, uploadPluginsCmd)
uploadCmd.AddCommand(uploadProfileCmd, uploadPluginCmd)
rootCmd.AddCommand(uploadCmd)
}
func processFiles(args []string) map[string][]byte {
// load data either from file or directly from args
var collection = make(map[string][]byte, len(args))
for _, arg := range args {
// if arg is empty string, then skip and continue
if len(arg) > 0 {
// determine if we're reading from file to load contents
if strings.HasPrefix(arg, "@") {
var (
path string = strings.TrimLeft(arg, "@")
contents []byte
err error
)
contents, err = os.ReadFile(path)
if err != nil {
log.Error().Err(err).Str("path", path).Msg("failed to read file")
continue
}
// skip empty files
if len(contents) == 0 {
log.Warn().Str("path", path).Msg("file is empty")
continue
}
// add loaded data to collection of all data
collection[path] = contents
} else {
log.Warn().Msg("only files can be uploaded")
continue
}
}
}
return collection
}
// processProfiles takes a slice of strings that check for the @ symbol and loads
// processDataArgs takes a slice of strings that check for the @ symbol and loads
// the contents from the file specified in place (which replaces the path).
//
// NOTE: The purpose is to make the input arguments uniform for our request. This
// function is meant to handle data passed with the `-d/--data` flag and positional
// args from the CLI.
func processProfiles(args []string) []*makeshift.Profile {
func processDataArgs(args []string) []map[string]any {
// JSON representation
type (
JSONObject = map[string]any
JSONArray = []JSONObject
)
// load data either from file or directly from args
var collection = make([]*makeshift.Profile, len(args))
var collection = make(JSONArray, len(args))
for i, arg := range args {
// if arg is empty string, then skip and continue
if len(arg) > 0 {
@ -216,7 +122,7 @@ func processProfiles(args []string) []*makeshift.Profile {
var (
path string = strings.TrimLeft(arg, "@")
contents []byte
data *makeshift.Profile
data JSONArray
err error
)
contents, err = os.ReadFile(path)
@ -232,17 +138,17 @@ func processProfiles(args []string) []*makeshift.Profile {
}
// convert/validate input data
data, err = parseProfile(contents, format.DataFormatFromFileExt(path, inputFormat))
data, err = parseInput(contents, format.DataFormatFromFileExt(path, inputFormat))
if err != nil {
log.Error().Err(err).Str("path", path).Msg("failed to validate input from file")
}
// add loaded data to collection of all data
collection = append(collection, data)
collection = append(collection, data...)
} else {
// input should be a valid JSON
var (
data *makeshift.Profile
data JSONArray
input = []byte(arg)
err error
)
@ -254,23 +160,57 @@ func processProfiles(args []string) []*makeshift.Profile {
if err != nil {
log.Error().Err(err).Msgf("failed to unmarshal input for argument %d", i)
}
return []*makeshift.Profile{data}
return data
}
}
}
return collection
}
func parseProfile(contents []byte, dataFormat format.DataFormat) (*makeshift.Profile, error) {
func handleArgs(args []string) []map[string]any {
// JSON representation
type (
JSONObject = map[string]any
JSONArray = []JSONObject
)
// no file to load, so we just use the joined args (since each one is a new line)
// and then stop
var (
data *makeshift.Profile
collection JSONArray
data []byte
err error
)
if len(dataArgs) > 0 {
return nil
}
data, err = ReadStdin()
if err != nil {
log.Error().Err(err).Msg("failed to read from standard input")
return nil
}
if len(data) == 0 {
log.Warn().Msg("no data found from standard input")
return nil
}
fmt.Println(string(data))
collection, err = parseInput([]byte(data), inputFormat)
if err != nil {
log.Error().Err(err).Msg("failed to validate input from arg")
}
return collection
}
func parseInput(contents []byte, dataFormat format.DataFormat) ([]map[string]any, error) {
var (
data []map[string]any
err error
)
// convert/validate JSON input format
err = format.Unmarshal(contents, &data, dataFormat)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal profile: %v", err)
return nil, fmt.Errorf("failed to unmarshal data: %v", err)
}
return data, nil
}

View file

@ -1,16 +1,12 @@
package client
import (
"crypto/tls"
"crypto/x509"
"fmt"
"io"
"mime/multipart"
"net"
"net/http"
"os"
"strings"
"time"
"git.towk2.me/towk/makeshift/pkg/util"
"github.com/cavaliergopher/grab/v3"
@ -111,43 +107,6 @@ func (c *Client) UploadMultipartFile(uri, key, path string) (*http.Response, err
return resp, nil
}
func (c *Client) LoadCertificateFromPath(path string) error {
cacert, err := os.ReadFile(path)
if err != nil {
return fmt.Errorf("failed to read certificate at path: %s", path)
}
certPool := x509.NewCertPool()
certPool.AppendCertsFromPEM(cacert)
err = c.LoadCertificateFromPool(certPool)
if err != nil {
return fmt.Errorf("could not initialize certificate from pool: %v", err)
}
return nil
}
func (c *Client) LoadCertificateFromPool(certPool *x509.CertPool) error {
// make sure we have a valid cert pool
if certPool == nil {
return fmt.Errorf("invalid cert pool")
}
// make sure that we can access the internal client
c.Transport = &http.Transport{
TLSClientConfig: &tls.Config{
RootCAs: certPool,
InsecureSkipVerify: false,
},
DisableKeepAlives: true,
Dial: (&net.Dialer{
Timeout: 120 * time.Second,
KeepAlive: 120 * time.Second,
}).Dial,
TLSHandshakeTimeout: 120 * time.Second,
ResponseHeaderTimeout: 120 * time.Second,
}
return nil
}
func mustOpen(f string) *os.File {
r, err := os.Open(f)
if err != nil {

View file

@ -1,30 +0,0 @@
package main
import "git.towk2.me/towk/makeshift/pkg/storage"
type Mapper struct{}
func (p *Mapper) Name() string { return "jinja2" }
func (p *Mapper) Version() string { return "test" }
func (p *Mapper) Description() string { return "Renders Jinja 2 templates" }
func (p *Mapper) Metadata() map[string]string {
return map[string]string{
"author.name": "David J. Allen",
"author.email": "davidallendj@gmail.com",
}
}
func (p *Mapper) Init() error {
// nothing to initialize
return nil
}
func (p *Mapper) Run(data storage.KVStore, args []string) error {
return nil
}
func (p *Mapper) Clean() error {
return nil
}
var Makeshift Mapper

View file

@ -0,0 +1,30 @@
package main
import "git.towk2.me/towk/makeshift/pkg/storage"
type UserData struct{}
func (p *UserData) Name() string { return "jinja2" }
func (p *UserData) Version() string { return "test" }
func (p *UserData) Description() string { return "Renders Jinja 2 templates" }
func (p *UserData) Metadata() map[string]string {
return map[string]string{
"author.name": "David J. Allen",
"author.email": "davidallendj@gmail.com",
}
}
func (p *UserData) Init() error {
// nothing to initialize
return nil
}
func (p *UserData) Run(data storage.KVStore, args []string) error {
return nil
}
func (p *UserData) Clean() error {
return nil
}
var Makeshift UserData

View file

@ -8,7 +8,6 @@ import (
makeshift "git.towk2.me/towk/makeshift/pkg"
"github.com/go-chi/chi/v5"
"github.com/rs/zerolog/log"
)
func (s *Service) ListPlugins() http.HandlerFunc {
@ -125,17 +124,24 @@ func (s *Service) CreatePlugin() http.HandlerFunc {
func (s *Service) DeletePlugin() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var (
pluginName = chi.URLParam(r, "name")
path = s.PathForPluginWithName(pluginName)
path string
plugin makeshift.Plugin
err error
)
log.Debug().Str("path", path).Send()
plugin, err = getPluginFromRequestBody(r)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
path = s.PathForPluginWithName(plugin.Name())
err = os.Remove(path)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusOK)
}
}

View file

@ -88,10 +88,13 @@ func (s *Service) GetProfile() http.HandlerFunc {
func (s *Service) CreateProfile() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
type input struct {
Path string `json:"path"`
Profile *makeshift.Profile `json:"profile"`
}
var (
body, contents []byte
path string
profile *makeshift.Profile
in input
err error
)
@ -102,24 +105,23 @@ func (s *Service) CreateProfile() http.HandlerFunc {
}
// use the request info to build profile
err = json.Unmarshal(body, &profile)
err = json.Unmarshal(body, &in)
if err != nil {
http.Error(w, fmt.Sprintf("failed to unmarshal profile: %v", err.Error()), http.StatusBadRequest)
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
// serialize just the profile part
contents, err = json.Marshal(profile)
contents, err = json.Marshal(in.Profile)
if err != nil {
http.Error(w, fmt.Sprintf("failed to marshal profile: %v", err.Error()), http.StatusBadRequest)
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
// create a new profile on disk
path = s.PathForProfileWithID(profile.ID)
err = os.WriteFile(path, contents, os.ModePerm)
err = os.WriteFile(in.Path, contents, os.ModePerm)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
@ -127,29 +129,6 @@ func (s *Service) CreateProfile() http.HandlerFunc {
}
}
func (s *Service) DeleteProfile() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var (
profileID = chi.URLParam(r, "id")
path string
err error
)
if profileID == "default" {
http.Error(w, "cannot delete the default profile", http.StatusBadRequest)
return
}
path = s.PathForProfileWithID(profileID)
err = os.Remove(path)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusOK)
}
}
func (s *Service) SetProfileData() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var (

View file

@ -181,9 +181,18 @@ func (s *Service) Download() http.HandlerFunc {
func (s *Service) Upload() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var (
_ = s.PathForData() + strings.TrimPrefix(r.URL.Path, "/upload")
)
}
}
func (s *Service) UploadPlugin() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
}
}
func (s *Service) UploadProfile() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
}
}
@ -230,23 +239,6 @@ func (s *Service) List() http.HandlerFunc {
}
}
func (s *Service) Delete() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var (
path = s.PathForData() + strings.TrimPrefix(r.URL.Path, "/delete")
err error
)
err = os.RemoveAll(path)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusOK)
}
}
func (s *Service) GetStatus(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
err := json.NewEncoder(w).Encode(map[string]any{

View file

@ -98,15 +98,15 @@ func (s *Service) Serve() error {
} else {
// general
router.Get("/download/*", s.Download())
router.Post("/upload/*", s.Upload())
router.Post("/upload/", s.Upload())
router.Post("/upload/plugin", s.UploadPlugin())
router.Post("/upload/profile", s.UploadProfile())
router.Get("/list/*", s.List())
router.Delete("/delete/*", s.Delete())
// profiles
router.Get("/profiles", s.ListProfiles())
router.Get("/profiles/{id}", s.GetProfile())
router.Post("/profiles/{id}", s.CreateProfile())
router.Delete("/profiles/{id}", s.DeleteProfile())
router.Get("/profiles/{id}/data", s.GetProfileData())
router.Post("/profiles/{id}/data", s.SetProfileData())
router.Delete("/profiles/{id}/data", s.DeleteProfileData())