refactor(foundryctl): silent-by-default logs, typed exit codes, ban fmt.Errorf (#118)
## Summary Reshape foundryctl's output contract so it composes with agents and shell pipelines. Three changes that fall out of the same observation: **stdout, stderr, and exit codes should be a stable contract — today they're conflated.** - **Logger to stderr, silent by default.** `instrumentation.NewLogger` writes to `os.Stderr` (was `os.Stdout`) and uses `slog.DiscardHandler` unless `--debug` is set. Matches helm/aws CLI convention. stdout is now reserved for command results. - **Typed exit codes.** `internal/errors.typ` carries a `code int` field; `errors.ExitCode(err)` walks the wrap chain via `errors.As` and returns a deterministic code: `InvalidInput=2, NotFound=3, Unsupported=4, Internal=5, Fatal=6`, untyped=1, nil=0. Compact 1-6 scheme rather than sysexits.h because sysexits would collapse `Internal` and `Fatal` into the same `EX_SOFTWARE (70)`, losing a distinction we care about (Fatal = recovered panic; Internal = expected-but-failed path). `cmd/foundryctl/main.go` now exits with `errors.ExitCode(err)`. - **`fmt.Errorf` forbidden by lint.** New forbidigo rules in `.golangci.yml` ban `fmt.Errorf` and `fmt.Print*` / `print` / `println`. 168 call sites across 38 files converted to `errors.Newf` / `errors.Wrapf` with contextually-chosen types. Narrow exception for `internal/errors/error_test.go` so the ExitCode wrap-chain test stays authentic. Sites of note for review: - `internal/errors/type.go` — exit code mapping table (one source of truth) - `internal/errors/error.go` — `ExitCode(err)` helper - `internal/instrumentation/logger.go` — `slog.DiscardHandler` default - `.golangci.yml` — forbidigo config + the single narrow test exclusion ## Test plan - [x] `go build ./...` - [x] `go test ./...` (all packages pass; new `TestExitCode` covers 9 cases: nil, untyped, each typed, fmt.Errorf-wrapped, foundry-Wrapf-wrapped) - [x] `golangci-lint run ./...` — 0 issues - [x] Manual: `foundryctl forge` on a missing file exits non-zero and emits nothing on stdout (logs hidden); `--debug` emits JSON on stderr only - [x] Manual: end-to-end forge + cast against the docker/compose flavor still produces a healthy stack
This commit is contained in:
@@ -24,3 +24,14 @@ linters:
|
||||
- identical
|
||||
sloglint:
|
||||
attr-only: true
|
||||
forbidigo:
|
||||
forbid:
|
||||
- pattern: fmt.Errorf
|
||||
- pattern: ^(fmt\.Print.*|print|println)$
|
||||
exclusions:
|
||||
rules:
|
||||
# ExitCode tests cover the wrap-chain path that fmt.Errorf("%w", ...)
|
||||
# exercises in real callers; using fmt.Errorf here keeps the test honest.
|
||||
- path: internal/errors/error_test\.go$
|
||||
linters:
|
||||
- forbidigo
|
||||
|
||||
@@ -2,9 +2,9 @@ package v1alpha1
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/signoz/foundry/internal/errors"
|
||||
"k8s.io/apimachinery/pkg/util/strategicpatch"
|
||||
)
|
||||
|
||||
@@ -19,27 +19,27 @@ func Merge(base, overrides any) error {
|
||||
|
||||
baseBytes, err := json.Marshal(base)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to convert current object to byte sequence: %w", err)
|
||||
return errors.Wrapf(err, errors.TypeInternal, "failed to convert current object to byte sequence")
|
||||
}
|
||||
|
||||
overrideBytes, err := json.Marshal(overrides)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to convert current object to byte sequence: %w", err)
|
||||
return errors.Wrapf(err, errors.TypeInternal, "failed to convert current object to byte sequence")
|
||||
}
|
||||
|
||||
patchMeta, err := strategicpatch.NewPatchMetaFromStruct(base)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to produce patch meta from struct: %w", err)
|
||||
return errors.Wrapf(err, errors.TypeInternal, "failed to produce patch meta from struct")
|
||||
}
|
||||
|
||||
patch, err := strategicpatch.CreateThreeWayMergePatch(overrideBytes, overrideBytes, baseBytes, patchMeta, true)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create three way merge patch: %w", err)
|
||||
return errors.Wrapf(err, errors.TypeInternal, "failed to create three way merge patch")
|
||||
}
|
||||
|
||||
merged, err := strategicpatch.StrategicMergePatchUsingLookupPatchMeta(baseBytes, patch, patchMeta)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to apply patch: %w", err)
|
||||
return errors.Wrapf(err, errors.TypeInternal, "failed to apply patch")
|
||||
}
|
||||
|
||||
valueOfBase := reflect.Indirect(reflect.ValueOf(base))
|
||||
@@ -50,7 +50,7 @@ func Merge(base, overrides any) error {
|
||||
}
|
||||
|
||||
if !valueOfBase.CanSet() {
|
||||
return fmt.Errorf("unable to set unmarshalled value into base object")
|
||||
return errors.Newf(errors.TypeInternal, "unable to set unmarshalled value into base object")
|
||||
}
|
||||
|
||||
valueOfBase.Set(reflect.Indirect(into))
|
||||
|
||||
@@ -3,11 +3,11 @@ package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/signoz/foundry/internal/domain"
|
||||
"github.com/signoz/foundry/internal/errors"
|
||||
"github.com/signoz/foundry/internal/foundry"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
@@ -47,7 +47,7 @@ func runCast(ctx context.Context, logger *slog.Logger, poursPath string, configP
|
||||
|
||||
poursPath, err = filepath.Abs(poursPath)
|
||||
if err != nil {
|
||||
return domain.NewProperties(), fmt.Errorf("failed to resolve pours path: %w", err)
|
||||
return domain.NewProperties(), errors.Wrapf(err, errors.TypeInternal, "failed to resolve pours path")
|
||||
}
|
||||
|
||||
machinery, err := foundry.Config.GetV1Alpha1Lock(ctx, configPath)
|
||||
|
||||
+15
-15
@@ -86,25 +86,25 @@ func runCatalog(logger *slog.Logger) (domain.Properties, error) {
|
||||
|
||||
props := domain.NewProperties()
|
||||
|
||||
if catalogCfg.Format == "json" {
|
||||
data, err := json.MarshalIndent(map[string]any{"Castings": entries}, "", " ")
|
||||
if err != nil {
|
||||
return props, err
|
||||
if commonCfg.Format == "text" {
|
||||
table := tablewriter.NewWriter(os.Stdout)
|
||||
table.Header("Mode", "Flavor", "Platform", "Example")
|
||||
for _, e := range entries {
|
||||
_ = table.Append(e.Mode, e.Flavor, e.Platform, e.Example)
|
||||
}
|
||||
if catalogCfg.OutPath != "" {
|
||||
err = os.WriteFile(catalogCfg.OutPath, data, 0644)
|
||||
return props, err
|
||||
}
|
||||
_, err = os.Stdout.Write(data)
|
||||
|
||||
err = table.Render()
|
||||
return props, err
|
||||
}
|
||||
|
||||
table := tablewriter.NewWriter(os.Stdout)
|
||||
table.Header("Mode", "Flavor", "Platform", "Example")
|
||||
for _, e := range entries {
|
||||
_ = table.Append(e.Mode, e.Flavor, e.Platform, e.Example)
|
||||
data, err := json.MarshalIndent(map[string]any{"Castings": entries}, "", " ")
|
||||
if err != nil {
|
||||
return props, err
|
||||
}
|
||||
|
||||
err = table.Render()
|
||||
if catalogCfg.OutPath != "" {
|
||||
err = os.WriteFile(catalogCfg.OutPath, data, 0644)
|
||||
return props, err
|
||||
}
|
||||
_, err = os.Stdout.Write(data)
|
||||
return props, err
|
||||
}
|
||||
|
||||
@@ -19,12 +19,14 @@ var (
|
||||
type commonConfig struct {
|
||||
File string
|
||||
Debug bool
|
||||
Format string
|
||||
NoLedger bool
|
||||
}
|
||||
|
||||
func (c *commonConfig) RegisterFlags(cmd *cobra.Command) {
|
||||
cmd.PersistentFlags().StringVarP(&c.File, "file", "f", "casting.yaml", "Path to the casting configuration file.")
|
||||
cmd.PersistentFlags().BoolVarP(&c.Debug, "debug", "d", false, "Enable debug mode.")
|
||||
cmd.PersistentFlags().StringVar(&c.Format, "format", "json", "Output format for results and errors (json|text).")
|
||||
cmd.PersistentFlags().BoolVar(&c.NoLedger, "no-ledger", false, "Disable anonymous usage ledger.")
|
||||
}
|
||||
|
||||
@@ -47,11 +49,9 @@ func (c *castConfig) RegisterFlags(cmd *cobra.Command) {
|
||||
}
|
||||
|
||||
type catalogConfig struct {
|
||||
Format string
|
||||
OutPath string
|
||||
}
|
||||
|
||||
func (c *catalogConfig) RegisterFlags(cmd *cobra.Command) {
|
||||
cmd.Flags().StringVar(&c.Format, "format", "", "Output format (json)")
|
||||
cmd.Flags().StringVarP(&c.OutPath, "output", "o", "", "Path to write castings.json")
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package main
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@@ -128,12 +127,12 @@ func runGenSchemas(_ context.Context) error {
|
||||
|
||||
schema, err := reflector.Reflect(target.val)
|
||||
if err != nil {
|
||||
return fmt.Errorf("reflect %T: %w", target.val, err)
|
||||
return foundryerrors.Wrapf(err, foundryerrors.TypeInternal, "reflect %T", target.val)
|
||||
}
|
||||
|
||||
contents, err := json.MarshalIndent(schema, "", " ")
|
||||
if err != nil {
|
||||
return fmt.Errorf("marshal %T: %w", target.val, err)
|
||||
return foundryerrors.Wrapf(err, foundryerrors.TypeInternal, "marshal %T", target.val)
|
||||
}
|
||||
|
||||
kindDir := strings.TrimPrefix(reflect.TypeOf(target.val).PkgPath(), moduleAPIPrefix)
|
||||
|
||||
@@ -3,6 +3,7 @@ package main
|
||||
import (
|
||||
"os"
|
||||
|
||||
foundryerrors "github.com/signoz/foundry/internal/errors"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@@ -31,6 +32,6 @@ func main() {
|
||||
defer closeRoot()
|
||||
|
||||
if err := rootCmd.Execute(); err != nil {
|
||||
os.Exit(1)
|
||||
os.Exit(foundryerrors.ExitCode(err))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"log/slog"
|
||||
"os"
|
||||
"runtime"
|
||||
|
||||
"github.com/signoz/foundry/internal/domain"
|
||||
@@ -10,6 +11,7 @@ import (
|
||||
"github.com/signoz/foundry/internal/ledger"
|
||||
"github.com/signoz/foundry/internal/ledger/noopledger"
|
||||
"github.com/signoz/foundry/internal/ledger/segmentledger"
|
||||
"github.com/signoz/foundry/internal/writer"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@@ -64,6 +66,10 @@ func recoverRunE(
|
||||
if err != nil {
|
||||
rootLogger.ErrorContext(ctx, event.String()+" failed", foundryerrors.LogAttr(err))
|
||||
rootTracker.Track(ctx, event.Failed(), props.WithError(err))
|
||||
if commonCfg.Format == "json" {
|
||||
_ = writer.WriteOutput(os.Stdout, foundryerrors.EnvelopeOf(err))
|
||||
cmd.SilenceErrors = true
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -3,13 +3,13 @@ package coolifycasting
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/signoz/foundry/api/v1alpha1/installation"
|
||||
rootcasting "github.com/signoz/foundry/internal/casting"
|
||||
"github.com/signoz/foundry/internal/domain"
|
||||
"github.com/signoz/foundry/internal/errors"
|
||||
"github.com/signoz/foundry/internal/molding"
|
||||
)
|
||||
|
||||
@@ -37,12 +37,12 @@ func (c *coolifyCasting) Forge(ctx context.Context, config installation.Casting,
|
||||
buf := bytes.NewBuffer(nil)
|
||||
err := coolifyYAMLTemplate.Execute(buf, config)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to execute coolify yaml template: %w", err)
|
||||
return nil, errors.Wrapf(err, errors.TypeInternal, "failed to execute coolify yaml template")
|
||||
}
|
||||
|
||||
coolifyMaterial, err := domain.NewYAMLMaterial(buf.Bytes(), filepath.Join(rootcasting.DeploymentDir, "coolify.yaml"))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create coolify yaml material: %w", err)
|
||||
return nil, errors.Wrapf(err, errors.TypeInternal, "failed to create coolify yaml material")
|
||||
}
|
||||
|
||||
return []domain.Material{coolifyMaterial}, nil
|
||||
@@ -60,7 +60,7 @@ func getCoolifyMaterial(config *installation.Casting, path string) (domain.Struc
|
||||
buf := bytes.NewBuffer(nil)
|
||||
err := coolifyYAMLTemplate.Execute(buf, config)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to execute coolify yaml template: %w", err)
|
||||
return nil, errors.Wrapf(err, errors.TypeInternal, "failed to execute coolify yaml template")
|
||||
}
|
||||
return domain.NewYAMLMaterial(buf.Bytes(), path)
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package coolifycasting
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
@@ -10,6 +9,7 @@ import (
|
||||
"github.com/signoz/foundry/api/v1alpha1/installation"
|
||||
rootcasting "github.com/signoz/foundry/internal/casting"
|
||||
"github.com/signoz/foundry/internal/domain"
|
||||
"github.com/signoz/foundry/internal/errors"
|
||||
"github.com/signoz/foundry/internal/molding"
|
||||
)
|
||||
|
||||
@@ -22,7 +22,7 @@ type coolifyMoldingEnricher struct {
|
||||
func newCoolifyMoldingEnricher(config *installation.Casting) (*coolifyMoldingEnricher, error) {
|
||||
material, err := getCoolifyMaterial(config, filepath.Join(rootcasting.DeploymentDir, "coolify.yaml"))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get coolify yaml material: %w", err)
|
||||
return nil, errors.Wrapf(err, errors.TypeInternal, "failed to get coolify yaml material")
|
||||
}
|
||||
return &coolifyMoldingEnricher{material: material}, nil
|
||||
}
|
||||
@@ -32,7 +32,7 @@ func (enricher *coolifyMoldingEnricher) EnrichStatus(ctx context.Context, kind v
|
||||
case v1alpha1.MoldingKindTelemetryStore:
|
||||
containerNames, err := enricher.material.GetStringSlice("services|@keys")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get telemetrystore container names: %w", err)
|
||||
return errors.Wrapf(err, errors.TypeInternal, "failed to get telemetrystore container names")
|
||||
}
|
||||
|
||||
var telemetrystoreContainerNames []string
|
||||
@@ -46,7 +46,7 @@ func (enricher *coolifyMoldingEnricher) EnrichStatus(ctx context.Context, kind v
|
||||
case v1alpha1.MoldingKindSignoz:
|
||||
containerNames, err := enricher.material.GetStringSlice("services|@keys")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get signoz container names: %w", err)
|
||||
return errors.Wrapf(err, errors.TypeInternal, "failed to get signoz container names")
|
||||
}
|
||||
|
||||
var apiServerAddr []string
|
||||
@@ -63,7 +63,7 @@ func (enricher *coolifyMoldingEnricher) EnrichStatus(ctx context.Context, kind v
|
||||
case v1alpha1.MoldingKindTelemetryKeeper:
|
||||
containerNames, err := enricher.material.GetStringSlice("services|@keys")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get telemetrykeeper container names: %w", err)
|
||||
return errors.Wrapf(err, errors.TypeInternal, "failed to get telemetrykeeper container names")
|
||||
}
|
||||
|
||||
var telemetrykeeperContainerNames []string
|
||||
@@ -89,7 +89,7 @@ func (enricher *coolifyMoldingEnricher) EnrichStatus(ctx context.Context, kind v
|
||||
}
|
||||
containerNames, err := enricher.material.GetStringSlice("services|@keys")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get metastore container names: %w", err)
|
||||
return errors.Wrapf(err, errors.TypeInternal, "failed to get metastore container names")
|
||||
}
|
||||
|
||||
var metastoreContainerNames []string
|
||||
@@ -103,7 +103,7 @@ func (enricher *coolifyMoldingEnricher) EnrichStatus(ctx context.Context, kind v
|
||||
case v1alpha1.MoldingKindIngester:
|
||||
containerNames, err := enricher.material.GetStringSlice("services|@keys")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get ingester container names: %w", err)
|
||||
return errors.Wrapf(err, errors.TypeInternal, "failed to get ingester container names")
|
||||
}
|
||||
|
||||
var ingesterContainerNames []string
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"os"
|
||||
"os/exec"
|
||||
@@ -15,6 +14,7 @@ import (
|
||||
"github.com/signoz/foundry/api/v1alpha1/installation"
|
||||
rootcasting "github.com/signoz/foundry/internal/casting"
|
||||
"github.com/signoz/foundry/internal/domain"
|
||||
foundryerrors "github.com/signoz/foundry/internal/errors"
|
||||
"github.com/signoz/foundry/internal/molding"
|
||||
)
|
||||
|
||||
@@ -42,12 +42,12 @@ func (casting *dockerComposeCasting) Forge(ctx context.Context, config installat
|
||||
buf := bytes.NewBuffer(nil)
|
||||
err := composeYAMLTemplate.Execute(buf, config)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to execute compose yaml template: %w", err)
|
||||
return nil, foundryerrors.Wrapf(err, foundryerrors.TypeInternal, "failed to execute compose yaml template")
|
||||
}
|
||||
|
||||
composeMaterial, err := domain.NewYAMLMaterial(buf.Bytes(), filepath.Join(rootcasting.DeploymentDir, "compose.yaml"))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create compose yaml material: %w", err)
|
||||
return nil, foundryerrors.Wrapf(err, foundryerrors.TypeInternal, "failed to create compose yaml material")
|
||||
}
|
||||
|
||||
materials := []domain.Material{composeMaterial}
|
||||
@@ -56,7 +56,7 @@ func (casting *dockerComposeCasting) Forge(ctx context.Context, config installat
|
||||
for filename, content := range config.Spec.TelemetryKeeper.Spec.Config.Data {
|
||||
material, err := domain.NewYAMLMaterial([]byte(content), filepath.Join(rootcasting.DeploymentDir, "telemetrykeeper", config.Spec.TelemetryKeeper.Kind.String(), filename))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create telemetrykeeper config material: %w", err)
|
||||
return nil, foundryerrors.Wrapf(err, foundryerrors.TypeInternal, "failed to create telemetrykeeper config material")
|
||||
}
|
||||
materials = append(materials, material)
|
||||
}
|
||||
@@ -65,7 +65,7 @@ func (casting *dockerComposeCasting) Forge(ctx context.Context, config installat
|
||||
for filename, content := range config.Spec.TelemetryStore.Spec.Config.Data {
|
||||
material, err := domain.NewYAMLMaterial([]byte(content), filepath.Join(rootcasting.DeploymentDir, "telemetrystore", config.Spec.TelemetryStore.Kind.String(), filename))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create telemetrystore config material: %w", err)
|
||||
return nil, foundryerrors.Wrapf(err, foundryerrors.TypeInternal, "failed to create telemetrystore config material")
|
||||
}
|
||||
materials = append(materials, material)
|
||||
}
|
||||
@@ -74,7 +74,7 @@ func (casting *dockerComposeCasting) Forge(ctx context.Context, config installat
|
||||
for filename, content := range config.Spec.MetaStore.Spec.Config.Data {
|
||||
material, err := domain.NewYAMLMaterial([]byte(content), filepath.Join(rootcasting.DeploymentDir, "metastore", config.Spec.MetaStore.Kind.String(), filename))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create metastore config material: %w", err)
|
||||
return nil, foundryerrors.Wrapf(err, foundryerrors.TypeInternal, "failed to create metastore config material")
|
||||
}
|
||||
materials = append(materials, material)
|
||||
}
|
||||
@@ -83,7 +83,7 @@ func (casting *dockerComposeCasting) Forge(ctx context.Context, config installat
|
||||
for filename, content := range config.Spec.Signoz.Spec.Config.Data {
|
||||
material, err := domain.NewYAMLMaterial([]byte(content), filepath.Join(rootcasting.DeploymentDir, "signoz", filename))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create signoz config material: %w", err)
|
||||
return nil, foundryerrors.Wrapf(err, foundryerrors.TypeInternal, "failed to create signoz config material")
|
||||
}
|
||||
materials = append(materials, material)
|
||||
}
|
||||
@@ -92,7 +92,7 @@ func (casting *dockerComposeCasting) Forge(ctx context.Context, config installat
|
||||
for filename, content := range config.Spec.Ingester.Spec.Config.Data {
|
||||
material, err := domain.NewYAMLMaterial([]byte(content), filepath.Join(rootcasting.DeploymentDir, "ingester", filename))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create ingester config material: %w", err)
|
||||
return nil, foundryerrors.Wrapf(err, foundryerrors.TypeInternal, "failed to create ingester config material")
|
||||
}
|
||||
materials = append(materials, material)
|
||||
}
|
||||
@@ -106,7 +106,7 @@ func (casting *dockerComposeCasting) Cast(ctx context.Context, config installati
|
||||
// Check if compose file exists
|
||||
composeFile := filepath.Join(outputPath, rootcasting.DeploymentDir, "compose.yaml")
|
||||
if _, err := os.Stat(composeFile); os.IsNotExist(err) {
|
||||
return fmt.Errorf("compose file does not exist at path: %s", composeFile)
|
||||
return foundryerrors.Newf(foundryerrors.TypeNotFound, "compose file does not exist at path: %s", composeFile)
|
||||
}
|
||||
|
||||
// Create a context with 5-minute timeout
|
||||
@@ -117,7 +117,7 @@ func (casting *dockerComposeCasting) Cast(ctx context.Context, config installati
|
||||
composeCmd, err := getComposeCommand(runctx)
|
||||
if err != nil {
|
||||
casting.logger.ErrorContext(runctx, "Docker compose not available", slog.String("error", err.Error()))
|
||||
return fmt.Errorf("docker compose not available: %w", err)
|
||||
return foundryerrors.Wrapf(err, foundryerrors.TypeNotFound, "docker compose not available")
|
||||
}
|
||||
|
||||
args := append(composeCmd[1:], "-f", composeFile, "up", "-d")
|
||||
@@ -143,7 +143,7 @@ func getComposeMaterial(config *installation.Casting, path string) (domain.Struc
|
||||
buf := bytes.NewBuffer(nil)
|
||||
err := composeYAMLTemplate.Execute(buf, config)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to execute compose yaml template: %w", err)
|
||||
return nil, foundryerrors.Wrapf(err, foundryerrors.TypeInternal, "failed to execute compose yaml template")
|
||||
}
|
||||
|
||||
return domain.NewYAMLMaterial(buf.Bytes(), path)
|
||||
|
||||
@@ -2,7 +2,6 @@ package dockercomposecasting
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
@@ -10,6 +9,7 @@ import (
|
||||
"github.com/signoz/foundry/api/v1alpha1/installation"
|
||||
rootcasting "github.com/signoz/foundry/internal/casting"
|
||||
"github.com/signoz/foundry/internal/domain"
|
||||
"github.com/signoz/foundry/internal/errors"
|
||||
"github.com/signoz/foundry/internal/molding"
|
||||
)
|
||||
|
||||
@@ -22,7 +22,7 @@ type dockerComposeMoldingEnricher struct {
|
||||
func newDockerComposeMoldingEnricher(config *installation.Casting) (*dockerComposeMoldingEnricher, error) {
|
||||
material, err := getComposeMaterial(config, filepath.Join(rootcasting.DeploymentDir, "compose.yaml"))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get compose yaml material: %w", err)
|
||||
return nil, errors.Wrapf(err, errors.TypeInternal, "failed to get compose yaml material")
|
||||
}
|
||||
|
||||
return &dockerComposeMoldingEnricher{material: material}, nil
|
||||
@@ -34,7 +34,7 @@ func (enricher *dockerComposeMoldingEnricher) EnrichStatus(ctx context.Context,
|
||||
// Get telemetrystore container names
|
||||
containerNames, err := enricher.material.GetStringSlice("services|@keys")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get telemetrystore container names: %w", err)
|
||||
return errors.Wrapf(err, errors.TypeInternal, "failed to get telemetrystore container names")
|
||||
}
|
||||
|
||||
var telemetrystoreContainerNames []string
|
||||
@@ -50,7 +50,7 @@ func (enricher *dockerComposeMoldingEnricher) EnrichStatus(ctx context.Context,
|
||||
// Get signoz container names
|
||||
containerNames, err := enricher.material.GetStringSlice("services|@keys")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get signoz container names: %w", err)
|
||||
return errors.Wrapf(err, errors.TypeInternal, "failed to get signoz container names")
|
||||
}
|
||||
|
||||
var apiServerAddr []string
|
||||
@@ -68,7 +68,7 @@ func (enricher *dockerComposeMoldingEnricher) EnrichStatus(ctx context.Context,
|
||||
// Get telemetrykeeper container names (using service keys since they match container_name)
|
||||
containerNames, err := enricher.material.GetStringSlice("services|@keys")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get telemetrykeeper container names: %w", err)
|
||||
return errors.Wrapf(err, errors.TypeInternal, "failed to get telemetrykeeper container names")
|
||||
}
|
||||
|
||||
var telemetrykeeperContainerNames []string
|
||||
@@ -97,7 +97,7 @@ func (enricher *dockerComposeMoldingEnricher) EnrichStatus(ctx context.Context,
|
||||
// Get metastore container names
|
||||
containerNames, err := enricher.material.GetStringSlice("services|@keys")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get metastore container names: %w", err)
|
||||
return errors.Wrapf(err, errors.TypeInternal, "failed to get metastore container names")
|
||||
}
|
||||
|
||||
var metastoreContainerNames []string
|
||||
@@ -113,7 +113,7 @@ func (enricher *dockerComposeMoldingEnricher) EnrichStatus(ctx context.Context,
|
||||
// Get ingester container names
|
||||
containerNames, err := enricher.material.GetStringSlice("services|@keys")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get ingester container names: %w", err)
|
||||
return errors.Wrapf(err, errors.TypeInternal, "failed to get ingester container names")
|
||||
}
|
||||
|
||||
var ingesterContainerNames []string
|
||||
|
||||
@@ -3,7 +3,6 @@ package dockerswarmcasting
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"os"
|
||||
"os/exec"
|
||||
@@ -14,6 +13,7 @@ import (
|
||||
"github.com/signoz/foundry/api/v1alpha1/installation"
|
||||
rootcasting "github.com/signoz/foundry/internal/casting"
|
||||
"github.com/signoz/foundry/internal/domain"
|
||||
"github.com/signoz/foundry/internal/errors"
|
||||
"github.com/signoz/foundry/internal/molding"
|
||||
)
|
||||
|
||||
@@ -42,12 +42,12 @@ func (casting *dockerSwarmCasting) Forge(ctx context.Context, config installatio
|
||||
buf := bytes.NewBuffer(nil)
|
||||
err := composeYAMLTemplate.Execute(buf, config)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to execute compose yaml template: %w", err)
|
||||
return nil, errors.Wrapf(err, errors.TypeInternal, "failed to execute compose yaml template")
|
||||
}
|
||||
|
||||
composeMaterial, err := domain.NewYAMLMaterial(buf.Bytes(), filepath.Join(rootcasting.DeploymentDir, "compose.yaml"))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create compose yaml material: %w", err)
|
||||
return nil, errors.Wrapf(err, errors.TypeInternal, "failed to create compose yaml material")
|
||||
}
|
||||
|
||||
materials := []domain.Material{composeMaterial}
|
||||
@@ -55,7 +55,7 @@ func (casting *dockerSwarmCasting) Forge(ctx context.Context, config installatio
|
||||
for filename, content := range config.Spec.TelemetryKeeper.Spec.Config.Data {
|
||||
material, err := domain.NewYAMLMaterial([]byte(content), filepath.Join(rootcasting.DeploymentDir, "telemetrykeeper", config.Spec.TelemetryKeeper.Kind.String(), filename))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create telemetrykeeper config material: %w", err)
|
||||
return nil, errors.Wrapf(err, errors.TypeInternal, "failed to create telemetrykeeper config material")
|
||||
}
|
||||
materials = append(materials, material)
|
||||
}
|
||||
@@ -63,7 +63,7 @@ func (casting *dockerSwarmCasting) Forge(ctx context.Context, config installatio
|
||||
for filename, content := range config.Spec.TelemetryStore.Spec.Config.Data {
|
||||
material, err := domain.NewYAMLMaterial([]byte(content), filepath.Join(rootcasting.DeploymentDir, "telemetrystore", config.Spec.TelemetryStore.Kind.String(), filename))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create telemetrystore config material: %w", err)
|
||||
return nil, errors.Wrapf(err, errors.TypeInternal, "failed to create telemetrystore config material")
|
||||
}
|
||||
materials = append(materials, material)
|
||||
}
|
||||
@@ -71,7 +71,7 @@ func (casting *dockerSwarmCasting) Forge(ctx context.Context, config installatio
|
||||
for filename, content := range config.Spec.MetaStore.Spec.Config.Data {
|
||||
material, err := domain.NewYAMLMaterial([]byte(content), filepath.Join(rootcasting.DeploymentDir, "metastore", config.Spec.MetaStore.Kind.String(), filename))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create metastore config material: %w", err)
|
||||
return nil, errors.Wrapf(err, errors.TypeInternal, "failed to create metastore config material")
|
||||
}
|
||||
materials = append(materials, material)
|
||||
}
|
||||
@@ -79,7 +79,7 @@ func (casting *dockerSwarmCasting) Forge(ctx context.Context, config installatio
|
||||
for filename, content := range config.Spec.Signoz.Spec.Config.Data {
|
||||
material, err := domain.NewYAMLMaterial([]byte(content), filepath.Join(rootcasting.DeploymentDir, "signoz", filename))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create signoz config material: %w", err)
|
||||
return nil, errors.Wrapf(err, errors.TypeInternal, "failed to create signoz config material")
|
||||
}
|
||||
materials = append(materials, material)
|
||||
}
|
||||
@@ -87,7 +87,7 @@ func (casting *dockerSwarmCasting) Forge(ctx context.Context, config installatio
|
||||
for filename, content := range config.Spec.Ingester.Spec.Config.Data {
|
||||
material, err := domain.NewYAMLMaterial([]byte(content), filepath.Join(rootcasting.DeploymentDir, "ingester", filename))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create ingester config material: %w", err)
|
||||
return nil, errors.Wrapf(err, errors.TypeInternal, "failed to create ingester config material")
|
||||
}
|
||||
materials = append(materials, material)
|
||||
}
|
||||
@@ -100,7 +100,7 @@ func (casting *dockerSwarmCasting) Cast(ctx context.Context, config installation
|
||||
|
||||
composeFile := filepath.Join(outputPath, rootcasting.DeploymentDir, "compose.yaml")
|
||||
if _, err := os.Stat(composeFile); os.IsNotExist(err) {
|
||||
return fmt.Errorf("compose file does not exist at path: %s", composeFile)
|
||||
return errors.Newf(errors.TypeNotFound, "compose file does not exist at path: %s", composeFile)
|
||||
}
|
||||
|
||||
runctx, cancel := context.WithTimeout(ctx, 5*time.Minute)
|
||||
@@ -131,7 +131,7 @@ func getComposeMaterial(config *installation.Casting, path string) (domain.Struc
|
||||
buf := bytes.NewBuffer(nil)
|
||||
err := composeYAMLTemplate.Execute(buf, config)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to execute compose yaml template: %w", err)
|
||||
return nil, errors.Wrapf(err, errors.TypeInternal, "failed to execute compose yaml template")
|
||||
}
|
||||
|
||||
return domain.NewYAMLMaterial(buf.Bytes(), path)
|
||||
|
||||
@@ -2,7 +2,6 @@ package dockerswarmcasting
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
@@ -10,6 +9,7 @@ import (
|
||||
"github.com/signoz/foundry/api/v1alpha1/installation"
|
||||
rootcasting "github.com/signoz/foundry/internal/casting"
|
||||
"github.com/signoz/foundry/internal/domain"
|
||||
"github.com/signoz/foundry/internal/errors"
|
||||
"github.com/signoz/foundry/internal/molding"
|
||||
)
|
||||
|
||||
@@ -22,7 +22,7 @@ type dockerSwarmMoldingEnricher struct {
|
||||
func newDockerSwarmMoldingEnricher(config *installation.Casting) (*dockerSwarmMoldingEnricher, error) {
|
||||
material, err := getComposeMaterial(config, filepath.Join(rootcasting.DeploymentDir, "compose.yaml"))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get compose yaml material: %w", err)
|
||||
return nil, errors.Wrapf(err, errors.TypeInternal, "failed to get compose yaml material")
|
||||
}
|
||||
|
||||
return &dockerSwarmMoldingEnricher{material: material}, nil
|
||||
@@ -33,7 +33,7 @@ func (enricher *dockerSwarmMoldingEnricher) EnrichStatus(ctx context.Context, ki
|
||||
case v1alpha1.MoldingKindTelemetryStore:
|
||||
containerNames, err := enricher.material.GetStringSlice("services|@keys")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get telemetrystore service names: %w", err)
|
||||
return errors.Wrapf(err, errors.TypeInternal, "failed to get telemetrystore service names")
|
||||
}
|
||||
|
||||
var telemetrystoreAddresses []string
|
||||
@@ -48,7 +48,7 @@ func (enricher *dockerSwarmMoldingEnricher) EnrichStatus(ctx context.Context, ki
|
||||
case v1alpha1.MoldingKindSignoz:
|
||||
containerNames, err := enricher.material.GetStringSlice("services|@keys")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get signoz service names: %w", err)
|
||||
return errors.Wrapf(err, errors.TypeInternal, "failed to get signoz service names")
|
||||
}
|
||||
|
||||
var apiServerAddr []string
|
||||
@@ -65,7 +65,7 @@ func (enricher *dockerSwarmMoldingEnricher) EnrichStatus(ctx context.Context, ki
|
||||
case v1alpha1.MoldingKindTelemetryKeeper:
|
||||
containerNames, err := enricher.material.GetStringSlice("services|@keys")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get telemetrykeeper service names: %w", err)
|
||||
return errors.Wrapf(err, errors.TypeInternal, "failed to get telemetrykeeper service names")
|
||||
}
|
||||
|
||||
var clientAddresses []string
|
||||
@@ -87,7 +87,7 @@ func (enricher *dockerSwarmMoldingEnricher) EnrichStatus(ctx context.Context, ki
|
||||
case v1alpha1.MoldingKindMetaStore:
|
||||
containerNames, err := enricher.material.GetStringSlice("services|@keys")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get metastore service names: %w", err)
|
||||
return errors.Wrapf(err, errors.TypeInternal, "failed to get metastore service names")
|
||||
}
|
||||
|
||||
var metastoreAddresses []string
|
||||
@@ -101,7 +101,7 @@ func (enricher *dockerSwarmMoldingEnricher) EnrichStatus(ctx context.Context, ki
|
||||
case v1alpha1.MoldingKindIngester:
|
||||
containerNames, err := enricher.material.GetStringSlice("services|@keys")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get ingester service names: %w", err)
|
||||
return errors.Wrapf(err, errors.TypeInternal, "failed to get ingester service names")
|
||||
}
|
||||
|
||||
var ingesterAddresses []string
|
||||
|
||||
@@ -2,7 +2,6 @@ package ecsterraformcasting
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"os"
|
||||
"os/exec"
|
||||
@@ -13,6 +12,7 @@ import (
|
||||
"github.com/signoz/foundry/api/v1alpha1/installation"
|
||||
rootcasting "github.com/signoz/foundry/internal/casting"
|
||||
"github.com/signoz/foundry/internal/domain"
|
||||
"github.com/signoz/foundry/internal/errors"
|
||||
"github.com/signoz/foundry/internal/molding"
|
||||
)
|
||||
|
||||
@@ -162,7 +162,7 @@ func (c *ecsCasting) Cast(ctx context.Context, config installation.Casting, outp
|
||||
|
||||
// Verify terraform files exist
|
||||
if _, err := os.Stat(filepath.Join(deploymentDir, "main.tf.json")); os.IsNotExist(err) {
|
||||
return fmt.Errorf("terraform files do not exist at path: %s; run forge first", deploymentDir)
|
||||
return errors.Newf(errors.TypeNotFound, "terraform files do not exist at path: %s; run forge first", deploymentDir)
|
||||
}
|
||||
|
||||
// Create a context with 10-minute timeout (terraform can be slow)
|
||||
@@ -176,7 +176,7 @@ func (c *ecsCasting) Cast(ctx context.Context, config installation.Casting, outp
|
||||
initCmd.Stderr = os.Stderr
|
||||
if err := initCmd.Run(); err != nil {
|
||||
c.logger.ErrorContext(runctx, "terraform init failed", slog.String("error", err.Error()))
|
||||
return fmt.Errorf("terraform init failed: %w", err)
|
||||
return errors.Wrapf(err, errors.TypeInternal, "terraform init failed")
|
||||
}
|
||||
|
||||
// Run terraform apply
|
||||
@@ -189,7 +189,7 @@ func (c *ecsCasting) Cast(ctx context.Context, config installation.Casting, outp
|
||||
applyCmd.Stderr = os.Stderr
|
||||
if err := applyCmd.Run(); err != nil {
|
||||
c.logger.ErrorContext(runctx, "terraform apply failed", slog.String("error", err.Error()))
|
||||
return fmt.Errorf("terraform apply failed: %w", err)
|
||||
return errors.Wrapf(err, errors.TypeInternal, "terraform apply failed")
|
||||
}
|
||||
|
||||
c.logger.InfoContext(runctx, "Terraform apply completed successfully")
|
||||
@@ -210,11 +210,11 @@ func getMaterials(config *installation.Casting) ([]domain.StructuredMaterial, er
|
||||
} {
|
||||
m, err := tmpl.Render(*config, tmpl.Path())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create material: %w", err)
|
||||
return nil, errors.Wrapf(err, errors.TypeInternal, "failed to create material")
|
||||
}
|
||||
sm, ok := m.(domain.StructuredMaterial)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("template %s does not produce a structured material", tmpl.Path())
|
||||
return nil, errors.Newf(errors.TypeInternal, "template %s does not produce a structured material", tmpl.Path())
|
||||
}
|
||||
materials = append(materials, sm)
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"github.com/signoz/foundry/api/v1alpha1"
|
||||
"github.com/signoz/foundry/api/v1alpha1/installation"
|
||||
"github.com/signoz/foundry/internal/domain"
|
||||
"github.com/signoz/foundry/internal/errors"
|
||||
"github.com/signoz/foundry/internal/molding"
|
||||
)
|
||||
|
||||
@@ -28,7 +29,7 @@ type ecsMoldingEnricher struct {
|
||||
func newEcsMoldingEnricher(config *installation.Casting) (*ecsMoldingEnricher, error) {
|
||||
materials, err := getMaterials(config)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get materials: %w", err)
|
||||
return nil, errors.Wrapf(err, errors.TypeInternal, "failed to get materials")
|
||||
}
|
||||
|
||||
return &ecsMoldingEnricher{materials: materials}, nil
|
||||
@@ -37,7 +38,7 @@ func newEcsMoldingEnricher(config *installation.Casting) (*ecsMoldingEnricher, e
|
||||
func (enricher *ecsMoldingEnricher) EnrichStatus(ctx context.Context, kind v1alpha1.MoldingKind, config *installation.Casting) error {
|
||||
namespaceBytes, err := enricher.materials[0].GetBytes("resource.aws_service_discovery_private_dns_namespace.main.name")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get namespace: %w", err)
|
||||
return errors.Wrapf(err, errors.TypeInternal, "failed to get namespace")
|
||||
}
|
||||
namespace := string(namespaceBytes)
|
||||
|
||||
@@ -45,7 +46,7 @@ func (enricher *ecsMoldingEnricher) EnrichStatus(ctx context.Context, kind v1alp
|
||||
case v1alpha1.MoldingKindTelemetryStore:
|
||||
sdName, err := enricher.materials[1].GetBytes("resource.aws_service_discovery_service.telemetrystore.name")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get telemetrystore service discovery name: %w", err)
|
||||
return errors.Wrapf(err, errors.TypeInternal, "failed to get telemetrystore service discovery name")
|
||||
}
|
||||
fqdn := fmt.Sprintf("%s.%s", string(sdName), namespace)
|
||||
config.Spec.TelemetryStore.Status.Addresses.TCP = []string{domain.MustNewAddress("tcp", fqdn, telemetryStorePort).String()}
|
||||
@@ -53,7 +54,7 @@ func (enricher *ecsMoldingEnricher) EnrichStatus(ctx context.Context, kind v1alp
|
||||
case v1alpha1.MoldingKindTelemetryKeeper:
|
||||
sdName, err := enricher.materials[2].GetBytes("resource.aws_service_discovery_service.telemetrykeeper.name")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get telemetrykeeper service discovery name: %w", err)
|
||||
return errors.Wrapf(err, errors.TypeInternal, "failed to get telemetrykeeper service discovery name")
|
||||
}
|
||||
fqdn := fmt.Sprintf("%s.%s", string(sdName), namespace)
|
||||
config.Spec.TelemetryKeeper.Status.Addresses.Client = []string{domain.MustNewAddress("tcp", fqdn, telemetryKeeperClientPort).String()}
|
||||
@@ -62,7 +63,7 @@ func (enricher *ecsMoldingEnricher) EnrichStatus(ctx context.Context, kind v1alp
|
||||
case v1alpha1.MoldingKindMetaStore:
|
||||
sdName, err := enricher.materials[3].GetBytes("resource.aws_service_discovery_service.metastore.name")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get metastore service discovery name: %w", err)
|
||||
return errors.Wrapf(err, errors.TypeInternal, "failed to get metastore service discovery name")
|
||||
}
|
||||
fqdn := fmt.Sprintf("%s.%s", string(sdName), namespace)
|
||||
config.Spec.MetaStore.Status.Addresses.DSN = []string{domain.MustNewAddress("tcp", fqdn, metaStorePort).String()}
|
||||
@@ -70,7 +71,7 @@ func (enricher *ecsMoldingEnricher) EnrichStatus(ctx context.Context, kind v1alp
|
||||
case v1alpha1.MoldingKindSignoz:
|
||||
sdName, err := enricher.materials[4].GetBytes("resource.aws_service_discovery_service.signoz.name")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get signoz service discovery name: %w", err)
|
||||
return errors.Wrapf(err, errors.TypeInternal, "failed to get signoz service discovery name")
|
||||
}
|
||||
fqdn := fmt.Sprintf("%s.%s", string(sdName), namespace)
|
||||
config.Spec.Signoz.Status.Addresses.APIServer = []string{domain.MustNewAddress("tcp", fqdn, signozAPIPort).String()}
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"github.com/signoz/foundry/api/v1alpha1/installation"
|
||||
rootcasting "github.com/signoz/foundry/internal/casting"
|
||||
"github.com/signoz/foundry/internal/domain"
|
||||
"github.com/signoz/foundry/internal/errors"
|
||||
"github.com/signoz/foundry/internal/molding"
|
||||
"helm.sh/helm/v3/pkg/action"
|
||||
"helm.sh/helm/v3/pkg/chart/loader"
|
||||
@@ -55,14 +56,14 @@ func (c *helmCasting) Forge(ctx context.Context, config installation.Casting, po
|
||||
buf := bytes.NewBuffer(nil)
|
||||
err := valuesYAMLTemplate.Execute(buf, config)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to execute values yaml template: %w", err)
|
||||
return nil, errors.Wrapf(err, errors.TypeInternal, "failed to execute values yaml template")
|
||||
}
|
||||
|
||||
valuesBytes := buf.Bytes()
|
||||
|
||||
valuesMaterial, err := domain.NewYAMLMaterial(valuesBytes, filepath.Join(rootcasting.DeploymentDir, "values.yaml"))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create values yaml material: %w", err)
|
||||
return nil, errors.Wrapf(err, errors.TypeInternal, "failed to create values yaml material")
|
||||
}
|
||||
|
||||
return []domain.Material{valuesMaterial}, nil
|
||||
@@ -72,17 +73,17 @@ func (c *helmCasting) Cast(ctx context.Context, config installation.Casting, pou
|
||||
|
||||
valuesFile := filepath.Join(poursPath, rootcasting.DeploymentDir, "values.yaml")
|
||||
if _, err := os.Stat(valuesFile); os.IsNotExist(err) {
|
||||
return fmt.Errorf("values.yaml does not exist at path %s, run 'forge' first", valuesFile)
|
||||
return errors.Newf(errors.TypeNotFound, "values.yaml does not exist at path %s, run 'forge' first", valuesFile)
|
||||
}
|
||||
|
||||
valuesBytes, err := os.ReadFile(valuesFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read values file: %w", err)
|
||||
return errors.Wrapf(err, errors.TypeInternal, "failed to read values file")
|
||||
}
|
||||
|
||||
vals := map[string]any{}
|
||||
if err := yaml.Unmarshal(valuesBytes, &vals); err != nil {
|
||||
return fmt.Errorf("failed to parse values: %w", err)
|
||||
return errors.Wrapf(err, errors.TypeInvalidInput, "failed to parse values")
|
||||
}
|
||||
|
||||
settings := cli.New()
|
||||
@@ -92,14 +93,14 @@ func (c *helmCasting) Cast(ctx context.Context, config installation.Casting, pou
|
||||
if err := actionConfig.Init(settings.RESTClientGetter(), config.Metadata.Name, os.Getenv("HELM_DRIVER"), func(format string, v ...any) {
|
||||
c.logger.Debug(fmt.Sprintf(format, v...))
|
||||
}); err != nil {
|
||||
return fmt.Errorf("failed to initialize helm action config: %w", err)
|
||||
return errors.Wrapf(err, errors.TypeInternal, "failed to initialize helm action config")
|
||||
}
|
||||
|
||||
var chartRef string
|
||||
if c.shouldForgeChart(&config) {
|
||||
chartRef = filepath.Join(poursPath, rootcasting.DeploymentDir, "chart", "signoz")
|
||||
if _, err := os.Stat(chartRef); os.IsNotExist(err) {
|
||||
return fmt.Errorf("local chart not found at %s, run 'forge' first with %s annotation set to 'true'", chartRef, annotationForgeChart)
|
||||
return errors.Newf(errors.TypeNotFound, "local chart not found at %s, run 'forge' first with %s annotation set to 'true'", chartRef, annotationForgeChart)
|
||||
}
|
||||
c.logger.InfoContext(ctx, "Installing from local chart", slog.String("path", chartRef))
|
||||
} else {
|
||||
@@ -126,7 +127,7 @@ func (c *helmCasting) Cast(ctx context.Context, config installation.Casting, pou
|
||||
|
||||
c.logger.InfoContext(ctx, "Adding Helm repo", slog.String("name", repoName), slog.String("url", repoURL), slog.String("chart", chartRef))
|
||||
if err := addHelmRepo(settings, repoName, repoURL); err != nil {
|
||||
return fmt.Errorf("failed to add helm repo: %w", err)
|
||||
return errors.Wrapf(err, errors.TypeInternal, "failed to add helm repo")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,16 +151,16 @@ func (c *helmCasting) Cast(ctx context.Context, config installation.Casting, pou
|
||||
|
||||
chartPath, err := install.LocateChart(chartRef, settings)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to locate chart: %w", err)
|
||||
return errors.Wrapf(err, errors.TypeInternal, "failed to locate chart")
|
||||
}
|
||||
|
||||
chart, err := loader.Load(chartPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to load chart: %w", err)
|
||||
return errors.Wrapf(err, errors.TypeInternal, "failed to load chart")
|
||||
}
|
||||
|
||||
if _, err := install.RunWithContext(ctx, chart, vals); err != nil {
|
||||
return fmt.Errorf("helm install failed: %w", err)
|
||||
return errors.Wrapf(err, errors.TypeInternal, "helm install failed")
|
||||
}
|
||||
} else {
|
||||
upgrade := action.NewUpgrade(actionConfig)
|
||||
@@ -169,16 +170,16 @@ func (c *helmCasting) Cast(ctx context.Context, config installation.Casting, pou
|
||||
|
||||
chartPath, err := upgrade.LocateChart(chartRef, settings)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to locate chart: %w", err)
|
||||
return errors.Wrapf(err, errors.TypeInternal, "failed to locate chart")
|
||||
}
|
||||
|
||||
chart, err := loader.Load(chartPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to load chart: %w", err)
|
||||
return errors.Wrapf(err, errors.TypeInternal, "failed to load chart")
|
||||
}
|
||||
|
||||
if _, err := upgrade.RunWithContext(ctx, config.Metadata.Name, chart, vals); err != nil {
|
||||
return fmt.Errorf("helm upgrade failed: %w", err)
|
||||
return errors.Wrapf(err, errors.TypeInternal, "helm upgrade failed")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,12 +206,12 @@ func addHelmRepo(settings *cli.EnvSettings, name, url string) error {
|
||||
|
||||
r, err := repo.NewChartRepository(repoEntry, getter.All(settings))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create chart repository: %w", err)
|
||||
return errors.Wrapf(err, errors.TypeInternal, "failed to create chart repository")
|
||||
}
|
||||
|
||||
r.CachePath = settings.RepositoryCache
|
||||
if _, err := r.DownloadIndexFile(); err != nil {
|
||||
return fmt.Errorf("failed to download repo index: %w", err)
|
||||
return errors.Wrapf(err, errors.TypeInternal, "failed to download repo index")
|
||||
}
|
||||
|
||||
f, err := repo.LoadFile(repoFile)
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"github.com/signoz/foundry/api/v1alpha1/installation"
|
||||
rootcasting "github.com/signoz/foundry/internal/casting"
|
||||
"github.com/signoz/foundry/internal/domain"
|
||||
"github.com/signoz/foundry/internal/errors"
|
||||
"github.com/signoz/foundry/internal/molding"
|
||||
)
|
||||
|
||||
@@ -69,7 +70,7 @@ func (c *kustomizeCasting) Forge(ctx context.Context, cfg installation.Casting,
|
||||
for _, tmpl := range c.castings {
|
||||
m, err := c.forgeCasting(tmpl, &cfg, poursPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to forge: %w", err)
|
||||
return nil, errors.Wrapf(err, errors.TypeInternal, "failed to forge")
|
||||
}
|
||||
materials = append(materials, m...)
|
||||
}
|
||||
@@ -90,14 +91,14 @@ func (c *kustomizeCasting) Cast(ctx context.Context, config installation.Casting
|
||||
|
||||
kustomizeDir := filepath.Join(poursPath, rootcasting.DeploymentDir)
|
||||
if _, err := os.Stat(filepath.Join(kustomizeDir, "kustomization.yaml")); os.IsNotExist(err) {
|
||||
return fmt.Errorf("kustomization.yaml does not exist at path: %s, run 'forge' first", kustomizeDir)
|
||||
return errors.Newf(errors.TypeNotFound, "kustomization.yaml does not exist at path: %s, run 'forge' first", kustomizeDir)
|
||||
}
|
||||
|
||||
runctx, cancel := context.WithTimeout(ctx, 5*time.Minute)
|
||||
defer cancel()
|
||||
|
||||
if err := c.applyCRDs(runctx); err != nil {
|
||||
return fmt.Errorf("failed to apply CRDs: %w", err)
|
||||
return errors.Wrapf(err, errors.TypeInternal, "failed to apply CRDs")
|
||||
}
|
||||
|
||||
cmd := exec.CommandContext(runctx, "kubectl", "apply", "-k", kustomizeDir)
|
||||
@@ -109,7 +110,7 @@ func (c *kustomizeCasting) Cast(ctx context.Context, config installation.Casting
|
||||
|
||||
if err := cmd.Run(); err != nil {
|
||||
c.logger.ErrorContext(runctx, "kubectl apply failed", slog.String("error", err.Error()))
|
||||
return fmt.Errorf("kubectl apply -k failed: %w", err)
|
||||
return errors.Wrapf(err, errors.TypeInternal, "kubectl apply -k failed")
|
||||
}
|
||||
|
||||
c.logger.InfoContext(runctx, "Kustomize manifests applied successfully")
|
||||
@@ -133,7 +134,7 @@ func (c *kustomizeCasting) applyCRDs(ctx context.Context) error {
|
||||
c.logger.DebugContext(ctx, "Applying CRD", slog.String("url", url))
|
||||
|
||||
if err := cmd.Run(); err != nil {
|
||||
return fmt.Errorf("failed to apply CRD %s: %w", crd, err)
|
||||
return errors.Wrapf(err, errors.TypeInternal, "failed to apply CRD %s", crd)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,7 +148,7 @@ func (c *kustomizeCasting) forgeCasting(tmpl *domain.Template, cfg *installation
|
||||
path := filepath.Join(rootcasting.DeploymentDir, relPath)
|
||||
material, err := tmpl.Render(cfg, path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("render template %s: %w", templatePath, err)
|
||||
return nil, errors.Wrapf(err, errors.TypeInternal, "render template %s", templatePath)
|
||||
}
|
||||
return []domain.Material{material}, nil
|
||||
}
|
||||
@@ -175,11 +176,11 @@ func renderStructured(config *installation.Casting, items []templateAt) ([]domai
|
||||
for _, item := range items {
|
||||
m, err := item.tmpl.Render(config, item.path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("render template %s: %w", item.tmpl.Path(), err)
|
||||
return nil, errors.Wrapf(err, errors.TypeInternal, "render template %s", item.tmpl.Path())
|
||||
}
|
||||
sm, ok := m.(domain.StructuredMaterial)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("template %s does not produce a structured material", item.tmpl.Path())
|
||||
return nil, errors.Newf(errors.TypeInternal, "template %s does not produce a structured material", item.tmpl.Path())
|
||||
}
|
||||
materials = append(materials, sm)
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"github.com/signoz/foundry/api/v1alpha1"
|
||||
"github.com/signoz/foundry/api/v1alpha1/installation"
|
||||
"github.com/signoz/foundry/internal/domain"
|
||||
"github.com/signoz/foundry/internal/errors"
|
||||
"github.com/signoz/foundry/internal/molding"
|
||||
)
|
||||
|
||||
@@ -27,12 +28,12 @@ type kustomizeMoldingEnricher struct {
|
||||
func newKustomizeMoldingEnricher(config *installation.Casting) (*kustomizeMoldingEnricher, error) {
|
||||
materials, err := getServiceMaterials(config)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get service yaml material: %w", err)
|
||||
return nil, errors.Wrapf(err, errors.TypeInternal, "failed to get service yaml material")
|
||||
}
|
||||
|
||||
overrideMaterials, err := getOverrideMaterials(config)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get override materials: %w", err)
|
||||
return nil, errors.Wrapf(err, errors.TypeInternal, "failed to get override materials")
|
||||
}
|
||||
|
||||
return &kustomizeMoldingEnricher{
|
||||
@@ -60,7 +61,7 @@ func (e *kustomizeMoldingEnricher) EnrichStatus(ctx context.Context, kind v1alph
|
||||
func (e *kustomizeMoldingEnricher) enrichTelemetryStore(config *installation.Casting) error {
|
||||
name, err := e.materials[0].GetBytes("spec.templates.serviceTemplates.0.generateName")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get telemetrystore service names: %w", err)
|
||||
return errors.Wrapf(err, errors.TypeInternal, "failed to get telemetrystore service names")
|
||||
}
|
||||
config.Spec.TelemetryStore.Status.Addresses.TCP = []string{domain.MustNewAddress("tcp", string(name), telemetryStorePort).String()}
|
||||
|
||||
@@ -97,7 +98,7 @@ func (e *kustomizeMoldingEnricher) enrichTelemetryKeeper(config *installation.Ca
|
||||
func (e *kustomizeMoldingEnricher) enrichMetaStore(config *installation.Casting) error {
|
||||
name, err := e.materials[1].GetBytes("metadata.name")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get metastore service names: %w", err)
|
||||
return errors.Wrapf(err, errors.TypeInternal, "failed to get metastore service names")
|
||||
}
|
||||
config.Spec.MetaStore.Status.Addresses.DSN = []string{
|
||||
fmt.Sprintf("postgres://%s:5432", name),
|
||||
|
||||
@@ -3,13 +3,13 @@ package railwaytemplatecasting
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/signoz/foundry/api/v1alpha1/installation"
|
||||
"github.com/signoz/foundry/internal/casting"
|
||||
"github.com/signoz/foundry/internal/domain"
|
||||
"github.com/signoz/foundry/internal/errors"
|
||||
"github.com/signoz/foundry/internal/molding"
|
||||
)
|
||||
|
||||
@@ -51,18 +51,18 @@ func (c *railwayTemplateCasting) Forge(ctx context.Context, config installation.
|
||||
if config.Spec.TelemetryKeeper.Spec.IsEnabled() {
|
||||
dockerfileBuf := bytes.NewBuffer(nil)
|
||||
if err := telemetryKeeperDockerfileTemplate.Execute(dockerfileBuf, config); err != nil {
|
||||
return nil, fmt.Errorf("telemetrykeeper dockerfile: %w", err)
|
||||
return nil, errors.Wrapf(err, errors.TypeInternal, "telemetrykeeper dockerfile")
|
||||
}
|
||||
materials = append(materials, domain.NewBlobMaterial(dockerfileBuf.Bytes(), filepath.Join(casting.DeploymentDir, "telemetrykeeper/Dockerfile")))
|
||||
railwayBuf := bytes.NewBuffer(nil)
|
||||
if err := railwayTelemetryKeeperTemplate.Execute(railwayBuf, config); err != nil {
|
||||
return nil, fmt.Errorf("telemetrykeeper railway.json: %w", err)
|
||||
return nil, errors.Wrapf(err, errors.TypeInternal, "telemetrykeeper railway.json")
|
||||
}
|
||||
materials = append(materials, domain.NewBlobMaterial(railwayBuf.Bytes(), filepath.Join(casting.DeploymentDir, "telemetrykeeper/railway.json")))
|
||||
for filename, content := range config.Spec.TelemetryKeeper.Spec.Config.Data {
|
||||
m, err := domain.NewYAMLMaterial([]byte(content), filepath.Join(casting.DeploymentDir, "telemetrykeeper/keeper.d/", filename))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("telemetrykeeper config: %w", err)
|
||||
return nil, errors.Wrapf(err, errors.TypeInternal, "telemetrykeeper config")
|
||||
}
|
||||
materials = append(materials, m)
|
||||
}
|
||||
@@ -72,18 +72,18 @@ func (c *railwayTemplateCasting) Forge(ctx context.Context, config installation.
|
||||
if config.Spec.TelemetryStore.Spec.IsEnabled() {
|
||||
dockerfileBuf := bytes.NewBuffer(nil)
|
||||
if err := telemetryStoreDockerfileTemplate.Execute(dockerfileBuf, config); err != nil {
|
||||
return nil, fmt.Errorf("telemetrystore dockerfile: %w", err)
|
||||
return nil, errors.Wrapf(err, errors.TypeInternal, "telemetrystore dockerfile")
|
||||
}
|
||||
materials = append(materials, domain.NewBlobMaterial(dockerfileBuf.Bytes(), filepath.Join(casting.DeploymentDir, "telemetrystore/Dockerfile")))
|
||||
railwayBuf := bytes.NewBuffer(nil)
|
||||
if err := railwayTelemetryStoreTemplate.Execute(railwayBuf, config); err != nil {
|
||||
return nil, fmt.Errorf("telemetrystore railway.json: %w", err)
|
||||
return nil, errors.Wrapf(err, errors.TypeInternal, "telemetrystore railway.json")
|
||||
}
|
||||
materials = append(materials, domain.NewBlobMaterial(railwayBuf.Bytes(), filepath.Join(casting.DeploymentDir, "telemetrystore/railway.json")))
|
||||
for filename, content := range config.Spec.TelemetryStore.Spec.Config.Data {
|
||||
m, err := domain.NewYAMLMaterial([]byte(content), filepath.Join(casting.DeploymentDir, "telemetrystore/config.d/", filename))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("telemetrystore config: %w", err)
|
||||
return nil, errors.Wrapf(err, errors.TypeInternal, "telemetrystore config")
|
||||
}
|
||||
materials = append(materials, m)
|
||||
}
|
||||
@@ -93,18 +93,18 @@ func (c *railwayTemplateCasting) Forge(ctx context.Context, config installation.
|
||||
if config.Spec.Ingester.Spec.IsEnabled() {
|
||||
dockerfileBuf := bytes.NewBuffer(nil)
|
||||
if err := ingesterDockerfileTemplate.Execute(dockerfileBuf, config); err != nil {
|
||||
return nil, fmt.Errorf("ingester dockerfile: %w", err)
|
||||
return nil, errors.Wrapf(err, errors.TypeInternal, "ingester dockerfile")
|
||||
}
|
||||
materials = append(materials, domain.NewBlobMaterial(dockerfileBuf.Bytes(), filepath.Join(casting.DeploymentDir, "ingester/Dockerfile")))
|
||||
railwayBuf := bytes.NewBuffer(nil)
|
||||
if err := railwayIngesterTemplate.Execute(railwayBuf, config); err != nil {
|
||||
return nil, fmt.Errorf("ingester railway.json: %w", err)
|
||||
return nil, errors.Wrapf(err, errors.TypeInternal, "ingester railway.json")
|
||||
}
|
||||
materials = append(materials, domain.NewBlobMaterial(railwayBuf.Bytes(), filepath.Join(casting.DeploymentDir, "ingester/railway.json")))
|
||||
for filename, content := range config.Spec.Ingester.Spec.Config.Data {
|
||||
m, err := domain.NewYAMLMaterial([]byte(content), filepath.Join(casting.DeploymentDir, "ingester/", filename))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("ingester config: %w", err)
|
||||
return nil, errors.Wrapf(err, errors.TypeInternal, "ingester config")
|
||||
}
|
||||
materials = append(materials, m)
|
||||
}
|
||||
@@ -114,12 +114,12 @@ func (c *railwayTemplateCasting) Forge(ctx context.Context, config installation.
|
||||
if config.Spec.Signoz.Spec.IsEnabled() {
|
||||
dockerfileBuf := bytes.NewBuffer(nil)
|
||||
if err := signozDockerfileTemplate.Execute(dockerfileBuf, config); err != nil {
|
||||
return nil, fmt.Errorf("signoz dockerfile: %w", err)
|
||||
return nil, errors.Wrapf(err, errors.TypeInternal, "signoz dockerfile")
|
||||
}
|
||||
materials = append(materials, domain.NewBlobMaterial(dockerfileBuf.Bytes(), filepath.Join(casting.DeploymentDir, "signoz/Dockerfile")))
|
||||
railwayBuf := bytes.NewBuffer(nil)
|
||||
if err := railwaySignozTemplate.Execute(railwayBuf, config); err != nil {
|
||||
return nil, fmt.Errorf("signoz railway.json: %w", err)
|
||||
return nil, errors.Wrapf(err, errors.TypeInternal, "signoz railway.json")
|
||||
}
|
||||
materials = append(materials, domain.NewBlobMaterial(railwayBuf.Bytes(), filepath.Join(casting.DeploymentDir, "signoz/railway.json")))
|
||||
}
|
||||
@@ -128,12 +128,12 @@ func (c *railwayTemplateCasting) Forge(ctx context.Context, config installation.
|
||||
if config.Spec.TelemetryStore.Spec.IsEnabled() {
|
||||
dockerfileBuf := bytes.NewBuffer(nil)
|
||||
if err := telemetryStoreMigratorDockerfileTemplate.Execute(dockerfileBuf, config); err != nil {
|
||||
return nil, fmt.Errorf("telemetrystore-migrator dockerfile: %w", err)
|
||||
return nil, errors.Wrapf(err, errors.TypeInternal, "telemetrystore-migrator dockerfile")
|
||||
}
|
||||
materials = append(materials, domain.NewBlobMaterial(dockerfileBuf.Bytes(), filepath.Join(casting.DeploymentDir, "telemetrystore-migrator/Dockerfile")))
|
||||
railwayBuf := bytes.NewBuffer(nil)
|
||||
if err := railwayTelemetryStoreMigratorTemplate.Execute(railwayBuf, config); err != nil {
|
||||
return nil, fmt.Errorf("telemetrystore-migrator railway.json: %w", err)
|
||||
return nil, errors.Wrapf(err, errors.TypeInternal, "telemetrystore-migrator railway.json")
|
||||
}
|
||||
materials = append(materials, domain.NewBlobMaterial(railwayBuf.Bytes(), filepath.Join(casting.DeploymentDir, "telemetrystore-migrator/railway.json")))
|
||||
}
|
||||
@@ -151,21 +151,21 @@ func getRailwayMaterial(config *installation.Casting) ([]domain.StructuredMateri
|
||||
|
||||
keeperBuf := bytes.NewBuffer(nil)
|
||||
if err := telemetryKeeperOverrideTemplate.Execute(keeperBuf, config); err != nil {
|
||||
return nil, fmt.Errorf("failed to execute keeper override template: %w", err)
|
||||
return nil, errors.Wrapf(err, errors.TypeInternal, "failed to execute keeper override template")
|
||||
}
|
||||
keeperMaterial, err := domain.NewYAMLMaterial(keeperBuf.Bytes(), "keeper_overrides.yaml")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create keeper override material: %w", err)
|
||||
return nil, errors.Wrapf(err, errors.TypeInternal, "failed to create keeper override material")
|
||||
}
|
||||
materials = append(materials, keeperMaterial)
|
||||
|
||||
storeBuf := bytes.NewBuffer(nil)
|
||||
if err := telemetryStoreOverrideTemplate.Execute(storeBuf, config); err != nil {
|
||||
return nil, fmt.Errorf("failed to execute keeper override template: %w", err)
|
||||
return nil, errors.Wrapf(err, errors.TypeInternal, "failed to execute keeper override template")
|
||||
}
|
||||
storeMaterial, err := domain.NewYAMLMaterial(storeBuf.Bytes(), "store_overrides.yaml")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create keeper override material: %w", err)
|
||||
return nil, errors.Wrapf(err, errors.TypeInternal, "failed to create keeper override material")
|
||||
}
|
||||
materials = append(materials, storeMaterial)
|
||||
return materials, nil
|
||||
|
||||
@@ -2,11 +2,11 @@ package railwaytemplatecasting
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/signoz/foundry/api/v1alpha1"
|
||||
"github.com/signoz/foundry/api/v1alpha1/installation"
|
||||
"github.com/signoz/foundry/internal/domain"
|
||||
"github.com/signoz/foundry/internal/errors"
|
||||
"github.com/signoz/foundry/internal/molding"
|
||||
)
|
||||
|
||||
@@ -19,7 +19,7 @@ type railwayTemplateMoldingEnricher struct {
|
||||
func newRailwayTemplateMoldingEnricher(config *installation.Casting) (*railwayTemplateMoldingEnricher, error) {
|
||||
material, err := getRailwayMaterial(config)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get compose yaml material: %w", err)
|
||||
return nil, errors.Wrapf(err, errors.TypeInternal, "failed to get compose yaml material")
|
||||
}
|
||||
return &railwayTemplateMoldingEnricher{material: material}, nil
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"github.com/signoz/foundry/api/v1alpha1/installation"
|
||||
"github.com/signoz/foundry/internal/casting"
|
||||
"github.com/signoz/foundry/internal/domain"
|
||||
"github.com/signoz/foundry/internal/errors"
|
||||
"github.com/signoz/foundry/internal/molding"
|
||||
)
|
||||
|
||||
@@ -43,7 +44,7 @@ func (c *renderCasting) Forge(ctx context.Context, config installation.Casting,
|
||||
// Generate render.yaml
|
||||
blueprintMaterial, err := getRenderMaterial(&config, filepath.Join(casting.DeploymentDir, "render.yaml"))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create blueprint yaml material: %w", err)
|
||||
return nil, errors.Wrapf(err, errors.TypeInternal, "failed to create blueprint yaml material")
|
||||
}
|
||||
materials = append(materials, blueprintMaterial)
|
||||
|
||||
@@ -52,7 +53,7 @@ func (c *renderCasting) Forge(ctx context.Context, config installation.Casting,
|
||||
dockerfileBuf := bytes.NewBuffer(nil)
|
||||
err := telemetryKeeperDockerfileTemplate.Execute(dockerfileBuf, config)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to execute dockerfile keeper template: %w", err)
|
||||
return nil, errors.Wrapf(err, errors.TypeInternal, "failed to execute dockerfile keeper template")
|
||||
}
|
||||
dockerfileMaterial := domain.NewBlobMaterial(dockerfileBuf.Bytes(), filepath.Join(configsDir, "telemetrykeeper/Dockerfile"))
|
||||
materials = append(materials, dockerfileMaterial)
|
||||
@@ -61,7 +62,7 @@ func (c *renderCasting) Forge(ctx context.Context, config installation.Casting,
|
||||
for filename, content := range config.Spec.TelemetryKeeper.Spec.Config.Data {
|
||||
material, err := domain.NewYAMLMaterial([]byte(content), filepath.Join(configsDir, fmt.Sprintf("telemetrykeeper/keeper.d/%s", filename)))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create telemetrykeeper config material: %w", err)
|
||||
return nil, errors.Wrapf(err, errors.TypeInternal, "failed to create telemetrykeeper config material")
|
||||
}
|
||||
materials = append(materials, material)
|
||||
}
|
||||
@@ -72,7 +73,7 @@ func (c *renderCasting) Forge(ctx context.Context, config installation.Casting,
|
||||
dockerfileBuf := bytes.NewBuffer(nil)
|
||||
err := telemetryStoreDockerfileTemplate.Execute(dockerfileBuf, config)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to execute dockerfile clickhouse template: %w", err)
|
||||
return nil, errors.Wrapf(err, errors.TypeInternal, "failed to execute dockerfile clickhouse template")
|
||||
}
|
||||
dockerfileMaterial := domain.NewBlobMaterial(dockerfileBuf.Bytes(), filepath.Join(configsDir, "telemetrystore/Dockerfile"))
|
||||
materials = append(materials, dockerfileMaterial)
|
||||
@@ -81,7 +82,7 @@ func (c *renderCasting) Forge(ctx context.Context, config installation.Casting,
|
||||
for filename, content := range config.Spec.TelemetryStore.Spec.Config.Data {
|
||||
material, err := domain.NewYAMLMaterial([]byte(content), filepath.Join(configsDir, fmt.Sprintf("telemetrystore/config.d/%s", filename)))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create telemetrystore config material: %w", err)
|
||||
return nil, errors.Wrapf(err, errors.TypeInternal, "failed to create telemetrystore config material")
|
||||
}
|
||||
materials = append(materials, material)
|
||||
}
|
||||
@@ -92,7 +93,7 @@ func (c *renderCasting) Forge(ctx context.Context, config installation.Casting,
|
||||
dockerfileBuf := bytes.NewBuffer(nil)
|
||||
err := ingesterDockerfileTemplate.Execute(dockerfileBuf, config)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to execute dockerfile otel template: %w", err)
|
||||
return nil, errors.Wrapf(err, errors.TypeInternal, "failed to execute dockerfile otel template")
|
||||
}
|
||||
dockerfileMaterial := domain.NewBlobMaterial(dockerfileBuf.Bytes(), filepath.Join(configsDir, "ingester/Dockerfile"))
|
||||
materials = append(materials, dockerfileMaterial)
|
||||
@@ -100,7 +101,7 @@ func (c *renderCasting) Forge(ctx context.Context, config installation.Casting,
|
||||
for filename, content := range config.Spec.Ingester.Spec.Config.Data {
|
||||
material, err := domain.NewYAMLMaterial([]byte(content), filepath.Join(configsDir, fmt.Sprintf("ingester/%s", filename)))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create ingester config material: %w", err)
|
||||
return nil, errors.Wrapf(err, errors.TypeInternal, "failed to create ingester config material")
|
||||
}
|
||||
materials = append(materials, material)
|
||||
}
|
||||
@@ -121,7 +122,7 @@ func getRenderMaterial(config *installation.Casting, path string) (domain.Struct
|
||||
buf := bytes.NewBuffer(nil)
|
||||
err := renderYAMLTemplate.Execute(buf, config)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to execute render yaml template: %w", err)
|
||||
return nil, errors.Wrapf(err, errors.TypeInternal, "failed to execute render yaml template")
|
||||
}
|
||||
return domain.NewYAMLMaterial(buf.Bytes(), path)
|
||||
}
|
||||
|
||||
@@ -2,12 +2,12 @@ package rendercasting
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/signoz/foundry/api/v1alpha1"
|
||||
"github.com/signoz/foundry/api/v1alpha1/installation"
|
||||
"github.com/signoz/foundry/internal/domain"
|
||||
"github.com/signoz/foundry/internal/errors"
|
||||
"github.com/signoz/foundry/internal/molding"
|
||||
)
|
||||
|
||||
@@ -20,7 +20,7 @@ type renderMoldingEnricher struct {
|
||||
func newRenderMoldingEnricher(config *installation.Casting) (*renderMoldingEnricher, error) {
|
||||
material, err := getRenderMaterial(config, "render.yaml")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get render yaml material: %w", err)
|
||||
return nil, errors.Wrapf(err, errors.TypeInternal, "failed to get render yaml material")
|
||||
}
|
||||
|
||||
return &renderMoldingEnricher{material: material}, nil
|
||||
@@ -32,7 +32,7 @@ func (enricher *renderMoldingEnricher) EnrichStatus(ctx context.Context, kind v1
|
||||
// Get telemetrystore service names
|
||||
serviceNames, err := enricher.material.GetStringSlice("services.#.name")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get telemetrystore service names: %w", err)
|
||||
return errors.Wrapf(err, errors.TypeInternal, "failed to get telemetrystore service names")
|
||||
}
|
||||
|
||||
var addrs []string
|
||||
@@ -55,7 +55,7 @@ func (enricher *renderMoldingEnricher) EnrichStatus(ctx context.Context, kind v1
|
||||
// Get telemetrystore service names
|
||||
serviceNames, err := enricher.material.GetStringSlice("services.#.name")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get telemetrystore service names: %w", err)
|
||||
return errors.Wrapf(err, errors.TypeInternal, "failed to get telemetrystore service names")
|
||||
}
|
||||
|
||||
var apiServerAddr []string
|
||||
@@ -73,7 +73,7 @@ func (enricher *renderMoldingEnricher) EnrichStatus(ctx context.Context, kind v1
|
||||
// Get telemetrykeeper service names
|
||||
serviceNames, err := enricher.material.GetStringSlice("services.#.name")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get telemetrykeeper service names: %w", err)
|
||||
return errors.Wrapf(err, errors.TypeInternal, "failed to get telemetrykeeper service names")
|
||||
}
|
||||
|
||||
var addrsClient []string
|
||||
@@ -99,7 +99,7 @@ func (enricher *renderMoldingEnricher) EnrichStatus(ctx context.Context, kind v1
|
||||
// Get ingester service names
|
||||
serviceNames, err := enricher.material.GetStringSlice("services.#.name")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get ingester service names: %w", err)
|
||||
return errors.Wrapf(err, errors.TypeInternal, "failed to get ingester service names")
|
||||
}
|
||||
|
||||
var addrs []string
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"log/slog"
|
||||
|
||||
rootcasting "github.com/signoz/foundry/internal/casting"
|
||||
"github.com/signoz/foundry/internal/errors"
|
||||
"github.com/signoz/foundry/internal/molding"
|
||||
|
||||
"os"
|
||||
@@ -51,7 +52,7 @@ func (c *systemdCasting) Forge(ctx context.Context, cfg installation.Casting, po
|
||||
for _, tmpl := range c.castings {
|
||||
m, err := c.forgeCasting(tmpl, &cfg)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to forge: %w", err)
|
||||
return nil, errors.Wrapf(err, errors.TypeInternal, "failed to forge")
|
||||
}
|
||||
materials = append(materials, m...)
|
||||
}
|
||||
@@ -87,7 +88,7 @@ func (c *systemdCasting) Cast(ctx context.Context, config installation.Casting,
|
||||
}
|
||||
case installation.MetaStoreKindSQLite:
|
||||
if err := os.MkdirAll("/var/lib/signoz", 0755); err != nil {
|
||||
return fmt.Errorf("failed to create sqlite data directory: %w", err)
|
||||
return errors.Wrapf(err, errors.TypeInternal, "failed to create sqlite data directory")
|
||||
}
|
||||
_ = c.execCommand(ctx, "chown", "-R", "signoz:signoz", "/var/lib/signoz")
|
||||
}
|
||||
@@ -289,7 +290,7 @@ func (c *systemdCasting) configMaterials(data map[string]string, component strin
|
||||
for filename, content := range data {
|
||||
m, err := domain.NewYAMLMaterial([]byte(content), filepath.Join(rootcasting.DeploymentDir, component, kind, filename))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create %s config material %s: %w", component, filename, err)
|
||||
return nil, errors.Wrapf(err, errors.TypeInternal, "failed to create %s config material %s", component, filename)
|
||||
}
|
||||
mats = append(mats, m)
|
||||
}
|
||||
@@ -313,7 +314,7 @@ func (c *systemdCasting) discoverAndPrepareServices(ctx context.Context, poursPa
|
||||
deploymentPath := filepath.Join(poursPath, rootcasting.DeploymentDir)
|
||||
entries, err := os.ReadDir(deploymentPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read directory %s: %w", deploymentPath, err)
|
||||
return nil, errors.Wrapf(err, errors.TypeInternal, "failed to read directory %s", deploymentPath)
|
||||
}
|
||||
|
||||
var services []string
|
||||
@@ -331,7 +332,7 @@ func (c *systemdCasting) discoverAndPrepareServices(ctx context.Context, poursPa
|
||||
c.logger.DebugContext(ctx, "Found services", slog.Int("count", len(services)))
|
||||
|
||||
if err := c.execCommand(ctx, "systemctl", "daemon-reload"); err != nil {
|
||||
return nil, fmt.Errorf("systemd daemon-reload failed: %w", err)
|
||||
return nil, errors.Wrapf(err, errors.TypeInternal, "systemd daemon-reload failed")
|
||||
}
|
||||
|
||||
return services, nil
|
||||
@@ -343,13 +344,13 @@ func (c *systemdCasting) setupSystemEnvironment(ctx context.Context, config *ins
|
||||
if _, err := user.Lookup("signoz"); err != nil {
|
||||
c.logger.InfoContext(ctx, "Creating user: signoz")
|
||||
if err := c.execCommand(ctx, "useradd", "-d", poursPath, "signoz"); err != nil {
|
||||
return fmt.Errorf("failed to create signoz user: %w", err)
|
||||
return errors.Wrapf(err, errors.TypeInternal, "failed to create signoz user")
|
||||
}
|
||||
}
|
||||
|
||||
// Setup working directory
|
||||
if err := os.MkdirAll(poursPath, 0755); err != nil {
|
||||
return fmt.Errorf("failed to create working directory %s: %w", poursPath, err)
|
||||
return errors.Wrapf(err, errors.TypeInternal, "failed to create working directory %s", poursPath)
|
||||
}
|
||||
_ = c.execCommand(ctx, "chown", "-R", "signoz:signoz", poursPath) // best effort
|
||||
_ = c.execCommand(ctx, "chown", "-R", "signoz:signoz", "/opt/signoz/") // best effort
|
||||
@@ -358,13 +359,13 @@ func (c *systemdCasting) setupSystemEnvironment(ctx context.Context, config *ins
|
||||
if config.Spec.TelemetryStore.Spec.IsEnabled() {
|
||||
src := filepath.Join(poursPath, rootcasting.DeploymentDir, "telemetrystore", config.Spec.TelemetryStore.Kind.String())
|
||||
if err := c.copyDir(src, "/etc/clickhouse-server/"); err != nil {
|
||||
return fmt.Errorf("failed to copy clickhouse-server configs: %w", err)
|
||||
return errors.Wrapf(err, errors.TypeInternal, "failed to copy clickhouse-server configs")
|
||||
}
|
||||
}
|
||||
if config.Spec.TelemetryKeeper.Spec.IsEnabled() {
|
||||
src := filepath.Join(poursPath, rootcasting.DeploymentDir, "telemetrykeeper", config.Spec.TelemetryKeeper.Kind.String())
|
||||
if err := c.copyDir(src, "/etc/clickhouse-keeper/"); err != nil {
|
||||
return fmt.Errorf("failed to copy clickhouse-keeper configs: %w", err)
|
||||
return errors.Wrapf(err, errors.TypeInternal, "failed to copy clickhouse-keeper configs")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -401,7 +402,7 @@ func (c *systemdCasting) copyDir(srcDir, dstDir string) error {
|
||||
func (c *systemdCasting) validateBinaries(config *installation.Casting) error {
|
||||
annotations := config.Metadata.Annotations
|
||||
if annotations == nil {
|
||||
return fmt.Errorf("no binary paths found in annotations")
|
||||
return errors.Newf(errors.TypeInvalidInput, "no binary paths found in annotations")
|
||||
}
|
||||
|
||||
var missing []string
|
||||
@@ -421,7 +422,7 @@ func (c *systemdCasting) validateBinaries(config *installation.Casting) error {
|
||||
}
|
||||
|
||||
if len(missing) > 0 {
|
||||
return fmt.Errorf("missing binaries: %s - please install before running cast", strings.Join(missing, ", "))
|
||||
return errors.Newf(errors.TypeNotFound, "missing binaries: %s - please install before running cast", strings.Join(missing, ", "))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -435,13 +436,13 @@ func (c *systemdCasting) startAllServices(ctx context.Context, services []string
|
||||
unitName := filepath.Base(svc)
|
||||
c.logger.DebugContext(ctx, "Enabling service", slog.String("service", unitName))
|
||||
if err := c.execCommand(ctx, "systemctl", "enable", svc); err != nil {
|
||||
return fmt.Errorf("failed to enable service %s: %w", unitName, err)
|
||||
return errors.Wrapf(err, errors.TypeInternal, "failed to enable service %s", unitName)
|
||||
}
|
||||
}
|
||||
|
||||
// Reload systemd to pick up all enabled services
|
||||
if err := c.execCommand(ctx, "systemctl", "daemon-reload"); err != nil {
|
||||
return fmt.Errorf("systemd daemon-reload failed: %w", err)
|
||||
return errors.Wrapf(err, errors.TypeInternal, "systemd daemon-reload failed")
|
||||
}
|
||||
|
||||
// Start all services without blocking — systemd dependencies handle ordering
|
||||
@@ -449,7 +450,7 @@ func (c *systemdCasting) startAllServices(ctx context.Context, services []string
|
||||
unitName := filepath.Base(svc)
|
||||
c.logger.InfoContext(ctx, "Starting service", slog.String("service", unitName))
|
||||
if err := c.execCommand(ctx, "systemctl", "start", "--no-block", unitName); err != nil {
|
||||
return fmt.Errorf("failed to start service %s: %w", unitName, err)
|
||||
return errors.Wrapf(err, errors.TypeInternal, "failed to start service %s", unitName)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -474,11 +475,11 @@ func (c *systemdCasting) initializePostgres(ctx context.Context, config *install
|
||||
|
||||
// Create directories
|
||||
if err := os.MkdirAll(pgDataDir, 0700); err != nil {
|
||||
return fmt.Errorf("failed to create PostgreSQL data directory: %w", err)
|
||||
return errors.Wrapf(err, errors.TypeInternal, "failed to create PostgreSQL data directory")
|
||||
}
|
||||
|
||||
if err := c.execCommand(ctx, "chown", "-R", "postgres:postgres", filepath.Dir(pgDataDir)); err != nil {
|
||||
return fmt.Errorf("failed to set ownership on PostgreSQL data directory: %w", err)
|
||||
return errors.Wrapf(err, errors.TypeInternal, "failed to set ownership on PostgreSQL data directory")
|
||||
}
|
||||
|
||||
// Get credentials
|
||||
@@ -498,7 +499,7 @@ func (c *systemdCasting) initializePostgres(ctx context.Context, config *install
|
||||
|
||||
// Create password file
|
||||
if err := os.WriteFile(pwfile, []byte(pgPass+"\n"), 0600); err != nil {
|
||||
return fmt.Errorf("failed to create password file: %w", err)
|
||||
return errors.Wrapf(err, errors.TypeInternal, "failed to create password file")
|
||||
}
|
||||
_ = c.execCommand(ctx, "chown", "postgres:postgres", pwfile)
|
||||
|
||||
@@ -506,7 +507,7 @@ func (c *systemdCasting) initializePostgres(ctx context.Context, config *install
|
||||
postgresBin := config.Metadata.Annotations["foundry.signoz.io/metastore-postgres-binary-path"]
|
||||
|
||||
if postgresBin == "" {
|
||||
return fmt.Errorf("metastore postgres binary is missing in annotations")
|
||||
return errors.Newf(errors.TypeInvalidInput, "metastore postgres binary is missing in annotations")
|
||||
}
|
||||
|
||||
postgresBinDir := filepath.Dir(postgresBin)
|
||||
@@ -518,7 +519,7 @@ func (c *systemdCasting) initializePostgres(ctx context.Context, config *install
|
||||
if err := c.execCommand(ctx, "su", "-", "postgres", "-c",
|
||||
fmt.Sprintf("%s -D %s --username=%s --pwfile=%s", initdbPath, pgDataDir, pgUser, pwfile)); err != nil {
|
||||
c.cleanupPostgresInit(ctx, pgDataDir, pwfile)
|
||||
return fmt.Errorf("failed to initialize PostgreSQL: %w", err)
|
||||
return errors.Wrapf(err, errors.TypeInternal, "failed to initialize PostgreSQL")
|
||||
}
|
||||
|
||||
// Start temp server and create database
|
||||
@@ -526,7 +527,7 @@ func (c *systemdCasting) initializePostgres(ctx context.Context, config *install
|
||||
if err := c.execCommand(ctx, "su", "-", "postgres", "-c",
|
||||
fmt.Sprintf("%s -D %s -o \"-c listen_addresses=localhost\" -w start", pgCtlPath, pgDataDir)); err != nil {
|
||||
c.cleanupPostgresInit(ctx, pgDataDir, pwfile)
|
||||
return fmt.Errorf("failed to start temporary postgres: %w", err)
|
||||
return errors.Wrapf(err, errors.TypeInternal, "failed to start temporary postgres")
|
||||
}
|
||||
|
||||
// Create database
|
||||
@@ -537,12 +538,12 @@ func (c *systemdCasting) initializePostgres(ctx context.Context, config *install
|
||||
|
||||
// Stop temporary PostgreSQL
|
||||
if err := c.execCommand(ctx, "su", "-", "postgres", "-c", fmt.Sprintf("%s -D %s -m fast -w stop", pgCtlPath, pgDataDir)); err != nil {
|
||||
return fmt.Errorf("failed to stop temporary postgres: %w", err)
|
||||
return errors.Wrapf(err, errors.TypeInternal, "failed to stop temporary postgres")
|
||||
}
|
||||
|
||||
// Clean up password file
|
||||
if err := os.Remove(pwfile); err != nil {
|
||||
return fmt.Errorf("failed to remove password file: %w", err)
|
||||
return errors.Wrapf(err, errors.TypeInternal, "failed to remove password file")
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -2,11 +2,11 @@ package systemdcasting
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/signoz/foundry/api/v1alpha1"
|
||||
"github.com/signoz/foundry/api/v1alpha1/installation"
|
||||
"github.com/signoz/foundry/internal/domain"
|
||||
"github.com/signoz/foundry/internal/errors"
|
||||
"github.com/signoz/foundry/internal/molding"
|
||||
)
|
||||
|
||||
@@ -57,7 +57,7 @@ func (e *linuxMoldingEnricher) enrichTelemetryStore(config *installation.Casting
|
||||
}
|
||||
|
||||
if replicas > 1 || shards > 1 {
|
||||
return fmt.Errorf("deployment mode '%s' does not support Distributed Clickhouse Setup, raise an issue at https://github.com/signoz/foundry/issues", config.Spec.Deployment.Mode)
|
||||
return errors.Newf(errors.TypeUnsupported, "deployment mode '%s' does not support Distributed Clickhouse Setup, raise an issue at https://github.com/signoz/foundry/issues", config.Spec.Deployment.Mode)
|
||||
}
|
||||
|
||||
// Generate addresses for each shard/replica
|
||||
@@ -83,7 +83,7 @@ func (e *linuxMoldingEnricher) enrichTelemetryKeeper(config *installation.Castin
|
||||
}
|
||||
|
||||
if replicas > 1 {
|
||||
return fmt.Errorf("deployment mode '%s' does not support Distributed Clickhouse Setup, raise an issue at https://github.com/signoz/foundry/issues", config.Spec.Deployment.Mode)
|
||||
return errors.Newf(errors.TypeUnsupported, "deployment mode '%s' does not support Distributed Clickhouse Setup, raise an issue at https://github.com/signoz/foundry/issues", config.Spec.Deployment.Mode)
|
||||
}
|
||||
|
||||
var clientAddresses, raftAddresses []string
|
||||
|
||||
@@ -3,7 +3,6 @@ package yamlconfig
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
@@ -27,7 +26,7 @@ func New() config.Config {
|
||||
func (*yamlConfig) GetV1Alpha1(ctx context.Context, path string) (v1alpha1.Machinery, error) {
|
||||
bytes, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read yaml file: %w", err)
|
||||
return nil, errors.Wrapf(err, errors.TypeNotFound, "failed to read yaml file")
|
||||
}
|
||||
|
||||
kind, err := peekKind(bytes)
|
||||
@@ -51,7 +50,7 @@ func peekKind(bytes []byte) (v1alpha1.Kind, error) {
|
||||
Kind v1alpha1.Kind `json:"kind" yaml:"kind"`
|
||||
}
|
||||
if err := domain.UnmarshalYAML(bytes, &probe); err != nil {
|
||||
return v1alpha1.Kind{}, fmt.Errorf("failed to peek kind: %w", err)
|
||||
return v1alpha1.Kind{}, errors.Wrapf(err, errors.TypeInvalidInput, "failed to peek kind")
|
||||
}
|
||||
if probe.Kind == (v1alpha1.Kind{}) {
|
||||
return v1alpha1.KindInstallation, nil
|
||||
@@ -62,21 +61,21 @@ func peekKind(bytes []byte) (v1alpha1.Kind, error) {
|
||||
func loadInstallation(bytes []byte, path string) (v1alpha1.Machinery, error) {
|
||||
var loaded installation.Casting
|
||||
if err := domain.UnmarshalYAML(bytes, &loaded); err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal installation casting: %w", err)
|
||||
return nil, errors.Wrapf(err, errors.TypeInvalidInput, "failed to unmarshal installation casting")
|
||||
}
|
||||
|
||||
base := installation.Default()
|
||||
if err := v1alpha1.Merge(base, &loaded); err != nil {
|
||||
return nil, fmt.Errorf("failed to merge default installation casting: %w", err)
|
||||
return nil, errors.Wrapf(err, errors.TypeInternal, "failed to merge default installation casting")
|
||||
}
|
||||
|
||||
contents, err := json.Marshal(base)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to marshal installation casting: %w", err)
|
||||
return nil, errors.Wrapf(err, errors.TypeInternal, "failed to marshal installation casting")
|
||||
}
|
||||
toValidate := map[string]any{}
|
||||
if err := json.Unmarshal(contents, &toValidate); err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal installation casting for validation: %w", err)
|
||||
return nil, errors.Wrapf(err, errors.TypeInternal, "failed to unmarshal installation casting for validation")
|
||||
}
|
||||
|
||||
if err := installation.Schema().Validate(toValidate); err != nil {
|
||||
@@ -89,21 +88,21 @@ func loadInstallation(bytes []byte, path string) (v1alpha1.Machinery, error) {
|
||||
func loadCollectionAgent(bytes []byte, path string) (v1alpha1.Machinery, error) {
|
||||
var loaded collectionagent.Casting
|
||||
if err := domain.UnmarshalYAML(bytes, &loaded); err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal collectionagent casting: %w", err)
|
||||
return nil, errors.Wrapf(err, errors.TypeInvalidInput, "failed to unmarshal collectionagent casting")
|
||||
}
|
||||
|
||||
base := collectionagent.Default()
|
||||
if err := v1alpha1.Merge(base, &loaded); err != nil {
|
||||
return nil, fmt.Errorf("failed to merge default collectionagent casting: %w", err)
|
||||
return nil, errors.Wrapf(err, errors.TypeInternal, "failed to merge default collectionagent casting")
|
||||
}
|
||||
|
||||
contents, err := json.Marshal(base)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to marshal collectionagent casting: %w", err)
|
||||
return nil, errors.Wrapf(err, errors.TypeInternal, "failed to marshal collectionagent casting")
|
||||
}
|
||||
toValidate := map[string]any{}
|
||||
if err := json.Unmarshal(contents, &toValidate); err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal collectionagent casting for validation: %w", err)
|
||||
return nil, errors.Wrapf(err, errors.TypeInternal, "failed to unmarshal collectionagent casting for validation")
|
||||
}
|
||||
|
||||
if err := collectionagent.Schema().Validate(toValidate); err != nil {
|
||||
@@ -117,11 +116,11 @@ func loadCollectionAgent(bytes []byte, path string) (v1alpha1.Machinery, error)
|
||||
func (*yamlConfig) CreateV1Alpha1Lock(ctx context.Context, machinery v1alpha1.Machinery, path string) error {
|
||||
contents, err := domain.MarshalYAML(machinery)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal yaml: %w", err)
|
||||
return errors.Wrapf(err, errors.TypeInternal, "failed to marshal yaml")
|
||||
}
|
||||
|
||||
if err := os.WriteFile(filepath.Join(filepath.Dir(path), "casting.yaml.lock"), contents, 0644); err != nil {
|
||||
return fmt.Errorf("failed to write yaml file: %w", err)
|
||||
return errors.Wrapf(err, errors.TypeInternal, "failed to write yaml file")
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -131,7 +130,7 @@ func (*yamlConfig) CreateV1Alpha1Lock(ctx context.Context, machinery v1alpha1.Ma
|
||||
func (*yamlConfig) GetV1Alpha1Lock(ctx context.Context, path string) (v1alpha1.Machinery, error) {
|
||||
bytes, err := os.ReadFile(filepath.Join(filepath.Dir(path), "casting.yaml.lock"))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read yaml file: %w", err)
|
||||
return nil, errors.Wrapf(err, errors.TypeNotFound, "failed to read yaml file")
|
||||
}
|
||||
|
||||
kind, err := peekKind(bytes)
|
||||
@@ -143,13 +142,13 @@ func (*yamlConfig) GetV1Alpha1Lock(ctx context.Context, path string) (v1alpha1.M
|
||||
case v1alpha1.KindInstallation:
|
||||
var c installation.Casting
|
||||
if err := domain.UnmarshalYAML(bytes, &c); err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal installation casting: %w", err)
|
||||
return nil, errors.Wrapf(err, errors.TypeInvalidInput, "failed to unmarshal installation casting")
|
||||
}
|
||||
return &c, nil
|
||||
case v1alpha1.KindCollectionAgent:
|
||||
var c collectionagent.Casting
|
||||
if err := domain.UnmarshalYAML(bytes, &c); err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal collectionagent casting: %w", err)
|
||||
return nil, errors.Wrapf(err, errors.TypeInvalidInput, "failed to unmarshal collectionagent casting")
|
||||
}
|
||||
return &c, nil
|
||||
}
|
||||
|
||||
@@ -35,17 +35,23 @@ func (p Properties) WithSuccess() Properties {
|
||||
return p
|
||||
}
|
||||
|
||||
// WithError records that the tracked operation failed and stores the typed
|
||||
// error kind, its message, and the underlying cause so analytics can group
|
||||
// failures by class while preserving the wrapped detail.
|
||||
// WithError records the typed kind, the outer message, and the next link's
|
||||
// own Message as the cause — using the link's Message (not the chained
|
||||
// Error()) gives stable grouping keys for analytics.
|
||||
func (p Properties) WithError(err error) Properties {
|
||||
t, info, cause := errors.Unwrapb(err)
|
||||
p.values[propertyKeySuccess] = false
|
||||
p.values[propertyKeyErrorType] = t.String()
|
||||
p.values[propertyKeyError] = info
|
||||
if cause != nil {
|
||||
p.values[propertyKeyErrorCause] = cause.Error()
|
||||
|
||||
e := errors.ExceptionOf(err)
|
||||
if e == nil {
|
||||
return p
|
||||
}
|
||||
|
||||
p.values[propertyKeyErrorType] = e.Type
|
||||
p.values[propertyKeyError] = e.Message
|
||||
if e.Cause != nil {
|
||||
p.values[propertyKeyErrorCause] = e.Cause.Message
|
||||
}
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
package domain
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/signoz/foundry/internal/errors"
|
||||
kyaml "sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
@@ -38,19 +37,19 @@ func MustMarshalYAML(v any) []byte {
|
||||
func MergeYAML(base, override string) (string, error) {
|
||||
var baseMap map[string]any
|
||||
if err := kyaml.Unmarshal([]byte(base), &baseMap); err != nil {
|
||||
return "", fmt.Errorf("failed to unmarshal base yaml: %w", err)
|
||||
return "", errors.Wrapf(err, errors.TypeInternal, "failed to unmarshal base yaml")
|
||||
}
|
||||
|
||||
var overrideMap map[string]any
|
||||
if err := kyaml.Unmarshal([]byte(override), &overrideMap); err != nil {
|
||||
return "", fmt.Errorf("failed to unmarshal override yaml: %w", err)
|
||||
return "", errors.Wrapf(err, errors.TypeInternal, "failed to unmarshal override yaml")
|
||||
}
|
||||
|
||||
deepMerge(baseMap, overrideMap)
|
||||
|
||||
merged, err := kyaml.Marshal(baseMap)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to marshal merged yaml: %w", err)
|
||||
return "", errors.Wrapf(err, errors.TypeInternal, "failed to marshal merged yaml")
|
||||
}
|
||||
|
||||
return string(merged), nil
|
||||
|
||||
+15
-30
@@ -1,6 +1,7 @@
|
||||
package errors
|
||||
|
||||
import (
|
||||
goerrors "errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
)
|
||||
@@ -27,6 +28,10 @@ func (b *base) Error() string {
|
||||
return b.info
|
||||
}
|
||||
|
||||
func (b *base) Unwrap() error {
|
||||
return b.cause
|
||||
}
|
||||
|
||||
func (b *base) WithStacktrace(stacktrace string) *base {
|
||||
b.stacktrace = rawStacktrace(stacktrace)
|
||||
return b
|
||||
@@ -54,39 +59,19 @@ func Wrapf(cause error, t typ, format string, args ...any) error {
|
||||
}
|
||||
}
|
||||
|
||||
func Unwrapb(cause error) (typ, string, error) {
|
||||
base, ok := cause.(*base)
|
||||
if ok {
|
||||
return base.t, base.info, base.cause
|
||||
func ExitCode(err error) int {
|
||||
if err == nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
return TypeInternal, cause.Error(), cause
|
||||
var b *base
|
||||
if goerrors.As(err, &b) {
|
||||
return b.t.ExitCode()
|
||||
}
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
func LogAttr(err error) slog.Attr {
|
||||
t, info, cause := Unwrapb(err)
|
||||
|
||||
attrs := []slog.Attr{
|
||||
slog.String("type", t.String()),
|
||||
slog.String("message", info),
|
||||
slog.String("cause", cause.Error()),
|
||||
}
|
||||
|
||||
type stacktracer interface {
|
||||
Stacktrace() string
|
||||
}
|
||||
|
||||
if t == TypeFatal {
|
||||
if st, ok := err.(stacktracer); ok && st.Stacktrace() != "" {
|
||||
attrs = append(attrs, slog.String("stacktrace", st.Stacktrace()))
|
||||
}
|
||||
|
||||
attrs = append(attrs, slog.String("action", "Please raise an issue at https://github.com/signoz/foundry/issues with the error message and stacktrace."))
|
||||
}
|
||||
|
||||
if t == TypeUnsupported {
|
||||
attrs = append(attrs, slog.String("action", "Please check the documentation for supported features or raise an issue at https://github.com/signoz/foundry/issues for feature requests."))
|
||||
}
|
||||
|
||||
return slog.GroupAttrs("exception", attrs...)
|
||||
return slog.GroupAttrs("exception", exceptionAttrs(ExceptionOf(err))...)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
package errors
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestExitCode(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
err error
|
||||
expected int
|
||||
}{
|
||||
{name: "Nil_Zero", err: nil, expected: 0},
|
||||
{name: "Untyped_One", err: fmt.Errorf("plain error"), expected: 1},
|
||||
{name: "InvalidInput_Two", err: Newf(TypeInvalidInput, "bad input"), expected: 2},
|
||||
{name: "NotFound_Three", err: Newf(TypeNotFound, "missing"), expected: 3},
|
||||
{name: "Unsupported_Four", err: Newf(TypeUnsupported, "no support"), expected: 4},
|
||||
{name: "Internal_Five", err: Newf(TypeInternal, "internal"), expected: 5},
|
||||
{name: "Fatal_Six", err: Newf(TypeFatal, "fatal"), expected: 6},
|
||||
{
|
||||
name: "WrappedWithFmtErrorf_WalksChain",
|
||||
err: fmt.Errorf("outer: %w", Newf(TypeNotFound, "inner")),
|
||||
expected: 3,
|
||||
},
|
||||
{
|
||||
name: "WrappedWithFoundryWrapf_PreservesOuterType",
|
||||
err: Wrapf(Newf(TypeNotFound, "inner"), TypeUnsupported, "outer"),
|
||||
expected: 4,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := ExitCode(tt.err); got != tt.expected {
|
||||
t.Errorf("ExitCode() = %d, want %d", got, tt.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package errors
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"log/slog"
|
||||
)
|
||||
|
||||
type Exception struct {
|
||||
Type string `json:"type,omitempty"`
|
||||
Message string `json:"message"`
|
||||
Cause *Exception `json:"cause,omitempty"`
|
||||
Action string `json:"action,omitempty"`
|
||||
Stacktrace string `json:"stacktrace,omitempty"`
|
||||
}
|
||||
|
||||
type Envelope struct {
|
||||
Exception *Exception
|
||||
}
|
||||
|
||||
func (e Envelope) MarshalJSON() ([]byte, error) {
|
||||
return json.MarshalIndent(map[string]*Exception{"exception": e.Exception}, "", " ")
|
||||
}
|
||||
|
||||
// The walk terminates at the first non-*base link, which emits Message alone
|
||||
// — stdlib wrappers format their full subtree in Error(), so re-walking them
|
||||
// would duplicate that text. Stacktrace emits on TypeFatal links only; every
|
||||
// *base captures one at construction time but emitting them all is noise.
|
||||
func ExceptionOf(err error) *Exception {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
b, ok := err.(*base)
|
||||
if !ok {
|
||||
return &Exception{Message: err.Error()}
|
||||
}
|
||||
|
||||
e := &Exception{
|
||||
Type: b.t.String(),
|
||||
Message: b.info,
|
||||
Action: b.t.action,
|
||||
Cause: ExceptionOf(b.cause),
|
||||
}
|
||||
if b.t == TypeFatal && b.stacktrace != nil {
|
||||
if st := b.stacktrace.String(); st != "" {
|
||||
e.Stacktrace = st
|
||||
}
|
||||
}
|
||||
|
||||
return e
|
||||
}
|
||||
|
||||
func EnvelopeOf(err error) Envelope {
|
||||
return Envelope{Exception: ExceptionOf(err)}
|
||||
}
|
||||
|
||||
func exceptionAttrs(e *Exception) []slog.Attr {
|
||||
if e == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var attrs []slog.Attr
|
||||
if e.Type != "" {
|
||||
attrs = append(attrs, slog.String("type", e.Type))
|
||||
}
|
||||
|
||||
attrs = append(attrs, slog.String("message", e.Message))
|
||||
if e.Cause != nil {
|
||||
attrs = append(attrs, slog.GroupAttrs("cause", exceptionAttrs(e.Cause)...))
|
||||
}
|
||||
|
||||
if e.Action != "" {
|
||||
attrs = append(attrs, slog.String("action", e.Action))
|
||||
}
|
||||
|
||||
if e.Stacktrace != "" {
|
||||
attrs = append(attrs, slog.String("stacktrace", e.Stacktrace))
|
||||
}
|
||||
|
||||
return attrs
|
||||
}
|
||||
+32
-7
@@ -1,16 +1,41 @@
|
||||
package errors
|
||||
|
||||
// Exit codes use a compact 1-6 scheme rather than BSD sysexits.h. sysexits
|
||||
// would force TypeInternal and TypeFatal to share EX_SOFTWARE (70), and the
|
||||
// distinction matters: TypeFatal marks a recovered panic that should page,
|
||||
// TypeInternal marks an expected-but-failed path. The custom scheme keeps
|
||||
// those orthogonal and stays easy to remember in shell scripts.
|
||||
//
|
||||
// The action string is the remediation hint surfaced to users (via the slog
|
||||
// "exception" payload and the --format=json error envelope). Co-locating it
|
||||
// with the type means adding a new error class is a one-place change.
|
||||
var (
|
||||
TypeInvalidInput typ = typ{"invalid-input"}
|
||||
TypeNotFound typ = typ{"not-found"}
|
||||
TypeInternal = typ{"internal"}
|
||||
TypeFatal = typ{"fatal"}
|
||||
TypeUnsupported = typ{"unsupported"}
|
||||
TypeInvalidInput = typ{"invalid-input", 2, ""}
|
||||
TypeNotFound = typ{"not-found", 3, ""}
|
||||
TypeUnsupported = typ{"unsupported", 4, "Please check the documentation for supported features or raise an issue at https://github.com/signoz/foundry/issues for feature requests."}
|
||||
TypeInternal = typ{"internal", 5, ""}
|
||||
TypeFatal = typ{"fatal", 6, "Please raise an issue at https://github.com/signoz/foundry/issues with the error message and stacktrace."}
|
||||
)
|
||||
|
||||
// Defines custom error types.
|
||||
type typ struct{ s string }
|
||||
// Defines custom error types, the process exit code they map to, and the
|
||||
// remediation hint shown to users.
|
||||
type typ struct {
|
||||
s string
|
||||
code int
|
||||
action string
|
||||
}
|
||||
|
||||
func (t typ) String() string {
|
||||
return t.s
|
||||
}
|
||||
|
||||
// ExitCode returns the process exit code associated with this error type.
|
||||
func (t typ) ExitCode() int {
|
||||
return t.code
|
||||
}
|
||||
|
||||
// Action returns the remediation hint for this error type, or an empty string
|
||||
// if no hint applies.
|
||||
func (t typ) Action() string {
|
||||
return t.action
|
||||
}
|
||||
|
||||
@@ -2,12 +2,12 @@ package foundry
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
|
||||
"github.com/signoz/foundry/api/v1alpha1"
|
||||
"github.com/signoz/foundry/api/v1alpha1/collectionagent"
|
||||
"github.com/signoz/foundry/api/v1alpha1/installation"
|
||||
foundryerrors "github.com/signoz/foundry/internal/errors"
|
||||
)
|
||||
|
||||
func (foundry *Foundry) Cast(ctx context.Context, machinery v1alpha1.Machinery, poursPath string) error {
|
||||
@@ -17,7 +17,7 @@ func (foundry *Foundry) Cast(ctx context.Context, machinery v1alpha1.Machinery,
|
||||
case *collectionagent.Casting:
|
||||
return foundry.castCollectionAgent(ctx, *c, poursPath)
|
||||
}
|
||||
return fmt.Errorf("unsupported casting kind %q", machinery.Kind())
|
||||
return foundryerrors.Newf(foundryerrors.TypeUnsupported, "unsupported casting kind %q", machinery.Kind())
|
||||
}
|
||||
|
||||
func (foundry *Foundry) castCollectionAgent(ctx context.Context, config collectionagent.Casting, _ string) error {
|
||||
|
||||
@@ -2,7 +2,6 @@ package foundry
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"path/filepath"
|
||||
|
||||
@@ -22,7 +21,7 @@ func (foundry *Foundry) Forge(ctx context.Context, machinery v1alpha1.Machinery,
|
||||
case *collectionagent.Casting:
|
||||
return foundry.forgeCollectionAgent(ctx, *c, path, poursWriterOpts)
|
||||
}
|
||||
return fmt.Errorf("unsupported casting kind %q", machinery.Kind())
|
||||
return foundryerrors.Newf(foundryerrors.TypeUnsupported, "unsupported casting kind %q", machinery.Kind())
|
||||
}
|
||||
|
||||
func (foundry *Foundry) forgeCollectionAgent(ctx context.Context, config collectionagent.Casting, path string, _ *writer.Options) error {
|
||||
@@ -46,14 +45,14 @@ func (foundry *Foundry) forgeInstallation(ctx context.Context, config installati
|
||||
moldingEnricher, err := casting.Enricher(ctx, &config)
|
||||
if err != nil {
|
||||
foundry.Logger.ErrorContext(ctx, "failed to get molding enricher", slog.String("casting.metadata.name", config.Metadata.Name), foundryerrors.LogAttr(err))
|
||||
return fmt.Errorf("failed to get molding enricher: %w", err)
|
||||
return foundryerrors.Wrapf(err, foundryerrors.TypeInternal, "failed to get molding enricher")
|
||||
}
|
||||
|
||||
foundry.Logger.InfoContext(ctx, "enriching configuration with casting specific information", slog.String("casting.metadata.name", config.Metadata.Name))
|
||||
for _, moldingKind := range molding.MoldingsInOrder() {
|
||||
err = moldingEnricher.EnrichStatus(ctx, moldingKind, &config)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to enrich configuration with casting specific information: %w", err)
|
||||
return foundryerrors.Wrapf(err, foundryerrors.TypeInternal, "failed to enrich configuration with casting specific information")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,13 +83,13 @@ func (foundry *Foundry) forgeInstallation(ctx context.Context, config installati
|
||||
for _, pe := range spec.Patches {
|
||||
patcher, ok := foundry.Patchers[pe.PatchType()]
|
||||
if !ok {
|
||||
return fmt.Errorf("unknown patch type %q", pe.PatchType())
|
||||
return foundryerrors.Newf(foundryerrors.TypeUnsupported, "unknown patch type %q", pe.PatchType())
|
||||
}
|
||||
foundry.Logger.InfoContext(ctx, "applying patch", slog.String("casting.metadata.name", config.Metadata.Name), slog.String("patch.type", pe.PatchType()), slog.String("patch.target", pe.Target))
|
||||
materials, err = patcher.Apply(ctx, materials, pe)
|
||||
if err != nil {
|
||||
foundry.Logger.ErrorContext(ctx, "failed to apply patch", slog.String("casting.metadata.name", config.Metadata.Name), slog.String("patch.target", pe.Target), foundryerrors.LogAttr(err))
|
||||
return fmt.Errorf("failed to apply patch for target %q: %w", pe.Target, err)
|
||||
return foundryerrors.Wrapf(err, foundryerrors.TypeInternal, "failed to apply patch for target %q", pe.Target)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,7 +103,7 @@ func (foundry *Foundry) forgeInstallation(ctx context.Context, config installati
|
||||
|
||||
infraMaterials, err = foundry.InfrastructureGenerator.Generate(ctx, config)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to generate infrastructure manifests: %w", err)
|
||||
return foundryerrors.Wrapf(err, foundryerrors.TypeInternal, "failed to generate infrastructure manifests")
|
||||
}
|
||||
|
||||
// Populate infrastructure status with generated file contents keyed by filename.
|
||||
|
||||
@@ -2,7 +2,6 @@ package foundry
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"strings"
|
||||
|
||||
@@ -20,7 +19,7 @@ func (foundry *Foundry) Gauge(ctx context.Context, machinery v1alpha1.Machinery)
|
||||
case *collectionagent.Casting:
|
||||
return foundry.gaugeCollectionAgent(ctx, *c)
|
||||
}
|
||||
return fmt.Errorf("unsupported casting kind %q", machinery.Kind())
|
||||
return foundryerrors.Newf(foundryerrors.TypeUnsupported, "unsupported casting kind %q", machinery.Kind())
|
||||
}
|
||||
|
||||
func (foundry *Foundry) gaugeCollectionAgent(ctx context.Context, config collectionagent.Casting) error {
|
||||
@@ -57,7 +56,7 @@ func (foundry *Foundry) gaugeInstallation(ctx context.Context, config installati
|
||||
}
|
||||
|
||||
if len(unavailableTools) > 0 {
|
||||
return fmt.Errorf("tools are not available, please install them and try again: %s", strings.Join(unavailableTools, ", "))
|
||||
return foundryerrors.Newf(foundryerrors.TypeNotFound, "tools are not available, please install them and try again: %s", strings.Join(unavailableTools, ", "))
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package foundry
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log/slog"
|
||||
|
||||
"github.com/signoz/foundry/api/v1alpha1"
|
||||
@@ -15,6 +14,7 @@ import (
|
||||
"github.com/signoz/foundry/internal/casting/railwaytemplatecasting"
|
||||
"github.com/signoz/foundry/internal/casting/rendercasting"
|
||||
"github.com/signoz/foundry/internal/casting/systemdcasting"
|
||||
foundryerrors "github.com/signoz/foundry/internal/errors"
|
||||
"github.com/signoz/foundry/internal/tooler"
|
||||
"github.com/signoz/foundry/internal/tooler/clickhousekeepertooler"
|
||||
"github.com/signoz/foundry/internal/tooler/clickhousetooler"
|
||||
@@ -130,7 +130,7 @@ func (registry *Registry) lookup(deployment v1alpha1.TypeDeployment) (CastingIte
|
||||
func (registry *Registry) Casting(deployment v1alpha1.TypeDeployment) (casting.Casting, error) {
|
||||
item, ok := registry.lookup(deployment)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("deployment '%+v' is not supported, raise an issue at https://github.com/signoz/foundry/issues to request support for this deployment", deployment)
|
||||
return nil, foundryerrors.Newf(foundryerrors.TypeUnsupported, "deployment '%+v' is not supported, raise an issue at https://github.com/signoz/foundry/issues to request support for this deployment", deployment)
|
||||
}
|
||||
|
||||
return item.Casting, nil
|
||||
@@ -139,7 +139,7 @@ func (registry *Registry) Casting(deployment v1alpha1.TypeDeployment) (casting.C
|
||||
func (registry *Registry) Toolers(deployment v1alpha1.TypeDeployment) ([]tooler.Tooler, error) {
|
||||
item, ok := registry.lookup(deployment)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("deployment '%+v' is not supported, raise an issue at https://github.com/signoz/foundry/issues to request support for this deployment", deployment)
|
||||
return nil, foundryerrors.Newf(foundryerrors.TypeUnsupported, "deployment '%+v' is not supported, raise an issue at https://github.com/signoz/foundry/issues to request support for this deployment", deployment)
|
||||
}
|
||||
|
||||
return item.Toolers, nil
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
package infrastructure
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/signoz/foundry/api/v1alpha1"
|
||||
"github.com/signoz/foundry/internal/errors"
|
||||
)
|
||||
|
||||
// ResolveProvider normalizes a deployment platform to the cloud platform that
|
||||
@@ -18,9 +17,9 @@ func ResolveProvider(platform v1alpha1.Platform) (v1alpha1.Platform, error) {
|
||||
case v1alpha1.PlatformAzure:
|
||||
return v1alpha1.PlatformAzure, nil
|
||||
case v1alpha1.Platform{}:
|
||||
return v1alpha1.Platform{}, fmt.Errorf("no platform specified in deployment.platform: infrastructure generation requires aws, gcp, or azure")
|
||||
return v1alpha1.Platform{}, errors.Newf(errors.TypeInvalidInput, "no platform specified in deployment.platform: infrastructure generation requires aws, gcp, or azure")
|
||||
default:
|
||||
return v1alpha1.Platform{}, fmt.Errorf("unsupported platform for infrastructure generation: %q (must be aws, gcp, azure, or ecs)", platform)
|
||||
return v1alpha1.Platform{}, errors.Newf(errors.TypeUnsupported, "unsupported platform for infrastructure generation: %q (must be aws, gcp, azure, or ecs)", platform)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,6 +56,6 @@ func ResolveComputeType(provider v1alpha1.Platform, deployment v1alpha1.TypeDepl
|
||||
return ComputeTypeVM, nil
|
||||
|
||||
default:
|
||||
return ComputeType{}, fmt.Errorf("unsupported infrastructure platform: %s", provider)
|
||||
return ComputeType{}, errors.Newf(errors.TypeUnsupported, "unsupported infrastructure platform: %s", provider)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package terraform
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
@@ -10,6 +9,7 @@ import (
|
||||
"github.com/signoz/foundry/api/v1alpha1"
|
||||
"github.com/signoz/foundry/api/v1alpha1/installation"
|
||||
"github.com/signoz/foundry/internal/domain"
|
||||
"github.com/signoz/foundry/internal/errors"
|
||||
"github.com/signoz/foundry/internal/infrastructure"
|
||||
)
|
||||
|
||||
@@ -79,7 +79,7 @@ func (g *Generator) Generate(ctx context.Context, config installation.Casting) (
|
||||
} {
|
||||
m, err := item.tmpl.Render(data, filepath.Join(infrastructureDir, item.path))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to render %s: %w", item.path, err)
|
||||
return nil, errors.Wrapf(err, errors.TypeInternal, "failed to render %s", item.path)
|
||||
}
|
||||
materials = append(materials, m)
|
||||
}
|
||||
@@ -96,7 +96,7 @@ func (g *Generator) Validate(ctx context.Context, poursPath string) error {
|
||||
cmd.Dir = infraDir
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return fmt.Errorf("terraform validate failed: %w\n%s", err, out)
|
||||
return errors.Wrapf(err, errors.TypeInternal, "terraform validate failed\n%s", out)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -126,5 +126,5 @@ func (g *Generator) templatesFor(provider v1alpha1.Platform, computeType infrast
|
||||
return azureAKSMainTFTemplate, azureAKSVariablesTFTemplate, azureAKSOutputsTFTemplate, nil
|
||||
}
|
||||
}
|
||||
return nil, nil, nil, fmt.Errorf("unsupported provider %q / compute type %q combination", provider, computeType)
|
||||
return nil, nil, nil, errors.Newf(errors.TypeUnsupported, "unsupported provider %q / compute type %q combination", provider, computeType)
|
||||
}
|
||||
|
||||
@@ -5,17 +5,17 @@ import (
|
||||
"os"
|
||||
)
|
||||
|
||||
// NewLogger returns the process logger. When debug is false logs are dropped
|
||||
// so the default UX matches helm/aws (silent on stdout/stderr, errors surface
|
||||
// through the cobra exit path). When debug is true, debug-level records are
|
||||
// emitted as JSON on stderr so stdout remains reserved for command results.
|
||||
func NewLogger(debug bool) *slog.Logger {
|
||||
if debug {
|
||||
return newLoggerWithLevel(slog.LevelDebug)
|
||||
if !debug {
|
||||
return slog.New(slog.DiscardHandler)
|
||||
}
|
||||
|
||||
return newLoggerWithLevel(slog.LevelInfo)
|
||||
}
|
||||
|
||||
func newLoggerWithLevel(level slog.Level) *slog.Logger {
|
||||
return slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
|
||||
Level: level,
|
||||
return slog.New(slog.NewJSONHandler(os.Stderr, &slog.HandlerOptions{
|
||||
Level: slog.LevelDebug,
|
||||
AddSource: false,
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package ingestermolding
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"strings"
|
||||
|
||||
@@ -62,13 +61,13 @@ func (molding *ingester) MoldV1Alpha1(ctx context.Context, config *installation.
|
||||
|
||||
func (molding *ingester) getData(config *installation.Casting) (Data, error) {
|
||||
if len(config.Spec.Signoz.Status.Addresses.Opamp) == 0 {
|
||||
return Data{}, fmt.Errorf("signoz address is not set")
|
||||
return Data{}, foundryerrors.Newf(foundryerrors.TypeInternal, "signoz address is not set")
|
||||
}
|
||||
|
||||
signozAddress := config.Spec.Signoz.Status.Addresses.Opamp[0]
|
||||
|
||||
if len(config.Spec.TelemetryStore.Status.Addresses.TCP) == 0 {
|
||||
return Data{}, fmt.Errorf("telemetry store address is not set")
|
||||
return Data{}, foundryerrors.Newf(foundryerrors.TypeInternal, "telemetry store address is not set")
|
||||
}
|
||||
|
||||
telemetryStoreAddresses := config.Spec.TelemetryStore.Status.Addresses.TCP
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"github.com/signoz/foundry/api/v1alpha1"
|
||||
"github.com/signoz/foundry/api/v1alpha1/installation"
|
||||
"github.com/signoz/foundry/internal/domain"
|
||||
"github.com/signoz/foundry/internal/errors"
|
||||
"github.com/signoz/foundry/internal/molding"
|
||||
)
|
||||
|
||||
@@ -60,7 +61,7 @@ func (molding *signoz) MoldV1Alpha1(ctx context.Context, config *installation.Ca
|
||||
// construct postgres dsn with user, password, host, port, and db
|
||||
addrs, err := domain.ParseAddresses(config.Spec.MetaStore.Status.Addresses.DSN)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse addresses: %w", err)
|
||||
return errors.Wrapf(err, errors.TypeInternal, "failed to parse addresses")
|
||||
}
|
||||
var dsns []string
|
||||
user := config.Spec.MetaStore.Status.Env["POSTGRES_USER"]
|
||||
|
||||
@@ -45,7 +45,7 @@ func (molding *telemetrykeeper) MoldV1Alpha1(ctx context.Context, config *instal
|
||||
configBuf := bytes.NewBuffer(nil)
|
||||
data.ServerID = i // 0-indexed, used for array indexing in template
|
||||
if err := KeeperClickhousev2556YAML.Execute(configBuf, data); err != nil {
|
||||
return fmt.Errorf("failed to execute keeper template for server %d: %w", data.ServerID, err)
|
||||
return foundryerrors.Wrapf(err, foundryerrors.TypeInternal, "failed to execute keeper template for server %d", data.ServerID)
|
||||
}
|
||||
|
||||
key := fmt.Sprintf("keeper-%d.yaml", i)
|
||||
@@ -54,7 +54,7 @@ func (molding *telemetrykeeper) MoldV1Alpha1(ctx context.Context, config *instal
|
||||
if overrides != "" {
|
||||
merged, err := domain.MergeYAML(base, overrides)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to merge config overrides for %s: %w", key, err)
|
||||
return foundryerrors.Wrapf(err, foundryerrors.TypeInternal, "failed to merge config overrides for %s", key)
|
||||
}
|
||||
base = merged
|
||||
}
|
||||
|
||||
@@ -2,10 +2,10 @@ package telemetrykeepermolding
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"fmt"
|
||||
|
||||
"github.com/signoz/foundry/api/v1alpha1/installation"
|
||||
"github.com/signoz/foundry/internal/domain"
|
||||
"github.com/signoz/foundry/internal/errors"
|
||||
)
|
||||
|
||||
//go:embed templates/*.gotmpl
|
||||
@@ -34,23 +34,23 @@ func newData(config *installation.Casting) (Data, error) {
|
||||
|
||||
raftAddresses := config.Spec.TelemetryKeeper.Status.Addresses.Raft
|
||||
if len(raftAddresses) < data.ServerCount {
|
||||
return Data{}, fmt.Errorf("insufficient raft addresses: have %d, need %d servers", len(raftAddresses), data.ServerCount)
|
||||
return Data{}, errors.Newf(errors.TypeInvalidInput, "insufficient raft addresses: have %d, need %d servers", len(raftAddresses), data.ServerCount)
|
||||
}
|
||||
|
||||
clientAddresses := config.Spec.TelemetryKeeper.Status.Addresses.Client
|
||||
if len(clientAddresses) < data.ServerCount {
|
||||
return Data{}, fmt.Errorf("insufficient client addresses: have %d, need %d servers", len(clientAddresses), data.ServerCount)
|
||||
return Data{}, errors.Newf(errors.TypeInvalidInput, "insufficient client addresses: have %d, need %d servers", len(clientAddresses), data.ServerCount)
|
||||
}
|
||||
|
||||
newRaftAddrs, err := domain.ParseAddresses(raftAddresses[:data.ServerCount])
|
||||
if err != nil {
|
||||
return Data{}, fmt.Errorf("failed to parse raft addresses: %w", err)
|
||||
return Data{}, errors.Wrapf(err, errors.TypeInternal, "failed to parse raft addresses")
|
||||
}
|
||||
data.RaftAddresses = newRaftAddrs
|
||||
|
||||
newClientAddrs, err := domain.ParseAddresses(clientAddresses[:data.ServerCount])
|
||||
if err != nil {
|
||||
return Data{}, fmt.Errorf("failed to parse client addresses: %w", err)
|
||||
return Data{}, errors.Wrapf(err, errors.TypeInternal, "failed to parse client addresses")
|
||||
}
|
||||
data.ClientAddresses = newClientAddrs
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ package telemetrystoremolding
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
|
||||
"github.com/signoz/foundry/api/v1alpha1"
|
||||
@@ -41,12 +40,12 @@ func (molding *telemetrystore) MoldV1Alpha1(ctx context.Context, config *install
|
||||
|
||||
configBuf := bytes.NewBuffer(nil)
|
||||
if err := ConfigClickhousev2556YAML.Execute(configBuf, data); err != nil {
|
||||
return fmt.Errorf("failed to execute config template: %w", err)
|
||||
return foundryerrors.Wrapf(err, foundryerrors.TypeInternal, "failed to execute config template")
|
||||
}
|
||||
|
||||
functionBuf := bytes.NewBuffer(nil)
|
||||
if err := FunctionsClickhousev2556YAML.Execute(functionBuf, data); err != nil {
|
||||
return fmt.Errorf("failed to execute config template: %w", err)
|
||||
return foundryerrors.Wrapf(err, foundryerrors.TypeInternal, "failed to execute config template")
|
||||
}
|
||||
|
||||
base := configBuf.String()
|
||||
@@ -54,7 +53,7 @@ func (molding *telemetrystore) MoldV1Alpha1(ctx context.Context, config *install
|
||||
if overrides != "" {
|
||||
merged, err := domain.MergeYAML(base, overrides)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to merge config overrides for config.yaml: %w", err)
|
||||
return foundryerrors.Wrapf(err, foundryerrors.TypeInternal, "failed to merge config overrides for config.yaml")
|
||||
}
|
||||
base = merged
|
||||
}
|
||||
@@ -70,7 +69,7 @@ func (molding *telemetrystore) MoldV1Alpha1(ctx context.Context, config *install
|
||||
func (molding *telemetrystore) getData(config *installation.Casting) (Data, error) {
|
||||
storeAddresses := config.Spec.TelemetryStore.Status.Addresses.TCP
|
||||
if len(storeAddresses) == 0 {
|
||||
return Data{}, fmt.Errorf("telemetry store addresses not set in status")
|
||||
return Data{}, foundryerrors.Newf(foundryerrors.TypeInternal, "telemetry store addresses not set in status")
|
||||
}
|
||||
|
||||
cluster := config.Spec.TelemetryStore.Spec.Cluster
|
||||
@@ -87,7 +86,8 @@ func (molding *telemetrystore) getData(config *installation.Casting) (Data, erro
|
||||
|
||||
expectedNodes := shardCount * replicaCount
|
||||
if len(storeAddresses) < expectedNodes {
|
||||
return Data{}, fmt.Errorf(
|
||||
return Data{}, foundryerrors.Newf(
|
||||
foundryerrors.TypeInvalidInput,
|
||||
"insufficient addresses: have %d, need %d (shards=%d × replicas=%d)",
|
||||
len(storeAddresses), expectedNodes, shardCount, replicaCount,
|
||||
)
|
||||
@@ -95,17 +95,17 @@ func (molding *telemetrystore) getData(config *installation.Casting) (Data, erro
|
||||
|
||||
newStoreAddrs, err := domain.ParseAddresses(storeAddresses[:expectedNodes])
|
||||
if err != nil {
|
||||
return Data{}, fmt.Errorf("failed to parse addresses: %w", err)
|
||||
return Data{}, foundryerrors.Wrapf(err, foundryerrors.TypeInternal, "failed to parse addresses")
|
||||
}
|
||||
|
||||
keeperAddresses := config.Spec.TelemetryKeeper.Status.Addresses.Client
|
||||
if len(keeperAddresses) == 0 {
|
||||
return Data{}, fmt.Errorf("telemetry keeper addresses not set in status")
|
||||
return Data{}, foundryerrors.Newf(foundryerrors.TypeInternal, "telemetry keeper addresses not set in status")
|
||||
}
|
||||
|
||||
newKeeperAddrs, err := domain.ParseAddresses(keeperAddresses)
|
||||
if err != nil {
|
||||
return Data{}, fmt.Errorf("failed to parse addresses: %w", err)
|
||||
return Data{}, foundryerrors.Wrapf(err, foundryerrors.TypeInternal, "failed to parse addresses")
|
||||
}
|
||||
|
||||
return Data{
|
||||
|
||||
@@ -3,11 +3,11 @@ package jsonpatch
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
jsonpatchv5 "github.com/evanphx/json-patch/v5"
|
||||
"github.com/signoz/foundry/api/v1alpha1"
|
||||
"github.com/signoz/foundry/internal/domain"
|
||||
"github.com/signoz/foundry/internal/errors"
|
||||
"github.com/signoz/foundry/internal/patch"
|
||||
)
|
||||
|
||||
@@ -22,7 +22,7 @@ func New() patch.Patch {
|
||||
func (p *jsonPatch) Apply(ctx context.Context, materials []domain.Material, pe v1alpha1.PatchEntry) ([]domain.Material, error) {
|
||||
patchDoc, err := json.Marshal(pe.Operations)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to marshal patch operations for target %q: %w", pe.Target, err)
|
||||
return nil, errors.Wrapf(err, errors.TypeInternal, "failed to marshal patch operations for target %q", pe.Target)
|
||||
}
|
||||
|
||||
result := make([]domain.Material, len(materials))
|
||||
@@ -32,7 +32,7 @@ func (p *jsonPatch) Apply(ctx context.Context, materials []domain.Material, pe v
|
||||
for i, mat := range result {
|
||||
ok, err := patch.MatchTarget(pe.Target, mat.Path())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid glob pattern %q: %w", pe.Target, err)
|
||||
return nil, errors.Wrapf(err, errors.TypeInvalidInput, "invalid glob pattern %q", pe.Target)
|
||||
}
|
||||
if !ok {
|
||||
continue
|
||||
@@ -40,23 +40,23 @@ func (p *jsonPatch) Apply(ctx context.Context, materials []domain.Material, pe v
|
||||
|
||||
structured, ok := mat.(domain.StructuredMaterial)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("json patch on blob material %q is not supported", mat.Path())
|
||||
return nil, errors.Newf(errors.TypeUnsupported, "json patch on blob material %q is not supported", mat.Path())
|
||||
}
|
||||
|
||||
if structured.HasMultipleDocuments() {
|
||||
return nil, fmt.Errorf("json patch on multi-doc yaml material %q is not supported", mat.Path())
|
||||
return nil, errors.Newf(errors.TypeUnsupported, "json patch on multi-doc yaml material %q is not supported", mat.Path())
|
||||
}
|
||||
|
||||
matched = true
|
||||
patched, err := applyToMaterial(structured, patchDoc)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to apply patch to %q: %w", mat.Path(), err)
|
||||
return nil, errors.Wrapf(err, errors.TypeInternal, "failed to apply patch to %q", mat.Path())
|
||||
}
|
||||
result[i] = patched
|
||||
}
|
||||
|
||||
if !matched {
|
||||
return nil, fmt.Errorf("patch target %q did not match any generated material", pe.Target)
|
||||
return nil, errors.Newf(errors.TypeNotFound, "patch target %q did not match any generated material", pe.Target)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
@@ -65,12 +65,12 @@ func (p *jsonPatch) Apply(ctx context.Context, materials []domain.Material, pe v
|
||||
func applyToMaterial(mat domain.StructuredMaterial, patchDoc []byte) (domain.StructuredMaterial, error) {
|
||||
decoded, err := jsonpatchv5.DecodePatch(patchDoc)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to decode json patch: %w", err)
|
||||
return nil, errors.Wrapf(err, errors.TypeInvalidInput, "failed to decode json patch")
|
||||
}
|
||||
|
||||
patched, err := decoded.Apply(mat.JSONContents())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to apply json patch: %w", err)
|
||||
return nil, errors.Wrapf(err, errors.TypeInternal, "failed to apply json patch")
|
||||
}
|
||||
|
||||
return mat.CloneWithJSONContents(patched), nil
|
||||
|
||||
@@ -2,9 +2,9 @@ package clickhousekeepertooler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/signoz/foundry/internal/errors"
|
||||
root "github.com/signoz/foundry/internal/tooler"
|
||||
)
|
||||
|
||||
@@ -32,7 +32,7 @@ func (tooler *clickhouseKeeperTooler) Gauge(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("clickhouse-keeper not found: neither command nor binary at %s", binaryPath)
|
||||
return errors.Newf(errors.TypeNotFound, "clickhouse-keeper not found: neither command nor binary at %s", binaryPath)
|
||||
}
|
||||
|
||||
func (tooler *clickhouseKeeperTooler) Install(ctx context.Context) error {
|
||||
|
||||
@@ -2,9 +2,9 @@ package clickhousetooler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/signoz/foundry/internal/errors"
|
||||
root "github.com/signoz/foundry/internal/tooler"
|
||||
)
|
||||
|
||||
@@ -32,7 +32,7 @@ func (tooler *clickhouseTooler) Gauge(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("clickhouse-server not found: neither command nor binary at %s", binaryPath)
|
||||
return errors.Newf(errors.TypeNotFound, "clickhouse-server not found: neither command nor binary at %s", binaryPath)
|
||||
}
|
||||
|
||||
func (tooler *clickhouseTooler) Install(ctx context.Context) error {
|
||||
|
||||
@@ -2,10 +2,10 @@ package postgrestooler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/signoz/foundry/internal/errors"
|
||||
root "github.com/signoz/foundry/internal/tooler"
|
||||
)
|
||||
|
||||
@@ -52,7 +52,7 @@ func (tooler *postgresTooler) Gauge(ctx context.Context) error {
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Errorf("postgres not found: neither command nor binary in common locations")
|
||||
return errors.Newf(errors.TypeNotFound, "postgres not found: neither command nor binary in common locations")
|
||||
}
|
||||
|
||||
func (tooler *postgresTooler) Install(ctx context.Context) error {
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package writer
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
)
|
||||
|
||||
// WriteOutput writes m's MarshalJSON bytes (with a trailing newline) to w.
|
||||
// Used for stream payloads that don't have a filesystem path. Each implementer
|
||||
// owns its own envelope (e.g. errors.Envelope wraps as {"exception": {...}})
|
||||
// via MarshalJSON, so the writer stays a thin transport.
|
||||
func WriteOutput(w io.Writer, m json.Marshaler) error {
|
||||
data, err := m.MarshalJSON()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = w.Write(append(data, '\n'))
|
||||
|
||||
return err
|
||||
}
|
||||
@@ -2,7 +2,6 @@ package writer
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"log/slog"
|
||||
"os"
|
||||
@@ -37,7 +36,7 @@ func New(logger *slog.Logger, options *Options) (*Writer, error) {
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(options.TargetDirectory, 0755); err != nil {
|
||||
return nil, fmt.Errorf("failed to create output directory '%s': %s", options.TargetDirectory, err.Error())
|
||||
return nil, foundryerrors.Wrapf(err, foundryerrors.TypeInternal, "failed to create output directory '%s'", options.TargetDirectory)
|
||||
}
|
||||
|
||||
return &Writer{
|
||||
|
||||
Reference in New Issue
Block a user