Skip to content

Commit

Permalink
Include airgap-bundle flag to node join command in airgap mode (#4550)
Browse files Browse the repository at this point in the history
  • Loading branch information
sgalsaleh authored Apr 16, 2024
1 parent 3c24246 commit 6a0602f
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 3 deletions.
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

0 comments on commit 6a0602f

Please sign in to comment.