Skip to content

Commit

Permalink
Added a new datasource for the civo size (#118)
Browse files Browse the repository at this point in the history
* Updated the size of the k3s cluster to a new version g4s.kube.medium by default
* Added a check to see if the size is available
* Added the new data source civo_size
* Fixed error with the format of the code
  • Loading branch information
alejandrojnm authored Jan 18, 2022
1 parent 0a3bd81 commit 8ed3687
Show file tree
Hide file tree
Showing 9 changed files with 313 additions and 11 deletions.
11 changes: 9 additions & 2 deletions civo/datasource_intances_size.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,10 @@ func dataSourceInstancesSize() *schema.Resource {
GetRecords: getInstancesSizes,
}

return datalist.NewResource(dataListConfig)
instanceSizeResource := datalist.NewResource(dataListConfig)
instanceSizeResource.DeprecationMessage = "Use the civo_size datasource instead"

return instanceSizeResource

}

Expand All @@ -47,12 +50,16 @@ func getInstancesSizes(m interface{}, extra map[string]interface{}) ([]interface
sizeList := []SizeList{}

for _, v := range partialSizes {
if !v.Selectable {
continue
}

typeName := ""

switch {
case strings.Contains(v.Name, "db"):
typeName = "database"
case strings.Contains(v.Name, "k3s"):
case strings.Contains(v.Name, "kube") || strings.Contains(v.Name, "k3s"):
typeName = "kubernetes"
default:
typeName = "instance"
Expand Down
6 changes: 3 additions & 3 deletions civo/datasource_kubernetes_cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,9 @@ func dataSourceKubernetesCluster() *schema.Resource {
Description: "The version of Kubernetes",
},
"cni": {
Type: schema.TypeString,
Computed: true,
Description: "The cni for the k3s to install (the default is `flannel`) valid options are `cilium` or `flannel`",
Type: schema.TypeString,
Computed: true,
Description: "The cni for the k3s to install (the default is `flannel`) valid options are `cilium` or `flannel`",
},
"tags": {
Type: schema.TypeString,
Expand Down
137 changes: 137 additions & 0 deletions civo/datasource_size.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
package civo

import (
"fmt"
"strings"

"github.com/civo/civogo"
"github.com/civo/terraform-provider-civo/internal/datalist"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

// SizeList is a temporal struct to save all size
type Size struct {
Name string
Description string
Type string
CPU int
RAM int
DisK int
Selectable bool
}

// Data source to get and filter all instances size
// use to define the size in resourceInstance
func dataSourceSize() *schema.Resource {
dataListConfig := &datalist.ResourceConfig{
Description: "Retrieves information about the sizes that Civo supports, with the ability to filter the results.",
RecordSchema: SizeSchema(),
ResultAttributeName: "sizes",
FlattenRecord: flattenSize,
GetRecords: getSizes,
}

return datalist.NewResource(dataListConfig)

}

func getSizes(m interface{}, extra map[string]interface{}) ([]interface{}, error) {
apiClient := m.(*civogo.Client)

sizes := []interface{}{}
partialSizes, err := apiClient.ListInstanceSizes()
if err != nil {
return nil, fmt.Errorf("[ERR] error retrieving sizes: %s", err)
}

sizeList := []Size{}

for _, v := range partialSizes {
if !v.Selectable {
continue
}

typeName := ""

switch {
case strings.Contains(v.Name, "db"):
typeName = "database"
case strings.Contains(v.Name, "kube") || strings.Contains(v.Name, "k3s"):
typeName = "kubernetes"
default:
typeName = "instance"
}

sizeList = append(sizeList, Size{
Name: v.Name,
Description: v.Description,
Type: typeName,
CPU: v.CPUCores,
RAM: v.RAMMegabytes,
DisK: v.DiskGigabytes,
Selectable: v.Selectable,
})
}

for _, partialSize := range sizeList {
sizes = append(sizes, partialSize)
}

return sizes, nil
}

func flattenSize(size, m interface{}, extra map[string]interface{}) (map[string]interface{}, error) {

s := size.(Size)

flattenedSize := map[string]interface{}{}
flattenedSize["name"] = s.Name
flattenedSize["type"] = s.Type
flattenedSize["cpu"] = s.CPU
flattenedSize["ram"] = s.RAM
flattenedSize["disk"] = s.DisK
flattenedSize["description"] = s.Description
flattenedSize["selectable"] = s.Selectable

return flattenedSize, nil
}

func SizeSchema() map[string]*schema.Schema {
return map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Computed: true,
Description: "The name of the instance size",
},
"type": {
Type: schema.TypeString,
Computed: true,
Description: "A human name of the instance size",
},
"cpu": {
Type: schema.TypeInt,
Computed: true,
Description: "Total of CPU in the instance",
},
"ram": {
Type: schema.TypeInt,
Computed: true,
Description: "Total of RAM of the instance",
},
"disk": {
Type: schema.TypeInt,
Computed: true,
Description: "The instance size of SSD",
},
"description": {
Type: schema.TypeString,
Computed: true,
Description: "A description of the instance size",
},
"selectable": {
Type: schema.TypeBool,
Computed: true,
Description: "If can use the instance size",
},
}
}
136 changes: 136 additions & 0 deletions civo/datasource_size_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
package civo

import (
"fmt"
"strconv"
"testing"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
)

func TestAccDataSourceCivoSize_basic(t *testing.T) {
datasourceName := "data.civo_size.foobar"

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccDataSourceCivoSizeConfig(),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckDataSourceCivoSizeExist(datasourceName),
),
},
},
})
}

