Skip to content

Conversation

@emosbaugh
Copy link
Member

@emosbaugh emosbaugh commented Nov 6, 2025

feat(v3): headless install orchestrator implementation - configure application

What this PR does / why we need it

This PR implements the headless installation orchestrator for the v3 API architecture. The orchestrator provides a programmatic way to execute complete installation workflows by coordinating with the v3 API server running in-process.

Key Components

Orchestrator Architecture (cmd/installer/cli/headless/install/orchestrator.go):

  • Implements the Orchestrator interface for managing headless installation workflows
  • Provides a clean abstraction layer between CLI and the v3 API client
  • Supports functional options pattern for configurable progress writers and loggers
  • Includes structured error handling with user-friendly error formatting

API Client Context Support (api/client/):

  • Adds context.Context support to all API client methods for better cancellation and timeout handling
  • Enables proper request lifecycle management in long-running operations
  • Maintains backward compatibility through interface updates

CLI Integration (cmd/installer/cli/install_v3.go):

  • Implements runV3InstallHeadless for the new headless installation flow
  • Includes builder functions for constructing orchestrator and install options from CLI flags
  • Provides clear error messages with recovery instructions based on failure point

Structured Error Handling (cmd/installer/cli/headless/install/errors.go):

  • Formats API validation errors for user display
  • Extracts field-level error details from API responses
  • Provides clear, actionable error messages

Implementation Status

This PR implements the first phase of the headless installation workflow:

  • ✅ Application configuration with config values
  • ⏳ Installation settings configuration (TODO)
  • ⏳ Host preflight checks (TODO)
  • ⏳ Infrastructure setup (TODO)
  • ⏳ Airgap bundle processing (TODO)
  • ⏳ App preflight checks (TODO)
  • ⏳ Application installation (TODO)

The orchestrator returns an appropriate error indicating the feature is not yet fully implemented. Remaining steps will be added in follow-up PRs.

Testing

Comprehensive test coverage includes:

  • Unit tests for orchestrator options (WithProgressWriter, WithLogger)
  • Integration tests for application configuration flow with validation error handling
  • Builder function tests for CLI input transformation
  • Error formatting tests for various API error structures
  • Test utilities with detailed documentation for future test development

Code Quality Improvements

  • Added comprehensive comments to all exported types and functions
  • Documented struct fields with clear descriptions
  • Included usage examples in test helper documentation
  • Followed Go best practices for interface design and error handling

Examples

# output/bin/embedded-cluster install --target=linux --headless --admin-console-password password --license local-dev/license-ethan.yaml --yes --config-values config-values.yaml 

No certificate files provided. A self-signed certificate will be used, and your browser will show a security warning.
To use your own certificate, provide both --tls-key and --tls-cert flags.
✔  Application configuration complete

Error: headless installation is not yet fully implemented - coming in a future release

For configuration options, run: embedded-cluster-smoke-test-staging-app install --help
Please correct the above issues and retry
# output/bin/embedded-cluster install --target=linux --headless --admin-console-password password --license local-dev/license-ethan.yaml --yes --config-values config-values.yaml 

No certificate files provided. A self-signed certificate will be used, and your browser will show a security warning.
To use your own certificate, provide both --tls-key and --tls-cert flags.
✗  Application configuration failed

Error: application configuration validation failed: field errors:
  - Field 'text_required_with_regex': Required Email Address is required
  - Field 'password_required': Password marked required is required

For configuration options, run: embedded-cluster-smoke-test-staging-app install --help
Please correct the above issues and retry

Which issue(s) this PR fixes

[SC-130867]

Does this PR require a test?

Yes - Comprehensive tests included:

  • cmd/installer/cli/headless/install/errors_test.go - Error formatting
  • cmd/installer/cli/headless/install/orchestrator_test.go - Orchestrator behavior and options
  • cmd/installer/cli/install_v3_test.go - CLI integration and builder functions
  • api/client/client_test.go - Updated for context support

All tests pass successfully.

Does this PR require a release note?

NONE

Does this PR require documentation?

Not at this time - Documentation will be added when the headless installation feature is fully implemented and ready for end-user consumption. Internal API documentation is included in code comments.


Technical Details

API Client Changes

