Skip to content

Commit b96cc1c

Browse files
m-brandoMatus Brandysgithub-actions[bot]CI/CD pipeline
authored
Add custom SSH port support for dynamic and static nodepools (#2026)
- Adds configurable SSH port support for static node pools, replacing the hardcoded port 22 -> optional `sshPort field `in the manifest - New dynamic nodepools (created via new terraform templates) use port 22522 by default, with the port confirmed from terraform output - Existing dynamic nodepools retain port 22 for backward compatibility via state transfer - Terraform templates output [IP, port] tuples; old templates outputting just IP. This will be handled in ansibler and kube-eleven stage as ssh port 22 for VMs - With this PR comes new templates berops/claudie-config#32. But changes in PR also works with old templates. Migration from old to new templates also tested - **This PR replaces the earlier PR #1997 - Closes #1837 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added configurable SSH port support for node pools, enabling SSH connections through non-standard ports. Defaults to port 22 when not specified. * Infrastructure provisioning and management services now fully support custom SSH port configurations for cluster operations. * **Documentation** * Updated API documentation, deployment examples, and platform-specific guides with the new optional `sshPort` field for node pool specifications. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Matus Brandys <matus.brandys@berops.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: CI/CD pipeline <CI/CD-pipeline@users.noreply.github.com>
1 parent bbff127 commit b96cc1c

25 files changed

Lines changed: 146 additions & 45 deletions

File tree

docs/input-manifest/api-reference.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,10 @@ Static nodepools are defined for static machines which Claudie will not manage.
370370

371371
To see the default taints Claudie applies on each node, refer to [this section](#default-taints).
372372

373+
- `sshPort`
374+
375+
SSH port used to connect to the static nodes in this node pool. This field is optional. If not specified, the default value of `22` is used.
376+
373377
## Static node
374378

375379
Static node defines single static node from a static nodepool.

docs/input-manifest/example.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,7 @@ spec:
262262
# secretRef: # Secret reference specification, holding private key which will be used to SSH into the node (as root or as a user specificed in the username attribute).
263263
# name: # Name of the secret resource.
264264
# namespace: # Namespace of the secret resource.
265+
# sshPort: # SSH port used to connect to the static nodes. Defaults to 22 if not set. (optional)
265266
# labels: # Map of custom user defined labels for this nodepool. This field is optional and is ignored if used in Loadbalancer cluster. (optional)
266267
# annotations: # Map of user defined annotations, which will be applied on every node in the node pool. (optional)
267268
# taints: # Array of custom user defined taints for this nodepool. This field is optional and is ignored if used in Loadbalancer cluster. (optional)

docs/input-manifest/providers/on-prem.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Claudie is designed to leverage your existing infrastructure and utilise it for
66

77
2. Connectivity between Static Nodes: Static nodes within the infrastructure should be able to communicate with each other using the specified endpoints. This connectivity is important for proper functioning of the Kubernetes cluster.
88

9-
3. SSH Access with Root Privileges: Claudie relies on SSH access to the nodes using the SSH key provided in the input manifest. The SSH key should grant root privileges to enable Claudie to perform required operations on the nodes.
9+
3. SSH Access with Root Privileges: Claudie relies on SSH access to the nodes using the SSH key provided in the input manifest. The SSH key should grant root privileges to enable Claudie to perform required operations on the nodes. By default, Claudie connects on port `22`. If your static nodes use a custom SSH port, you can specify it with the `sshPort` field on the static nodepool definition.
1010

1111
4. Meeting the Kubernetes nodes requirements: Learn [more](https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm/#before-you-begin).
1212

@@ -43,13 +43,15 @@ spec:
4343
nodePools:
4444
static:
4545
- name: control
46+
# sshPort: 2222 # Optional: SSH port for connecting to static nodes. Defaults to 22.
4647
nodes:
4748
- endpoint: "192.168.10.1"
4849
secretRef:
4950
name: static-node-key
5051
namespace: <your-namespace>
5152

5253
- name: compute
54+
# sshPort: 2222 # Optional: SSH port for connecting to static nodes. Defaults to 22.
5355
nodes:
5456
- endpoint: "192.168.10.2"
5557
secretRef:

internal/api/crd/inputmanifest/v1beta1/inputmanifest_types.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,11 @@ type StaticNodePool struct {
123123
Annotations map[string]string `json:"annotations"`
124124
// +optional
125125
Taints []corev1.Taint `json:"taints"`
126+
// SSH port used to connect to the static nodes. Defaults to 22 if not set.
127+
// +optional
128+
// +kubebuilder:validation:Minimum=1
129+
// +kubebuilder:validation:Maximum=65535
130+
SshPort int32 `json:"sshPort,omitempty"`
126131
}
127132

128133
// StaticNode defines a single static node for a particular static nodepool.

internal/api/manifest/manifest.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,9 @@ type StaticNodePool struct {
236236
// User defined taints for this nodepool.
237237
// +optional
238238
Taints []k8sV1.Taint `validate:"omitempty" yaml:"taints" json:"taints"`
239+
// SSH port used to connect to the static nodes. Defaults to 22 if not set.
240+
// +optional
241+
SshPort *int32 `validate:"omitempty,min=1,max=65535" yaml:"sshPort" json:"sshPort"`
239242
}
240243

241244
// Node represents a static node assigned to a particular static nodepool.

internal/api/manifest/utils.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"math"
77
"slices"
88

9+
"github.com/berops/claudie/internal/nodepools"
910
"github.com/berops/claudie/proto/pb/spec"
1011
"github.com/go-git/go-git/v5"
1112
"github.com/go-git/go-git/v5/config"
@@ -397,6 +398,7 @@ func (ds *Manifest) CreateNodepools(pools []string, isControl bool) ([]*spec.Nod
397398
Labels: nodePool.Labels,
398399
Annotations: nodePool.Annotations,
399400
Taints: taints,
401+
SshPort: resolveSSHPort(nodePool.SshPort),
400402
Type: &spec.NodePool_StaticNodePool{
401403
StaticNodePool: &spec.StaticNodePool{
402404
NodeKeys: keys,
@@ -483,6 +485,13 @@ func staticNodes(np *StaticNodePool, isControl bool) []*spec.Node {
483485
return nodes
484486
}
485487

488+
func resolveSSHPort(port *int32) int32 {
489+
if port == nil {
490+
return nodepools.DefaultSSHPort
491+
}
492+
return *port
493+
}
494+
486495
// getNodeKeys returns map of keys for static nodes in map[endpoint]key.
487496
func getNodeKeys(nodepool *StaticNodePool) map[string]string {
488497
m := make(map[string]string)

internal/nodepools/nodepools.go

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,20 @@ import (
1616
"google.golang.org/protobuf/proto"
1717
)
1818

19+
const (
20+
// DefaultSSHPort is the standard SSH port used by existing/legacy nodepools.
21+
DefaultSSHPort = int32(22)
22+
)
23+
24+
// SSHPort returns the effective SSH port for a nodepool and normalizes the
25+
// stored value in-place, replacing 0 with DefaultSSHPort.
26+
func SSHPort(np *spec.NodePool) int32 {
27+
if np.SshPort == 0 {
28+
np.SshPort = DefaultSSHPort
29+
}
30+
return np.SshPort
31+
}
32+
1933
type RegionNetwork struct {
2034
Region string
2135
ExternalNetwork string
@@ -102,6 +116,7 @@ func PartialCopyWithNodeExclusion(np *spec.NodePool, nodes []string) *spec.NodeP
102116
Labels: np.Labels,
103117
Taints: np.Taints,
104118
Annotations: np.Annotations,
119+
SshPort: np.SshPort,
105120
}
106121

107122
for _, n := range np.Nodes {
@@ -148,6 +163,7 @@ func PartialCopyWithNodeFilter(np *spec.NodePool, nodes []string) *spec.NodePool
148163
Labels: np.Labels,
149164
Taints: np.Taints,
150165
Annotations: np.Annotations,
166+
SshPort: np.SshPort,
151167
}
152168

153169
for _, n := range np.Nodes {
@@ -497,35 +513,37 @@ func RandomDynamicNode(nodepools iter.Seq[*spec.NodePool]) *spec.Node {
497513
return nodes[idx]
498514
}
499515

500-
// Returns a random node public Endpoint and a SSH key to connect to it. Nil if there is none.
501-
func RandomNodePublicEndpoint(nps []*spec.NodePool) (string, string, string) {
516+
// Returns a random node public Endpoint, SSH key, and SSH port to connect to it. Empty strings if there is none.
517+
func RandomNodePublicEndpoint(nps []*spec.NodePool) (username, endpoint, key, sshPort string) {
502518
if len(nps) == 0 {
503-
return "", "", ""
519+
return "", "", "", ""
504520
}
505521

506522
idx := rand.IntN(len(nps))
507523
np := nps[idx]
508524

509525
if len(np.Nodes) == 0 {
510-
return "", "", ""
526+
return "", "", "", ""
511527
}
512528

513529
idx = rand.IntN(len(np.Nodes))
514530
node := np.Nodes[idx]
515531

516-
endpoint := node.Public
517-
username := "root"
532+
endpoint = node.Public
533+
username = "root"
518534
if node.Username != "" && node.Username != username {
519535
username = node.Username
520536
}
521537

522-
switch np := np.Type.(type) {
538+
port := fmt.Sprint(SSHPort(np))
539+
540+
switch t := np.Type.(type) {
523541
case *spec.NodePool_DynamicNodePool:
524-
return username, endpoint, np.DynamicNodePool.PrivateKey
542+
return username, endpoint, t.DynamicNodePool.PrivateKey, port
525543
case *spec.NodePool_StaticNodePool:
526-
return username, endpoint, np.StaticNodePool.NodeKeys[node.Public]
544+
return username, endpoint, t.StaticNodePool.NodeKeys[node.Public], port
527545
default:
528-
return "", "", ""
546+
return "", "", "", ""
529547
}
530548
}
531549

internal/templateUtils/templates.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"text/template"
1212

1313
"github.com/Masterminds/sprig/v3"
14+
"github.com/berops/claudie/internal/nodepools"
1415
)
1516

1617
// directory - output directory
@@ -65,6 +66,7 @@ func LoadTemplate(tplFile string) (*template.Template, error) {
6566
funcMap["replaceAll"] = strings.ReplaceAll
6667
funcMap["extractNetmaskFromCIDR"] = ExtractNetmaskFromCIDR
6768
funcMap["hasExtension"] = HasExtension
69+
funcMap["sshPort"] = nodepools.SSHPort
6870

6971
tpl, err := template.New("").Funcs(funcMap).Parse(tplFile)
7072
if err != nil {

manifests/claudie/crd/claudie.io_inputmanifests.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,13 @@ spec:
462462
- secretRef
463463
type: object
464464
type: array
465+
sshPort:
466+
description: SSH port used to connect to the static nodes.
467+
Defaults to 22 if not set.
468+
format: int32
469+
maximum: 65535
470+
minimum: 1
471+
type: integer
465472
taints:
466473
items:
467474
description: |-

manifests/claudie/kustomization.yaml

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -56,16 +56,16 @@ apiVersion: kustomize.config.k8s.io/v1beta1
5656
kind: Kustomization
5757
images:
5858
- name: ghcr.io/berops/claudie/ansibler
59-
newTag: ea529e6-4017
59+
newTag: cb86452-4043
6060
- name: ghcr.io/berops/claudie/autoscaler-adapter
61-
newTag: ea529e6-4017
61+
newTag: cb86452-4043
6262
- name: ghcr.io/berops/claudie/claudie-operator
63-
newTag: ea529e6-4017
63+
newTag: cb86452-4043
6464
- name: ghcr.io/berops/claudie/kube-eleven
65-
newTag: ea529e6-4017
65+
newTag: cb86452-4043
6666
- name: ghcr.io/berops/claudie/kuber
67-
newTag: ea529e6-4017
67+
newTag: cb86452-4043
6868
- name: ghcr.io/berops/claudie/manager
69-
newTag: ea529e6-4017
69+
newTag: cb86452-4043
7070
- name: ghcr.io/berops/claudie/terraformer
71-
newTag: ea529e6-4017
71+
newTag: cb86452-4043

0 commit comments

Comments
 (0)