Skip to content

Commit a3da8fd

Browse files
committed
Merge commit '3992013d299a0e0006911dcc28336292a21f472e' into k0s-1-30
2 parents 50f2e2f + 3992013 commit a3da8fd

File tree

107 files changed

+4107
-843
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

107 files changed

+4107
-843
lines changed

.github/actions/scan-image/action.yml

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,17 +51,32 @@ runs:
5151
id: image_details
5252
shell: bash
5353
run: |
54+
# Extract base image name and tag
5455
IMAGE_NAME=$(echo "${{ inputs.image-ref }}" | cut -d':' -f1)
5556
IMAGE_TAG=$(echo "${{ inputs.image-ref }}" | cut -d':' -f2 | cut -d'@' -f1)
57+
58+
# Default to latest tag if none specified
5659
[[ "$IMAGE_TAG" == "$IMAGE_NAME" ]] && IMAGE_TAG="latest"
57-
SAFE_NAME=$(echo "${IMAGE_NAME}-${IMAGE_TAG}" | sed 's/[\/:]/-/g')
60+
61+
# Extract digest if present
62+
IMAGE_DIGEST=$(echo "${{ inputs.image-ref }}" | grep -o 'sha256:[a-f0-9]*' || true)
63+
64+
# Create safe names for file paths and identifiers
65+
if [[ -n "$IMAGE_DIGEST" ]]; then
66+
DIGEST_SHORT=$(echo "$IMAGE_DIGEST" | cut -c1-15)
67+
SAFE_NAME="${IMAGE_NAME}-${IMAGE_TAG}-${DIGEST_SHORT}"
68+
else
69+
SAFE_NAME="${IMAGE_NAME}-${IMAGE_TAG}"
70+
fi
71+
SAFE_NAME=$(echo "$SAFE_NAME" | sed 's/[\/:]/-/g')
5872
SAFE_IMAGE_NAME=$(echo "${IMAGE_NAME}" | sed 's/[\/:]/-/g')
59-
{
60-
echo "image_name=${IMAGE_NAME}"
61-
echo "image_tag=${IMAGE_TAG}"
62-
echo "safe_name=${SAFE_NAME}"
63-
echo "safe_image_name=${SAFE_IMAGE_NAME}"
6473
74+
# Output variables for use in subsequent steps
75+
{
76+
echo "image_name=${IMAGE_NAME}"
77+
echo "image_tag=${IMAGE_TAG}"
78+
echo "safe_name=${SAFE_NAME}"
79+
echo "safe_image_name=${SAFE_IMAGE_NAME}"
6580
} >> "$GITHUB_OUTPUT"
6681
6782
- name: Scan image with Grype

.github/workflows/ci.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -910,6 +910,7 @@ jobs:
910910
test:
911911
- TestResetAndReinstallAirgap
912912
- TestSingleNodeAirgapUpgrade
913+
- TestSingleNodeAirgapUpgradeSelinux
913914
- TestSingleNodeAirgapUpgradeConfigValues
914915
- TestSingleNodeAirgapUpgradeCustomCIDR
915916
- TestMultiNodeAirgapUpgrade

.github/workflows/image-scan.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,8 @@ jobs:
135135
with:
136136
image-ref: '${{ matrix.image }}'
137137
upload-sarif: ${{ github.ref == 'refs/heads/main' }}
138-
fail-build: 'true'
138+
# TODO: set this to true once we are fully using securebuild images
139+
fail-build: 'false'
139140
severity-cutoff: 'medium'
140141
output-file: 'results.sarif'
141142
retention-days: '90'

.github/workflows/release-prod.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -569,6 +569,7 @@ jobs:
569569
test:
570570
- TestResetAndReinstallAirgap
571571
- TestSingleNodeAirgapUpgrade
572+
- TestSingleNodeAirgapUpgradeSelinux
572573
- TestSingleNodeAirgapUpgradeConfigValues
573574
- TestSingleNodeAirgapUpgradeCustomCIDR
574575
- TestMultiNodeAirgapUpgrade
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
package install
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"runtime/debug"
7+
8+
apppreflightmanager "github.com/replicatedhq/embedded-cluster/api/internal/managers/app/preflight"
9+
"github.com/replicatedhq/embedded-cluster/api/internal/statemachine"
10+
states "github.com/replicatedhq/embedded-cluster/api/internal/states/install"
11+
"github.com/replicatedhq/embedded-cluster/api/types"
12+
ecv1beta1 "github.com/replicatedhq/embedded-cluster/kinds/apis/v1beta1"
13+
"github.com/replicatedhq/embedded-cluster/pkg-new/preflights"
14+
)
15+
16+
type RunAppPreflightOptions struct {
17+
ConfigValues types.AppConfigValues
18+
PreflightBinaryPath string
19+
ProxySpec *ecv1beta1.ProxySpec
20+
ExtraPaths []string
21+
}
22+
23+
func (c *InstallController) RunAppPreflights(ctx context.Context, opts RunAppPreflightOptions) (finalErr error) {
24+
lock, err := c.stateMachine.AcquireLock()
25+
if err != nil {
26+
return types.NewConflictError(err)
27+
}
28+
29+
defer func() {
30+
if r := recover(); r != nil {
31+
finalErr = fmt.Errorf("panic: %v: %s", r, string(debug.Stack()))
32+
}
33+
if finalErr != nil {
34+
lock.Release()
35+
}
36+
}()
37+
38+
if err := c.stateMachine.ValidateTransition(lock, states.StateAppPreflightsRunning); err != nil {
39+
return types.NewConflictError(err)
40+
}
41+
42+
// Extract app preflight spec from Helm charts
43+
appPreflightSpec, err := c.appReleaseManager.ExtractAppPreflightSpec(ctx, opts.ConfigValues)
44+
if err != nil {
45+
return fmt.Errorf("extract app preflight spec: %w", err)
46+
}
47+
48+
err = c.stateMachine.Transition(lock, states.StateAppPreflightsRunning)
49+
if err != nil {
50+
return fmt.Errorf("transition states: %w", err)
51+
}
52+
53+
go func() (finalErr error) {
54+
// Background context is used to avoid canceling the operation if the context is canceled
55+
ctx := context.Background()
56+
57+
defer lock.Release()
58+
59+
defer func() {
60+
if r := recover(); r != nil {
61+
finalErr = fmt.Errorf("panic running app preflights: %v: %s", r, string(debug.Stack()))
62+
}
63+
// Handle errors from preflight execution
64+
if finalErr != nil {
65+
c.logger.Error(finalErr)
66+
67+
if err := c.stateMachine.Transition(lock, states.StateAppPreflightsExecutionFailed); err != nil {
68+
c.logger.Errorf("failed to transition states: %w", err)
69+
}
70+
return
71+
}
72+
73+
// Get the state from the preflights output
74+
state := c.getStateFromAppPreflightsOutput(ctx)
75+
// Transition to the appropriate state based on preflight results
76+
if err := c.stateMachine.Transition(lock, state); err != nil {
77+
c.logger.Errorf("failed to transition states: %w", err)
78+
}
79+
}()
80+
81+
// Create RunOptions from the provided options
82+
runOpts := preflights.RunOptions{
83+
PreflightBinaryPath: opts.PreflightBinaryPath,
84+
ProxySpec: opts.ProxySpec,
85+
ExtraPaths: opts.ExtraPaths,
86+
}
87+
88+
err := c.appPreflightManager.RunAppPreflights(ctx, apppreflightmanager.RunAppPreflightOptions{
89+
AppPreflightSpec: appPreflightSpec,
90+
RunOptions: runOpts,
91+
})
92+
if err != nil {
93+
return fmt.Errorf("run app preflights: %w", err)
94+
}
95+
96+
return nil
97+
}()
98+
99+
return nil
100+
}
101+
102+
func (c *InstallController) getStateFromAppPreflightsOutput(ctx context.Context) statemachine.State {
103+
output, err := c.GetAppPreflightOutput(ctx)
104+
// If there was an error getting the state we assume preflight execution failed
105+
if err != nil {
106+
c.logger.WithError(err).Error("error getting app preflight output")
107+
return states.StateAppPreflightsExecutionFailed
108+
}
109+
// If there is no output, we assume preflights succeeded
110+
if output == nil || !output.HasFail() {
111+
return states.StateAppPreflightsSucceeded
112+
}
113+
return states.StateAppPreflightsFailed
114+
}
115+
116+
func (c *InstallController) GetAppPreflightStatus(ctx context.Context) (types.Status, error) {
117+
return c.appPreflightManager.GetAppPreflightStatus(ctx)
118+
}
119+
120+
func (c *InstallController) GetAppPreflightOutput(ctx context.Context) (*types.PreflightsOutput, error) {
121+
return c.appPreflightManager.GetAppPreflightOutput(ctx)
122+
}
123+
124+
func (c *InstallController) GetAppPreflightTitles(ctx context.Context) ([]string, error) {
125+
return c.appPreflightManager.GetAppPreflightTitles(ctx)
126+
}

