diff --git a/civo/datasource_common_schema.go b/civo/datasource_common_schema.go new file mode 100644 index 00000000..b1631408 --- /dev/null +++ b/civo/datasource_common_schema.go @@ -0,0 +1,31 @@ +package civo + +import ( + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" +) + +func dataSourceFiltersSchema() *schema.Schema { + return &schema.Schema{ + Type: schema.TypeSet, + Optional: true, + ForceNew: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + }, + "values": { + Type: schema.TypeList, + Required: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "regex": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + }, + }, + } +} diff --git a/civo/datasource_common_struct.go b/civo/datasource_common_struct.go new file mode 100644 index 00000000..9036b4f0 --- /dev/null +++ b/civo/datasource_common_struct.go @@ -0,0 +1,7 @@ +package civo + +type Filter struct { + Name string + Values []string + Regex bool +} diff --git a/civo/datasource_intances_size.go b/civo/datasource_intances_size.go new file mode 100644 index 00000000..bc3727e3 --- /dev/null +++ b/civo/datasource_intances_size.go @@ -0,0 +1,165 @@ +package civo + +import ( + "fmt" + "github.com/civo/civogo" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "regexp" + "strconv" +) + +func dataSourceInstancesSize() *schema.Resource { + return &schema.Resource{ + Read: dataSourceInstancesSizeRead, + Schema: map[string]*schema.Schema{ + "filter": dataSourceFiltersSchema(), + // computed attributes + "name": { + Type: schema.TypeString, + Computed: true, + }, + "nice_name": { + Type: schema.TypeString, + Computed: true, + }, + "cpu_cores": { + Type: schema.TypeInt, + Computed: true, + }, + "ram_mb": { + Type: schema.TypeInt, + Computed: true, + }, + "disk_gb": { + Type: schema.TypeInt, + Computed: true, + }, + "description": { + Type: schema.TypeString, + Computed: true, + }, + "selectable": { + Type: schema.TypeBool, + Computed: true, + }, + }, + } +} + +func dataSourceInstancesSizeRead(d *schema.ResourceData, m interface{}) error { + apiClient := m.(*civogo.Client) + + filters, filtersOk := d.GetOk("filter") + + if !filtersOk { + return fmt.Errorf("one of filters must be assigned") + } + + if filtersOk { + resp, err := apiClient.ListInstanceSizes() + if err != nil { + return fmt.Errorf("no instances size was found in the server") + } + + size, err := findInstancesSizeByFilter(resp, filters.(*schema.Set)) + if err != nil { + return fmt.Errorf("no instances size was found in the server, %s", err) + } + + d.SetId(size.ID) + d.Set("name", size.Name) + d.Set("nice_name", size.NiceName) + d.Set("cpu_cores", size.CPUCores) + d.Set("ram_mb", size.RAMMegabytes) + d.Set("disk_gb", size.DiskGigabytes) + d.Set("description", size.Description) + d.Set("selectable", size.Selectable) + } + + return nil +} + +func findInstancesSizeByFilter(sizes []civogo.InstanceSize, set *schema.Set) (*civogo.InstanceSize, error) { + results := make([]civogo.InstanceSize, 0) + + var filters []Filter + + for _, v := range set.List() { + m := v.(map[string]interface{}) + var filterValues []string + for _, e := range m["values"].([]interface{}) { + filterValues = append(filterValues, e.(string)) + } + filters = append(filters, Filter{Name: m["name"].(string), Values: filterValues, Regex: m["regex"].(bool)}) + } + + for _, valueFilters := range filters { + for _, valueSize := range sizes { + + // filter for the name + if valueFilters.Name == "name" { + if valueFilters.Regex { + r, _ := regexp.Compile(valueFilters.Values[0]) + if r.MatchString(valueSize.Name) { + results = append(results, valueSize) + } + } else { + if valueSize.Name == valueFilters.Values[0] { + results = append(results, valueSize) + } + } + } + + // filter for the CPU + if valueFilters.Name == "cpu" { + if valueFilters.Regex { + r, _ := regexp.Compile(valueFilters.Values[0]) + if r.MatchString(strconv.Itoa(valueSize.CPUCores)) { + results = append(results, valueSize) + } + } else { + if strconv.Itoa(valueSize.CPUCores) == valueFilters.Values[0] { + results = append(results, valueSize) + } + } + } + + // filter for the RAM + if valueFilters.Name == "ram" { + if valueFilters.Regex { + r, _ := regexp.Compile(valueFilters.Values[0]) + if r.MatchString(strconv.Itoa(valueSize.RAMMegabytes)) { + results = append(results, valueSize) + } + } else { + if strconv.Itoa(valueSize.RAMMegabytes) == valueFilters.Values[0] { + results = append(results, valueSize) + } + } + } + + // filter for the Disk + if valueFilters.Name == "disk" { + if valueFilters.Regex { + r, _ := regexp.Compile(valueFilters.Values[0]) + if r.MatchString(strconv.Itoa(valueSize.DiskGigabytes)) { + results = append(results, valueSize) + } + } else { + if strconv.Itoa(valueSize.DiskGigabytes) == valueFilters.Values[0] { + results = append(results, valueSize) + } + } + } + + } + } + + if len(results) == 1 { + return &results[0], nil + } + if len(results) == 0 { + return nil, fmt.Errorf("no sizes found for your search") + } + return nil, fmt.Errorf("too many sizes found (found %d, expected 1)", len(results)) +} diff --git a/civo/datasource_kubernetes_version.go b/civo/datasource_kubernetes_version.go new file mode 100644 index 00000000..9ce5d95e --- /dev/null +++ b/civo/datasource_kubernetes_version.go @@ -0,0 +1,105 @@ +package civo + +import ( + "fmt" + "github.com/civo/civogo" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" +) + +func dataSourceKubernetesVersion() *schema.Resource { + return &schema.Resource{ + Read: dataSourceKubernetesVersionRead, + Schema: map[string]*schema.Schema{ + "filter": dataSourceFiltersSchema(), + // computed attributes + "version": { + Type: schema.TypeString, + Computed: true, + }, + "label": { + Type: schema.TypeString, + Computed: true, + }, + "type": { + Type: schema.TypeString, + Computed: true, + }, + "default": { + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func dataSourceKubernetesVersionRead(d *schema.ResourceData, m interface{}) error { + apiClient := m.(*civogo.Client) + + filters, filtersOk := d.GetOk("filter") + + if !filtersOk { + return fmt.Errorf("one of filters must be assigned") + } + + if filtersOk { + resp, err := apiClient.ListAvailableKubernetesVersions() + if err != nil { + return fmt.Errorf("no version was found in the server") + } + + version, err := findKubernetesVersionByFilter(resp, filters.(*schema.Set)) + if err != nil { + return fmt.Errorf("no version was found in the server, %s", err) + } + + d.SetId(version.Version) + d.Set("version", version.Version) + d.Set("label", fmt.Sprintf("v%s", version.Version)) + d.Set("type", version.Type) + d.Set("default", version.Default) + } + + return nil +} + +func findKubernetesVersionByFilter(version []civogo.KubernetesVersion, set *schema.Set) (*civogo.KubernetesVersion, error) { + results := make([]civogo.KubernetesVersion, 0) + + var filters []Filter + + for _, v := range set.List() { + m := v.(map[string]interface{}) + var filterValues []string + for _, e := range m["values"].([]interface{}) { + filterValues = append(filterValues, e.(string)) + } + filters = append(filters, Filter{Name: m["name"].(string), Values: filterValues, Regex: m["regex"].(bool)}) + } + + for _, valueFilters := range filters { + for _, valueVersion := range version { + + // Filter for version + if valueFilters.Name == "version" { + if valueVersion.Version == valueFilters.Values[0] { + results = append(results, valueVersion) + } + } + + // Filter for type + if valueFilters.Name == "type" { + if valueVersion.Type == valueFilters.Values[0] { + results = append(results, valueVersion) + } + } + } + } + + if len(results) == 1 { + return &results[0], nil + } + if len(results) == 0 { + return nil, fmt.Errorf("no version found for your search") + } + return nil, fmt.Errorf("too many version found (found %d, expected 1)", len(results)) +} diff --git a/civo/provider.go b/civo/provider.go index b965317b..4fcb24d7 100644 --- a/civo/provider.go +++ b/civo/provider.go @@ -16,7 +16,9 @@ func Provider() terraform.ResourceProvider { }, }, DataSourcesMap: map[string]*schema.Resource{ - "civo_template": dataSourceTemplate(), + "civo_template": dataSourceTemplate(), + "civo_kubernetes_version": dataSourceKubernetesVersion(), + "civo_instances_size": dataSourceInstancesSize(), }, ResourcesMap: map[string]*schema.Resource{ "civo_instance": resourceInstance(), diff --git a/civo/resource_kubernetes_cluster.go b/civo/resource_kubernetes_cluster.go index ad240aeb..dbaefc90 100644 --- a/civo/resource_kubernetes_cluster.go +++ b/civo/resource_kubernetes_cluster.go @@ -32,6 +32,7 @@ func resourceKubernetesCluster() *schema.Resource { "kubernetes_version": { Type: schema.TypeString, Optional: true, + Default: "1.0.0", Description: "the version of k3s to install (optional, the default is currently the latest available)", }, "tags": { @@ -188,7 +189,7 @@ func resourceKubernetesClusterCreate(d *schema.ResourceData, m interface{}) erro d.SetId(resp.ID) return resource.Retry(d.Timeout(schema.TimeoutCreate), func() *resource.RetryError { - resp, err := apiClient.FindKubernetesCluster(d.Get("name").(string)) + resp, err := apiClient.FindKubernetesCluster(d.Id()) if err != nil { return resource.NonRetryableError(fmt.Errorf("[WARN] error geting kubernetes cluster: %s", err)) } @@ -236,26 +237,32 @@ func resourceKubernetesClusterRead(d *schema.ResourceData, m interface{}) error func resourceKubernetesClusterUpdate(d *schema.ResourceData, m interface{}) error { apiClient := m.(*civogo.Client) - config := &civogo.KubernetesClusterConfig{ - Name: d.Get("name").(string), - TargetNodesSize: d.Get("target_nodes_size").(string), - } + config := &civogo.KubernetesClusterConfig{} - if d.HasChange("num_target_nodes") { + if d.HasChange("num_target_nodes") || d.HasChange("kubernetes_version") || d.HasChange("applications") || d.HasChange("name") { + config.Name = d.Get("name").(string) config.NumTargetNodes = d.Get("num_target_nodes").(int) - } - - if d.HasChange("applications") { + config.KubernetesVersion = d.Get("kubernetes_version").(string) config.Applications = d.Get("applications").(string) } _, err := apiClient.UpdateKubernetesCluster(d.Id(), config) if err != nil { - fmt.Errorf("[WARN] failed to update load balancer: %s", err) - return err + return fmt.Errorf("[WARN] failed to update kubernetes cluster: %s", err) } - return resourceKubernetesClusterRead(d, m) + return resource.Retry(d.Timeout(schema.TimeoutCreate), func() *resource.RetryError { + resp, err := apiClient.FindKubernetesCluster(d.Id()) + if err != nil { + return resource.NonRetryableError(fmt.Errorf("[WARN] error geting kubernetes cluster: %s", err)) + } + + if resp.Status != "ACTIVE" { + return resource.RetryableError(fmt.Errorf("[WARN] waiting for the kubernets cluster to be created but the status is %s", resp.Status)) + } + + return resource.NonRetryableError(resourceKubernetesClusterRead(d, m)) + }) } func resourceKubernetesClusterDelete(d *schema.ResourceData, m interface{}) error {