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
185 changes: 162 additions & 23 deletions castai/resource_node_configuration.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,29 +21,32 @@ import (
)

const (
FieldNodeConfigurationName = "name"
FieldNodeConfigurationDiskCpuRatio = "disk_cpu_ratio"
FieldNodeConfigurationMinDiskSize = "min_disk_size"
FieldNodeConfigurationDrainTimeoutSec = "drain_timeout_sec"
FieldNodeConfigurationSubnets = "subnets"
FieldNodeConfigurationSSHPublicKey = "ssh_public_key"
FieldNodeConfigurationImage = "image"
FieldNodeConfigurationTags = "tags"
FieldNodeConfigurationInitScript = "init_script"
FieldNodeConfigurationContainerRuntime = "container_runtime"
FieldNodeConfigurationDockerConfig = "docker_config"
FieldNodeConfigurationKubeletConfig = "kubelet_config"
FieldNodeConfigurationAKS = "aks"
FieldNodeConfigurationEKS = "eks"
FieldNodeConfigurationKOPS = "kops"
FieldNodeConfigurationGKE = "gke"
FieldNodeConfigurationEKSTargetGroup = "target_group"
FieldNodeConfigurationAKSImageFamily = "aks_image_family"
FieldNodeConfigurationAKSEphemeralOSDisk = "ephemeral_os_disk"
FieldNodeConfigurationEKSImageFamily = "eks_image_family"
FieldNodeConfigurationLoadbalancers = "loadbalancers"
FieldNodeConfigurationAKSLoadbalancerIPPools = "ip_based_backend_pools"
FieldNodeConfigurationAKSLoadbalancerNICPools = "nic_based_backend_pools"
FieldNodeConfigurationName = "name"
FieldNodeConfigurationDiskCpuRatio = "disk_cpu_ratio"
FieldNodeConfigurationMinDiskSize = "min_disk_size"
FieldNodeConfigurationDrainTimeoutSec = "drain_timeout_sec"
FieldNodeConfigurationSubnets = "subnets"
FieldNodeConfigurationSSHPublicKey = "ssh_public_key"
FieldNodeConfigurationImage = "image"
FieldNodeConfigurationTags = "tags"
FieldNodeConfigurationInitScript = "init_script"
FieldNodeConfigurationContainerRuntime = "container_runtime"
FieldNodeConfigurationDockerConfig = "docker_config"
FieldNodeConfigurationKubeletConfig = "kubelet_config"
FieldNodeConfigurationAKS = "aks"
FieldNodeConfigurationEKS = "eks"
FieldNodeConfigurationKOPS = "kops"
FieldNodeConfigurationGKE = "gke"
FieldNodeConfigurationEKSTargetGroup = "target_group"
FieldNodeConfigurationAKSImageFamily = "aks_image_family"
FieldNodeConfigurationAKSEphemeralOSDisk = "ephemeral_os_disk"
FieldNodeConfigurationEKSImageFamily = "eks_image_family"
FieldNodeConfigurationLoadbalancers = "loadbalancers"
FieldNodeConfigurationAKSLoadbalancerIPPools = "ip_based_backend_pools"
FieldNodeConfigurationAKSLoadbalancerNICPools = "nic_based_backend_pools"
FieldNodeConfigurationAKSNetworkSecurityGroup = "network_security_group"
FieldNodeConfigurationAKSApplicationSecurityGroups = "application_security_groups"
FieldNodeConfigurationAKSPublicIP = "public_ip"
)

const (
Expand Down Expand Up @@ -367,6 +370,61 @@ func resourceNodeConfiguration() *schema.Resource {
},
},
},
FieldNodeConfigurationAKSNetworkSecurityGroup: {
Type: schema.TypeString,
Optional: true,
Description: "Network security group to be used for provisioned nodes, if not provided default security group from `castpool` will be used",
},
FieldNodeConfigurationAKSApplicationSecurityGroups: {
Type: schema.TypeList,
Optional: true,
Description: "Application security groups to be used for provisioned nodes",
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
FieldNodeConfigurationAKSPublicIP: {
Type: schema.TypeList,
Optional: true,
Description: "Public IP configuration for CAST AI provisioned nodes",
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"public_ip_prefix": {
Type: schema.TypeString,
Optional: true,
Description: "Public IP prefix to be used for provisioned nodes",
},
"tags": {
Type: schema.TypeMap,
Optional: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) {
allowedKeys := []string{
"FirstPartyUsage",
"NetworkDomain",
"RoutingPreference",
}

tags := v.(map[string]interface{})
for key := range tags {
if !lo.Contains(allowedKeys, key) {
errors = append(errors, fmt.Errorf("invalid key %q in %q, allowed keys: %v", key, k, allowedKeys))
}
}
return
},
},
"idle_timeout_in_minutes": {
Type: schema.TypeInt,
Optional: true,
Description: "Idle timeout in minutes for public IP",
},
},
},
},
FieldNodeConfigurationLoadbalancers: {
Type: schema.TypeList,
Optional: true,
Expand Down Expand Up @@ -1046,9 +1104,52 @@ func toAKSSConfig(obj map[string]interface{}) *sdk.NodeconfigV1AKSConfig {
out.LoadBalancers = toAksLoadBalancers(v)
}

if v, ok := obj[FieldNodeConfigurationAKSPublicIP].([]interface{}); ok && len(v) > 0 {
out.PublicIp = toAKSNodePublicIP(v[0])
}

if v, ok := obj[FieldNodeConfigurationAKSNetworkSecurityGroup].(string); ok && v != "" {
out.NetworkSecurityGroupId = toPtr(v)
}

if v, ok := obj[FieldNodeConfigurationAKSApplicationSecurityGroups].([]interface{}); ok && len(v) > 0 {
out.ApplicationSecurityGroupIds = toPtr(toStringList(v))
}

return out
}

