Skip to content

Commit

Permalink
Merge pull request #90 from canonical/KU-454/machine-addresses
Browse files Browse the repository at this point in the history
ensure we use InternalIP or ExternalIP machine addresses
  • Loading branch information
neoaggelos authored Mar 1, 2024
2 parents d31d053 + e4bd4d5 commit 3dfd18a
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 45 deletions.
10 changes: 6 additions & 4 deletions controllers/cloudinit/controlplane_join.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ type ControlPlaneJoinInput struct {
// IPinIP defines whether Calico will use IPinIP mode for cluster networking.
IPinIP bool
// JoinNodeIPs is the IP addresses of the nodes to join.
JoinNodeIPs [2]string
JoinNodeIPs []string
// Confinement specifies a classic or strict deployment of microk8s snap.
Confinement string
// RiskLevel specifies the risk level (strict, candidate, beta, edge) for the snap channels.
Expand Down Expand Up @@ -111,8 +111,10 @@ func NewJoinControlPlane(input *ControlPlaneJoinInput) (*CloudConfig, error) {
})
}

joinStr := fmt.Sprintf("%s:%s/%s", input.JoinNodeIPs[0], input.ClusterAgentPort, input.Token)
joinStrAlt := fmt.Sprintf("%s:%s/%s", input.JoinNodeIPs[1], input.ClusterAgentPort, input.Token)
joinURLs := make([]string, 0, len(input.JoinNodeIPs))
for _, nodeIP := range input.JoinNodeIPs {
joinURLs = append(joinURLs, fmt.Sprintf("%q", fmt.Sprintf("%s:%s/%s", nodeIP, input.ClusterAgentPort, input.Token)))
}

cloudConfig.BootCommands = append(cloudConfig.BootCommands, input.BootCommands...)

