Skip to content
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
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@

Versioning follows [SemVer](https://semver.org/). Sections: **Added**, **Changed**, **Deprecated**, **Fixed**, **Removed**, **Known Limitations**, **Dependencies**. Only user-visible changes listed. Older entries may use non-standard section names.

## [Unreleased]
## [v6.10.5] - October 2026

### Added
- `k8s nodepool create` and `k8s nodepool update` take `--taints KEY[=VALUE]:EFFECT,...` to set Kubernetes taints on the pool's Nodes. On `update` the flag replaces all taints and `--taints ""` removes them. Node pool output has a new `Taints` column, shown by default on create/update when a taint flag is used.
- `k8s nodepool update` takes `--add-taints` and `--remove-taints` to edit the current taints without retyping them. `--remove-taints` matches by `KEY`, `KEY:EFFECT` or `KEY=VALUE:EFFECT`, completes the pool's current taints, and fails if nothing matches.
- `--taints` rejects duplicate `KEY:EFFECT` pairs and values containing `=` before calling the API.

### Changed
- Help text overhauled across every resource group (compute, Managed Kubernetes, DNS, VPN, Kafka, DBaaS, Object Storage, Container Registry, Certificate Manager, CDN, Monitoring, Logging, VM Autoscaling, IAM). Each resource group now opens with a conceptual overview of the domain model; flag descriptions explain accepted values, units, defaults and cross-flag relationships instead of restating the flag name; and create/update commands include both a basic and an advanced worked example.
Expand Down
25 changes: 25 additions & 0 deletions commands/compute/completer/versions.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,28 @@ func K8sNodePoolUpgradeVersions(clusterId, nodepoolId string) []string {
}
return *nodepool.Properties.AvailableUpgradeVersions
}

// K8sNodePoolTaints returns the node pool's taints as KEY[=VALUE]:EFFECT.
func K8sNodePoolTaints(clusterId, nodepoolId string) []string {
client, err := client2.Get()
if err != nil {
return nil
}
k8sSvc := resources.NewK8sService(client, context.Background())
nodepool, _, err := k8sSvc.GetNodePool(clusterId, nodepoolId)
if err != nil || nodepool.Properties == nil || nodepool.Properties.Taints == nil {
return nil
}
out := make([]string, 0, len(*nodepool.Properties.Taints))
for _, t := range *nodepool.Properties.Taints {
if t.Key == nil || t.Effect == nil {
continue
}
s := *t.Key
if t.Value != nil && *t.Value != "" {
s += "=" + *t.Value
}
out = append(out, s+":"+string(*t.Effect))
}
return out
}
16 changes: 14 additions & 2 deletions commands/compute/k8s/nodepool/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (
)

