Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
8d40f47
fix(installer): move MetalLB config under Cluster struct
OliverTrautvetter Aug 4, 2026
74d5608
chore(docs): Auto-update docs and licenses
OliverTrautvetter Aug 4, 2026
4f0b321
feat(test): add non-interactive install-config generation tests for a…
OliverTrautvetter Aug 5, 2026
46316d5
ci: add install-config generation and validation job to CLI workflow
OliverTrautvetter Aug 5, 2026
1d85759
Merge remote-tracking branch 'origin/main' into fix/init-install-conf…
OliverTrautvetter Aug 5, 2026
132172c
fix: use EnsureCertIssuer to prevent nil pointer dereference in apply…
OliverTrautvetter Aug 5, 2026
15ab0b2
ref: consolidate CI jobs, extract Slack action, and deduplicate confi…
OliverTrautvetter Aug 6, 2026
ff77486
Merge remote-tracking branch 'origin/main' into fix/init-install-conf…
OliverTrautvetter Aug 6, 2026
3ae7ca9
fix(installer): use unencrypted vault write path in generation test
OliverTrautvetter Aug 6, 2026
6b8438b
Merge branch 'main' into fix/init-install-config-generation
OliverTrautvetter Aug 6, 2026
bc51fa9
style: add blank lines for visual separation in test and profile code
OliverTrautvetter Aug 6, 2026
b712bd5
Merge branch 'main' into fix/init-install-config-generation
OliverTrautvetter Aug 6, 2026
bf83987
Merge branch 'main' into fix/init-install-config-generation
OliverTrautvetter Aug 7, 2026
90cba6d
Merge remote-tracking branch 'origin/main' into fix/init-install-conf…
OliverTrautvetter Aug 18, 2026
f717466
fix(ci): setup SOPS age key for install-config generation and clarify…
OliverTrautvetter Aug 18, 2026
17ef4ce
fix(ci): fetch pinned sops release binary instead of relying on apt p…
OliverTrautvetter Aug 18, 2026
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
31 changes: 31 additions & 0 deletions .github/actions/slack-notify/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Copyright (c) Codesphere Inc.
# SPDX-License-Identifier: Apache-2.0

# Posts a failure notification to the #team-oms-sdk Slack channel.
name: Slack Notification on Failure
description: Notify #team-oms-sdk on job failure

inputs:
job-name:
description: Display name of the failing job (e.g. "Build", "Test", "Install-Config")
required: true
webhook:
description: Slack webhook URL for the notification
required: true

runs:
using: composite
steps:
- name: Post failure to Slack
shell: bash
env:
SLACK_WEBHOOK: ${{ inputs.webhook }}
run: |
curl -X POST \
-H 'Content-type: application/json' \
--data "{
\"channel\": \"#team-oms-sdk\",
\"icon_emoji\": \":siren:\",
\"text\": \"🚨 ${{ inputs.job-name }} Job Failure 🚨\nRepository: ${{ github.repository }}\nBranch/Ref: \`${{ github.ref }}\`\nRun url: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}\"
}" \
"${SLACK_WEBHOOK}"
84 changes: 52 additions & 32 deletions .github/workflows/cli-build_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,19 @@ on:

jobs:

build:
build-test:
name: ${{ matrix.label }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- task: build
label: Build
- task: test
label: Test
- task: install-config
label: Install-Config
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6

Expand All @@ -24,42 +35,51 @@ jobs:
with:
go-version-file: 'go.mod'

- name: Build
- name: Build CLI
if: ${{ matrix.task == 'build' || matrix.task == 'install-config' }}
run: make build-cli

- name: Slack Notification on Failure
if: ${{ failure() && github.ref == 'refs/heads/main' }}
run: |
curl -X POST \
-H 'Content-type: application/json' \
--data '{
"channel": "#team-oms-sdk",
"icon_emoji": ":siren:",
"text": "🚨 Build Job Failure 🚨\nRepository: ${{ github.repository }}\nBranch/Ref: `${{ github.ref }}`\nRun url: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
}' \
${{ secrets.PACKAGE_JOB_SLACK_WEBHOOK }}
- name: Test
if: ${{ matrix.task == 'test' }}
run: make test

test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- name: Setup SOPS and age for vault encryption
if: ${{ matrix.task == 'install-config' }}
run: |
sudo apt-get update
sudo apt-get install -y age
# sops is not packaged in Ubuntu's repos, so fetch the pinned release binary.
curl -fsSL -o /tmp/sops \
https://github.com/getsops/sops/releases/download/v3.13.3/sops-v3.13.3.linux.amd64
sudo install -m 0755 /tmp/sops /usr/local/bin/sops
age-keygen -o age_key.txt
echo "SOPS_AGE_KEY_FILE=${GITHUB_WORKSPACE}/age_key.txt" >> "$GITHUB_ENV"

- name: Set up Go
uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6
with:
go-version-file: 'go.mod'
- name: Generate and validate install configs
if: ${{ matrix.task == 'install-config' }}
run: |
set -euo pipefail
for profile in dev minimal production; do
echo "==> Generating install config for profile: ${profile}"
./oms init install-config \
--profile "${profile}" \
--interactive=false \
-c "config-${profile}.yaml" \
--vault "prod-${profile}.vault.yaml"

