Skip to content

feat: preflight storage needed to perform airgap install #2336

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
0b06490
Add airgap bundle size to Installation CRD
banjoh Jun 18, 2025
e270d49
Generate operator CRDs
banjoh Jun 18, 2025
d54331b
Create airgapinfo package to parse airgap bundle metadata
banjoh Jun 18, 2025
2143149
Store airgap bundle size in Installation custom resource
banjoh Jun 19, 2025
668b930
Add airgap storage space to host preflights for controller nodes
banjoh Jun 19, 2025
473f5e1
Add controller airgap storage space calculation
banjoh Jun 19, 2025
46ca2d3
Separate airgap storage space preflight for controller and worker nodes
banjoh Jun 19, 2025
b88f435
Extract airgap.yaml once
banjoh Jun 19, 2025
5e53eca
Fix failing tests
banjoh Jun 19, 2025
9911048
Add airgap bundle size to Installation CRD
banjoh Jun 18, 2025
3fff57f
Generate operator CRDs
banjoh Jun 18, 2025
a1e8816
Create airgapinfo package to parse airgap bundle metadata
banjoh Jun 18, 2025
a3d3847
Store airgap bundle size in Installation custom resource
banjoh Jun 19, 2025
367c093
Add airgap storage space to host preflights for controller nodes
banjoh Jun 19, 2025
69038ae
Add controller airgap storage space calculation
banjoh Jun 19, 2025
a1e0ee4
Separate airgap storage space preflight for controller and worker nodes
banjoh Jun 19, 2025
ee7964f
Extract airgap.yaml once
banjoh Jun 19, 2025
d93f5cf
Fix failing tests
banjoh Jun 19, 2025
8691b79
Merge branch 'evansmungai/sc-123579/take-airgap-bundle-size-into-acco…
banjoh Jun 19, 2025
fb4f1b5
Comment out CI jobs
banjoh Jun 19, 2025
05f7910
Fix imports
banjoh Jun 19, 2025
fc96cf4
Revert ci.yaml
banjoh Jun 19, 2025
30e78de
Pass airgap info to the api
banjoh Jun 20, 2025
f72e05c
Merge remote-tracking branch 'origin/main' into evansmungai/sc-123579…
banjoh Jun 23, 2025
5206aab
Move airgapInfo to preRunInstall
banjoh Jun 24, 2025
5235538
Merge remote-tracking branch 'origin/main' into evansmungai/sc-123579…
banjoh Jun 24, 2025
00f00dc
A few more refactorings
banjoh Jun 24, 2025
9f3562b
Pass airgap info to infra manager
banjoh Jun 24, 2025
a8f86ba
Merge remote-tracking branch 'origin/main' into evansmungai/sc-123579…
banjoh Jun 26, 2025
b263856
Commit missing changes
banjoh Jun 26, 2025
ea2604e
Include embedded assets and k0s image to preflight calculation
banjoh Jul 25, 2025
b3c5911
Regenerate CRDs
banjoh Jul 25, 2025
f973cf0
Merge remote-tracking branch 'origin/main' into evansmungai/sc-123579…
banjoh Jul 25, 2025
f5fa0e6
Run go mod tidy
banjoh Jul 25, 2025
73e1766
Rerun CRD generation
banjoh Jul 25, 2025
184e13f
Add k0s image to test airgap bundle
banjoh Jul 25, 2025
d5f93ab
Update failing tests
banjoh Jul 25, 2025
1e822cc
Run go fmt
banjoh Jul 25, 2025
1673f4e
Add k0s image to test airgap bundles
banjoh Jul 25, 2025
24557bf
Fix failing test
banjoh Jul 25, 2025
111980f
Update cmd/installer/goods/materializer.go
banjoh Jul 25, 2025
759b11c
Update pkg/airgap/airgapinfo.go
banjoh Jul 25, 2025
bdcbb56
Update pkg/airgap/airgapinfo.go
banjoh Jul 25, 2025
49dbcf2
Changes from PR comments
banjoh Jul 25, 2025
a6d574a
Fix failing test
banjoh Jul 28, 2025
a32155d
Merge remote-tracking branch 'origin/main' into evansmungai/sc-123579…
banjoh Jul 28, 2025
f1151ff
Changes from manual testing
banjoh Jul 29, 2025
79d5191
Merge remote-tracking branch 'origin/main' into evansmungai/sc-123579…
banjoh Jul 29, 2025
41dc001
Fix failing test
banjoh Jul 29, 2025
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
9 changes: 9 additions & 0 deletions api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"github.com/replicatedhq/embedded-cluster/pkg/metrics"
"github.com/replicatedhq/embedded-cluster/pkg/release"
"github.com/replicatedhq/embedded-cluster/pkg/runtimeconfig"
kotsv1beta1 "github.com/replicatedhq/kotskinds/apis/kots/v1beta1"
"github.com/sirupsen/logrus"
httpSwagger "github.com/swaggo/http-swagger/v2"
)
Expand Down Expand Up @@ -50,6 +51,7 @@ type API struct {
tlsConfig types.TLSConfig
license []byte
airgapBundle string
airgapInfo *kotsv1beta1.Airgap
configValues string
endUserConfig *ecv1beta1.Config
logger logrus.FieldLogger
Expand Down Expand Up @@ -125,6 +127,12 @@ func WithAirgapBundle(airgapBundle string) APIOption {
}
}