func K8sNodePoolCreateCmd() *core.Command {
jsonPropertiesExample := "{\n \"metadata\": {},\n \"properties\": {\n \"name\": \"K8s-node-pool\",\n \"datacenterId\": \"12345678-90ab-cdef-1234-567890abcdef\",\n \"nodeCount\": 2,\n \"cpuFamily\": \"INTEL_SKYLAKE\",\n \"coresCount\": 4,\n \"ramSize\": 2048,\n \"availabilityZone\": \"AUTO\",\n \"storageType\": \"HDD\",\n \"storageSize\": 100,\n \"k8sVersion\": \"1.27.6\",\n \"maintenanceWindow\": {\n \"dayOfTheWeek\": \"Monday\",\n \"time\": \"13:00:00\"\n },\n \"autoScaling\": {\n \"minNodeCount\": \"1\",\n \"maxNodeCount\": \"2\"\n },\n \"lans\": [\n {\n \"id\": 1,\n \"dhcp\": true,\n \"routes\": [\n {\n \"network\": \"1.2.3.4/24\",\n \"gatewayIp\": \"10.1.5.16\"\n }\n ]\n }\n ],\n \"labels\": {\n \"property1\": \"string\",\n \"property2\": \"string\"\n },\n \"annotations\": {\n \"property1\": \"string\",\n \"property2\": \"string\"\n },\n \"publicIps\": [\n \"203.0.113.1\",\n \"203.0.113.2\",\n \"203.0.113.3\"\n ]\n }\n}"
jsonPropertiesExample := "{\n \"metadata\": {},\n \"properties\": {\n \"name\": \"K8s-node-pool\",\n \"datacenterId\": \"12345678-90ab-cdef-1234-567890abcdef\",\n \"nodeCount\": 2,\n \"cpuFamily\": \"INTEL_SKYLAKE\",\n \"coresCount\": 4,\n \"ramSize\": 2048,\n \"availabilityZone\": \"AUTO\",\n \"storageType\": \"HDD\",\n \"storageSize\": 100,\n \"k8sVersion\": \"1.27.6\",\n \"maintenanceWindow\": {\n \"dayOfTheWeek\": \"Monday\",\n \"time\": \"13:00:00\"\n },\n \"autoScaling\": {\n \"minNodeCount\": \"1\",\n \"maxNodeCount\": \"2\"\n },\n \"lans\": [\n {\n \"id\": 1,\n \"dhcp\": true,\n \"routes\": [\n {\n \"network\": \"1.2.3.4/24\",\n \"gatewayIp\": \"10.1.5.16\"\n }\n ]\n }\n ],\n \"labels\": {\n \"property1\": \"string\",\n \"property2\": \"string\"\n },\n \"annotations\": {\n \"property1\": \"string\",\n \"property2\": \"string\"\n },\n \"taints\": [\n {\n \"key\": \"dedicated\",\n \"value\": \"gpu-workloads\",\n \"effect\": \"NoSchedule\"\n }\n ],\n \"publicIps\": [\n \"203.0.113.1\",\n \"203.0.113.2\",\n \"203.0.113.3\"\n ]\n }\n}"
nodepoolViaJsonPropertiesFlag := ionoscloud.KubernetesNodePoolForPost{}
cmd := core.NewCommandWithJsonProperties(context.TODO(), nil, jsonPropertiesExample, &nodepoolViaJsonPropertiesFlag, core.CommandBuilder{
Namespace: "k8s",
Expand Down Expand Up @@ -42,6 +42,10 @@ Autoscaling and reserved public IPs are not configurable at create time via
dedicated flags; set them afterwards with ` + "`ionosctl compute k8s nodepool update`" + `,
or pass a full JSON body with --json-properties.

Taints: --taints takes KEY[=VALUE]:EFFECT, the same syntax as ` + "`kubectl taint`" + `.
Every Node in the pool gets the taints, and Pods need a matching toleration to
run there.

Networking: attach existing LANs with --lan-ids=LAN_ID1,LAN_ID2. To also set a
route network and gateway IP on a LAN, use ` + "`ionosctl compute k8s nodepool lan add`" + `
per LAN after creation.
Expand All @@ -57,7 +61,11 @@ ionosctl compute k8s nodepool create --cluster-id CLUSTER_ID --datacenter-id DAT

# Create a 3-Node pool with a specific shape, SSD storage, pinned Kubernetes version and two attached LANs
ionosctl compute k8s nodepool create --cluster-id CLUSTER_ID --datacenter-id DATACENTER_ID --name workers \
--node-count 3 --cores 4 --ram 8GB --storage-type SSD --storage-size 100 --k8s-version 1.29.5 --lan-ids 1,2`,
--node-count 3 --cores 4 --ram 8GB --storage-type SSD --storage-size 100 --k8s-version 1.29.5 --lan-ids 1,2

# Create a GPU pool that only Pods tolerating dedicated=gpu can use
ionosctl compute k8s nodepool create --cluster-id CLUSTER_ID --datacenter-id DATACENTER_ID --name gpu \
--labels pool=gpu --taints dedicated=gpu:NoSchedule`,
PreCmdRun: func(c *core.PreCommandConfig) error {
return core.CheckRequiredFlagsSets(c.Command, c.NS,
[]string{cloudapiv6.ArgDataCenterId, constants.FlagClusterId},
Expand Down Expand Up @@ -120,6 +128,10 @@ ionosctl compute k8s nodepool create --cluster-id CLUSTER_ID --datacenter-id DAT
})
cmd.AddStringToStringFlag(constants.FlagLabels, constants.FlagLabelsShort, map[string]string{}, "Kubernetes labels propagated onto the pool's Nodes (usable for scheduling/nodeSelectors). Overwrites any existing labels. Format: --labels KEY=VALUE,KEY=VALUE")
cmd.AddStringToStringFlag(constants.FlagAnnotations, constants.FlagAnnotationsShort, map[string]string{}, "Kubernetes annotations propagated onto the pool's Nodes. Overwrites any existing annotations. Format: --annotations KEY=VALUE,KEY=VALUE")
cmd.AddStringSliceFlag(constants.FlagTaints, "", []string{}, "Kubernetes taints for the pool's Nodes. Format: KEY[=VALUE]:EFFECT, where EFFECT is NoSchedule, NoExecute or PreferNoSchedule. Max 50. e.g. --taints dedicated=gpu:NoSchedule,spot:PreferNoSchedule")
_ = cmd.Command.RegisterFlagCompletionFunc(constants.FlagTaints, func(c *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return taintCompletions(toComplete), cobra.ShellCompDirectiveNoFileComp | cobra.ShellCompDirectiveNoSpace
})

return cmd
}
20 changes: 20 additions & 0 deletions commands/compute/k8s/nodepool/nodepool.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package nodepool

import (
"fmt"
"strings"

nplan "github.com/ionos-cloud/ionosctl/v6/commands/compute/k8s/nodepool/lan"
"github.com/ionos-cloud/ionosctl/v6/internal/core"
Expand Down Expand Up @@ -37,6 +38,25 @@ var allK8sNodePoolCols = []table.Column{
{Name: "AvailableUpgradeVersions", JSONPath: "properties.availableUpgradeVersions"},
{Name: "Annotations", JSONPath: "properties.annotations"},
{Name: "Labels", JSONPath: "properties.labels"},
{Name: "Taints", Format: func(item map[string]any) any {
taints, ok := table.Navigate(item, "properties.taints").([]any)
if !ok || len(taints) == 0 {
return nil
}
out := make([]string, 0, len(taints))
for _, t := range taints {
m, ok := t.(map[string]any)
if !ok {
continue
}
s := fmt.Sprint(m["key"])
if v, ok := m["value"].(string); ok && v != "" {
s += "=" + v
}
out = append(out, fmt.Sprintf("%s:%v", s, m["effect"]))
}
return strings.Join(out, ",")
}},
{Name: "ClusterId", JSONPath: "href"},
}

Expand Down
Loading
Loading