6 changed files with 256 additions and 4 deletions
+20
View File
@@ -1 +1,21 @@
# Foundry
## Schema
Definition:
### Platforms
- docker
- linux
- kubernetes
- aws
- gcp
- azure
- windows
- aws_marketplace
# Installation
# Usage
+22
View File
@@ -0,0 +1,22 @@
schemaVersion: v1
platform: linux
components:
signoz:
enabled: true
replicas: 3 # HA configuration
version: "0.39.2"
env:
- key: CLICKHOUSE_HOST
value: localhost:9000
clickhouse:
enabled: true
replicas: 3 # HA configuration
version: "24.8"
zookeeper:
enabled: true
replicas: 1 # Single instance
version: "3.7"
signoz-collector:
enabled: true
replicas: 2 # HA configuration
version: "0.39.2"
+98 -1
View File
@@ -1,19 +1,41 @@
package main
import (
"fmt"
"log/slog"
"os"
"path/filepath"
"cuelang.org/go/cue"
"cuelang.org/go/cue/cuecontext"
"cuelang.org/go/cue/errors"
"cuelang.org/go/encoding/json"
"cuelang.org/go/encoding/yaml"
"github.com/SigNoz/foundry/internal/instrumentation"
"github.com/spf13/cobra"
)
var (
errorFilenotFound = errors.New("File not found")
errorSchemaNotFound = errors.New("Schema file not found")
logger = instrumentation.NewLogger(cfg.Debug).With(slog.String("cmd.name", "gauge"))
)
const (
schemaFileName = "../../internal/schema/schema.cue"
)
func registerGaugeCmd(rootCmd *cobra.Command) {
gaugeCmd := &cobra.Command{
Use: "gauge",
Short: "Gauge whether required tools are available.",
RunE: func(cmd *cobra.Command, args []string) error {
logger := instrumentation.NewLogger(cfg.Debug).With(slog.String("cmd.name", "gauge"))
ctx := cmd.Context()
filePath := cfg.File
err := validateConfig(filePath)
if err != nil {
logger.ErrorContext(ctx, "failed to validate config", slog.String("cfg.file", cfg.File), slog.String("error", err.Error()))
}
logger.DebugContext(ctx, "starting command", slog.String("cfg.file", cfg.File))
return nil
@@ -22,3 +44,78 @@ func registerGaugeCmd(rootCmd *cobra.Command) {
rootCmd.AddCommand(gaugeCmd)
}
func compileDataFile(ctx *cue.Context, filename string, data []byte) (cue.Value, error) {
ext := filepath.Ext(filename)
var expr cue.Value
var err error
switch ext {
case ".yaml", ".yml":
yamlExpr, err := yaml.Extract(filename, data)
if err != nil {
return cue.Value{}, fmt.Errorf("failed to parse YAML: %w", err)
}
expr = ctx.BuildFile(yamlExpr)
case ".json":
jsonExpr, err := json.Extract(filename, data)
if err != nil {
return cue.Value{}, fmt.Errorf("failed to parse JSON: %w", err)
}
expr = ctx.BuildExpr(jsonExpr)
default:
return cue.Value{}, fmt.Errorf("unsupported file format: %s (supported: .yaml, .yml, .json, .toml)", ext)
}
if expr.Err() != nil {
return cue.Value{}, fmt.Errorf("config parsing error:\n%s", errors.Details(expr.Err(), nil))
}
return expr, err
}
func validateConfig(filename string) error {
configFile, err := os.ReadFile(filename)
if err != nil {
return errorFilenotFound
}
schemaFile, err := os.ReadFile(schemaFileName)
if err != nil {
return errorSchemaNotFound
}
ctx := cuecontext.New()
// Compile schema
schema := ctx.CompileBytes(schemaFile, cue.Filename(schemaFileName))
if schema.Err() != nil {
return fmt.Errorf("schema compilation error:\n%s", errors.Details(schema.Err(), nil))
}
// Compile data based on file extension
data, err := compileDataFile(ctx, filename, configFile)
if err != nil {
return err
}
// Lookup #Config definition
configSchema := schema.LookupPath(cue.ParsePath("#Config"))
if configSchema.Err() != nil {
return fmt.Errorf("#Config not found in schema:\n%s", errors.Details(configSchema.Err(), nil))
}
// Unify and validate
unified := configSchema.Unify(data)
if err := unified.Validate(cue.Concrete(true)); err != nil {
// Use errors.Details for much better error messages
logger.Error("Validation failed")
return fmt.Errorf("validation failed")
}
logger.Info("✓ Valid Schema")
return nil
}
+15 -2
View File
@@ -2,9 +2,22 @@ module github.com/SigNoz/foundry
go 1.25.3
require github.com/spf13/cobra v1.10.1
require (
cuelang.org/go v0.15.1
github.com/spf13/cobra v1.10.1
)
require (
github.com/cockroachdb/apd/v3 v3.2.1 // indirect
github.com/emicklei/proto v1.14.2 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/spf13/pflag v1.0.9 // indirect
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
github.com/protocolbuffers/txtpbfmt v0.0.0-20251016062345-16587c79cd91 // indirect
github.com/spf13/pflag v1.0.10 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/net v0.46.0 // indirect
golang.org/x/text v0.30.0 // indirect
google.golang.org/protobuf v1.33.0 // indirect
)
+54 -1
View File
@@ -1,10 +1,63 @@
cuelabs.dev/go/oci/ociregistry v0.0.0-20250722084951-074d06050084 h1:4k1yAtPvZJZQTu8DRY8muBo0LHv6TqtrE0AO5n6IPYs=
cuelabs.dev/go/oci/ociregistry v0.0.0-20250722084951-074d06050084/go.mod h1:4WWeZNxUO1vRoZWAHIG0KZOd6dA25ypyWuwD3ti0Tdc=
cuelang.org/go v0.15.1 h1:MRnjc/KJE+K42rnJ3a+425f1jqXeOOgq9SK4tYRTtWw=
cuelang.org/go v0.15.1/go.mod h1:NYw6n4akZcTjA7QQwJ1/gqWrrhsN4aZwhcAL0jv9rZE=
github.com/cockroachdb/apd/v3 v3.2.1 h1:U+8j7t0axsIgvQUqthuNm82HIrYXodOV2iWLWtEaIwg=
github.com/cockroachdb/apd/v3 v3.2.1/go.mod h1:klXJcjp+FffLTHlhIG69tezTDvdP065naDsHzKhYSqc=
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/emicklei/proto v1.14.2 h1:wJPxPy2Xifja9cEMrcA/g08art5+7CGJNFNk35iXC1I=
github.com/emicklei/proto v1.14.2/go.mod h1:rn1FgRS/FANiZdD2djyH7TMA9jdRDcYQ9IEN9yvjX0A=
github.com/go-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7eI=
github.com/go-quicktest/qt v1.101.0/go.mod h1:14Bz/f7NwaXPtdYEgzsx46kqSxVwTbzVZsDC26tQJow=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw=
github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=
github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
github.com/protocolbuffers/txtpbfmt v0.0.0-20251016062345-16587c79cd91 h1:s1LvMaU6mVwoFtbxv/rCZKE7/fwDmDY684FfUe4c1Io=
github.com/protocolbuffers/txtpbfmt v0.0.0-20251016062345-16587c79cd91/go.mod h1:JSbkp0BviKovYYt9XunS95M3mLPibE9bGg+Y95DsEEY=
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/spf13/cobra v1.10.1 h1:lJeBwCfmrnXthfAupyUTzJ/J4Nc1RsHC/mSRU2dll/s=
github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4XaB0=
github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY=
github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA=
golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w=
golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4=
golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210=
golang.org/x/oauth2 v0.32.0 h1:jsCblLleRMDrxMN29H3z/k1KliIvpLgCkE6R8FXXNgY=
golang.org/x/oauth2 v0.32.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ=
golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+47
View File
@@ -0,0 +1,47 @@
package schema
// Schema version must follow semantic versioning
#SchemaVersion: =~"^v[0-9]+$"
// Platform enumeration - add more platforms as needed
#Platform: "docker" | "linux" | "kubernetes" | "aws" | "gcp" | "azure" | "windows"
// Environment variable key-value pair
#EnvVar: {
key: string
value: string
}
// Component definition
#Component: {
enabled: bool
replicas: int & >=1
version: string & =~"^[0-9]+\\.[0-9]+(\\.[0-9]+)?(-.*)?$"
env?: [...#EnvVar]
}
// Platform-specific requirements
_requirements: {
docker: ["docker", "docker-compose"]
linux: ["systemd", "curl", "tar"]
kubernetes: ["kubectl", "helm"]
aws: ["aws-cli", "kubectl", "helm"]
gcp: ["gcloud", "kubectl", "helm"]
azure: ["az-cli", "kubectl", "helm"]
windows: ["powershell", "chocolatey"]
}
// Main configuration schema
#Config: {
schemaVersion: #SchemaVersion
platform: #Platform
// Components involved in the deployment
components: [string]: #Component
// Requirements based on platform
requirements: _requirements[platform]
}
// Validate that the config conforms to the schema
#Config