Skip to content

Commit 61bed38

Browse files
committed
feat(control): enable kubectl completion
add bash completion as external component control node completes kubectl commands and parameters via bash completion kubectl fabric will be autocompleted also when it is supported Signed-off-by: Pau Capdevila <pau@githedgehog.com>
1 parent 14a9113 commit 61bed38

File tree

8 files changed

+145
-16
lines changed

8 files changed

+145
-16
lines changed

api/fabricator/v1beta1/fabricator_types.go

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -218,14 +218,15 @@ type Versions struct {
218218
}
219219

220220
type PlatformVersions struct {
221-
K3s meta.Version `json:"k3s,omitempty"`
222-
Zot meta.Version `json:"zot,omitempty"`
223-
CertManager meta.Version `json:"certManager,omitempty"`
224-
K9s meta.Version `json:"k9s,omitempty"`
225-
Toolbox meta.Version `json:"toolbox,omitempty"`
226-
Reloader meta.Version `json:"reloader,omitempty"`
227-
NTP meta.Version `json:"ntp,omitempty"`
228-
NTPChart meta.Version `json:"ntpChart,omitempty"`
221+
K3s meta.Version `json:"k3s,omitempty"`
222+
Zot meta.Version `json:"zot,omitempty"`
223+
CertManager meta.Version `json:"certManager,omitempty"`
224+
K9s meta.Version `json:"k9s,omitempty"`
225+
Toolbox meta.Version `json:"toolbox,omitempty"`
226+
Reloader meta.Version `json:"reloader,omitempty"`
227+
NTP meta.Version `json:"ntp,omitempty"`
228+
NTPChart meta.Version `json:"ntpChart,omitempty"`
229+
BashCompletion meta.Version `json:"bashCompletion,omitempty"`
229230
}
230231