func toAKSNodePublicIP(obj any) *sdk.NodeconfigV1AKSConfigPublicIP {
if obj == nil {
return nil
}

publicIP := &sdk.NodeconfigV1AKSConfigPublicIP{}

if v, ok := obj.(map[string]any)["public_ip_prefix"].(string); ok && v != "" {
publicIP.IpPrefix = lo.ToPtr(v)
}

if v, ok := obj.(map[string]any)["tags"].(map[string]any); ok && len(v) > 0 {
tagList := []sdk.NodeconfigV1AKSConfigPublicIPAKSPublicIPTags{}

for k, vv := range v {
tagList = append(tagList, sdk.NodeconfigV1AKSConfigPublicIPAKSPublicIPTags{
TagValue: lo.ToPtr(vv.(string)),
IpTagType: lo.ToPtr(k),
})
}
publicIP.Tags = &tagList
}

if v, ok := obj.(map[string]any)["idle_timeout_in_minutes"].(int); ok && v > 0 {
publicIP.IdleTimeoutInMinutes = lo.ToPtr(int32(v))
}

return publicIP

}

func toAKSEphemeralOSDisk(obj any) *sdk.NodeconfigV1AKSConfigOsDiskEphemeral {
if obj == nil {
return nil
Expand Down Expand Up @@ -1197,9 +1298,47 @@ func flattenAKSConfig(config *sdk.NodeconfigV1AKSConfig) []map[string]interface{
m[FieldNodeConfigurationAKSEphemeralOSDisk] = fromAKSEphemeralOSDisk(v)
}

if v := config.PublicIp; v != nil {
m[FieldNodeConfigurationAKSPublicIP] = fromAKSNodePublicIP(v)
}

if v := config.NetworkSecurityGroupId; v != nil {
m[FieldNodeConfigurationAKSNetworkSecurityGroup] = *config.NetworkSecurityGroupId
}

if v := config.ApplicationSecurityGroupIds; v != nil {
m[FieldNodeConfigurationAKSApplicationSecurityGroups] = *config.ApplicationSecurityGroupIds
}

return []map[string]interface{}{m}
}

func fromAKSNodePublicIP(sdkPublicIp *sdk.NodeconfigV1AKSConfigPublicIP) []map[string]any {
if sdkPublicIp == nil {
return nil
}

m := map[string]interface{}{}
if sdkPublicIp.IpPrefix != nil {
m["public_ip_prefix"] = *sdkPublicIp.IpPrefix
}

if sdkPublicIp.Tags != nil {
tags := make(map[string]interface{})
for _, tag := range *sdkPublicIp.Tags {
tags[lo.FromPtr(tag.IpTagType)] = lo.FromPtr(tag.TagValue)
}
m["tags"] = tags
}

if sdkPublicIp.IdleTimeoutInMinutes != nil {
m["idle_timeout_in_minutes"] = *sdkPublicIp.IdleTimeoutInMinutes
}

return []map[string]any{m}

}

func fromAKSEphemeralOSDisk(sdkEph *sdk.NodeconfigV1AKSConfigOsDiskEphemeral) []map[string]interface{} {
if sdkEph == nil {
return nil
Expand Down
14 changes: 14 additions & 0 deletions castai/resource_node_configuration_aks_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ func TestAccResourceNodeConfiguration_aks(t *testing.T) {
resource.TestCheckResourceAttr(resourceName, "aks.0.ephemeral_os_disk.0.cache", "ReadOnly"),
resource.TestCheckResourceAttr(resourceName, "aks.0.loadbalancers.0.name", "test-lb"),
resource.TestCheckResourceAttr(resourceName, "aks.0.loadbalancers.0.ip_based_backend_pools.0.name", "test"),
resource.TestCheckResourceAttr(resourceName, "aks.0.network_security_group", "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg/providers/Microsoft.Network/networkSecurityGroups/test-nsg"),
resource.TestCheckResourceAttr(resourceName, "aks.0.application_security_groups.0", "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg/providers/Microsoft.Network/applicationSecurityGroups/test-asg"),
resource.TestCheckResourceAttr(resourceName, "aks.0.public_ip.0.public_ip_prefix", "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg/providers/Microsoft.Network/publicIPAddresses/test-ip"),
resource.TestCheckResourceAttr(resourceName, "aks.0.public_ip.0.tags.FirstPartyUsage", "something"),
resource.TestCheckResourceAttr(resourceName, "aks.0.public_ip.0.idle_timeout_in_minutes", "10"),
resource.TestCheckResourceAttr(resourceName, "eks.#", "0"),
resource.TestCheckResourceAttr(resourceName, "kops.#", "0"),
resource.TestCheckResourceAttr(resourceName, "gke.#", "0"),
Expand Down Expand Up @@ -113,6 +118,15 @@ resource "castai_node_configuration" "test" {
ip_based_backend_pools {
name = "test"
}
}
network_security_group = "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg/providers/Microsoft.Network/networkSecurityGroups/test-nsg"
application_security_groups = ["/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg/providers/Microsoft.Network/applicationSecurityGroups/test-asg"]
public_ip {
public_ip_prefix = "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg/providers/Microsoft.Network/publicIPAddresses/test-ip"
tags = {
FirstPartyUsage = "something"
}
idle_timeout_in_minutes = 10
}
}
}
Expand Down
41 changes: 39 additions & 2 deletions castai/sdk/api.gen.go

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

Loading
Loading