Skip to content
Open
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
3 changes: 3 additions & 0 deletions internal/api/manifest/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"math"
"slices"

"github.com/berops/claudie/internal/nodepools"
"github.com/berops/claudie/proto/pb/spec"
"github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/config"
Expand Down Expand Up @@ -333,6 +334,7 @@ func (ds *Manifest) CreateNodepools(pools []string, isControl bool) ([]*spec.Nod
Labels: nodePool.Labels,
Annotations: nodePool.Annotations,
Taints: getTaints(nodePool.Taints),
SshPort: nodepools.NewSSHPort,
// The nodes are left empty, as the desired state
// in the manifest does not specify each of the nodes
// individually, just the count of the nodes that the
Expand Down Expand Up @@ -370,6 +372,7 @@ func (ds *Manifest) CreateNodepools(pools []string, isControl bool) ([]*spec.Nod
Labels: nodePool.Labels,
Annotations: nodePool.Annotations,
Taints: taints,
SshPort: nodepools.NewSSHPort,
Type: &spec.NodePool_StaticNodePool{
StaticNodePool: &spec.StaticNodePool{
NodeKeys: keys,
Expand Down
53 changes: 43 additions & 10 deletions internal/nodepools/nodepools.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,34 @@ import (
"google.golang.org/protobuf/proto"
)

const (
// DefaultSSHPort is the standard SSH port used by old/existing nodepools.
DefaultSSHPort = int32(22)
// NewSSHPort is the SSH port assigned to newly created nodepools.
NewSSHPort = int32(22522)
)

// SSHPort returns the effective SSH port for a nodepool.
// Returns DefaultSSHPort (22) if not set (backwards compatibility with old nodepools).
func SSHPort(np *spec.NodePool) int32 {
if np.GetSshPort() == 0 {
return DefaultSSHPort
}
return np.GetSshPort()
}

// NodeSSHPort returns the SSH port for a node based on its terraform output.
// Returns DefaultSSHPort (22) if not set.
func NodeSSHPort(node *spec.Node) int32 {
if node.GetSshPort() != "" {
var port int32
if _, err := fmt.Sscanf(node.GetSshPort(), "%d", &port); err == nil && port > 0 {
return port
}
}
return DefaultSSHPort
}

type RegionNetwork struct {
Region string
ExternalNetwork string
Expand Down Expand Up @@ -102,6 +130,7 @@ func PartialCopyWithNodeExclusion(np *spec.NodePool, nodes []string) *spec.NodeP
Labels: np.Labels,
Taints: np.Taints,
Annotations: np.Annotations,
SshPort: np.SshPort,
}

for _, n := range np.Nodes {
Expand Down Expand Up @@ -148,6 +177,7 @@ func PartialCopyWithNodeFilter(np *spec.NodePool, nodes []string) *spec.NodePool
Labels: np.Labels,
Taints: np.Taints,
Annotations: np.Annotations,
SshPort: np.SshPort,
}

for _, n := range np.Nodes {
Expand Down Expand Up @@ -195,6 +225,7 @@ func PartialCopyWithReplacedNodes(np *spec.NodePool, nodes []*spec.Node, nodeKey
Labels: np.Labels,
Taints: np.Taints,
Annotations: np.Annotations,
SshPort: np.SshPort,
}

// To avoid issues with possible node counts, deep clone the node type itself.
Expand Down Expand Up @@ -493,35 +524,37 @@ func RandomDynamicNode(nodepools iter.Seq[*spec.NodePool]) *spec.Node {
return nodes[idx]
}

// Returns a random node public Endpoint and a SSH key to connect to it. Nil if there is none.
func RandomNodePublicEndpoint(nps []*spec.NodePool) (string, string, string) {
// Returns a random node public Endpoint, SSH key, and SSH port to connect to it.
// Empty strings and 0 are returned if there are no nodepools/nodes.
func RandomNodePublicEndpoint(nps []*spec.NodePool) (username, endpoint, key string, sshPort int32) {
if len(nps) == 0 {
return "", "", ""
return "", "", "", 0
}

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

if len(np.Nodes) == 0 {
return "", "", ""
return "", "", "", 0
}

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

endpoint := node.Public
username := "root"
endpoint = node.Public
username = "root"
if node.Username != "" && node.Username != username {
username = node.Username
}
sshPort = NodeSSHPort(node)

switch np := np.Type.(type) {
switch npt := np.Type.(type) {
case *spec.NodePool_DynamicNodePool:
return username, endpoint, np.DynamicNodePool.PrivateKey
return username, endpoint, npt.DynamicNodePool.PrivateKey, sshPort
case *spec.NodePool_StaticNodePool:
return username, endpoint, np.StaticNodePool.NodeKeys[node.Public]
return username, endpoint, npt.StaticNodePool.NodeKeys[node.Public], sshPort
default:
return "", "", ""
return "", "", "", 0
}
}

Expand Down
12 changes: 12 additions & 0 deletions internal/templateUtils/templates.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import (
"text/template"

"github.com/Masterminds/sprig/v3"
"github.com/berops/claudie/internal/nodepools"
"github.com/berops/claudie/proto/pb/spec"
)

// directory - output directory
Expand Down Expand Up @@ -65,6 +67,7 @@ func LoadTemplate(tplFile string) (*template.Template, error) {
funcMap["replaceAll"] = strings.ReplaceAll
funcMap["extractNetmaskFromCIDR"] = ExtractNetmaskFromCIDR
funcMap["hasExtension"] = HasExtension
funcMap["nodeSshPort"] = NodeSSHPort

tpl, err := template.New("").Funcs(funcMap).Parse(tplFile)
if err != nil {
Expand All @@ -73,6 +76,15 @@ func LoadTemplate(tplFile string) (*template.Template, error) {
return tpl, nil
}

// NodeSSHPort returns the SSH port for a node.
// Uses the port from terraform output if present, otherwise defaults to DefaultSSHPort -> 22.
func NodeSSHPort(node *spec.Node) string {
if node.SshPort != "" {
return node.SshPort
}
return fmt.Sprintf("%d", nodepools.DefaultSSHPort)
}

// ExtractNetmaskFromCIDR extracts the netmask from the CIDR notation.
func ExtractNetmaskFromCIDR(cidr string) string {
_, n, err := net.ParseCIDR(cidr)
Expand Down
14 changes: 7 additions & 7 deletions manifests/claudie/kustomization.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -56,16 +56,16 @@ apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
images:
- name: ghcr.io/berops/claudie/ansibler
newTag: 24da72e-3952
newTag: dfdf0f9-3961
- name: ghcr.io/berops/claudie/autoscaler-adapter
newTag: 24da72e-3952
newTag: dfdf0f9-3961
- name: ghcr.io/berops/claudie/claudie-operator
newTag: 24da72e-3952
newTag: dfdf0f9-3961
- name: ghcr.io/berops/claudie/kube-eleven
newTag: 24da72e-3952
newTag: dfdf0f9-3961
- name: ghcr.io/berops/claudie/kuber
newTag: 24da72e-3952
newTag: dfdf0f9-3961
- name: ghcr.io/berops/claudie/manager
newTag: 24da72e-3952
newTag: dfdf0f9-3961
- name: ghcr.io/berops/claudie/terraformer
newTag: 24da72e-3952
newTag: dfdf0f9-3961
2 changes: 1 addition & 1 deletion manifests/testing-framework/kustomization.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -89,4 +89,4 @@ secretGenerator:

images:
- name: ghcr.io/berops/claudie/testing-framework
newTag: 24da72e-3952
newTag: dfdf0f9-3961
34 changes: 28 additions & 6 deletions proto/pb/spec/nodepool.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions proto/spec/nodepool.proto
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ message NodePool {
repeated Taint taints = 7;
// User definded annotations.
map<string, string> annotations = 8;
// SSH port used to connect to nodes in this nodepool.
// 0 means default (port 22) for backwards compatibility with old nodepools.
// New nodepools are assigned port 22522.
int32 sshPort = 9;
}

// Taint defines a custom defined taint for the node pools.
Expand Down Expand Up @@ -51,6 +55,8 @@ message Node {

// Status of the node.
NodeStatus status = 6;
// Ssh port
string sshPort = 7;
}

// NodeType specifies the type of the node.
Expand Down
4 changes: 2 additions & 2 deletions services/ansibler/templates/all-node-inventory.goini
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
{{- range $nodepoolInfo := .NodepoolsInfo }}
{{- range $nodepool := $nodepoolInfo.Nodepools.Dynamic }}
{{- range $node := $nodepool.Nodes }}
{{ trimPrefix (printf "%s-" $nodepoolInfo.ClusterID) $node.Name }} ansible_user=root ansible_host={{ $node.Public }} private_ip={{ $node.Private }} netmask={{ extractNetmaskFromCIDR $nodepoolInfo.ClusterNetwork }} ansible_ssh_private_key_file={{ $nodepool.Name }}.pem ansible_ssh_extra_args="-o IdentitiesOnly=yes"
{{ trimPrefix (printf "%s-" $nodepoolInfo.ClusterID) $node.Name }} ansible_user=root ansible_host={{ $node.Public }} ansible_port={{ nodeSshPort $node }} private_ip={{ $node.Private }} netmask={{ extractNetmaskFromCIDR $nodepoolInfo.ClusterNetwork }} ansible_ssh_private_key_file={{ $nodepool.Name }}.pem ansible_ssh_extra_args="-o IdentitiesOnly=yes"
{{- end }}
{{- end }}
{{- end }}
Expand All @@ -11,7 +11,7 @@
{{- range $nodepoolInfo := .NodepoolsInfo }}
{{- range $nodepool := $nodepoolInfo.Nodepools.Static }}
{{- range $node := $nodepool.Nodes }}
{{ $node.Name }} ansible_user={{ $node.Username }} ansible_host={{ $node.Public }} private_ip={{ $node.Private }} netmask={{ extractNetmaskFromCIDR $nodepoolInfo.ClusterNetwork }} ansible_ssh_private_key_file={{ $node.Name }}.pem ansible_ssh_extra_args="-o IdentitiesOnly=yes"
{{ $node.Name }} ansible_user={{ $node.Username }} ansible_host={{ $node.Public }} ansible_port={{ nodeSshPort $node }} private_ip={{ $node.Private }} netmask={{ extractNetmaskFromCIDR $nodepoolInfo.ClusterNetwork }} ansible_ssh_private_key_file={{ $node.Name }}.pem ansible_ssh_extra_args="-o IdentitiesOnly=yes"
{{- end }}
{{- end }}
{{- end }}
8 changes: 4 additions & 4 deletions services/ansibler/templates/k8s-inventory.goini
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@
{{- range $nodepool := .K8sNodepools.Dynamic }}
{{- if $nodepool.IsControl }}
{{- range $node := $nodepool.Nodes }}
{{ trimPrefix (printf "%s-" $.ClusterID) $node.Name }} ansible_user=root ansible_host={{ $node.Public }} private_ip={{ $node.Private }} ansible_ssh_private_key_file={{ $nodepool.Name }}.pem ansible_ssh_extra_args="-o IdentitiesOnly=yes"
{{ trimPrefix (printf "%s-" $.ClusterID) $node.Name }} ansible_user=root ansible_host={{ $node.Public }} ansible_port={{ nodeSshPort $node }} private_ip={{ $node.Private }} ansible_ssh_private_key_file={{ $nodepool.Name }}.pem ansible_ssh_extra_args="-o IdentitiesOnly=yes"
{{- end }}
{{- end }}
{{- end }}

{{- range $nodepool := .K8sNodepools.Static }}
{{- if $nodepool.IsControl }}
{{- range $node := $nodepool.Nodes }}
{{ $node.Name }} ansible_user={{ $node.Username }} ansible_host={{ $node.Public }} private_ip={{ $node.Private }} ansible_ssh_private_key_file={{ $node.Name }}.pem ansible_ssh_extra_args="-o IdentitiesOnly=yes"
{{ $node.Name }} ansible_user={{ $node.Username }} ansible_host={{ $node.Public }} ansible_port={{ nodeSshPort $node }} private_ip={{ $node.Private }} ansible_ssh_private_key_file={{ $node.Name }}.pem ansible_ssh_extra_args="-o IdentitiesOnly=yes"
{{- end }}
{{- end }}
{{- end }}
Expand All @@ -19,15 +19,15 @@
{{- range $nodepool := .K8sNodepools.Dynamic }}
{{- if not $nodepool.IsControl }}
{{- range $node := $nodepool.Nodes }}
{{ trimPrefix (printf "%s-" $.ClusterID) $node.Name }} ansible_user=root ansible_host={{ $node.Public }} private_ip={{ $node.Private }} ansible_ssh_private_key_file={{ $nodepool.Name }}.pem ansible_ssh_extra_args="-o IdentitiesOnly=yes"
{{ trimPrefix (printf "%s-" $.ClusterID) $node.Name }} ansible_user=root ansible_host={{ $node.Public }} ansible_port={{ nodeSshPort $node }} private_ip={{ $node.Private }} ansible_ssh_private_key_file={{ $nodepool.Name }}.pem ansible_ssh_extra_args="-o IdentitiesOnly=yes"
{{- end }}
{{- end }}
{{- end }}

{{- range $nodepool := .K8sNodepools.Static }}
{{- if not $nodepool.IsControl }}
{{- range $node := $nodepool.Nodes }}
{{ $node.Name }} ansible_user={{ $node.Username }} ansible_host={{ $node.Public }} private_ip={{ $node.Private }} ansible_ssh_private_key_file={{ $node.Name }}.pem ansible_ssh_extra_args="-o IdentitiesOnly=yes"
{{ $node.Name }} ansible_user={{ $node.Username }} ansible_host={{ $node.Public }} ansible_port={{ nodeSshPort $node }} private_ip={{ $node.Private }} ansible_ssh_private_key_file={{ $node.Name }}.pem ansible_ssh_extra_args="-o IdentitiesOnly=yes"
{{- end }}
{{- end }}
{{- end }}
4 changes: 2 additions & 2 deletions services/ansibler/templates/lb-inventory.goini
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@
{{- range $lbNodepool := $.LBnodepools.Dynamic }}
{{- range $lbNode := $lbNodepool.Nodes }}
{{/*key.pem is taken from a directory where ansible-playbook is called, thus it does not need to specify path relative to inventory.ini*/}}
{{ trimPrefix (printf "%s-%s-" $.Name $.Hash) $lbNode.Name }} ansible_user=root ansible_host={{ $lbNode.Public }} private_ip={{ $lbNode.Private }} ansible_ssh_private_key_file={{ $lbNodepool.Name }}.pem ansible_ssh_extra_args="-o IdentitiesOnly=yes"
{{ trimPrefix (printf "%s-%s-" $.Name $.Hash) $lbNode.Name }} ansible_user=root ansible_host={{ $lbNode.Public }} ansible_port={{ nodeSshPort $lbNode }} private_ip={{ $lbNode.Private }} ansible_ssh_private_key_file={{ $lbNodepool.Name }}.pem ansible_ssh_extra_args="-o IdentitiesOnly=yes"
{{- end }}
{{- end }}

{{- range $lbNodepool := $.LBnodepools.Static }}
{{- range $lbNode := $lbNodepool.Nodes }}
{{/*key.pem is taken from a directory where ansible-playbook is called, thus it does not need to specify path relative to inventory.ini*/}}
{{ $lbNode.Name }} ansible_user={{ $lbNode.Username }} ansible_host={{ $lbNode.Public }} private_ip={{ $lbNode.Private }} ansible_ssh_private_key_file={{ $lbNode.Name }}.pem ansible_ssh_extra_args="-o IdentitiesOnly=yes"
{{ $lbNode.Name }} ansible_user={{ $lbNode.Username }} ansible_host={{ $lbNode.Public }} ansible_port={{ nodeSshPort $lbNode }} private_ip={{ $lbNode.Private }} ansible_ssh_private_key_file={{ $lbNode.Name }}.pem ansible_ssh_extra_args="-o IdentitiesOnly=yes"
{{- end }}
{{- end }}
Loading