diff --git a/cmd/internal/skills/command.go b/cmd/internal/skills/command.go index 9ccd36bb12b9..5e9b17b05a95 100644 --- a/cmd/internal/skills/command.go +++ b/cmd/internal/skills/command.go @@ -89,6 +89,8 @@ func run(cmd *skillsCmd, opts *internal.ToolboxOptions) error { return err } + opts.Cfg.SkipSourceInitialization = true + if err := os.MkdirAll(cmd.outputDir, 0755); err != nil { errMsg := fmt.Errorf("error creating output directory: %w", err) opts.Logger.ErrorContext(ctx, errMsg.Error()) diff --git a/internal/server/config.go b/internal/server/config.go index efa947cefeac..eb83fe1ef2d0 100644 --- a/internal/server/config.go +++ b/internal/server/config.go @@ -84,6 +84,8 @@ type ServerConfig struct { UserAgentMetadata []string // PollInterval sets the polling frequency for configuration file updates. PollInterval int + // SkipSourceInitialization indicates if the server should skip initializing sources. + SkipSourceInitialization bool } type logFormat string diff --git a/internal/server/server.go b/internal/server/server.go index d42c25b9cfcd..bbec8956aefe 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -89,6 +89,14 @@ func InitializeConfigs(ctx context.Context, cfg ServerConfig) ( // initialize and validate the sources from configs sourcesMap := make(map[string]sources.Source) for name, sc := range cfg.SourceConfigs { + if cfg.SkipSourceInitialization { + sourcesMap[name] = &sources.UninitializedSource{ + Name: name, + Config: sc, + } + continue + } + s, err := func() (sources.Source, error) { childCtx, span := instrumentation.Tracer.Start( ctx, @@ -183,6 +191,10 @@ func InitializeConfigs(ctx context.Context, cfg ServerConfig) ( defer span.End() t, err := tc.Initialize(sourcesMap) if err != nil { + if cfg.SkipSourceInitialization { + l.WarnContext(ctx, fmt.Sprintf("unable to initialize tool %q (source skip enabled): %v", name, err)) + return nil, nil + } return nil, fmt.Errorf("unable to initialize tool %q: %w", name, err) } return t, nil @@ -190,7 +202,9 @@ func InitializeConfigs(ctx context.Context, cfg ServerConfig) ( if err != nil { return nil, nil, nil, nil, nil, nil, nil, err } - toolsMap[name] = t + if t != nil { + toolsMap[name] = t + } } toolNames := make([]string, 0, len(toolsMap)) for name := range toolsMap { diff --git a/internal/sources/sources.go b/internal/sources/sources.go index 93ae0233b127..b2f213b7d045 100644 --- a/internal/sources/sources.go +++ b/internal/sources/sources.go @@ -16,6 +16,7 @@ package sources import ( "context" + "net/http" "fmt" @@ -65,6 +66,26 @@ type Source interface { ToConfig() SourceConfig } +// UninitializedSource is a placeholder for a source that hasn't been initialized yet. +// It implements many common methods to satisfy type assertions during tool initialization. +type UninitializedSource struct { + Name string + Config SourceConfig +} + +func (s *UninitializedSource) SourceType() string { return s.Config.SourceConfigType() } +func (s *UninitializedSource) ToConfig() SourceConfig { return s.Config } +func (s *UninitializedSource) HttpDefaultHeaders() map[string]string { return nil } +func (s *UninitializedSource) HttpBaseURL() string { return "" } +func (s *UninitializedSource) HttpQueryParams() map[string]string { return nil } +func (s *UninitializedSource) RunRequest(ctx context.Context, r *http.Request) (any, error) { return nil, nil } +func (s *UninitializedSource) PostgresPool() any { return nil } +func (s *UninitializedSource) SQLiteDB() any { return nil } +func (s *UninitializedSource) BigQueryClient() any { return nil } +func (s *UninitializedSource) RunSQL(ctx context.Context, stmt string, args []any) (any, error) { return nil, nil } +func (s *UninitializedSource) GetDefaultProject() string { return "" } +func (s *UninitializedSource) UseClientAuthorization() bool { return false } + // InitConnectionSpan adds a span for database pool connection initialization func InitConnectionSpan(ctx context.Context, tracer trace.Tracer, sourceType, sourceName string) (context.Context, trace.Span) { ctx, span := tracer.Start(