func TestAccDataSourceCivoSize_WithFilterAndSort(t *testing.T) {
datasourceName := "data.civo_size.foobar"

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccDataSourceCivoSizeConfigWhitFilterAndSort(),
Check: resource.ComposeTestCheckFunc(
testAccCheckDataSourceCivoSizeExist(datasourceName),
testAccCheckDataSourceCivoSizeFilteredAndSorted(datasourceName),
),
},
},
})
}

func testAccCheckDataSourceCivoSizeExist(n string) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[n]

if !ok {
return fmt.Errorf("Not found: %s", n)
}

if rs.Primary.ID == "" {
return fmt.Errorf("No Record ID is set")
}

rawTotal := rs.Primary.Attributes["sizes.#"]
total, err := strconv.Atoi(rawTotal)
if err != nil {
return err
}

if total < 1 {
return fmt.Errorf("No Civo sizes retrieved")
}

return nil
}
}

func testAccCheckDataSourceCivoSizeFilteredAndSorted(n string) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[n]

if !ok {
return fmt.Errorf("Not found: %s", n)
}

rawTotal := rs.Primary.Attributes["sizes.#"]
total, err := strconv.Atoi(rawTotal)
if err != nil {
return err
}

stringInSlice := func(value string, slice []string) bool {
for _, item := range slice {
if item == value {
return true
}
}
return false
}

var prevCPUCore float64
for i := 0; i < total; i++ {
name := rs.Primary.Attributes[fmt.Sprintf("sizes.%d.name", i)]
if !stringInSlice(name, []string{"g2.large", "g2.xlarge", "g2.2xlarge"}) {
return fmt.Errorf("Name is not in expected test filter values")
}

CPUCore, _ := strconv.ParseFloat(rs.Primary.Attributes[fmt.Sprintf("sizes.%d.cpu_cores", i)], 64)
if prevCPUCore > 0 {
return fmt.Errorf("Sizes is not sorted by CPU Core in descending order")
}
prevCPUCore = CPUCore

}

return nil
}
}

func testAccDataSourceCivoSizeConfig() string {
return `
data "civo_size" "foobar" {
}
`
}