All api/client.Client interface methods now accept context.Context as the first parameter:

// Before
func (c *client) Authenticate(password string) error

// After
func (c *client) Authenticate(ctx context.Context, password string) error

This enables:

  • Request cancellation via context
  • Timeout enforcement
  • Proper cleanup of resources
  • Distributed tracing support (future)

Orchestrator Pattern

The orchestrator uses the functional options pattern for flexibility:

orchestrator, err := install.NewOrchestrator(
    ctx,
    apiClient,
    password,
    "linux",
    install.WithProgressWriter(customWriter),
    install.WithLogger(customLogger),
)

Error Handling

API errors are structured and user-friendly:

Error: application configuration validation failed: field errors:
  - Field 'database_host': required field missing
  - Field 'replica_count': value "10" exceeds maximum allowed value 5
  - Field 'enable_ssl': validation rule failed: SSL requires cert_path to be set

For configuration options, run: embedded-cluster install --help
Please correct the above issues and retry

Reset Detection

The orchestrator tracks which failures require a system reset:

resetNeeded, err := orchestrator.RunHeadlessInstall(ctx, opts)
if err != nil {
    displayInstallErrorAndRecoveryInstructions(err, resetNeeded, binaryName, logger)
}

This helps users understand recovery steps without trial and error.

Next Steps

Follow-up PRs will implement:

  1. Installation settings configuration
  2. Host and infrastructure setup
  3. Airgap bundle processing
  4. Application preflight checks
  5. Final application installation
  6. End-to-end integration tests
  7. User documentation

Reviewers

Please pay special attention to:

  • Orchestrator interface design - is it flexible enough for future needs?
  • Error handling patterns - are errors actionable and clear?
  • Test coverage - are edge cases adequately covered?
  • Context propagation - is it consistent throughout the call chain?

@github-actions
Copy link

github-actions bot commented Nov 6, 2025

This PR has been released (on staging) and is available for download with a embedded-cluster-smoke-test-staging-app license ID.

Online Installer:

curl "https://staging.replicated.app/embedded/embedded-cluster-smoke-test-staging-app/ci/appver-dev-ec10e1c" -H "Authorization: $EC_SMOKE_TEST_LICENSE_ID" -o embedded-cluster-smoke-test-staging-app-ci.tgz

Airgap Installer (may take a few minutes before the airgap bundle is built):

curl "https://staging.replicated.app/embedded/embedded-cluster-smoke-test-staging-app/ci-airgap/appver-dev-ec10e1c?airgap=true" -H "Authorization: $EC_SMOKE_TEST_LICENSE_ID" -o embedded-cluster-smoke-test-staging-app-ci.tgz

Happy debugging!

@emosbaugh emosbaugh marked this pull request as ready for review November 6, 2025 14:53
// It implements the logrus.Hook interface to intercept all log messages and
// store them for verification in tests. This allows tests to verify that
// specific log messages are produced without requiring actual log output.
type logMessageCapture struct {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this seems helpful overall, should it be moved to a util package so it can be re-used? maybe in the spinner package even?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i will reuse it heavily within this package. if we want to move it to a utility package perhaps we can do that later.

return orchestrator, nil
}

// buildHeadlessInstallOptions (Hop) creates HeadlessInstallOptions from CLI inputs.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! 🙌

Comment on lines 307 to 309
// Note: This test requires a real API server to be running for authentication.
// In practice, we would need to mock the API client or have a test server.
// For now, we'll test the target validation logic which happens before API calls.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this intentional or is the test incomplete?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

refactored

assert.Contains(t, err.Error(), tt.expectedError)
assert.Nil(t, orchestrator)
} else {
// We expect an error here because there's no actual API server running
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

refactored

@emosbaugh emosbaugh changed the title feat(v3): headless install orchestrator implementation feat(v3): headless install orchestrator implementation - configure application Nov 6, 2025
@emosbaugh emosbaugh enabled auto-merge (squash) November 6, 2025 19:21
@emosbaugh emosbaugh merged commit 29fc126 into main Nov 7, 2025
142 of 149 checks passed
@emosbaugh emosbaugh deleted the emosbaugh/sc-130867/headless-install-headless-orchestrator-implementation branch November 7, 2025 00:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants