Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 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
8 changes: 8 additions & 0 deletions .github/workflows/dependencies.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,14 @@ jobs:
echo "troubleshoot version: $version"
sed -i "/^TROUBLESHOOT_VERSION/c\TROUBLESHOOT_VERSION = $version" versions.mk

- name: Helm
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
version=$(gh release list --repo helm/helm --json tagName,isLatest | jq -r '.[] | select(.isLatest) | .tagName')
echo "helm version: $version"
sed -i "/^HELM_VERSION/c\HELM_VERSION = $version" versions.mk

- name: FIO
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Expand Down
19 changes: 19 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,23 @@ output/bins/k0s-override:
chmod +x $@
touch $@

.PHONY: cmd/installer/goods/bins/helm
cmd/installer/goods/bins/helm:
$(MAKE) output/bins/helm-$(HELM_VERSION)-$(ARCH)
cp output/bins/helm-$(HELM_VERSION)-$(ARCH) $@
touch $@

output/bins/helm-%:
mkdir -p output/bins
mkdir -p output/tmp
curl --retry 5 --retry-all-errors -fL -o output/tmp/helm.tar.gz \
https://get.helm.sh/helm-$(call split-hyphen,$*,1)-$(OS)-$(call split-hyphen,$*,2).tar.gz
tar -xzf output/tmp/helm.tar.gz -C output/tmp
mv output/tmp/$(OS)-$(call split-hyphen,$*,2)/helm $@
rm -rf output/tmp
chmod +x $@
touch $@

.PHONY: cmd/installer/goods/bins/kubectl-support_bundle
cmd/installer/goods/bins/kubectl-support_bundle:
$(MAKE) output/bins/kubectl-support_bundle-$(TROUBLESHOOT_VERSION)-$(ARCH)
Expand Down Expand Up @@ -217,6 +234,7 @@ static: cmd/installer/goods/bins/k0s \
cmd/installer/goods/bins/kubectl-support_bundle \
cmd/installer/goods/bins/local-artifact-mirror \
cmd/installer/goods/bins/fio \
cmd/installer/goods/bins/helm \
cmd/installer/goods/internal/bins/kubectl-kots

.PHONY: static-dryrun
Expand All @@ -226,6 +244,7 @@ static-dryrun:
cmd/installer/goods/bins/kubectl-support_bundle \
cmd/installer/goods/bins/local-artifact-mirror \
cmd/installer/goods/bins/fio \
cmd/installer/goods/bins/helm \
cmd/installer/goods/internal/bins/kubectl-kots

.PHONY: embedded-cluster-linux-amd64
Expand Down
17 changes: 17 additions & 0 deletions api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
linuxupgrade "github.com/replicatedhq/embedded-cluster/api/controllers/linux/upgrade"
"github.com/replicatedhq/embedded-cluster/api/pkg/logger"
"github.com/replicatedhq/embedded-cluster/api/types"
"github.com/replicatedhq/embedded-cluster/pkg/helm"
"github.com/replicatedhq/embedded-cluster/pkg/metrics"
"github.com/replicatedhq/embedded-cluster/pkg/runtimeconfig"
"github.com/sirupsen/logrus"
Expand Down Expand Up @@ -39,6 +40,7 @@ import (
type API struct {
cfg types.APIConfig

hcli helm.Client
logger logrus.FieldLogger
metricsReporter metrics.ReporterInterface

Expand Down Expand Up @@ -111,8 +113,19 @@ func WithMetricsReporter(metricsReporter metrics.ReporterInterface) Option {
}
}

// WithHelmClient configures the helm client for the API.
func WithHelmClient(hcli helm.Client) Option {
return func(a *API) {
a.hcli = hcli
}
}

// New creates a new API instance.
func New(cfg types.APIConfig, opts ...Option) (*API, error) {
if cfg.InstallTarget == "" {
return nil, fmt.Errorf("target is required")
}

api := &API{
cfg: cfg,
}
Expand All @@ -133,6 +146,10 @@ func New(cfg types.APIConfig, opts ...Option) (*API, error) {
api.logger = l
}

if err := api.initClients(); err != nil {
return nil, fmt.Errorf("init clients: %w", err)
}

if err := api.initHandlers(); err != nil {
return nil, fmt.Errorf("init handlers: %w", err)
}
Expand Down
88 changes: 88 additions & 0 deletions api/clients.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package api

import (
"fmt"

"github.com/replicatedhq/embedded-cluster/api/internal/clients"
"github.com/replicatedhq/embedded-cluster/api/types"
"github.com/replicatedhq/embedded-cluster/pkg/helm"
"github.com/replicatedhq/embedded-cluster/pkg/versions"
)

func (a *API) initClients() error {
if a.hcli == nil {
if err := a.initHelmClient(); err != nil {
return fmt.Errorf("init helm client: %w", err)
}
}
return nil
}

// initHelmClient initializes the Helm client based on the installation target
func (a *API) initHelmClient() error {
switch a.cfg.InstallTarget {
case types.InstallTargetLinux:
return a.initLinuxHelmClient()
case types.InstallTargetKubernetes:
return a.initKubernetesHelmClient()
default:
return fmt.Errorf("unsupported install target: %s", a.cfg.InstallTarget)
}
}

// initLinuxHelmClient initializes the Helm client for Linux installations
func (a *API) initLinuxHelmClient() error {
airgapPath := ""
if a.cfg.AirgapBundle != "" {
airgapPath = a.cfg.RuntimeConfig.EmbeddedClusterChartsSubDir()
}

hcli, err := helm.NewClient(helm.HelmOptions{
HelmPath: a.cfg.RuntimeConfig.PathToEmbeddedClusterBinary("helm"),
KubernetesEnvSettings: a.cfg.RuntimeConfig.GetKubernetesEnvSettings(),
K8sVersion: versions.K0sVersion,
AirgapPath: airgapPath,
})
if err != nil {
return fmt.Errorf("create linux helm client: %w", err)
}

a.hcli = hcli
return nil
}

// initKubernetesHelmClient initializes the Helm client for Kubernetes installations
func (a *API) initKubernetesHelmClient() error {
// get the kubernetes version
kcli, err := clients.NewDiscoveryClient(clients.KubeClientOptions{
RESTClientGetter: a.cfg.Installation.GetKubernetesEnvSettings().RESTClientGetter(),
})
if err != nil {
return fmt.Errorf("create discovery client: %w", err)
}
k8sVersion, err := kcli.ServerVersion()
if err != nil {
return fmt.Errorf("get server version: %w", err)
}

// get the helm binary path
helmPath, err := a.cfg.Installation.PathToEmbeddedBinary("helm")
if err != nil {
return fmt.Errorf("get helm path: %w", err)
}

// create the helm client
hcli, err := helm.NewClient(helm.HelmOptions{
HelmPath: helmPath,
KubernetesEnvSettings: a.cfg.Installation.GetKubernetesEnvSettings(),
// TODO: how can we support airgap?
AirgapPath: "",
K8sVersion: k8sVersion.String(),
})
if err != nil {
return fmt.Errorf("create kubernetes helm client: %w", err)
}

a.hcli = hcli
return nil
}
9 changes: 9 additions & 0 deletions api/controllers/app/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/replicatedhq/embedded-cluster/api/internal/store"
"github.com/replicatedhq/embedded-cluster/api/pkg/logger"
"github.com/replicatedhq/embedded-cluster/api/types"
"github.com/replicatedhq/embedded-cluster/pkg/helm"
"github.com/replicatedhq/embedded-cluster/pkg/release"
kotsv1beta1 "github.com/replicatedhq/kotskinds/apis/kots/v1beta1"
"github.com/sirupsen/logrus"
Expand Down Expand Up @@ -46,6 +47,7 @@ type AppController struct {
logger logrus.FieldLogger
license []byte
releaseData *release.ReleaseData
hcli helm.Client
store store.Store
configValues types.AppConfigValues
clusterID string
Expand Down Expand Up @@ -109,6 +111,12 @@ func WithReleaseData(releaseData *release.ReleaseData) AppControllerOption {
}
}

func WithHelmClient(hcli helm.Client) AppControllerOption {
return func(c *AppController) {
c.hcli = hcli
}
}

func WithConfigValues(configValues types.AppConfigValues) AppControllerOption {
return func(c *AppController) {
c.configValues = configValues
Expand Down Expand Up @@ -202,6 +210,7 @@ func NewAppController(opts ...AppControllerOption) (*AppController, error) {
appreleasemanager.WithLicense(license),
appreleasemanager.WithIsAirgap(controller.airgapBundle != ""),
appreleasemanager.WithPrivateCACertConfigMapName(controller.privateCACertConfigMapName),
appreleasemanager.WithHelmClient(controller.hcli),
)
if err != nil {
return nil, fmt.Errorf("create app release manager: %w", err)
Expand Down
53 changes: 31 additions & 22 deletions api/controllers/kubernetes/install/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ import (
"github.com/replicatedhq/embedded-cluster/api/types"
ecv1beta1 "github.com/replicatedhq/embedded-cluster/kinds/apis/v1beta1"
"github.com/replicatedhq/embedded-cluster/pkg-new/kubernetesinstallation"
"github.com/replicatedhq/embedded-cluster/pkg/helm"
"github.com/replicatedhq/embedded-cluster/pkg/metrics"
"github.com/replicatedhq/embedded-cluster/pkg/release"
"github.com/sirupsen/logrus"
helmcli "helm.sh/helm/v3/pkg/cli"
"k8s.io/cli-runtime/pkg/genericclioptions"
)

type Controller interface {
Expand All @@ -34,21 +34,22 @@ type Controller interface {
var _ Controller = (*InstallController)(nil)

type InstallController struct {
installationManager installation.InstallationManager
infraManager infra.InfraManager
metricsReporter metrics.ReporterInterface
restClientGetter genericclioptions.RESTClientGetter
releaseData *release.ReleaseData
password string
tlsConfig types.TLSConfig
license []byte
airgapBundle string
configValues types.AppConfigValues
endUserConfig *ecv1beta1.Config
store store.Store
ki kubernetesinstallation.Installation
stateMachine statemachine.Interface
logger logrus.FieldLogger
installationManager installation.InstallationManager
infraManager infra.InfraManager
metricsReporter metrics.ReporterInterface
kubernetesEnvSettings *helmcli.EnvSettings
hcli helm.Client
releaseData *release.ReleaseData
password string
tlsConfig types.TLSConfig
license []byte
airgapBundle string
configValues types.AppConfigValues
endUserConfig *ecv1beta1.Config
store store.Store
ki kubernetesinstallation.Installation
stateMachine statemachine.Interface
logger logrus.FieldLogger
// App controller composition
*appcontroller.AppController
}
Expand All @@ -73,9 +74,15 @@ func WithMetricsReporter(metricsReporter metrics.ReporterInterface) InstallContr
}
}

func WithRESTClientGetter(restClientGetter genericclioptions.RESTClientGetter) InstallControllerOption {
func WithHelmClient(hcli helm.Client) InstallControllerOption {
return func(c *InstallController) {
c.restClientGetter = restClientGetter
c.hcli = hcli
}
}

func WithKubernetesEnvSettings(envSettings *helmcli.EnvSettings) InstallControllerOption {
return func(c *InstallController) {
c.kubernetesEnvSettings = envSettings
}
}

Expand Down Expand Up @@ -169,9 +176,9 @@ func NewInstallController(opts ...InstallControllerOption) (*InstallController,
controller.stateMachine = NewStateMachine(WithStateMachineLogger(controller.logger))
}

// If none is provided, use the default env settings from helm to create a RESTClientGetter
if controller.restClientGetter == nil {
controller.restClientGetter = helmcli.New().RESTClientGetter()
// If none is provided, use the default env settings from helm
if controller.kubernetesEnvSettings == nil {
controller.kubernetesEnvSettings = helmcli.New()
}

if controller.installationManager == nil {
Expand All @@ -192,6 +199,7 @@ func NewInstallController(opts ...InstallControllerOption) (*InstallController,
appcontroller.WithConfigValues(controller.configValues),
appcontroller.WithAirgapBundle(controller.airgapBundle),
appcontroller.WithPrivateCACertConfigMapName(""), // Private CA ConfigMap functionality not yet implemented for Kubernetes installations
appcontroller.WithHelmClient(controller.hcli),
)
if err != nil {
return nil, fmt.Errorf("create app install controller: %w", err)
Expand All @@ -203,13 +211,14 @@ func NewInstallController(opts ...InstallControllerOption) (*InstallController,
infraManager, err := infra.NewInfraManager(
infra.WithLogger(controller.logger),
infra.WithInfraStore(controller.store.KubernetesInfraStore()),
infra.WithRESTClientGetter(controller.restClientGetter),
infra.WithKubernetesEnvSettings(controller.kubernetesEnvSettings),
infra.WithPassword(controller.password),
infra.WithTLSConfig(controller.tlsConfig),
infra.WithLicense(controller.license),
infra.WithAirgapBundle(controller.airgapBundle),
infra.WithReleaseData(controller.releaseData),
infra.WithEndUserConfig(controller.endUserConfig),
infra.WithHelmClient(controller.hcli),
)
if err != nil {
return nil, fmt.Errorf("create infra manager: %w", err)
Expand Down
7 changes: 7 additions & 0 deletions api/controllers/kubernetes/install/controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/replicatedhq/embedded-cluster/api/types"
ecv1beta1 "github.com/replicatedhq/embedded-cluster/kinds/apis/v1beta1"
"github.com/replicatedhq/embedded-cluster/pkg-new/kubernetesinstallation"
"github.com/replicatedhq/embedded-cluster/pkg/helm"
"github.com/replicatedhq/embedded-cluster/pkg/metrics"
"github.com/replicatedhq/embedded-cluster/pkg/release"
kotsv1beta1 "github.com/replicatedhq/kotskinds/apis/kots/v1beta1"
Expand Down Expand Up @@ -111,6 +112,7 @@ func TestGetInstallationConfig(t *testing.T) {
WithInstallation(ki),
WithInstallationManager(mockManager),
WithReleaseData(getTestReleaseData(&kotsv1beta1.Config{})),
WithHelmClient(&helm.MockClient{}),
)
require.NoError(t, err)

Expand Down Expand Up @@ -228,6 +230,7 @@ func TestConfigureInstallation(t *testing.T) {
WithStore(mockStore),
WithMetricsReporter(mockMetricsReporter),
WithReleaseData(getTestReleaseData(&kotsv1beta1.Config{})),
WithHelmClient(&helm.MockClient{}),
)
require.NoError(t, err)

Expand Down Expand Up @@ -299,6 +302,7 @@ func TestGetInstallationStatus(t *testing.T) {
controller, err := NewInstallController(
WithInstallationManager(mockManager),
WithReleaseData(getTestReleaseData(&kotsv1beta1.Config{})),
WithHelmClient(&helm.MockClient{}),
)
require.NoError(t, err)

Expand Down Expand Up @@ -425,6 +429,7 @@ func TestSetupInfra(t *testing.T) {
appcontroller.WithStore(mockStore),
appcontroller.WithReleaseData(getTestReleaseData(&appConfig)),
appcontroller.WithAppConfigManager(mockAppConfigManager),
appcontroller.WithHelmClient(&helm.MockClient{}),
)
require.NoError(t, err)

Expand All @@ -437,6 +442,7 @@ func TestSetupInfra(t *testing.T) {
WithMetricsReporter(mockMetricsReporter),
WithReleaseData(getTestReleaseData(&appConfig)),
WithStore(mockStore),
WithHelmClient(&helm.MockClient{}),
)
require.NoError(t, err)

Expand Down Expand Up @@ -538,6 +544,7 @@ func TestGetInfra(t *testing.T) {
controller, err := NewInstallController(
WithInfraManager(mockManager),
WithReleaseData(getTestReleaseData(&kotsv1beta1.Config{})),
WithHelmClient(&helm.MockClient{}),
)
require.NoError(t, err)

Expand Down
Loading
Loading