Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,6 @@ hack/release
# Test binary, built with `go test -c`
*.test

# helm charts dependencies
*.tgz

# test coverage files
cover.out

Expand Down
18 changes: 18 additions & 0 deletions api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import (
"github.com/replicatedhq/embedded-cluster/pkg/metrics"
"github.com/replicatedhq/embedded-cluster/pkg/runtimeconfig"
"github.com/sirupsen/logrus"
"k8s.io/client-go/metadata"
"sigs.k8s.io/controller-runtime/pkg/client"
)

// API represents the main HTTP API server for the Embedded Cluster application.
Expand All @@ -41,6 +43,8 @@ type API struct {
cfg types.APIConfig

hcli helm.Client
kcli client.Client
mcli metadata.Interface
logger logrus.FieldLogger
metricsReporter metrics.ReporterInterface

Expand Down Expand Up @@ -120,6 +124,20 @@ func WithHelmClient(hcli helm.Client) Option {
}
}

// WithKubeClient configures the kube client for the API.
func WithKubeClient(kcli client.Client) Option {
return func(a *API) {
a.kcli = kcli
}
}

// WithMetadataClient configures the metadata client for the API.
func WithMetadataClient(mcli metadata.Interface) Option {
return func(a *API) {
a.mcli = mcli
}
}