api/controllers/app/install/config.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ func (c *InstallController) PatchAppConfigValues(ctx context.Context, values typ
5757
}
5858

5959
func (c *InstallController) TemplateAppConfig(ctx context.Context, values types.AppConfigValues, maskPasswords bool) (types.AppConfig, error) {
60-
return c.appConfigManager.TemplateConfig(values, maskPasswords)
60+
return c.appConfigManager.TemplateConfig(values, maskPasswords, true)
6161
}
6262

6363
func (c *InstallController) GetAppConfigValues(ctx context.Context) (types.AppConfigValues, error) {

api/controllers/app/install/controller.go

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import (
55
"errors"
66

77
appconfig "github.com/replicatedhq/embedded-cluster/api/internal/managers/app/config"
8+
apppreflightmanager "github.com/replicatedhq/embedded-cluster/api/internal/managers/app/preflight"
9+
appreleasemanager "github.com/replicatedhq/embedded-cluster/api/internal/managers/app/release"
810
"github.com/replicatedhq/embedded-cluster/api/internal/statemachine"
911
"github.com/replicatedhq/embedded-cluster/api/pkg/logger"
1012
"github.com/replicatedhq/embedded-cluster/api/types"
@@ -15,14 +17,20 @@ type Controller interface {
1517
TemplateAppConfig(ctx context.Context, values types.AppConfigValues, maskPasswords bool) (types.AppConfig, error)
1618
PatchAppConfigValues(ctx context.Context, values types.AppConfigValues) error
1719
GetAppConfigValues(ctx context.Context) (types.AppConfigValues, error)
20+
RunAppPreflights(ctx context.Context, opts RunAppPreflightOptions) error
21+
GetAppPreflightStatus(ctx context.Context) (types.Status, error)
22+
GetAppPreflightOutput(ctx context.Context) (*types.PreflightsOutput, error)
23+
GetAppPreflightTitles(ctx context.Context) ([]string, error)
1824
}
1925

2026
var _ Controller = (*InstallController)(nil)
2127

2228
type InstallController struct {
23-
appConfigManager appconfig.AppConfigManager
24-
stateMachine statemachine.Interface
25-
logger logrus.FieldLogger
29+
appConfigManager appconfig.AppConfigManager
30+
appPreflightManager apppreflightmanager.AppPreflightManager
31+
appReleaseManager appreleasemanager.AppReleaseManager
32+
stateMachine statemachine.Interface
33+
logger logrus.FieldLogger
2634
}
2735

2836
type InstallControllerOption func(*InstallController)
@@ -45,6 +53,18 @@ func WithStateMachine(stateMachine statemachine.Interface) InstallControllerOpti
4553
}
4654
}
4755