Expand All @@ -130,7 +132,7 @@ func NewJoinControlPlane(input *ControlPlaneJoinInput) (*CloudConfig, error) {
fmt.Sprintf("%s %q", scriptPath(configureDqlitePortScript), input.DqlitePort),
"microk8s status --wait-ready",
fmt.Sprintf("%s %q %q", scriptPath(configureCertLB), endpointType, input.ControlPlaneEndpoint),
fmt.Sprintf("%s no %q %q", scriptPath(microk8sJoinScript), joinStr, joinStrAlt),
fmt.Sprintf("%s no %s", scriptPath(microk8sJoinScript), strings.Join(joinURLs, " ")),
scriptPath(configureAPIServerScript),
fmt.Sprintf("microk8s add-node --token-ttl %v --token %q", input.TokenTTL, input.Token),
)
Expand Down
5 changes: 2 additions & 3 deletions controllers/cloudinit/controlplane_join_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ func TestControlPlaneJoin(t *testing.T) {
t.Run("Simple", func(t *testing.T) {
g := NewWithT(t)

joins := [2]string{"10.0.3.39", "10.0.3.40"}
cloudConfig, err := cloudinit.NewJoinControlPlane(&cloudinit.ControlPlaneJoinInput{
ControlPlaneEndpoint: "k8s.my-domain.com",
KubernetesVersion: "v1.25.2",
Expand All @@ -37,7 +36,7 @@ func TestControlPlaneJoin(t *testing.T) {
IPinIP: true,
Token: strings.Repeat("a", 32),
TokenTTL: 10000,
JoinNodeIPs: joins,
JoinNodeIPs: []string{"10.0.3.39", "10.0.3.40", "10.0.3.41"},
})
g.Expect(err).NotTo(HaveOccurred())

Expand All @@ -55,7 +54,7 @@ func TestControlPlaneJoin(t *testing.T) {
`/capi-scripts/10-configure-dqlite-port.sh "2379"`,
`microk8s status --wait-ready`,
`/capi-scripts/10-configure-cert-for-lb.sh "DNS" "k8s.my-domain.com"`,
`/capi-scripts/20-microk8s-join.sh no "10.0.3.39:30000/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "10.0.3.40:30000/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"`,
`/capi-scripts/20-microk8s-join.sh no "10.0.3.39:30000/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "10.0.3.40:30000/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "10.0.3.41:30000/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"`,
`/capi-scripts/10-configure-apiserver.sh`,
`microk8s add-node --token-ttl 10000 --token "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"`,
}))
Expand Down
32 changes: 19 additions & 13 deletions controllers/cloudinit/scripts/20-microk8s-join.sh
Original file line number Diff line number Diff line change
@@ -1,27 +1,33 @@
#!/bin/bash -xe

# Usage:
# $0 $worker_yes_no $join_string $alternative_join_string
# $0 $worker_yes_no $join_string_1 $join_string_2 ... $join_string_N
#
# Assumptions:
# - microk8s is installed
# - microk8s node is ready to join the cluster

join="${2}"
join_alt="${3}"

join_args=""
if [ ${1} == "yes" ]; then
join+=" --worker"
join_alt+=" --worker"
join_args="--worker"
fi

while ! microk8s join ${join}; do
echo "Failed to join MicroK8s cluster, retring alternative join string"
if ! microk8s join ${join_alt} ; then
break
fi
echo "Failed to join MicroK8s cluster, will retry"
sleep 5
shift

# Loop over the given join addresses until microk8s join command succeeds.
joined="false"
while [ "$joined" = "false" ]; do

for url in "${@}"; do
if microk8s join "${url}" $join_args; then
joined="true"
break
fi

echo "Failed to join MicroK8s cluster, will retry"
sleep 5
done

done

# What is this hack? Why do we call snap set here?
Expand Down
10 changes: 6 additions & 4 deletions controllers/cloudinit/worker_join.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ type WorkerInput struct {
// ContainerdNoProxy is no_proxy configuration for containerd.
ContainerdNoProxy string
// JoinNodeIPs is the IP addresses of the nodes to join.
JoinNodeIPs [2]string
JoinNodeIPs []string
// Confinement specifies a classic or strict deployment of microk8s snap.
Confinement string
// RiskLevel specifies the risk level (strict, candidate, beta, edge) for the snap channels.
Expand Down Expand Up @@ -100,8 +100,10 @@ func NewJoinWorker(input *WorkerInput) (*CloudConfig, error) {
})
}

joinStr := fmt.Sprintf("%s:%s/%s", input.JoinNodeIPs[0], input.ClusterAgentPort, input.Token)
joinStrAlt := fmt.Sprintf("%s:%s/%s", input.JoinNodeIPs[1], input.ClusterAgentPort, input.Token)
joinURLs := make([]string, 0, len(input.JoinNodeIPs))
for _, nodeIP := range input.JoinNodeIPs {
joinURLs = append(joinURLs, fmt.Sprintf("%q", fmt.Sprintf("%s:%s/%s", nodeIP, input.ClusterAgentPort, input.Token)))
}

cloudConfig.BootCommands = append(cloudConfig.BootCommands, input.BootCommands...)

Expand All @@ -115,7 +117,7 @@ func NewJoinWorker(input *WorkerInput) (*CloudConfig, error) {
scriptPath(configureKubeletScript),
"microk8s status --wait-ready",
fmt.Sprintf("%s %q", scriptPath(configureClusterAgentPortScript), input.ClusterAgentPort),
fmt.Sprintf("%s yes %q %q", scriptPath(microk8sJoinScript), joinStr, joinStrAlt),
fmt.Sprintf("%s yes %s", scriptPath(microk8sJoinScript), strings.Join(joinURLs, " ")),
fmt.Sprintf("%s %s 6443 %s", scriptPath(configureTraefikScript), input.ControlPlaneEndpoint, stopApiServerProxyRefreshes),
)
cloudConfig.RunCommands = append(cloudConfig.RunCommands, input.PostRunCommands...)
Expand Down
3 changes: 1 addition & 2 deletions controllers/cloudinit/worker_join_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,12 @@ func TestWorkerJoin(t *testing.T) {
t.Run("Simple", func(t *testing.T) {
g := NewWithT(t)

joins := [2]string{"10.0.3.194", "10.0.3.195"}
cloudConfig, err := cloudinit.NewJoinWorker(&cloudinit.WorkerInput{
ControlPlaneEndpoint: "capi-aws-apiserver-1647391446.us-east-1.elb.amazonaws.com",
KubernetesVersion: "v1.24.3",
ClusterAgentPort: "30000",
Token: strings.Repeat("a", 32),
JoinNodeIPs: joins,
JoinNodeIPs: []string{"10.0.3.194", "10.0.3.195"},
})
g.Expect(err).NotTo(HaveOccurred())

Expand Down
49 changes: 30 additions & 19 deletions controllers/microk8sconfig_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,14 @@ const (
remappedClusterAgentPort string = "30000"
)

var (
// preferMachineAddressTypeList is the order of preference of machine addresses to use for joining microk8s nodes to a cluster.
preferMachineAddressTypeList = []clusterv1.MachineAddressType{
clusterv1.MachineInternalIP,
clusterv1.MachineExternalIP,
}
)

//+kubebuilder:rbac:groups=bootstrap.cluster.x-k8s.io,resources=microk8sconfigs,verbs=get;list;watch;create;update;patch;delete
//+kubebuilder:rbac:groups=bootstrap.cluster.x-k8s.io,resources=microk8sconfigs/status,verbs=get;update;patch
//+kubebuilder:rbac:groups=bootstrap.cluster.x-k8s.io,resources=microk8sconfigs/finalizers,verbs=update
Expand Down Expand Up @@ -366,7 +374,7 @@ func (r *MicroK8sConfigReconciler) handleJoiningControlPlaneNode(ctx context.Con

scope.Info("Creating BootstrapData for the join control plane")
ipsOfNodesToConnectTo, err := r.getControlPlaneNodesToJoin(ctx, scope)
if err != nil || ipsOfNodesToConnectTo[0] == "" {
if err != nil || len(ipsOfNodesToConnectTo) == 0 {
scope.Info("Failed to discover a control plane IP, requeueing.")
return ctrl.Result{RequeueAfter: 30 * time.Second}, nil
}
Expand Down Expand Up @@ -482,7 +490,7 @@ func (r *MicroK8sConfigReconciler) handleJoiningWorkerNode(ctx context.Context,
}

ipOfNodesToConnectTo, err := r.getControlPlaneNodesToJoin(ctx, scope)
if err != nil || ipOfNodesToConnectTo[0] == "" {
if err != nil || len(ipOfNodesToConnectTo) == 0 {
scope.Info("Failed to discover a control plane IP, requeueing.")
return ctrl.Result{RequeueAfter: 30 * time.Second}, nil
}
Expand Down Expand Up @@ -539,34 +547,37 @@ func (r *MicroK8sConfigReconciler) handleJoiningWorkerNode(ctx context.Context,
return ctrl.Result{}, nil
}

func (r *MicroK8sConfigReconciler) getControlPlaneNodesToJoin(ctx context.Context, scope *Scope) ([2]string, error) {
var ipOfNodesToConnectTo [2]string
func (r *MicroK8sConfigReconciler) getControlPlaneNodesToJoin(ctx context.Context, scope *Scope) ([]string, error) {
nodes, err := r.getControlPlaneMachinesForCluster(ctx, util.ObjectKey(scope.Cluster))
if err != nil {
scope.Error(err, "Lookup control plane nodes")
return ipOfNodesToConnectTo, err
return nil, err
}

n := 0
addressesByType := make(map[clusterv1.MachineAddressType][]string)
for _, node := range nodes {
if n >= 2 {
break
if node.Spec.ProviderID == nil || node.Status.Phase != "Running" {
continue
}
if node.Spec.ProviderID != nil && node.Status.Phase == "Running" {
for _, address := range node.Status.Addresses {
if address.Address != "" {
ipOfNodesToConnectTo[n] = address.Address
n += 1
if n == 1 {
ipOfNodesToConnectTo[n] = address.Address
}
break
}
for _, address := range node.Status.Addresses {
if address.Address == "" {
continue
}
addressesByType[address.Type] = append(addressesByType[address.Type], address.Address)
}
}

return ipOfNodesToConnectTo, nil
for _, addressType := range preferMachineAddressTypeList {
if addresses, ok := addressesByType[addressType]; ok && len(addresses) > 0 {
return addresses, nil
}
}

// if we are here, no addresses were found
err = fmt.Errorf("machines do not have any addresses with types %v", preferMachineAddressTypeList)
scope.Error(err, "Lookup control plane node IPs", "addressesByType", addressesByType)

return nil, err
}

func (r *MicroK8sConfigReconciler) storeBootstrapData(ctx context.Context, scope *Scope, data []byte) error {
Expand Down

0 comments on commit 3dfd18a

Please sign in to comment.