func WithAirgapInfo(airgapInfo *kotsv1beta1.Airgap) APIOption {
return func(a *API) {
a.airgapInfo = airgapInfo
}
}

func WithConfigValues(configValues string) APIOption {
return func(a *API) {
a.configValues = configValues
Expand Down Expand Up @@ -190,6 +198,7 @@ func New(password string, opts ...APIOption) (*API, error) {
install.WithTLSConfig(api.tlsConfig),
install.WithLicense(api.license),
install.WithAirgapBundle(api.airgapBundle),
install.WithAirgapInfo(api.airgapInfo),
install.WithConfigValues(api.configValues),
install.WithEndUserConfig(api.endUserConfig),
)
Expand Down
8 changes: 8 additions & 0 deletions api/controllers/install/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"github.com/replicatedhq/embedded-cluster/pkg/metrics"
"github.com/replicatedhq/embedded-cluster/pkg/release"
"github.com/replicatedhq/embedded-cluster/pkg/runtimeconfig"
kotsv1beta1 "github.com/replicatedhq/kotskinds/apis/kots/v1beta1"
"github.com/sirupsen/logrus"
)

Expand Down Expand Up @@ -52,6 +53,7 @@ type InstallController struct {
tlsConfig types.TLSConfig
license []byte
airgapBundle string
airgapInfo *kotsv1beta1.Airgap
configValues string
endUserConfig *ecv1beta1.Config

Expand Down Expand Up @@ -125,6 +127,12 @@ func WithAirgapBundle(airgapBundle string) InstallControllerOption {
}
}

func WithAirgapInfo(airgapInfo *kotsv1beta1.Airgap) InstallControllerOption {
return func(c *InstallController) {
c.airgapInfo = airgapInfo
}
}

func WithConfigValues(configValues string) InstallControllerOption {
return func(c *InstallController) {
c.configValues = configValues
Expand Down
20 changes: 14 additions & 6 deletions api/controllers/install/hostpreflight.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/replicatedhq/embedded-cluster/api/internal/managers/preflight"
"github.com/replicatedhq/embedded-cluster/api/pkg/utils"
"github.com/replicatedhq/embedded-cluster/api/types"
"github.com/replicatedhq/embedded-cluster/pkg-new/preflights"
"github.com/replicatedhq/embedded-cluster/pkg/netutils"
)

Expand All @@ -33,14 +34,21 @@ func (c *InstallController) RunHostPreflights(ctx context.Context, opts RunHostP
// Get the configured custom domains
ecDomains := utils.GetDomains(c.releaseData)

// Calculate airgap storage space requirement (2x uncompressed size for controller nodes)
var controllerAirgapStorageSpace string
if c.airgapInfo != nil {
controllerAirgapStorageSpace = preflights.CalculateAirgapStorageSpace(c.airgapInfo.Spec.UncompressedSize, true)
}

// Prepare host preflights
hpf, err := c.hostPreflightManager.PrepareHostPreflights(ctx, c.rc, preflight.PrepareHostPreflightOptions{
ReplicatedAppURL: netutils.MaybeAddHTTPS(ecDomains.ReplicatedAppDomain),
ProxyRegistryURL: netutils.MaybeAddHTTPS(ecDomains.ProxyRegistryDomain),
HostPreflightSpec: c.releaseData.HostPreflights,
EmbeddedClusterConfig: c.releaseData.EmbeddedClusterConfig,
IsAirgap: c.airgapBundle != "",
IsUI: opts.IsUI,
ReplicatedAppURL: netutils.MaybeAddHTTPS(ecDomains.ReplicatedAppDomain),
ProxyRegistryURL: netutils.MaybeAddHTTPS(ecDomains.ProxyRegistryDomain),
HostPreflightSpec: c.releaseData.HostPreflights,
EmbeddedClusterConfig: c.releaseData.EmbeddedClusterConfig,
IsAirgap: c.airgapBundle != "",
IsUI: opts.IsUI,
ControllerAirgapStorageSpace: controllerAirgapStorageSpace,
})
if err != nil {
return fmt.Errorf("failed to prepare host preflights: %w", err)
Expand Down
33 changes: 25 additions & 8 deletions api/internal/managers/infra/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/replicatedhq/embedded-cluster/pkg/addons"
"github.com/replicatedhq/embedded-cluster/pkg/addons/registry"
addontypes "github.com/replicatedhq/embedded-cluster/pkg/addons/types"
"github.com/replicatedhq/embedded-cluster/pkg/airgap"
"github.com/replicatedhq/embedded-cluster/pkg/extensions"
"github.com/replicatedhq/embedded-cluster/pkg/helm"
"github.com/replicatedhq/embedded-cluster/pkg/kubeutils"
Expand Down Expand Up @@ -98,6 +99,15 @@ func (m *infraManager) install(ctx context.Context, rc runtimeconfig.RuntimeConf
return fmt.Errorf("parse license: %w", err)
}

var airgapInfo *kotsv1beta1.Airgap
if m.airgapBundle != "" {
var err error
airgapInfo, err = airgap.AirgapInfoFromPath(m.airgapBundle)
if err != nil {
return fmt.Errorf("failed to get airgap info: %w", err)
}
}

Copy link
Member

Choose a reason for hiding this comment

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

Can you follow the same pattern described here where you make airgapInfo a property of the manager and pass it with the function WithAirgapInfo?

if err := m.initComponentsList(license, rc); err != nil {
return fmt.Errorf("init components: %w", err)
}
Expand All @@ -123,7 +133,7 @@ func (m *infraManager) install(ctx context.Context, rc runtimeconfig.RuntimeConf
}
defer hcli.Close()

in, err := m.recordInstallation(ctx, kcli, license, rc)
in, err := m.recordInstallation(ctx, kcli, license, rc, airgapInfo)
if err != nil {
return fmt.Errorf("record installation: %w", err)
}
Expand Down Expand Up @@ -218,21 +228,28 @@ func (m *infraManager) installK0s(ctx context.Context, rc runtimeconfig.RuntimeC
return k0sCfg, nil
}

func (m *infraManager) recordInstallation(ctx context.Context, kcli client.Client, license *kotsv1beta1.License, rc runtimeconfig.RuntimeConfig) (*ecv1beta1.Installation, error) {
func (m *infraManager) recordInstallation(ctx context.Context, kcli client.Client, license *kotsv1beta1.License, rc runtimeconfig.RuntimeConfig, airgapInfo *kotsv1beta1.Airgap) (*ecv1beta1.Installation, error) {
Copy link
Member

Choose a reason for hiding this comment

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

this will no longer need to be an argument as infraManager will have a property airgapInfo

logFn := m.logFn("metadata")

// get the configured custom domains
ecDomains := utils.GetDomains(m.releaseData)

// extract airgap uncompressed size if airgap info is provided
var airgapUncompressedSize int64
if airgapInfo != nil {
airgapUncompressedSize = airgapInfo.Spec.UncompressedSize
}

// record the installation
logFn("recording installation")
in, err := kubeutils.RecordInstallation(ctx, kcli, kubeutils.RecordInstallationOptions{
IsAirgap: m.airgapBundle != "",
License: license,
ConfigSpec: m.getECConfigSpec(),
MetricsBaseURL: netutils.MaybeAddHTTPS(ecDomains.ReplicatedAppDomain),
RuntimeConfig: rc.Get(),
EndUserConfig: m.endUserConfig,
IsAirgap: m.airgapBundle != "",
License: license,
ConfigSpec: m.getECConfigSpec(),
MetricsBaseURL: netutils.MaybeAddHTTPS(ecDomains.ReplicatedAppDomain),
RuntimeConfig: rc.Get(),
EndUserConfig: m.endUserConfig,
AirgapUncompressedSize: airgapUncompressedSize,
})
if err != nil {
return nil, fmt.Errorf("record installation: %w", err)
Expand Down
52 changes: 28 additions & 24 deletions api/internal/managers/preflight/hostpreflight.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,16 @@ import (
)

type PrepareHostPreflightOptions struct {
ReplicatedAppURL string
ProxyRegistryURL string
HostPreflightSpec *troubleshootv1beta2.HostPreflightSpec
EmbeddedClusterConfig *ecv1beta1.Config
TCPConnectionsRequired []string
IsAirgap bool
IsJoin bool
IsUI bool
ReplicatedAppURL string
ProxyRegistryURL string
HostPreflightSpec *troubleshootv1beta2.HostPreflightSpec
EmbeddedClusterConfig *ecv1beta1.Config
TCPConnectionsRequired []string
IsAirgap bool
IsJoin bool
IsUI bool
ControllerAirgapStorageSpace string
WorkerAirgapStorageSpace string
}

type RunHostPreflightOptions struct {
Expand All @@ -38,22 +40,24 @@ func (m *hostPreflightManager) PrepareHostPreflights(ctx context.Context, rc run

// Use the shared Prepare function to prepare host preflights
prepareOpts := preflights.PrepareOptions{
HostPreflightSpec: opts.HostPreflightSpec,
ReplicatedAppURL: opts.ReplicatedAppURL,
ProxyRegistryURL: opts.ProxyRegistryURL,
AdminConsolePort: rc.AdminConsolePort(),
LocalArtifactMirrorPort: rc.LocalArtifactMirrorPort(),
DataDir: rc.EmbeddedClusterHomeDirectory(),
K0sDataDir: rc.EmbeddedClusterK0sSubDir(),
OpenEBSDataDir: rc.EmbeddedClusterOpenEBSLocalSubDir(),
Proxy: rc.ProxySpec(),
PodCIDR: rc.PodCIDR(),
ServiceCIDR: rc.ServiceCIDR(),
NodeIP: nodeIP,
IsAirgap: opts.IsAirgap,
TCPConnectionsRequired: opts.TCPConnectionsRequired,
IsJoin: opts.IsJoin,
IsUI: opts.IsUI,
HostPreflightSpec: opts.HostPreflightSpec,
ReplicatedAppURL: opts.ReplicatedAppURL,
ProxyRegistryURL: opts.ProxyRegistryURL,
AdminConsolePort: rc.AdminConsolePort(),
LocalArtifactMirrorPort: rc.LocalArtifactMirrorPort(),
DataDir: rc.EmbeddedClusterHomeDirectory(),
K0sDataDir: rc.EmbeddedClusterK0sSubDir(),
OpenEBSDataDir: rc.EmbeddedClusterOpenEBSLocalSubDir(),
Proxy: rc.ProxySpec(),
PodCIDR: rc.PodCIDR(),
ServiceCIDR: rc.ServiceCIDR(),
NodeIP: nodeIP,
IsAirgap: opts.IsAirgap,
TCPConnectionsRequired: opts.TCPConnectionsRequired,
IsJoin: opts.IsJoin,
IsUI: opts.IsUI,
ControllerAirgapStorageSpace: opts.ControllerAirgapStorageSpace,
WorkerAirgapStorageSpace: opts.WorkerAirgapStorageSpace,
}
if cidr := rc.GlobalCIDR(); cidr != "" {
prepareOpts.GlobalCIDR = &cidr
Expand Down
3 changes: 3 additions & 0 deletions cmd/installer/cli/api.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/replicatedhq/embedded-cluster/web"
kotsv1beta1 "github.com/replicatedhq/kotskinds/apis/kots/v1beta1"
"github.com/sirupsen/logrus"
)

Expand All @@ -37,6 +38,7 @@ type apiConfig struct {
ManagerPort int
License []byte
AirgapBundle string
AirgapInfo *kotsv1beta1.Airgap
ConfigValues string
ReleaseData *release.ReleaseData
EndUserConfig *ecv1beta1.Config
Expand Down Expand Up @@ -89,6 +91,7 @@ func serveAPI(ctx context.Context, listener net.Listener, cert tls.Certificate,
api.WithTLSConfig(config.TLSConfig),
api.WithLicense(config.License),
api.WithAirgapBundle(config.AirgapBundle),
api.WithAirgapInfo(config.AirgapInfo),
api.WithConfigValues(config.ConfigValues),
api.WithEndUserConfig(config.EndUserConfig),
)
Expand Down
Loading
Loading