func testAccDataSourceCivoSizeConfigWhitFilterAndSort() string {
return `
data "civo_size" "foobar" {
filter {
key = "name"
values = ["large"]
}
sort {
key = "cpu_cores"
direction = "desc"
}
}
`
}
1 change: 1 addition & 0 deletions civo/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ func Provider() *schema.Provider {
"civo_kubernetes_version": dataSourceKubernetesVersion(),
"civo_kubernetes_cluster": dataSourceKubernetesCluster(),
"civo_instances_size": dataSourceInstancesSize(),
"civo_size": dataSourceSize(),
"civo_instances": dataSourceInstances(),
"civo_instance": dataSourceInstance(),
"civo_dns_domain_name": dataSourceDNSDomainName(),
Expand Down
4 changes: 2 additions & 2 deletions civo/resource_kubernetes_cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ func resourceKubernetesCluster() *schema.Resource {
Type: schema.TypeString,
Optional: true,
Computed: true,
Description: "The size of each node (optional, the default is currently g3.k3s.medium)",
Description: "The size of each node (optional, the default is currently g4s.kube.medium)",
},
"kubernetes_version": {
Type: schema.TypeString,
Expand Down Expand Up @@ -292,7 +292,7 @@ func resourceKubernetesClusterCreate(d *schema.ResourceData, m interface{}) erro
if attr, ok := d.GetOk("target_nodes_size"); ok {
config.TargetNodesSize = attr.(string)
} else {
config.TargetNodesSize = "g3.k3s.medium"
config.TargetNodesSize = "g4s.kube.medium"
}

if attr, ok := d.GetOk("kubernetes_version"); ok {
Expand Down
4 changes: 2 additions & 2 deletions civo/resource_kubernetes_cluster_nodepool.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ func resourceKubernetesClusterNodePool() *schema.Resource {
Type: schema.TypeString,
Optional: true,
Computed: true,
Description: "the size of each node (optional, the default is currently g3.k3s.medium)",
Description: "the size of each node (optional, the default is currently g4s.kube.medium)",
},
},
Create: resourceKubernetesClusterNodePoolCreate,
Expand Down Expand Up @@ -79,7 +79,7 @@ func resourceKubernetesClusterNodePoolCreate(d *schema.ResourceData, m interface
if attr, ok := d.GetOk("target_nodes_size"); ok {
size = attr.(string)
} else {
size = "g3.k3s.medium"
size = "g4s.kube.medium"
}

log.Printf("[INFO] getting kubernetes cluster %s in the region %s", cluster_id, apiClient.Region)
Expand Down
4 changes: 2 additions & 2 deletions civo/resource_kubernetes_cluster_nodepool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,11 @@ func TestAccCivoKubernetesClusterNodePool_basic(t *testing.T) {
// query the API to retrieve the widget object
testAccCheckCivoKubernetesClusterNodePoolResourceExists(resPoolName, &kubernetes, &kubernetesNodePool),
// verify remote values
testAccCheckCivoKubernetesClusterNodePoolValues(&kubernetesNodePool, "g3.k3s.medium"),
testAccCheckCivoKubernetesClusterNodePoolValues(&kubernetesNodePool, "g4s.kube.medium"),
// verify local values
// resource.TestCheckResourceAttr(resPoolName, "cluster_id", kubernetes.ID),
resource.TestCheckResourceAttr(resPoolName, "num_target_nodes", "3"),
resource.TestCheckResourceAttr(resPoolName, "target_nodes_size", "g3.k3s.medium"),
resource.TestCheckResourceAttr(resPoolName, "target_nodes_size", "g4s.kube.medium"),
),
},
},
Expand Down
21 changes: 21 additions & 0 deletions examples/data-sources/civo_size/data-source.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
data "civo_size" "small" {
filter {
key = "name"
values = ["g3.small"]
match_by = "re"
}

filter {
key = "type"
values = ["instance"]
}

}

resource "civo_instance" "my-test-instance" {
hostname = "foo.com"
tags = ["python", "nginx"]
notes = "this is a note for the server"
size = element(data.civo_size.small.sizes, 0).name
disk_image = element(data.civo_disk_image.debian.diskimages, 0).id
}

0 comments on commit 8ed3687

Please sign in to comment.