- name: Test
run: make test
echo "==> Validating generated install config for profile: ${profile}"
# Validate the config only. The generated vault is SOPS-encrypted and
# its contents are covered by the round-trip unit tests, so this step
# stays focused on the config (--vault "" skips vault loading).
./oms init install-config \
--validate \
-c "config-${profile}.yaml" \
--vault ""
done

- name: Slack Notification on Failure
if: ${{ failure() && github.ref == 'refs/heads/main' }}
run: |
curl -X POST \
-H 'Content-type: application/json' \
--data '{
"channel": "#team-oms-sdk",
"icon_emoji": ":siren:",
"text": "🚨 Build Job Failure 🚨\nRepository: ${{ github.repository }}\nBranch/Ref: `${{ github.ref }}`\nRun url: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
}' \
${{ secrets.PACKAGE_JOB_SLACK_WEBHOOK }}
uses: ./.github/actions/slack-notify
with:
job-name: ${{ matrix.label }}
webhook: ${{ secrets.PACKAGE_JOB_SLACK_WEBHOOK }}
18 changes: 13 additions & 5 deletions cli/cmd/init_install_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,8 @@ func AddInitInstallConfigCmd(init *cobra.Command, opts *util.GlobalOptions) {
// K8s
c.cmd.Flags().BoolVar(&c.Opts.KubernetesManagedByCodesphere, "k8s-managed", true, "Use Codesphere-managed Kubernetes")
c.cmd.Flags().StringSliceVar(&c.Opts.KubernetesControlPlanes, "k8s-control-plane", []string{}, "K8s control plane IPs (comma-separated)")
c.cmd.Flags().StringVar(&c.Opts.KubernetesPodCIDR, "k8s-pod-cidr", "", "Pod CIDR (required when --k8s-managed=false)")
c.cmd.Flags().StringVar(&c.Opts.KubernetesServiceCIDR, "k8s-service-cidr", "", "Service CIDR (required when --k8s-managed=false)")

// Ceph
c.cmd.Flags().StringVar(&c.Opts.CephCsiKubeletDir, "ceph-csi-kubelet-dir", "", "Directory of kubelet for ceph csi. Required for some cloud providers")
Expand Down Expand Up @@ -268,6 +270,8 @@ func (c *InitInstallConfigCmd) InitInstallConfig(icg installer.InstallConfigMana
return fmt.Errorf("failed to write config file: %w", err)
}

// The freshly generated vault is SOPS-encrypted automatically with the
// configured age key (--age-key or SOPS_AGE_KEY[_FILE]).
if err := icg.WriteVault(c.Opts.VaultFile, c.Opts.WithComments); err != nil {
return fmt.Errorf("failed to write vault file: %w", err)
}
Expand Down Expand Up @@ -304,6 +308,7 @@ func (c *InitInstallConfigCmd) printSuccessMessage(warningCount int) {
log.Println(strings.Repeat("=", 70))

log.Println("\nIMPORTANT: Keys and certificates have been generated and embedded in the vault file.")
log.Println(" The vault file has been encrypted with SOPS automatically.")
log.Println(" Keep the vault file and its decryption key secure.")
log.Println()
}
Expand Down Expand Up @@ -418,6 +423,9 @@ func (c *InitInstallConfigCmd) updateConfigFromOpts(config *files.RootConfig, va
}

// Kubernetes settings
if c.cmd != nil && c.cmd.Flags().Changed("k8s-managed") {
config.Kubernetes.ManagedByCodesphere = c.Opts.KubernetesManagedByCodesphere
}
if c.Opts.KubernetesAPIServerHost != "" {
config.Kubernetes.APIServerHost = c.Opts.KubernetesAPIServerHost
}
Expand Down Expand Up @@ -464,18 +472,18 @@ func (c *InitInstallConfigCmd) updateConfigFromOpts(config *files.RootConfig, va

// MetalLB settings
if c.Opts.MetalLBEnabled {
if config.MetalLB == nil {
config.MetalLB = &files.MetalLBConfig{
if config.Cluster.MetalLB == nil {
config.Cluster.MetalLB = &files.MetalLBConfig{
Enabled: c.Opts.MetalLBEnabled,
Pools: []files.MetalLBPoolDef{},
}
} else {
config.MetalLB.Enabled = c.Opts.MetalLBEnabled
config.MetalLB.Pools = []files.MetalLBPoolDef{}
config.Cluster.MetalLB.Enabled = c.Opts.MetalLBEnabled
config.Cluster.MetalLB.Pools = []files.MetalLBPoolDef{}
}

for _, pool := range c.Opts.MetalLBPools {
config.MetalLB.Pools = append(config.MetalLB.Pools, files.MetalLBPoolDef(pool))
config.Cluster.MetalLB.Pools = append(config.Cluster.MetalLB.Pools, files.MetalLBPoolDef(pool))
}
}

Expand Down
Loading
Loading