Skip to content

Include airgap-bundle flag to node join command in airgap mode #4550

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
10 changes: 8 additions & 2 deletions pkg/embeddedcluster/node_join.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ func firstPrimaryIpAddress(ctx context.Context, client kubernetes.Interface) (st

// GenerateAddNodeCommand returns the command a user should run to add a node with the provided token
// the command will be of the form 'embeddedcluster node join ip:port UUID'
func GenerateAddNodeCommand(ctx context.Context, client kubernetes.Interface, token string) (string, error) {
func GenerateAddNodeCommand(ctx context.Context, client kubernetes.Interface, token string, isAirgap bool) (string, error) {
cm, err := ReadConfigMap(client)
if err != nil {
return "", fmt.Errorf("failed to read configmap: %w", err)
Expand All @@ -154,7 +154,13 @@ func GenerateAddNodeCommand(ctx context.Context, client kubernetes.Interface, to
return "", fmt.Errorf("failed to get admin console port: %w", err)
}

return fmt.Sprintf("sudo ./%s join %s:%d %s", binaryName, nodeIP, port, token), nil
// if airgap, add the airgap bundle flag
airgapBundleFlag := ""
if isAirgap {
airgapBundleFlag = fmt.Sprintf(" --airgap-bundle %s.airgap", binaryName)
}

return fmt.Sprintf("sudo ./%s join%s %s:%d %s", binaryName, airgapBundleFlag, nodeIP, port, token), nil
}

// GenerateK0sJoinCommand returns the k0s node join command, without the token but with all other required flags
Expand Down
92 changes: 92 additions & 0 deletions pkg/embeddedcluster/node_join_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package embeddedcluster

import (
"context"
"testing"

"github.com/replicatedhq/kots/pkg/util"
"github.com/stretchr/testify/require"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes/fake"
)

func TestGenerateAddNodeCommand(t *testing.T) {
util.PodNamespace = "kotsadm"
defer func() {
util.PodNamespace = ""
}()

// Create a fake clientset
clientset := fake.NewSimpleClientset(
&corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: "embedded-cluster-config",
Namespace: "embedded-cluster",
},
Data: map[string]string{
"embedded-binary-name": "my-app",
},
},
&corev1.Node{
ObjectMeta: metav1.ObjectMeta{
Name: "fake-node",
Labels: map[string]string{
"node-role.kubernetes.io/control-plane": "true",
},
},
Status: corev1.NodeStatus{
Conditions: []corev1.NodeCondition{
{
Type: corev1.NodeReady,
Status: corev1.ConditionTrue,
},
},
Addresses: []corev1.NodeAddress{
{
Type: corev1.NodeInternalIP,
Address: "192.168.0.100",
},
},
},
},
&corev1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: "admin-console",
Namespace: util.PodNamespace,
},
Spec: corev1.ServiceSpec{
Ports: []corev1.ServicePort{
{
Name: "http",
Protocol: corev1.ProtocolTCP,
Port: 80,
NodePort: 30000,
},
},
},
},
)

req := require.New(t)

// Generate the add node command for online
gotCommand, err := GenerateAddNodeCommand(context.Background(), clientset, "token", false)
if err != nil {
t.Fatalf("Failed to generate add node command: %v", err)
}

// Verify the generated command
wantCommand := "sudo ./my-app join 192.168.0.100:30000 token"
req.Equal(wantCommand, gotCommand)

// Generate the add node command for airgap
gotCommand, err = GenerateAddNodeCommand(context.Background(), clientset, "token", true)
if err != nil {
t.Fatalf("Failed to generate add node command: %v", err)
}

// Verify the generated command
wantCommand = "sudo ./my-app join --airgap-bundle my-app.airgap 192.168.0.100:30000 token"
req.Equal(wantCommand, gotCommand)
}
16 changes: 15 additions & 1 deletion pkg/handlers/embedded_cluster_node_join_command.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,21 @@ func (h *Handler) GenerateEmbeddedClusterNodeJoinCommand(w http.ResponseWriter,
w.WriteHeader(http.StatusInternalServerError)
return
}
nodeJoinCommand, err := embeddedcluster.GenerateAddNodeCommand(r.Context(), client, token)

apps, err := store.GetStore().ListInstalledApps()
if err != nil {
logger.Error(fmt.Errorf("failed to list installed apps: %w", err))
w.WriteHeader(http.StatusInternalServerError)
return
}
if len(apps) == 0 {
logger.Error(fmt.Errorf("no installed apps found"))
w.WriteHeader(http.StatusInternalServerError)
return
}
app := apps[0]

nodeJoinCommand, err := embeddedcluster.GenerateAddNodeCommand(r.Context(), client, token, app.IsAirgap)
if err != nil {
logger.Error(fmt.Errorf("failed to generate add node command: %w", err))
w.WriteHeader(http.StatusInternalServerError)
Expand Down