231232
type FabricatorVersions struct {

config/crd/bases/fabricator.githedgehog.com_fabricators.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,8 @@ spec:
324324
type: object
325325
platform:
326326
properties:
327+
bashCompletion:
328+
type: string
327329
certManager:
328330
type: string
329331
k3s:
@@ -521,6 +523,8 @@ spec:
521523
type: object
522524
platform:
523525
properties:
526+
bashCompletion:
527+
type: string
524528
certManager:
525529
type: string
526530
k3s:

docs/api.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -542,6 +542,7 @@ _Appears in:_
542542
| `reloader` _[Version](#version)_ | | | |
543543
| `ntp` _[Version](#version)_ | | | |
544544
| `ntpChart` _[Version](#version)_ | | | |
545+
| `bashCompletion` _[Version](#version)_ | | | |
545546

546547

547548
#### RegistryConfig
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
// Copyright 2024 Hedgehog
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package bashcompletion
5+
6+
import (
7+
"context"
8+
"embed"
9+
"fmt"
10+
"io"
11+
"log/slog"
12+
"os"
13+
"path/filepath"
14+
"strings"
15+
16+
fabapi "go.githedgehog.com/fabricator/api/fabricator/v1beta1"
17+
"go.githedgehog.com/fabricator/api/meta"
18+
)
19+
20+
//go:embed scripts/profile.sh
21+
var scriptFS embed.FS
22+
23+
const (
24+
BashCompletionRef = "bash-completion"
25+
BashCompletionFile = "bash_completion"
26+
InstallDir = "/opt/bash-completion"
27+
ProfileDir = "/etc/profile.d"
28+
ProfileFilename = "bash-completion.sh"
29+
)
30+
31+
func Version(f fabapi.Fabricator) meta.Version {
32+
return f.Status.Versions.Platform.BashCompletion
33+
}
34+
35+
func Install(_ context.Context, workDir string, fab fabapi.Fabricator) error {
36+
slog.Info("Installing bash-completion")
37+
38+
versionStr := strings.TrimPrefix(string(Version(fab)), "v")
39+
slog.Info("Using bash-completion version", "version", versionStr)
40+
41+
dirs := []string{
42+
InstallDir,
43+
ProfileDir,
44+
}
45+
46+
for _, dir := range dirs {
47+
if err := os.MkdirAll(dir, 0755); err != nil {
48+
return fmt.Errorf("creating directory %s: %w", dir, err)
49+
}
50+
}
51+
52+
srcPath := filepath.Join(workDir, BashCompletionFile)
53+
dstPath := filepath.Join(InstallDir, BashCompletionFile)
54+
55+
srcFile, err := os.Open(srcPath)
56+
if err != nil {
57+
return fmt.Errorf("opening source file: %w", err)
58+
}
59+
defer srcFile.Close()
60+
61+
dstFile, err := os.OpenFile(dstPath, os.O_CREATE|os.O_WRONLY, 0644)
62+
if err != nil {
63+
return fmt.Errorf("creating destination file: %w", err)
64+
}
65+
defer dstFile.Close()
66+
67+
if _, err := io.Copy(dstFile, srcFile); err != nil {
68+
return fmt.Errorf("copying file content: %w", err)
69+
}
70+
71+
profileScript, err := scriptFS.ReadFile("scripts/profile.sh")
72+
if err != nil {
73+
return fmt.Errorf("reading profile script: %w", err)
74+
}
75+
76+
profilePath := filepath.Join(ProfileDir, ProfileFilename)
77+
if err := os.WriteFile(profilePath, profileScript, 0644); err != nil { //nolint:gosec
78+
return fmt.Errorf("writing bash-completion profile script: %w", err)
79+
}
80+
81+
return nil
82+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#!/bin/bash
2+
# Copyright 2024 Hedgehog
3+
# SPDX-License-Identifier: Apache-2.0
4+
5+
export LC_ALL=C
6+
export LANG=C
7+
8+
if [ -f /opt/bash-completion/bash_completion ]; then
9+
. /opt/bash-completion/bash_completion
10+
else
11+
echo "Warning: bash_completion file not found" >&2
12+
fi
13+
14+
alias k=kubectl
15+
16+
if command -v kubectl &>/dev/null; then
17+
source <(kubectl completion bash) 2>/dev/null || true
18+
complete -o default -F __start_kubectl k 2>/dev/null || true
19+
fi
20+
21+
if command -v kubectl &>/dev/null; then
22+
if kubectl fabric --help >/dev/null 2>&1; then
23+
kubectl fabric completion bash >/dev/null 2>&1 || true
24+
fi
25+
fi

pkg/fab/recipe/control_build.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
fabapi "go.githedgehog.com/fabricator/api/fabricator/v1beta1"
1717
"go.githedgehog.com/fabricator/pkg/artificer"
1818
"go.githedgehog.com/fabricator/pkg/fab/comp"
19+
"go.githedgehog.com/fabricator/pkg/fab/comp/bashcompletion"
1920
"go.githedgehog.com/fabricator/pkg/fab/comp/certmanager"
2021
"go.githedgehog.com/fabricator/pkg/fab/comp/f8r"
2122
"go.githedgehog.com/fabricator/pkg/fab/comp/fabric"
@@ -134,6 +135,15 @@ func (b *ControlInstallBuilder) addPayload(ctx context.Context, slog *slog.Logge
134135
return fmt.Errorf("downloading cert-manager: %w", err)
135136
}
136137

138+
slog.Info("Adding bash-completion to installer", "control", b.Control.Name)
139+
if err := b.Downloader.FromORAS(ctx, installDir, bashcompletion.BashCompletionRef, bashcompletion.Version(b.Fab), []artificer.ORASFile{
140+
{
141+
Name: bashcompletion.BashCompletionFile,
142+
},
143+
}); err != nil {
144+
return fmt.Errorf("downloading bash-completion: %w", err)
145+
}
146+
137147
slog.Info("Adding config and wiring files to installer")
138148
fabF, err := os.Create(filepath.Join(installDir, FabName))
139149
if err != nil {

pkg/fab/recipe/control_install.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"go.githedgehog.com/fabric/pkg/util/logutil"
2121
fabapi "go.githedgehog.com/fabricator/api/fabricator/v1beta1"
2222
"go.githedgehog.com/fabricator/pkg/fab/comp"
23+
"go.githedgehog.com/fabricator/pkg/fab/comp/bashcompletion"
2324
"go.githedgehog.com/fabricator/pkg/fab/comp/certmanager"
2425
"go.githedgehog.com/fabricator/pkg/fab/comp/k3s"
2526
"go.githedgehog.com/fabricator/pkg/fab/comp/k9s"
@@ -75,6 +76,10 @@ func (c *ControlInstall) Run(ctx context.Context) error {
7576
return fmt.Errorf("installing zot: %w", err)
7677
}
7778

79+
if err := bashcompletion.Install(ctx, c.WorkDir, c.Fab); err != nil {
80+
return fmt.Errorf("installing bash completion: %w", err)
81+
}
82+
7883
// we should use in-cluster registry from now on
7984
c.Fab.Status.IsBootstrap = false
8085

pkg/fab/versions.go

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,15 @@ var (
1818

1919
var Versions = fabapi.Versions{
2020
Platform: fabapi.PlatformVersions{
21-
K3s: "v1.32.1-k3s1",
22-
Zot: "v2.1.1",
23-
CertManager: "v1.17.1",
24-
K9s: "v0.40.6",
25-
Toolbox: "latest", // TODO use specific version, move to fabricator repo
26-
Reloader: "v1.0.40", // TODO upgrade or get rid of?
27-
NTP: "v0.0.2",
28-
NTPChart: FabricatorVersion,
21+
K3s: "v1.32.1-k3s1",
22+
Zot: "v2.1.1",
23+
CertManager: "v1.17.1",
24+
K9s: "v0.40.6",
25+
Toolbox: "latest", // TODO use specific version, move to fabricator repo
26+
Reloader: "v1.0.40", // TODO upgrade or get rid of?
27+
NTP: "v0.0.2",
28+
BashCompletion: "v2.16.0",
29+
NTPChart: FabricatorVersion,
2930
},
3031
Fabricator: fabapi.FabricatorVersions{
3132
API: FabricatorVersion,

0 commit comments

Comments
 (0)