- Add API server with WebSocket support and REST endpoints - Implement authentication system with API keys and permissions - Add task queue system with Redis backend and error handling - Include storage layer with database migrations and schemas - Add comprehensive logging, metrics, and telemetry - Implement security middleware and network utilities - Add experiment management and container orchestration - Include configuration management with smart defaults
116 lines
2.4 KiB
Go
116 lines
2.4 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"flag"
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/xeipuuv/gojsonschema"
|
|
"gopkg.in/yaml.v3"
|
|
)
|
|
|
|
func main() {
|
|
var (
|
|
schemaPath string
|
|
failFast bool
|
|
)
|
|
|
|
flag.StringVar(&schemaPath, "schema", "configs/schema.yaml", "Path to JSON schema in YAML format")
|
|
flag.BoolVar(&failFast, "fail-fast", false, "Stop on first error")
|
|
flag.Parse()
|
|
|
|
if flag.NArg() == 0 {
|
|
log.Fatalf("usage: configlint [--schema path] [--fail-fast] <config files...>")
|
|
}
|
|
|
|
schemaLoader, err := loadSchema(schemaPath)
|
|
if err != nil {
|
|
log.Fatalf("failed to load schema: %v", err)
|
|
}
|
|
|
|
var hadError bool
|
|
for _, configPath := range flag.Args() {
|
|
if err := validateConfig(schemaLoader, configPath); err != nil {
|
|
hadError = true
|
|
fmt.Fprintf(os.Stderr, "configlint: %s: %v\n", configPath, err)
|
|
if failFast {
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
}
|
|
|
|
if hadError {
|
|
os.Exit(1)
|
|
}
|
|
|
|
fmt.Println("All configuration files are valid.")
|
|
}
|
|
|
|
func loadSchema(schemaPath string) (gojsonschema.JSONLoader, error) {
|
|
data, err := os.ReadFile(schemaPath)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var schemaYAML interface{}
|
|
if err := yaml.Unmarshal(data, &schemaYAML); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
schemaJSON, err := json.Marshal(schemaYAML)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
tmpFile, err := os.CreateTemp("", "fetchml-schema-*.json")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer tmpFile.Close()
|
|
|
|
if _, err := tmpFile.Write(schemaJSON); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return gojsonschema.NewReferenceLoader("file://" + filepath.ToSlash(tmpFile.Name())), nil
|
|
}
|
|
|
|
func validateConfig(schemaLoader gojsonschema.JSONLoader, configPath string) error {
|
|
data, err := os.ReadFile(configPath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
var configYAML interface{}
|
|
if err := yaml.Unmarshal(data, &configYAML); err != nil {
|
|
return fmt.Errorf("failed to parse YAML: %w", err)
|
|
}
|
|
|
|
configJSON, err := json.Marshal(configYAML)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
result, err := gojsonschema.Validate(schemaLoader, gojsonschema.NewBytesLoader(configJSON))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if result.Valid() {
|
|
fmt.Printf("%s: valid\n", configPath)
|
|
return nil
|
|
}
|
|
|
|
var builder strings.Builder
|
|
for _, issue := range result.Errors() {
|
|
builder.WriteString("- ")
|
|
builder.WriteString(issue.String())
|
|
builder.WriteByte('\n')
|
|
}
|
|
|
|
return fmt.Errorf("validation failed:\n%s", builder.String())
|
|
}
|