8000 MKAAS-1519 Add support for Adv DDoS in k8sv2 by pedrodeoliveira · Pull Request #225 · G-Core/terraform-provider-gcore · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

MKAAS-1519 Add support for Adv DDoS in k8sv2 #225

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
May 22, 2025
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
82 changes: 82 additions & 0 deletions docs/resources/k8sv2.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,65 @@ output "kubeconfig" {
}
```

### Creating a Cluster with Advanced DDoS Protection

```terraform
resource "gcore_k8sv2" "cl" {
project_id = 1
region_id = 1
name = "cluster1"
keypair = "test_key"
version = "v1.26.7"
pool {
name = "pool1"
flavor_id = "g1-standard-1-2"
min_node_count = 1
max_node_count = 1
boot_volume_size = 10
boot_volume_type = "standard"
is_public_ipv4 = true
}
ddos_profile {
enabled = true
fields {
base_field = 1353
field_value = jsonencode(["AF"])
}
fields {
base_field = 1354
field_value = jsonencode(50)
}
fields {
base_field = 1355
field_value = jsonencode(150)
}
fields {
base_field = 1356
field_value = jsonencode(300)
}
fields {
base_field = 1357
field_value = jsonencode(300)
}

fields {
base_field = 1352
field_value = jsonencode([
{
"sip_list":["192.168.0.1","10.10.0.1"],
"dport_list": ["27015","27025"],
"proto_list": ["udp"],
"sport_list": ["27025"],
"policy": "DROP"
}
])
}
profile_template = 1128
}
}
```


<!-- schema generated by tfplugindocs -->
## Schema

Expand Down Expand Up @@ -76,6 +135,7 @@ output "kubeconfig" {
- `services_ip_pool` (String) Services IPv4 IP pool in CIDR notation.
- `services_ipv6_pool` (String) Services IPv6 IP pool in CIDR notation.
- `timeouts` (Block, Optional) (see [below for nested schema](#nestedblock--timeouts))
- `ddos_profile` (Block List, Max: 1) Advanced DDoS protection profile. (see [below for nested schema](#nestedblock--ddos_profile))

### Read-Only

Expand Down Expand Up @@ -197,6 +257,28 @@ Optional:
- `create` (String)
- `update` (String)


<a id="nestedblock--ddos_profile"></a>
### Nested Schema for `ddos_profile`

Required:
- `enabled` (Boolean) Enable/disable DDoS protection.

Optional:
- `profile_template` (Number) Profile template ID. Changing the value of this attribute will trigger recreation of the cluster.
- `profile_template_name` (String) Profile template name. Changing the value of this attribute will trigger recreation of the cluster.
- `fields` (Block List) (see [below for nested schema](#nestedblock--ddos_profile--fields))

<a id="nestedblock--ddos_profile--fields"></a>
### Nested Schema for `fields`

Required:
- `base_field` (Number) Base field ID.

Optional:
- `field_value` (String) Complex value. Only one of 'value' or 'field_value' must be specified.
- `value` (String) Basic type value. Only one of 'value' or 'field_value' must be specified.

## Import

Import is supported using the following syntax:
Expand Down
76 changes: 76 additions & 0 deletions gcore/data_source_gcore_k8sv2.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package gcore

import (
"context"
"encoding/json"
"log"
"time"

Expand Down Expand Up @@ -193,6 +194,54 @@ func dataSourceK8sV2() *schema.Resource {
},
},
},
"ddos_profile": {
Type: schema.TypeList,
Description: "DDoS profile configuration.",
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"enabled": {
Type: schema.TypeBool,
Description: "Indicates if the DDoS profile is enabled.",
Computed: true,
},
"fields": {
Type: schema.TypeList,
Description: "List of fields for the DDoS profile.",
Optional: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"base_field": {
Type: schema.TypeInt,
Description: "Base field ID.",
Computed: true,
},
"field_value": {
Type: schema.TypeString,
Computed: true,
Description: "Complex value. Only one of 'value' or 'field_value' must be specified.",
},
"value": {
Type: schema.TypeString,
Computed: true,
Description: "Basic type value. Only one of 'value' or 'field_value' must be specified.",
},
},
},
},
"profile_template": {
Type: schema.TypeInt,
Description: "Profile template ID.",
Computed: true,
},
"profile_template_name": {
Type: schema.TypeString,
Description: "Profile template name.",
Computed: true,
},
},
},
},
"fixed_network": {
Type: schema.TypeString,
Computed: true,
Expand Down Expand Up @@ -456,6 +505,33 @@ func dataSourceK8sV2Read(ctx context.Context, d *schema.ResourceData, m interfac
}
}

if cluster.DDoSProfile != nil {
var fields []interface{}
for _, f := range cluster.DDoSProfile.Fields {
field := map[string]interface{}{
"base_field": f.BaseField,
"value": f.Value,
}
if f.FieldValue != nil {
b, err := json.Marshal(f.FieldValue)
if err != nil {
return diag.FromErr(err)
}
field["field_value"] = string(b)
}
fields = append(fields, field)
}
v := map[string]interface{}{
"enabled": cluster.DDoSProfile.Enabled,
"fields": fields,
"profile_template": cluster.DDoSProfile.ProfileTemplate,
"profile_template_name": cluster.DDoSProfile.ProfileTemplateName,
}
if err := d.Set("ddos_profile", []interface{}{v}); err != nil {
return diag.FromErr(err)
}
}

var ps []map[string]interface{}
for _, pool := range cluster.Pools {
ps = append(ps, map[string]interface{}{
Expand Down
157 changes: 156 additions & 1 deletion gcore/resource_gcore_k8sv2.go
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,55 @@ func resourceK8sV2() *schema.Resource {
}},
},
},
"ddos_profile": {
Type: schema.TypeList,
Description: "DDoS profile configuration.",
Optional: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"enabled": {
Type: schema.TypeBool,
Description: "Indicates if the DDoS profile is enabled.",
Required: true,
},
"fields": {
Type: schema.TypeList,
Description: "List of fields for the DDoS profile.",
Optional: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"base_field": {
Type: schema.TypeInt,
Description: "Base field ID.",
Required: true,
},
"field_value": {
Type: schema.TypeString,
Optional: true,
Description: "Complex value. Only one of 'value' or 'field_value' must be specified.",
},
"value": {
Type: schema.TypeString,
Optional: true,
Description: "Basic type value. Only one of 'value' or 'field_value' must be specified.",
},
},
},
},
"profile_template": {
Type: schema.TypeInt,
Description: "Profile template ID.",
Optional: true,
},
"profile_template_name": {
Type: schema.TypeString,
Description: "Profile template name.",
Optional: true,
},
},
},
},
"fixed_network": {
Type: schema.TypeString,
Description: "Fixed network used to allocate network addresses for cluster nodes.",
Expand Down Expand Up @@ -648,6 +697,46 @@ func resourceK8sV2Create(ctx context.Context, d *schema.ResourceData, m interfac
}
}

if ddosProfileI, ok := d.GetOk("ddos_profile"); ok {
ddosProfile := ddosProfileI.([]interface{})
if len(ddosProfile) != 0 {
profile := ddosProfile[0].(map[string]interface{})
opts.DDoSProfile = &clusters.DDoSProfileCreateOpts{
Enabled: profile["enabled"].(bool),
}
if fields, ok := profile["fields"].([]interface{}); ok {
if len(fields) != 0 {
opts.DDoSProfile.Fields = make([]clusters.DDoSProfileField, len(fields))
for i, field := range fields {
fieldMap := field.(map[string]interface{})
opts.DDoSProfile.Fields[i] = clusters.DDoSProfileField{
BaseField: fieldMap["base_field"].(int),
}
value, valueOk := fieldMap["value"].(string)
if valueOk && value != "" {
opts.DDoSProfile.Fields[i].Value = &value
}
fieldValueStr, fieldValueOk := fieldMap["field_value"]
if fieldValueOk {
var fieldValue interface{}
err := json.Unmarshal([]byte(fieldValueStr.(string)), &fieldValue)
if err != nil {
return diag.FromErr(fmt.Errorf("failed to unmarshal field_value: %w", err))
}
opts.DDoSProfile.Fields[i].FieldValue = &fieldValue
}
}
}
}
if profileTemplate, ok := profile["profile_template"].(int); ok {
opts.DDoSProfile.ProfileTemplate = &profileTemplate
}
if profileTemplateName, ok := profile["profile_template_name"].(string); ok {
opts.DDoSProfile.ProfileTemplateName = &profileTemplateName
}
}
}

if podsIP, ok := d.GetOk("pods_ip_pool"); ok {
gccidr, err := parseCIDRFromString(podsIP.(string))
if err != nil {
Expand Down Expand Up @@ -884,6 +973,28 @@ func resourceK8sV2Read(ctx context.Context, d *schema.ResourceData, m interface{
}
}

if cluster.DDoSProfile != nil {
v := map[string]interface{}{
"enabled": cluster.DDoSProfile.Enabled,
}
if cluster.DDoSProfile.Fields != nil {
v["fields"] = []interface{}{}
for _, field := range cluster.DDoSProfile.Fields {
v["fields"] = append(v["fields"].([]interface{}), map[string]interface{}{
"base_field": field.BaseField,
"value": field.Value,
"field_value": field.FieldValue,
})
}
}
if cluster.DDoSProfile.ProfileTemplate != nil {
v["profile_template"] = *cluster.DDoSProfile.ProfileTemplate
}
if cluster.DDoSProfile.ProfileTemplateName != nil {
v["profile_template_name"] = *cluster.DDoSProfile.ProfileTemplateName
}
}

poolMap := map[string]pools.ClusterPool{}
for _, pool := range cluster.Pools {
poolMap[pool.Name] = pool
Expand Down Expand Up @@ -959,7 +1070,7 @@ func resourceK8sV2Update(ctx context.Context, d *schema.ResourceData, m interfac
}
}

if d.HasChanges("authentication", "autoscaler_config", "cni") {
if d.HasChanges("authentication", "autoscaler_config", "cni", "ddos_profile") {
if err := resourceK8sV2UpdateCluster(client, tasksClient, clusterName, d); err != nil {
return diag.FromErr(err)
}
Expand Down Expand Up @@ -1167,6 +1278,50 @@ func resourceK8sV2UpdateCluster(client, tasksClient *gcorecloud.ServiceClient, c
}
}

if d.HasChange("ddos_profile") {
if ddosProfileI, ok := d.GetOk("ddos_profile"); ok {
ddosProfile := ddosProfileI.([]interface{})
if len(ddosProfile) != 0 {
profile := ddosProfile[0].(map[string]interface{})
opts.DDoSProfile = &clusters.DDoSProfileCreateOpts{
Enabled: profile["enabled"].(bool),
}
if fields, ok := profile["fields"].([]interface{}); ok {
log.Printf("[DEBUG] fields: %v", fields)
if len(fields) != 0 {
opts.DDoSProfile.Fields = make([]clusters.DDoSProfileField, len(fields))
for i, field := range fields {
fieldMap := field.(map[string]interface{})
opts.DDoSProfile.Fields[i] = clusters.DDoSProfileField{
BaseField: fieldMap["base_field"].(int),
}
value, valueOk := fieldMap["value"].(string)
if valueOk && value != "" {
opts.DDoSProfile.Fields[i].Value = &value
}
fieldValueStr, fieldValueOk := fieldMap["field_value"]
if fieldValueOk {
var fieldValue interface{}
err := json.Unmarshal([]byte(fieldValueStr.(string)), &fieldValue)
if err != nil {
return fmt.Errorf("failed to unmarshal field_value: %w", err)
}
log.Printf("[DEBUG] DDoS profile field value: %v, %v", fieldValue, reflect.TypeOf(fieldValue))
opts.DDoSProfile.Fields[i].FieldValue = &fieldValue
}
}
}
}
if profileTemplate, ok := profile["profile_template"].(int); ok {
opts.DDoSProfile.ProfileTemplate = &profileTemplate
}
if profileTemplateName, ok := profile["profile_template_name"].(string); ok {
opts.DDoSProfile.ProfileTemplateName = &profileTemplateName
}
}
}
}

results, err := clusters.Update(client, clusterName, opts).Extract()
if err != nil {
return fmt.Errorf("update cluster: %w", err)
Expand Down
Loading
0