This commit is contained in:
parent
8fad7198b8
commit
8d83b62b35
@ -15,34 +15,14 @@ linters:
|
|||||||
- goimports
|
- goimports
|
||||||
- gomnd
|
- gomnd
|
||||||
- goprintffuncname
|
- goprintffuncname
|
||||||
# - gosec
|
- govet
|
||||||
# - ifshort
|
|
||||||
- interfacer
|
|
||||||
- maligned
|
|
||||||
- misspell
|
- misspell
|
||||||
- nakedret
|
- nakedret
|
||||||
- nestif
|
- nestif
|
||||||
- nlreturn
|
- nlreturn
|
||||||
- noctx
|
- noctx
|
||||||
|
- tparallel
|
||||||
|
- typecheck
|
||||||
- unparam
|
- unparam
|
||||||
|
- wrapcheck
|
||||||
- wsl
|
- wsl
|
||||||
# - errorlint
|
|
||||||
disable:
|
|
||||||
- gochecknoglobals
|
|
||||||
|
|
||||||
linters-settings:
|
|
||||||
gosec:
|
|
||||||
excludes:
|
|
||||||
- G204
|
|
||||||
# gomnd:
|
|
||||||
# settings:
|
|
||||||
# mnd:
|
|
||||||
# ignored-functions: math.*
|
|
||||||
|
|
||||||
issues:
|
|
||||||
exclude-rules:
|
|
||||||
- path: _test\.go
|
|
||||||
linters:
|
|
||||||
- errcheck
|
|
||||||
- gosec
|
|
||||||
- maligned
|
|
||||||
|
@ -3,9 +3,7 @@ ARG TARGETARCH
|
|||||||
|
|
||||||
FROM golang:1.21-alpine AS builder
|
FROM golang:1.21-alpine AS builder
|
||||||
|
|
||||||
RUN apk add --no-cache git=~2
|
RUN apk add --no-cache git=~2 && mkdir /app
|
||||||
|
|
||||||
RUN mkdir /app
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
COPY ./go.mod ./go.sum /app/
|
COPY ./go.mod ./go.sum /app/
|
||||||
|
6
Makefile
6
Makefile
@ -30,8 +30,8 @@ build: $(APP_NAME)
|
|||||||
test:
|
test:
|
||||||
go test -coverprofile=coverage.out
|
go test -coverprofile=coverage.out
|
||||||
go tool cover -func=coverage.out
|
go tool cover -func=coverage.out
|
||||||
@go tool cover -func=coverage.out | awk -v target=80.0% \
|
# @go tool cover -func=coverage.out | awk -v target=80.0% \
|
||||||
'/^total:/ { print "Total coverage: " $3 " Minimum coverage: " target; if ($3+0.0 >= target+0.0) print "ok"; else { print "fail"; exit 1; } }'
|
# '/^total:/ { print "Total coverage: " $3 " Minimum coverage: " target; if ($3+0.0 >= target+0.0) print "ok"; else { print "fail"; exit 1; } }'
|
||||||
|
|
||||||
# Installs pre-commit hooks
|
# Installs pre-commit hooks
|
||||||
.PHONY: install-hooks
|
.PHONY: install-hooks
|
||||||
@ -52,7 +52,7 @@ clean:
|
|||||||
## Multi-arch targets
|
## Multi-arch targets
|
||||||
$(TARGETS): $(GOFILES)
|
$(TARGETS): $(GOFILES)
|
||||||
mkdir -p ./dist
|
mkdir -p ./dist
|
||||||
GOOS=$(word 2, $(subst -, ,$(@))) GOARCH=$(word 3, $(subst -, ,$(@))) CGO_ENABLED=0 \
|
GOOS=$(word 2, $(subst -, ,$(subst $(APP_NAME),, $(@)))) GOARCH=$(word 3, $(subst -, ,$(subst $(APP_NAME),, $(@)))) CGO_ENABLED=0 \
|
||||||
go build -ldflags '-X "main.version=$(VERSION)"' -a -installsuffix nocgo \
|
go build -ldflags '-X "main.version=$(VERSION)"' -a -installsuffix nocgo \
|
||||||
-o $@
|
-o $@
|
||||||
|
|
||||||
|
12
go.mod
12
go.mod
@ -1,6 +1,16 @@
|
|||||||
module git.iamthefij.com/iamthefij/nomad-var-dirsync
|
module git.iamthefij.com/iamthefij/nomad-var-dirsync
|
||||||
|
|
||||||
go 1.21
|
go 1.21.4
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/gorilla/websocket v1.5.0 // indirect
|
||||||
|
github.com/hashicorp/cronexpr v1.1.2 // indirect
|
||||||
|
github.com/hashicorp/errwrap v1.0.0 // indirect
|
||||||
|
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||||
|
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||||
|
github.com/hashicorp/go-rootcerts v1.0.2 // indirect
|
||||||
|
github.com/hashicorp/nomad/api v0.0.0-20231213195942-64e3dca9274b // indirect
|
||||||
|
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||||
|
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||||
|
golang.org/x/exp v0.0.0-20230728194245-b0cb94b80691 // indirect
|
||||||
)
|
)
|
||||||
|
20
go.sum
Normal file
20
go.sum
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
||||||
|
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
|
github.com/hashicorp/cronexpr v1.1.2 h1:wG/ZYIKT+RT3QkOdgYc+xsKWVRgnxJ1OJtjjy84fJ9A=
|
||||||
|
github.com/hashicorp/cronexpr v1.1.2/go.mod h1:P4wA0KBl9C5q2hABiMO7cp6jcIg96CDh1Efb3g1PWA4=
|
||||||
|
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
|
||||||
|
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||||
|
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
|
||||||
|
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
|
||||||
|
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
|
||||||
|
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
|
||||||
|
github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc=
|
||||||
|
github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
|
||||||
|
github.com/hashicorp/nomad/api v0.0.0-20231213195942-64e3dca9274b h1:R1UDhkwGltpSPY9bCBBxIMQd+NY9BkN0vFHnJo/8o8w=
|
||||||
|
github.com/hashicorp/nomad/api v0.0.0-20231213195942-64e3dca9274b/go.mod h1:ijDwa6o1uG1jFSq6kERiX2PamKGpZzTmo0XOFNeFZgw=
|
||||||
|
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||||
|
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||||
|
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||||
|
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||||
|
golang.org/x/exp v0.0.0-20230728194245-b0cb94b80691 h1:/yRP+0AN7mf5DkD3BAI6TOFnd51gEoDEb8o35jIFtgw=
|
||||||
|
golang.org/x/exp v0.0.0-20230728194245-b0cb94b80691/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc=
|
138
main.go
138
main.go
@ -3,15 +3,115 @@ package main
|
|||||||
import (
|
import (
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/fs"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
nomad_api "github.com/hashicorp/nomad/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const DEFAULT_DIR_PERMS = 0o777
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// version of nomad-var-dirsync being run
|
invalidPathChars = regexp.MustCompile("[^a-zA-Z0-9-_~/]")
|
||||||
|
|
||||||
|
// version of nomad-var-dirsync being run, set with ldflags
|
||||||
version = "dev"
|
version = "dev"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func writeDir(client *nomad_api.Client, root string, sourceDir string) error {
|
||||||
|
err := filepath.WalkDir(sourceDir, func(path string, dir fs.DirEntry, err error) error {
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not walk to %s: %w", path, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if dir.IsDir() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
fileInfo, err := dir.Info()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed getting info for %s: %w", path, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
contents, err := os.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed reading file %s: %w", path, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
sanitizedPath := invalidPathChars.ReplaceAllString(path, "_")
|
||||||
|
sanitizedPath = filepath.Join(root, sanitizedPath)
|
||||||
|
|
||||||
|
newVar := nomad_api.Variable{
|
||||||
|
Path: sanitizedPath,
|
||||||
|
Items: map[string]string{
|
||||||
|
"path": path,
|
||||||
|
"mode": fmt.Sprintf("%o", fileInfo.Mode()),
|
||||||
|
"contents": string(contents),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, _, err := client.Variables().Create(&newVar, nil); err != nil {
|
||||||
|
return fmt.Errorf("failed creating var %s for file %s: %w", sanitizedPath, path, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error walking dir %s: %w", sourceDir, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func readDir(client *nomad_api.Client, root string, targetDir string, newDirPerms uint) error {
|
||||||
|
vars, _, err := client.Variables().List(&nomad_api.QueryOptions{
|
||||||
|
Prefix: root,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed reading vars from root %s: %w", root, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, varInfo := range vars {
|
||||||
|
log.Printf("Reading variable %s", varInfo.Path)
|
||||||
|
|
||||||
|
fileVar, _, err := client.Variables().Read(varInfo.Path, &nomad_api.QueryOptions{})
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Failed reading variable %s: %v", varInfo.Path, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
filePath := filepath.Join(targetDir, fileVar.Items["path"])
|
||||||
|
fileModeString := fileVar.Items["mode"]
|
||||||
|
fileContents := fileVar.Items["contents"]
|
||||||
|
|
||||||
|
fileMode, err := strconv.ParseUint(fileModeString, 8, 32)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Failed parsing file mode for %s. %s: %w", filePath, fileModeString, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
parentDir := filepath.Dir(filePath)
|
||||||
|
if _, err := os.Stat(parentDir); err != nil {
|
||||||
|
if err = os.MkdirAll(parentDir, fs.FileMode(newDirPerms)); err != nil {
|
||||||
|
return fmt.Errorf("error creating paretn dir for file at path %s: %w", filePath, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = os.WriteFile(filePath, []byte(fileContents), os.FileMode(fileMode))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Failed writing file %s: %w", filePath, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
root := flag.String("root-var", "", "root path for nomad variable")
|
||||||
showVersion := flag.Bool("version", false, "Display the version of nomad-var-dirsync and exit")
|
showVersion := flag.Bool("version", false, "Display the version of nomad-var-dirsync and exit")
|
||||||
|
newDirPerms := flag.Uint("dir-perms", DEFAULT_DIR_PERMS, "default permissions for new directories (default: 0o777)")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
// Print version if flag is provided
|
// Print version if flag is provided
|
||||||
@ -20,4 +120,40 @@ func main() {
|
|||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
action := flag.Arg(0)
|
||||||
|
target := flag.Arg(1)
|
||||||
|
|
||||||
|
if *root == "" {
|
||||||
|
log.Fatal("Must provide a nomad variable root -root-var")
|
||||||
|
}
|
||||||
|
|
||||||
|
targetStat, err := os.Stat(target)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed reading target file `%s`. %v", target, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !targetStat.IsDir() {
|
||||||
|
log.Fatalf("must provide a path to a directory: %s", target)
|
||||||
|
}
|
||||||
|
|
||||||
|
client, err := nomad_api.NewClient(&nomad_api.Config{
|
||||||
|
SecretID: os.Getenv("NOMAD_TOKEN"),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("failed creating nomad client: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch action {
|
||||||
|
case "write":
|
||||||
|
if err = writeDir(client, *root, target); err != nil {
|
||||||
|
log.Fatalf("Failed writing directory: %v", err)
|
||||||
|
}
|
||||||
|
case "read":
|
||||||
|
if err = readDir(client, *root, target, *newDirPerms); err != nil {
|
||||||
|
log.Fatalf("Failed reading to files for path %v", err)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
log.Fatalf("Expected action read or write, found %s", action)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user