Skip to content

Commit 668b930

Browse files
committed
Add airgap storage space to host preflights for controller nodes
Signed-off-by: Evans Mungai <evans@replicated.com>
1 parent 2143149 commit 668b930

File tree

8 files changed

+180
-122
lines changed

8 files changed

+180
-122
lines changed

api/controllers/install/hostpreflight.go

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,35 @@ import (
77
"github.com/replicatedhq/embedded-cluster/api/internal/managers/preflight"
88
"github.com/replicatedhq/embedded-cluster/api/pkg/utils"
99
"github.com/replicatedhq/embedded-cluster/api/types"
10+
"github.com/replicatedhq/embedded-cluster/pkg-new/preflights"
11+
"github.com/replicatedhq/embedded-cluster/pkg/airgap"
1012
"github.com/replicatedhq/embedded-cluster/pkg/netutils"
1113
)
1214

1315
func (c *InstallController) RunHostPreflights(ctx context.Context, opts RunHostPreflightsOptions) error {
1416
// Get the configured custom domains
1517
ecDomains := utils.GetDomains(c.releaseData)
1618

19+
// Calculate airgap storage space requirement (2x uncompressed size for controller nodes)
20+
var controllerAirgapStorageSpace string
21+
if c.airgapBundle != "" {
22+
airgapInfo, err := airgap.AirgapInfoFromPath(c.airgapBundle)
23+
if err != nil {
24+
return fmt.Errorf("failed to get airgap info: %w", err)
25+
}
26+
// Controller nodes require 2x the extracted bundle size for processing
27+
controllerAirgapStorageSpace = preflights.CalculateControllerAirgapStorageSpace(airgapInfo.Spec.UncompressedSize)
28+
}
29+
1730
// Prepare host preflights
1831
hpf, err := c.hostPreflightManager.PrepareHostPreflights(ctx, c.rc, preflight.PrepareHostPreflightOptions{
19-
ReplicatedAppURL: netutils.MaybeAddHTTPS(ecDomains.ReplicatedAppDomain),
20-
ProxyRegistryURL: netutils.MaybeAddHTTPS(ecDomains.ProxyRegistryDomain),
21-
HostPreflightSpec: c.releaseData.HostPreflights,
22-
EmbeddedClusterConfig: c.releaseData.EmbeddedClusterConfig,
23-
IsAirgap: c.airgapBundle != "",
24-
IsUI: opts.IsUI,
32+
ReplicatedAppURL: netutils.MaybeAddHTTPS(ecDomains.ReplicatedAppDomain),
33+
ProxyRegistryURL: netutils.MaybeAddHTTPS(ecDomains.ProxyRegistryDomain),
34+
HostPreflightSpec: c.releaseData.HostPreflights,
35+
EmbeddedClusterConfig: c.releaseData.EmbeddedClusterConfig,
36+
IsAirgap: c.airgapBundle != "",
37+
IsUI: opts.IsUI,
38+
ControllerAirgapStorageSpace: controllerAirgapStorageSpace,
2539
})
2640
if err != nil {
2741
return fmt.Errorf("failed to prepare host preflights: %w", err)

api/internal/managers/preflight/hostpreflight.go

Lines changed: 26 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,15 @@ import (
1515
)
1616

1717
type PrepareHostPreflightOptions struct {
18-
ReplicatedAppURL string
19-
ProxyRegistryURL string
20-
HostPreflightSpec *troubleshootv1beta2.HostPreflightSpec
21-
EmbeddedClusterConfig *ecv1beta1.Config
22-
TCPConnectionsRequired []string
23-
IsAirgap bool
24-
IsJoin bool
25-
IsUI bool
18+
ReplicatedAppURL string
19+
ProxyRegistryURL string
20+
HostPreflightSpec *troubleshootv1beta2.HostPreflightSpec
21+
EmbeddedClusterConfig *ecv1beta1.Config
22+
TCPConnectionsRequired []string
23+
IsAirgap bool
24+
IsJoin bool
25+
IsUI bool
26+
ControllerAirgapStorageSpace string
2627
}
2728

2829
type RunHostPreflightOptions struct {
@@ -76,22 +77,23 @@ func (m *hostPreflightManager) prepareHostPreflights(ctx context.Context, rc run
7677

7778
// Use the shared Prepare function to prepare host preflights
7879
prepareOpts := preflights.PrepareOptions{
79-
HostPreflightSpec: opts.HostPreflightSpec,
80-
ReplicatedAppURL: opts.ReplicatedAppURL,
81-
ProxyRegistryURL: opts.ProxyRegistryURL,
82-
AdminConsolePort: rc.AdminConsolePort(),
83-
LocalArtifactMirrorPort: rc.LocalArtifactMirrorPort(),
84-
DataDir: rc.EmbeddedClusterHomeDirectory(),
85-
K0sDataDir: rc.EmbeddedClusterK0sSubDir(),
86-
OpenEBSDataDir: rc.EmbeddedClusterOpenEBSLocalSubDir(),
87-
Proxy: rc.ProxySpec(),
88-
PodCIDR: rc.PodCIDR(),
89-
ServiceCIDR: rc.ServiceCIDR(),
90-
NodeIP: nodeIP,
91-
IsAirgap: opts.IsAirgap,
92-
TCPConnectionsRequired: opts.TCPConnectionsRequired,
93-
IsJoin: opts.IsJoin,
94-
IsUI: opts.IsUI,
80+
HostPreflightSpec: opts.HostPreflightSpec,
81+
ReplicatedAppURL: opts.ReplicatedAppURL,
82+
ProxyRegistryURL: opts.ProxyRegistryURL,
83+
AdminConsolePort: rc.AdminConsolePort(),
84+
LocalArtifactMirrorPort: rc.LocalArtifactMirrorPort(),
85+
DataDir: rc.EmbeddedClusterHomeDirectory(),
86+
K0sDataDir: rc.EmbeddedClusterK0sSubDir(),
87+
OpenEBSDataDir: rc.EmbeddedClusterOpenEBSLocalSubDir(),
88+
Proxy: rc.ProxySpec(),
89+
PodCIDR: rc.PodCIDR(),
90+
ServiceCIDR: rc.ServiceCIDR(),
91+
NodeIP: nodeIP,
92+
IsAirgap: opts.IsAirgap,
93+
TCPConnectionsRequired: opts.TCPConnectionsRequired,
94+
IsJoin: opts.IsJoin,
95+
IsUI: opts.IsUI,
96+
ControllerAirgapStorageSpace: opts.ControllerAirgapStorageSpace,
9597
}
9698
if cidr := rc.GlobalCIDR(); cidr != "" {
9799
prepareOpts.GlobalCIDR = &cidr

cmd/installer/cli/install_runpreflights.go

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -105,20 +105,32 @@ func runInstallPreflights(ctx context.Context, flags InstallCmdFlags, rc runtime
105105
return fmt.Errorf("unable to find first valid address: %w", err)
106106
}
107107

108+
// Calculate airgap storage space requirement (2x uncompressed size for controller nodes)
109+
var controllerAirgapStorageSpace string
110+
if flags.airgapBundle != "" {
111+
airgapInfo, err := airgap.AirgapInfoFromPath(flags.airgapBundle)
112+
if err != nil {
113+
return fmt.Errorf("failed to get airgap info: %w", err)
114+
}
115+
// Controller nodes require 2x the extracted bundle size for processing
116+
controllerAirgapStorageSpace = preflights.CalculateControllerAirgapStorageSpace(airgapInfo.Spec.UncompressedSize)
117+
}
118+
108119
opts := preflights.PrepareOptions{
109-
HostPreflightSpec: release.GetHostPreflights(),
110-
ReplicatedAppURL: replicatedAppURL,
111-
ProxyRegistryURL: proxyRegistryURL,
112-
AdminConsolePort: rc.AdminConsolePort(),
113-
LocalArtifactMirrorPort: rc.LocalArtifactMirrorPort(),
114-
DataDir: rc.EmbeddedClusterHomeDirectory(),
115-
K0sDataDir: rc.EmbeddedClusterK0sSubDir(),
116-
OpenEBSDataDir: rc.EmbeddedClusterOpenEBSLocalSubDir(),
117-
Proxy: rc.ProxySpec(),
118-
PodCIDR: rc.PodCIDR(),
119-
ServiceCIDR: rc.ServiceCIDR(),
120-
NodeIP: nodeIP,
121-
IsAirgap: flags.isAirgap,
120+
HostPreflightSpec: release.GetHostPreflights(),
121+
ReplicatedAppURL: replicatedAppURL,
122+
ProxyRegistryURL: proxyRegistryURL,
123+
AdminConsolePort: rc.AdminConsolePort(),
124+
LocalArtifactMirrorPort: rc.LocalArtifactMirrorPort(),
125+
DataDir: rc.EmbeddedClusterHomeDirectory(),
126+
K0sDataDir: rc.EmbeddedClusterK0sSubDir(),
127+
OpenEBSDataDir: rc.EmbeddedClusterOpenEBSLocalSubDir(),
128+
Proxy: rc.ProxySpec(),
129+
PodCIDR: rc.PodCIDR(),
130+
ServiceCIDR: rc.ServiceCIDR(),
131+
NodeIP: nodeIP,
132+
IsAirgap: flags.isAirgap,
133+
ControllerAirgapStorageSpace: controllerAirgapStorageSpace,
122134
}
123135
if globalCIDR := rc.GlobalCIDR(); globalCIDR != "" {
124136
opts.GlobalCIDR = &globalCIDR

cmd/installer/cli/join_runpreflights.go

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -103,22 +103,30 @@ func runJoinPreflights(ctx context.Context, jcmd *join.JoinCommandResponse, flag
103103

104104
domains := runtimeconfig.GetDomains(jcmd.InstallationSpec.Config)
105105

106+
// Calculate airgap storage space requirement (2x uncompressed size for controller nodes)
107+
var controllerAirgapStorageSpace string
108+
if jcmd.InstallationSpec.AirGap && jcmd.InstallationSpec.AirgapUncompressedSize > 0 {
109+
// Controller nodes require 2x the extracted bundle size for processing
110+
controllerAirgapStorageSpace = preflights.CalculateControllerAirgapStorageSpace(jcmd.InstallationSpec.AirgapUncompressedSize)
111+
}
112+
106113
hpf, err := preflights.Prepare(ctx, preflights.PrepareOptions{
107-
HostPreflightSpec: release.GetHostPreflights(),
108-
ReplicatedAppURL: netutils.MaybeAddHTTPS(domains.ReplicatedAppDomain),
109-
ProxyRegistryURL: netutils.MaybeAddHTTPS(domains.ProxyRegistryDomain),
110-
AdminConsolePort: rc.AdminConsolePort(),
111-
LocalArtifactMirrorPort: rc.LocalArtifactMirrorPort(),
112-
DataDir: rc.EmbeddedClusterHomeDirectory(),
113-
K0sDataDir: rc.EmbeddedClusterK0sSubDir(),
114-
OpenEBSDataDir: rc.EmbeddedClusterOpenEBSLocalSubDir(),
115-
Proxy: rc.ProxySpec(),
116-
PodCIDR: cidrCfg.PodCIDR,
117-
ServiceCIDR: cidrCfg.ServiceCIDR,
118-
NodeIP: nodeIP,
119-
IsAirgap: jcmd.InstallationSpec.AirGap,
120-
TCPConnectionsRequired: jcmd.TCPConnectionsRequired,
121-
IsJoin: true,
114+
HostPreflightSpec: release.GetHostPreflights(),
115+
ReplicatedAppURL: netutils.MaybeAddHTTPS(domains.ReplicatedAppDomain),
116+
ProxyRegistryURL: netutils.MaybeAddHTTPS(domains.ProxyRegistryDomain),
117+
AdminConsolePort: rc.AdminConsolePort(),
118+
LocalArtifactMirrorPort: rc.LocalArtifactMirrorPort(),
119+
DataDir: rc.EmbeddedClusterHomeDirectory(),
120+
K0sDataDir: rc.EmbeddedClusterK0sSubDir(),
121+
OpenEBSDataDir: rc.EmbeddedClusterOpenEBSLocalSubDir(),
122+
Proxy: rc.ProxySpec(),
123+
PodCIDR: cidrCfg.PodCIDR,
124+
ServiceCIDR: cidrCfg.ServiceCIDR,
125+
NodeIP: nodeIP,
126+
IsAirgap: jcmd.InstallationSpec.AirGap,
127+
TCPConnectionsRequired: jcmd.TCPConnectionsRequired,
128+
IsJoin: true,
129+
ControllerAirgapStorageSpace: controllerAirgapStorageSpace,
122130
})
123131
if err != nil {
124132
return err

pkg-new/preflights/host-preflight.yaml

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,25 @@ spec:
221221
{{- end }}
222222
- pass:
223223
message: The filesystem at {{ .DataDir }} has sufficient space
224+
- diskUsage:
225+
checkName: Airgap Storage Space
226+
collectorName: embedded-cluster-path-usage
227+
exclude: '{{ eq .ControllerAirgapStorageSpace "" }}'
228+
outcomes:
229+
- fail:
230+
when: 'available < {{ .ControllerAirgapStorageSpace }}'
231+
message: >-
232+
{{ if .IsUI -}}
233+
The filesystem at {{ .DataDir }} has less than {{ .ControllerAirgapStorageSpace }} of available storage space needed to process the air gap bundle.
234+
Controller nodes require 2x the extracted bundle size for processing.
235+
Ensure sufficient space is available, or go back to the Setup page and choose a different data directory.
236+
{{- else -}}
237+
The filesystem at {{ .DataDir }} has less than {{ .ControllerAirgapStorageSpace }} of available storage space needed to process the air gap bundle.
238+
Controller nodes require 2x the extracted bundle size for processing.
239+
Ensure sufficient space is available, or use --data-dir to specify an alternative data directory.
240+
{{- end }}
241+
- pass:
242+
message: The filesystem at {{ .DataDir }} has sufficient available space for airgap bundle processing
224243
- textAnalyze:
225244
checkName: Default Route
226245
fileName: host-collectors/run-host/ip-route-table.txt
@@ -937,7 +956,7 @@ spec:
937956
The node IP {{ .NodeIP }} cannot be within the Pod CIDR range {{ .PodCIDR.CIDR }}. Use --pod-cidr to specify a different Pod CIDR, or use --network-interface to specify a different network interface.
938957
{{- end }}
939958
- pass:
940-
when: "false"
959+
when: "false"
941960
message: The node IP {{ .NodeIP }} is not within the Pod CIDR range {{ .PodCIDR.CIDR }}.
942961
- subnetContainsIP:
943962
checkName: Node IP in Service CIDR Check

pkg-new/preflights/prepare.go

Lines changed: 34 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -17,23 +17,24 @@ var ErrPreflightsHaveFail = metrics.NewErrorNoFail(fmt.Errorf("host preflight fa
1717

1818
// PrepareOptions contains options for preparing preflights (shared across CLI and API)
1919
type PrepareOptions struct {
20-
HostPreflightSpec *v1beta2.HostPreflightSpec
21-
ReplicatedAppURL string
22-
ProxyRegistryURL string
23-
AdminConsolePort int
24-
LocalArtifactMirrorPort int
25-
DataDir string
26-
K0sDataDir string
27-
OpenEBSDataDir string
28-
Proxy *ecv1beta1.ProxySpec
29-
PodCIDR string
30-
ServiceCIDR string
31-
GlobalCIDR *string
32-
NodeIP string
33-
IsAirgap bool
34-
TCPConnectionsRequired []string
35-
IsJoin bool
36-
IsUI bool
20+
HostPreflightSpec *v1beta2.HostPreflightSpec
21+
ReplicatedAppURL string
22+
ProxyRegistryURL string
23+
AdminConsolePort int
24+
LocalArtifactMirrorPort int
25+
DataDir string
26+
K0sDataDir string
27+
OpenEBSDataDir string
28+
Proxy *ecv1beta1.ProxySpec
29+
PodCIDR string
30+
ServiceCIDR string
31+
GlobalCIDR *string
32+
NodeIP string
33+
IsAirgap bool
34+
TCPConnectionsRequired []string
35+
IsJoin bool
36+
IsUI bool
37+
ControllerAirgapStorageSpace string
3738
}
3839

3940
// Prepare prepares the host preflights spec by merging provided spec with cluster preflights
@@ -44,21 +45,22 @@ func (p *PreflightsRunner) Prepare(ctx context.Context, opts PrepareOptions) (*v
4445
}
4546

4647
data, err := types.TemplateData{
47-
ReplicatedAppURL: opts.ReplicatedAppURL,
48-
ProxyRegistryURL: opts.ProxyRegistryURL,
49-
IsAirgap: opts.IsAirgap,
50-
AdminConsolePort: opts.AdminConsolePort,
51-
LocalArtifactMirrorPort: opts.LocalArtifactMirrorPort,
52-
DataDir: opts.DataDir,
53-
K0sDataDir: opts.K0sDataDir,
54-
OpenEBSDataDir: opts.OpenEBSDataDir,
55-
SystemArchitecture: runtime.GOARCH,
56-
FromCIDR: opts.PodCIDR,
57-
ToCIDR: opts.ServiceCIDR,
58-
TCPConnectionsRequired: opts.TCPConnectionsRequired,
59-
NodeIP: opts.NodeIP,
60-
IsJoin: opts.IsJoin,
61-
IsUI: opts.IsUI,
48+
ReplicatedAppURL: opts.ReplicatedAppURL,
49+
ProxyRegistryURL: opts.ProxyRegistryURL,
50+
IsAirgap: opts.IsAirgap,
51+
AdminConsolePort: opts.AdminConsolePort,
52+
LocalArtifactMirrorPort: opts.LocalArtifactMirrorPort,
53+
DataDir: opts.DataDir,
54+
K0sDataDir: opts.K0sDataDir,
55+
OpenEBSDataDir: opts.OpenEBSDataDir,
56+
SystemArchitecture: runtime.GOARCH,
57+
FromCIDR: opts.PodCIDR,
58+
ToCIDR: opts.ServiceCIDR,
59+
TCPConnectionsRequired: opts.TCPConnectionsRequired,
60+
NodeIP: opts.NodeIP,
61+
IsJoin: opts.IsJoin,
62+
IsUI: opts.IsUI,
63+
ControllerAirgapStorageSpace: opts.ControllerAirgapStorageSpace,
6264
}.WithCIDRData(opts.PodCIDR, opts.ServiceCIDR, opts.GlobalCIDR)
6365

6466
if err != nil {

pkg-new/preflights/types/template.go

Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -13,28 +13,29 @@ type CIDRData struct {
1313
}
1414

1515
type TemplateData struct {
16-
IsAirgap bool
17-
ReplicatedAppURL string
18-
ProxyRegistryURL string
19-
AdminConsolePort int
20-
LocalArtifactMirrorPort int
21-
DataDir string
22-
K0sDataDir string
23-
OpenEBSDataDir string
24-
SystemArchitecture string
25-
ServiceCIDR CIDRData
26-
PodCIDR CIDRData
27-
GlobalCIDR CIDRData
28-
HTTPProxy string
29-
HTTPSProxy string
30-
ProvidedNoProxy string
31-
NoProxy string
32-
FromCIDR string
33-
ToCIDR string
34-
TCPConnectionsRequired []string
35-
NodeIP string
36-
IsJoin bool
37-
IsUI bool
16+
IsAirgap bool
17+
ReplicatedAppURL string
18+
ProxyRegistryURL string
19+
AdminConsolePort int
20+
LocalArtifactMirrorPort int
21+
DataDir string
22+
K0sDataDir string
23+
OpenEBSDataDir string
24+
SystemArchitecture string
25+
ServiceCIDR CIDRData
26+
PodCIDR CIDRData
27+
GlobalCIDR CIDRData
28+
HTTPProxy string
29+
HTTPSProxy string
30+
ProvidedNoProxy string
31+
NoProxy string
32+
FromCIDR string
33+
ToCIDR string
34+
TCPConnectionsRequired []string
35+
NodeIP string
36+
IsJoin bool
37+
IsUI bool
38+
ControllerAirgapStorageSpace string
3839
}
3940

4041
// WithCIDRData sets the respective CIDR properties in the TemplateData struct based on the provided CIDR strings

0 commit comments

Comments
 (0)