// New creates a new API instance.
func New(cfg types.APIConfig, opts ...Option) (*API, error) {
if cfg.InstallTarget == "" {
Expand Down
6 changes: 5 additions & 1 deletion api/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,18 @@ type Client interface {
GetLinuxInstallationConfig(ctx context.Context) (types.LinuxInstallationConfigResponse, error)
GetLinuxInstallationStatus(ctx context.Context) (types.Status, error)
ConfigureLinuxInstallation(ctx context.Context, config types.LinuxInstallationConfig) (types.Status, error)
RunLinuxInstallHostPreflights(ctx context.Context) (types.InstallHostPreflightsStatusResponse, error)
GetLinuxInstallHostPreflightsStatus(ctx context.Context) (types.InstallHostPreflightsStatusResponse, error)
SetupLinuxInfra(ctx context.Context, ignoreHostPreflights bool) (types.Infra, error)
GetLinuxInfraStatus(ctx context.Context) (types.Infra, error)
ProcessLinuxAirgap(ctx context.Context) (types.Airgap, error)
GetLinuxAirgapStatus(ctx context.Context) (types.Airgap, error)
GetLinuxInstallAppConfigValues(ctx context.Context) (types.AppConfigValues, error)
PatchLinuxInstallAppConfigValues(ctx context.Context, values types.AppConfigValues) (types.AppConfigValues, error)
TemplateLinuxInstallAppConfig(ctx context.Context, values types.AppConfigValues) (types.AppConfig, error)
RunLinuxInstallAppPreflights(ctx context.Context) (types.InstallAppPreflightsStatusResponse, error)
GetLinuxInstallAppPreflightsStatus(ctx context.Context) (types.InstallAppPreflightsStatusResponse, error)
InstallLinuxApp(ctx context.Context) (types.AppInstall, error)
InstallLinuxApp(ctx context.Context, ignoreAppPreflights bool) (types.AppInstall, error)
GetLinuxAppInstallStatus(ctx context.Context) (types.AppInstall, error)
GetLinuxUpgradeAppConfigValues(ctx context.Context) (types.AppConfigValues, error)
PatchLinuxUpgradeAppConfigValues(ctx context.Context, values types.AppConfigValues) (types.AppConfigValues, error)
Expand Down
13 changes: 10 additions & 3 deletions api/client/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1226,6 +1226,13 @@ func TestClient_InstallLinuxApp(t *testing.T) {
assert.Equal(t, "/api/linux/install/app/install", r.URL.Path)
assert.Equal(t, "Bearer test-token", r.Header.Get("Authorization"))

// Decode request body
var config types.InstallAppRequest
err := json.NewDecoder(r.Body).Decode(&config)
require.NoError(t, err, "Failed to decode request body")

assert.True(t, config.IgnoreAppPreflights)

appInstall := types.AppInstall{
Status: types.Status{State: types.StateRunning, Description: "Installing app"},
Logs: "Installation started\n",
Expand All @@ -1236,7 +1243,7 @@ func TestClient_InstallLinuxApp(t *testing.T) {
defer server.Close()

c := New(server.URL, WithToken("test-token"))
appInstall, err := c.InstallLinuxApp(context.Background())
appInstall, err := c.InstallLinuxApp(context.Background(), true)

require.NoError(t, err)
assert.Equal(t, types.StateRunning, appInstall.Status.State)
Expand Down Expand Up @@ -1331,7 +1338,7 @@ func TestClient_AppInstallErrorHandling(t *testing.T) {
c := New(server.URL, WithToken("test-token"))

t.Run("InstallLinuxApp error", func(t *testing.T) {
_, err := c.InstallLinuxApp(context.Background())
_, err := c.InstallLinuxApp(context.Background(), true)
require.Error(t, err)
apiErr, ok := err.(*types.APIError)
require.True(t, ok)
Expand Down Expand Up @@ -1382,7 +1389,7 @@ func TestClient_AppInstallWithoutToken(t *testing.T) {
c := New(server.URL) // No token provided

t.Run("InstallLinuxApp without token", func(t *testing.T) {
_, err := c.InstallLinuxApp(context.Background())
_, err := c.InstallLinuxApp(context.Background(), true)
require.Error(t, err)
apiErr, ok := err.(*types.APIError)
require.True(t, ok)
Expand Down
127 changes: 125 additions & 2 deletions api/client/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,67 @@ func (c *client) GetLinuxInstallationStatus(ctx context.Context) (types.Status,
return status, nil
}

func (c *client) RunLinuxInstallHostPreflights(ctx context.Context) (types.InstallHostPreflightsStatusResponse, error) {
b, err := json.Marshal(types.PostInstallRunHostPreflightsRequest{
IsUI: false,
})
if err != nil {
return types.InstallHostPreflightsStatusResponse{}, err
}

req, err := http.NewRequestWithContext(ctx, "POST", c.apiURL+"/api/linux/install/host-preflights/run", bytes.NewBuffer(b))
if err != nil {
return types.InstallHostPreflightsStatusResponse{}, err
}
req.Header.Set("Content-Type", "application/json")
setAuthorizationHeader(req, c.token)

resp, err := c.httpClient.Do(req)
if err != nil {
return types.InstallHostPreflightsStatusResponse{}, err
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
return types.InstallHostPreflightsStatusResponse{}, errorFromResponse(resp)
}

var status types.InstallHostPreflightsStatusResponse
err = json.NewDecoder(resp.Body).Decode(&status)
if err != nil {
return types.InstallHostPreflightsStatusResponse{}, err
}

return status, nil
}

func (c *client) GetLinuxInstallHostPreflightsStatus(ctx context.Context) (types.InstallHostPreflightsStatusResponse, error) {
req, err := http.NewRequestWithContext(ctx, "GET", c.apiURL+"/api/linux/install/host-preflights/status", nil)
if err != nil {
return types.InstallHostPreflightsStatusResponse{}, err
}
req.Header.Set("Content-Type", "application/json")
setAuthorizationHeader(req, c.token)

resp, err := c.httpClient.Do(req)
if err != nil {
return types.InstallHostPreflightsStatusResponse{}, err
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
return types.InstallHostPreflightsStatusResponse{}, errorFromResponse(resp)
}

var status types.InstallHostPreflightsStatusResponse
err = json.NewDecoder(resp.Body).Decode(&status)
if err != nil {
return types.InstallHostPreflightsStatusResponse{}, err
}

return status, nil
}

func (c *client) SetupLinuxInfra(ctx context.Context, ignoreHostPreflights bool) (types.Infra, error) {
b, err := json.Marshal(types.LinuxInfraSetupRequest{
IgnoreHostPreflights: ignoreHostPreflights,
Expand Down Expand Up @@ -156,6 +217,60 @@ func (c *client) GetLinuxInfraStatus(ctx context.Context) (types.Infra, error) {
return infra, nil
}

func (c *client) ProcessLinuxAirgap(ctx context.Context) (types.Airgap, error) {
req, err := http.NewRequestWithContext(ctx, "POST", c.apiURL+"/api/linux/install/airgap/process", nil)
if err != nil {
return types.Airgap{}, err
}
req.Header.Set("Content-Type", "application/json")
setAuthorizationHeader(req, c.token)

resp, err := c.httpClient.Do(req)
if err != nil {
return types.Airgap{}, err
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
return types.Airgap{}, errorFromResponse(resp)
}

var airgap types.Airgap
err = json.NewDecoder(resp.Body).Decode(&airgap)
if err != nil {
return types.Airgap{}, err
}

return airgap, nil
}

func (c *client) GetLinuxAirgapStatus(ctx context.Context) (types.Airgap, error) {
req, err := http.NewRequestWithContext(ctx, "GET", c.apiURL+"/api/linux/install/airgap/status", nil)
if err != nil {
return types.Airgap{}, err
}
req.Header.Set("Content-Type", "application/json")
setAuthorizationHeader(req, c.token)

resp, err := c.httpClient.Do(req)
if err != nil {
return types.Airgap{}, err
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
return types.Airgap{}, errorFromResponse(resp)
}

var airgap types.Airgap
err = json.NewDecoder(resp.Body).Decode(&airgap)
if err != nil {
return types.Airgap{}, err
}

return airgap, nil
}

func (c *client) GetKubernetesInstallationConfig(ctx context.Context) (types.KubernetesInstallationConfigResponse, error) {
req, err := http.NewRequestWithContext(ctx, "GET", c.apiURL+"/api/kubernetes/install/installation/config", nil)
if err != nil {
Expand Down Expand Up @@ -601,8 +716,16 @@ func (c *client) GetKubernetesInstallAppPreflightsStatus(ctx context.Context) (t
return status, nil
}

func (c *client) InstallLinuxApp(ctx context.Context) (types.AppInstall, error) {
req, err := http.NewRequestWithContext(ctx, "POST", c.apiURL+"/api/linux/install/app/install", nil)
func (c *client) InstallLinuxApp(ctx context.Context, ignoreAppPreflights bool) (types.AppInstall, error) {
request := types.InstallAppRequest{
IgnoreAppPreflights: ignoreAppPreflights,
}
b, err := json.Marshal(request)
if err != nil {
return types.AppInstall{}, err
}

req, err := http.NewRequestWithContext(ctx, "POST", c.apiURL+"/api/linux/install/app/install", bytes.NewBuffer(b))
if err != nil {
return types.AppInstall{}, err
}
Expand Down
1 change: 1 addition & 0 deletions api/controllers/app/apppreflight.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ func (c *AppController) RunAppPreflights(ctx context.Context, opts RunAppPreflig
return fmt.Errorf("extract app preflight spec: %w", err)
}
if appPreflightSpec == nil {
// TODO: support for installing without an app preflight spec
return fmt.Errorf("no app preflight spec found")
}

Expand Down
10 changes: 10 additions & 0 deletions api/controllers/kubernetes/install/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"github.com/replicatedhq/embedded-cluster/pkg/release"
"github.com/sirupsen/logrus"
helmcli "helm.sh/helm/v3/pkg/cli"
"k8s.io/client-go/metadata"
"sigs.k8s.io/controller-runtime/pkg/client"
)

Expand All @@ -40,6 +41,7 @@ type InstallController struct {
metricsReporter metrics.ReporterInterface
hcli helm.Client
kcli client.Client
mcli metadata.Interface
kubernetesEnvSettings *helmcli.EnvSettings
releaseData *release.ReleaseData
password string
Expand Down Expand Up @@ -88,6 +90,12 @@ func WithKubeClient(kcli client.Client) InstallControllerOption {
}
}

func WithMetadataClient(mcli metadata.Interface) InstallControllerOption {
return func(c *InstallController) {
c.mcli = mcli
}
}

func WithKubernetesEnvSettings(envSettings *helmcli.EnvSettings) InstallControllerOption {
return func(c *InstallController) {
c.kubernetesEnvSettings = envSettings
Expand Down Expand Up @@ -229,6 +237,8 @@ func NewInstallController(opts ...InstallControllerOption) (*InstallController,
infra.WithReleaseData(controller.releaseData),
infra.WithEndUserConfig(controller.endUserConfig),
infra.WithHelmClient(controller.hcli),
infra.WithKubeClient(controller.kcli),
infra.WithMetadataClient(controller.mcli),
)
if err != nil {
return nil, fmt.Errorf("create infra manager: %w", err)
Expand Down
10 changes: 10 additions & 0 deletions api/controllers/linux/install/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"github.com/replicatedhq/embedded-cluster/pkg/release"
"github.com/replicatedhq/embedded-cluster/pkg/runtimeconfig"
"github.com/sirupsen/logrus"
"k8s.io/client-go/metadata"
"sigs.k8s.io/controller-runtime/pkg/client"
)

Expand Down Expand Up @@ -72,6 +73,7 @@ type InstallController struct {
rc runtimeconfig.RuntimeConfig
hcli helm.Client
kcli client.Client
mcli metadata.Interface
stateMachine statemachine.Interface
logger logrus.FieldLogger
allowIgnoreHostPreflights bool
Expand Down Expand Up @@ -231,6 +233,12 @@ func WithKubeClient(kcli client.Client) InstallControllerOption {
}
}

func WithMetadataClient(mcli metadata.Interface) InstallControllerOption {
return func(c *InstallController) {
c.mcli = mcli
}
}

func NewInstallController(opts ...InstallControllerOption) (*InstallController, error) {
controller := &InstallController{
store: store.NewMemoryStore(),
Expand Down Expand Up @@ -319,6 +327,8 @@ func NewInstallController(opts ...InstallControllerOption) (*InstallController,
infra.WithEndUserConfig(controller.endUserConfig),
infra.WithClusterID(controller.clusterID),
infra.WithHelmClient(controller.hcli),
infra.WithKubeClient(controller.kcli),
infra.WithMetadataClient(controller.mcli),
)
}

Expand Down
10 changes: 10 additions & 0 deletions api/controllers/linux/upgrade/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"github.com/replicatedhq/embedded-cluster/pkg/release"
"github.com/replicatedhq/embedded-cluster/pkg/runtimeconfig"
"github.com/sirupsen/logrus"
"k8s.io/client-go/metadata"
"sigs.k8s.io/controller-runtime/pkg/client"
)

Expand Down Expand Up @@ -58,6 +59,7 @@ type UpgradeController struct {
rc runtimeconfig.RuntimeConfig
hcli helm.Client
kcli client.Client
mcli metadata.Interface
stateMachine statemachine.Interface
requiresInfraUpgrade bool
logger logrus.FieldLogger
Expand Down Expand Up @@ -189,6 +191,12 @@ func WithKubeClient(kcli client.Client) UpgradeControllerOption {
}
}

func WithMetadataClient(mcli metadata.Interface) UpgradeControllerOption {
return func(c *UpgradeController) {
c.mcli = mcli
}
}

func WithEndUserConfig(endUserConfig *ecv1beta1.Config) UpgradeControllerOption {
return func(c *UpgradeController) {
c.endUserConfig = endUserConfig
Expand Down Expand Up @@ -262,6 +270,8 @@ func NewUpgradeController(opts ...UpgradeControllerOption) (*UpgradeController,
infra.WithEndUserConfig(controller.endUserConfig),
infra.WithClusterID(controller.clusterID),
infra.WithHelmClient(controller.hcli),
infra.WithKubeClient(controller.kcli),
infra.WithMetadataClient(controller.mcli),
)
}

Expand Down
4 changes: 4 additions & 0 deletions api/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ func (a *API) initHandlers() error {
linuxhandler.WithInstallController(a.linuxInstallController),
linuxhandler.WithUpgradeController(a.linuxUpgradeController),
linuxhandler.WithHelmClient(a.hcli),
linuxhandler.WithKubeClient(a.kcli),
linuxhandler.WithMetadataClient(a.mcli),
)
if err != nil {
return fmt.Errorf("new linux handler: %w", err)
Expand All @@ -72,6 +74,8 @@ func (a *API) initHandlers() error {
kuberneteshandler.WithInstallController(a.kubernetesInstallController),
kuberneteshandler.WithUpgradeController(a.kubernetesUpgradeController),
kuberneteshandler.WithHelmClient(a.hcli),
kuberneteshandler.WithKubeClient(a.kcli),
kuberneteshandler.WithMetadataClient(a.mcli),
)
if err != nil {
return fmt.Errorf("new kubernetes handler: %w", err)
Expand Down
Loading