Skip to content

Commit 22a352b

Browse files
authored
Apply additional kube manifests from configs to cluster (#817)
* Apply kube resources to the cluster Signed-off-by: Kimmo Lehto <klehto@mirantis.com>
1 parent a3795b7 commit 22a352b

File tree

5 files changed

+122
-0
lines changed

5 files changed

+122
-0
lines changed

action/apply.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ func NewApply(opts ApplyOptions) *Apply {
9090
&phase.ResetWorkers{NoDrain: opts.NoDrain},
9191
&phase.ResetControllers{NoDrain: opts.NoDrain},
9292
&phase.RunHooks{Stage: "after", Action: "apply"},
93+
&phase.ApplyManifests{},
9394
unlockPhase,
9495
&phase.Disconnect{},
9596
},

cmd/flags.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"path"
99
"path/filepath"
1010
"runtime"
11+
"strings"
1112
"time"
1213

1314
"github.com/a8m/envsubst"
@@ -239,6 +240,23 @@ func readConfig(ctx *cli.Context) (*v1beta1.Cluster, error) {
239240
cfg.Spec.K0s.Config.Merge(k0s)
240241
}
241242
}
243+
otherConfigs := mr.FilterResources(func(rd *manifest.ResourceDefinition) bool {
244+
if strings.EqualFold(rd.APIVersion, v1beta1.APIVersion) && strings.EqualFold(rd.Kind, "cluster") {
245+
return false
246+
}
247+
if strings.EqualFold(rd.APIVersion, "k0s.k0sproject.io/v1beta1") && strings.EqualFold(rd.Kind, "clusterconfig") {
248+
return false
249+
}
250+
return true
251+
})
252+
if len(otherConfigs) > 0 {
253+
cfg.Metadata.Manifests = make(map[string][]byte)
254+
log.Debugf("found %d additional resources in the configuration", len(otherConfigs))
255+
for _, otherConfig := range otherConfigs {
256+
log.Debugf("found resource: %s (%d bytes)", otherConfig.Filename(), len(otherConfig.Raw))
257+
cfg.Metadata.Manifests[otherConfig.Filename()] = otherConfig.Raw
258+
}
259+
}
242260

243261
if err := cfg.Validate(); err != nil {
244262
return nil, fmt.Errorf("cluster config validation failed: %w", err)

phase/apply_manifests.go

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package phase
2+
3+
import (
4+
"bytes"
5+
"fmt"
6+
"io"
7+
8+
"github.com/k0sproject/k0sctl/pkg/apis/k0sctl.k0sproject.io/v1beta1"
9+
"github.com/k0sproject/k0sctl/pkg/apis/k0sctl.k0sproject.io/v1beta1/cluster"
10+
"github.com/k0sproject/rig/exec"
11+
log "github.com/sirupsen/logrus"
12+
)
13+
14+
// ApplyManifests is a phase that applies additional manifests to the cluster
15+
type ApplyManifests struct {
16+
GenericPhase
17+
leader *cluster.Host
18+
}
19+
20+
// Title for the phase
21+
func (p *ApplyManifests) Title() string {
22+
return "Apply additional manifests"
23+
}
24+
25+
// Prepare the phase
26+
func (p *ApplyManifests) Prepare(config *v1beta1.Cluster) error {
27+
p.Config = config
28+
p.leader = p.Config.Spec.K0sLeader()
29+
30+
return nil
31+
}
32+
33+
// ShouldRun is true when there are additional manifests to apply
34+
func (p *ApplyManifests) ShouldRun() bool {
35+
return len(p.Config.Metadata.Manifests) > 0
36+
}
37+
38+
// Run the phase
39+
func (p *ApplyManifests) Run() error {
40+
for name, content := range p.Config.Metadata.Manifests {
41+
if err := p.apply(name, content); err != nil {
42+
return err
43+
}
44+
}
45+
46+
return nil
47+
}
48+
49+
func (p *ApplyManifests) apply(name string, content []byte) error {
50+
if !p.IsWet() {
51+
p.DryMsgf(p.leader, "apply manifest %s (%d bytes)", name, len(content))
52+
return nil
53+
}
54+
55+
log.Infof("%s: apply manifest %s (%d bytes)", p.leader, name, len(content))
56+
kubectlCmd := p.leader.Configurer.KubectlCmdf(p.leader, p.leader.K0sDataDir(), "apply -f -")
57+
var stdout, stderr bytes.Buffer
58+
59+
cmd, err := p.leader.ExecStreams(kubectlCmd, io.NopCloser(bytes.NewReader(content)), &stdout, &stderr, exec.Sudo(p.leader))
60+
if err != nil {
61+
return fmt.Errorf("failed to run apply for manifest %s: %w", name, err)
62+
}
63+
if err := cmd.Wait(); err != nil {
64+
log.Errorf("%s: kubectl apply failed for manifest %s", p.leader, name)
65+
log.Errorf("%s: kubectl apply stderr: %s", p.leader, stderr.String())
66+
}
67+
log.Infof("%s: kubectl apply: %s", p.leader, stdout.String())
68+
return nil
69+
}

pkg/apis/k0sctl.k0sproject.io/v1beta1/cluster.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ type ClusterMetadata struct {
1818
User string `yaml:"user" default:"admin"`
1919
Kubeconfig string `yaml:"-"`
2020
EtcdMembers []string `yaml:"-"`
21+
Manifests map[string][]byte `yaml:"-"`
2122
}
2223

2324
// Cluster describes launchpad.yaml configuration

smoke-test/smoke-multidoc.sh

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,39 @@ echo "* Starting apply"
2121
../k0sctl apply --config multidoc/ --kubeconfig-out applykubeconfig --debug
2222
echo "* Apply OK"
2323

24+
echo "* Downloading kubectl for local test"
25+
downloadKubectl
26+
27+
export KUBECONFIG=applykubeconfig
28+
29+
echo "*Waiting until the test pod is running"
30+
./kubectl wait --for=condition=Ready pod/hello --timeout=120s
31+
32+
retries=10
33+
delay=2
34+
nginx_ready=false
35+
i=1
36+
37+
while [ "$i" -le "$retries" ]; do
38+
echo "* Attempt $i: Checking if nginx is ready..."
39+
./kubectl exec pod/hello -- curl http://localhost/ | grep -q "Welcome to nginx!"
40+
if kubectl exec pod/hello -- curl -s http://localhost/ | grep -q "Welcome to nginx!"; then
41+
echo "nginx is ready!"
42+
nginx_ready=true
43+
break
44+
fi
45+
echo " - nginx is not ready"
46+
sleep $delay
47+
i=$((i + 1))
48+
done
49+
50+
if [ "$nginx_ready" = false ]; then
51+
echo "nginx failed to become ready after $retries attempts."
52+
exit 1
53+
fi
54+
55+
echo " - nginx is ready"
56+
2457
remoteCommand root@manager0 "cat /etc/k0s/k0s.yaml" > k0syaml
2558
echo Resulting k0s.yaml:
2659
cat k0syaml

0 commit comments

Comments
 (0)