56+
func WithAppPreflightManager(appPreflightManager apppreflightmanager.AppPreflightManager) InstallControllerOption {
57+
return func(c *InstallController) {
58+
c.appPreflightManager = appPreflightManager
59+
}
60+
}
61+
62+
func WithAppReleaseManager(appReleaseManager appreleasemanager.AppReleaseManager) InstallControllerOption {
63+
return func(c *InstallController) {
64+
c.appReleaseManager = appReleaseManager
65+
}
66+
}
67+
4868
func NewInstallController(opts ...InstallControllerOption) (*InstallController, error) {
4969
controller := &InstallController{
5070
logger: logger.NewDiscardLogger(),
@@ -68,5 +88,11 @@ func (c *InstallController) validateInit() error {
6888
if c.stateMachine == nil {
6989
return errors.New("stateMachine is required for App Install Controller")
7090
}
91+
if c.appPreflightManager == nil {
92+
return errors.New("appPreflightManager is required for App Install Controller")
93+
}
94+
if c.appReleaseManager == nil {
95+
return errors.New("appReleaseManager is required for App Install Controller")
96+
}
7197
return nil
7298
}

api/controllers/app/install/controller_mock.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,36 @@ func (m *MockController) GetAppConfigValues(ctx context.Context) (types.AppConfi
3434
}
3535
return args.Get(0).(types.AppConfigValues), args.Error(1)
3636
}
37+
38+
// RunAppPreflights mocks the RunAppPreflights method
39+
func (m *MockController) RunAppPreflights(ctx context.Context, opts RunAppPreflightOptions) error {
40+
args := m.Called(ctx, opts)
41+
return args.Error(0)
42+
}
43+
44+
// GetAppPreflightStatus mocks the GetAppPreflightStatus method
45+
func (m *MockController) GetAppPreflightStatus(ctx context.Context) (types.Status, error) {
46+
args := m.Called(ctx)
47+
if args.Get(0) == nil {
48+
return types.Status{}, args.Error(1)
49+
}
50+
return args.Get(0).(types.Status), args.Error(1)
51+
}
52+
53+
// GetAppPreflightOutput mocks the GetAppPreflightOutput method
54+
func (m *MockController) GetAppPreflightOutput(ctx context.Context) (*types.PreflightsOutput, error) {
55+
args := m.Called(ctx)
56+
if args.Get(0) == nil {
57+
return nil, args.Error(1)
58+
}
59+
return args.Get(0).(*types.PreflightsOutput), args.Error(1)
60+
}
61+
62+
// GetAppPreflightTitles mocks the GetAppPreflightTitles method
63+
func (m *MockController) GetAppPreflightTitles(ctx context.Context) ([]string, error) {
64+
args := m.Called(ctx)
65+
if args.Get(0) == nil {
66+
return nil, args.Error(1)
67+
}
68+
return args.Get(0).([]string), args.Error(1)
69+
}

0 commit comments

Comments
 (0)