Skip to content

Commit

Permalink
Merge branch 'master' into volume-boot-attach
Browse files Browse the repository at this point in the history
  • Loading branch information
uzaxirr authored Oct 7, 2024
2 parents f659161 + ebd1997 commit b410d8f
Show file tree
Hide file tree
Showing 14 changed files with 180 additions and 22 deletions.
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,15 @@

## [v1.1.2](https://github.com/civo/terraform-provider-civo/releases/tag/v1.1.2) (3 September 2024)

### Merged
- [#338](https://github.com/civo/terraform-provider-civo/pull/338) - Make script field immutable for instance resource
- [#333](https://github.com/civo/terraform-provider-civo/pull/333) - Addition of privateIP in DB resource
- [#336](https://github.com/civo/terraform-provider-civo/pull/336) - Decode Base64 script before saving state
- [#337](https://github.com/civo/terraform-provider-civo/pull/337) - Add missing instance states
- [#329](https://github.com/civo/terraform-provider-civo/pull/329) - Fix: Enhance Kubernetes version handling
- [#326](https://github.com/civo/terraform-provider-civo/pull/326) - Improving the documentation for firewall resource
- [#321](https://github.com/civo/terraform-provider-civo/pull/321) - adding documentation for the new write_kubeconfig property

## [v1.1.1](https://github.com/civo/terraform-provider-civo/releases/tag/v1.1.1) (20 August 2024)

### Merged
Expand Down
6 changes: 6 additions & 0 deletions civo/database/resource_database.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,11 @@ func ResourceDatabase() *schema.Resource {
Computed: true,
Description: "The status of the database",
},
"private_ipv4": {
Type: schema.TypeString,
Computed: true,
Description: "The private IPv4 address for the database",
},
},
CreateContext: resourceDatabaseCreate,
ReadContext: resourceDatabaseRead,
Expand Down Expand Up @@ -270,6 +275,7 @@ func resourceDatabaseRead(ctx context.Context, d *schema.ResourceData, m interfa
d.Set("dns_endpoint", fmt.Sprintf("%s.db.civo.com", resp.ID))
d.Set("port", resp.Port)
d.Set("status", resp.Status)
d.Set("private_ipv4", resp.PrivateIPv4)

return nil
}
Expand Down
36 changes: 33 additions & 3 deletions civo/instances/resource_instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ package instances

import (
"context"
"encoding/base64"
"errors"
"fmt"
"log"
"strings"
"time"
Expand Down Expand Up @@ -93,6 +95,11 @@ func ResourceInstance() *schema.Resource {
ValidateFunc: utils.ValidateUUID,
Description: "The ID of the firewall to use, from the current list. If left blank or not sent, the default firewall will be used (open to all)",
},
"volume_type": {
Type: schema.TypeString,
Optional: true,
Description: "The type of volume to use, either 'ssd' or 'bssd' (optional; default 'ssd')",
},
"tags": {
Type: schema.TypeSet,
Optional: true,
Expand Down Expand Up @@ -203,6 +210,7 @@ func ResourceInstance() *schema.Resource {
Update: schema.DefaultTimeout(30 * time.Minute),
Delete: schema.DefaultTimeout(30 * time.Minute),
},
CustomizeDiff: customizeDiffInstance,
}
}

Expand Down Expand Up @@ -251,6 +259,10 @@ func resourceInstanceCreate(ctx context.Context, d *schema.ResourceData, m inter
config.ReservedIPv4 = v.(string)
}

if v, ok := d.GetOk("volume_type"); ok {
config.VolumeType = v.(string)
}

if networtID, ok := d.GetOk("network_id"); ok {
config.NetworkID = networtID.(string)
} else {
Expand Down Expand Up @@ -309,7 +321,8 @@ func resourceInstanceCreate(ctx context.Context, d *schema.ResourceData, m inter
if parseErr == nil {
err = customErr
}
return diag.Errorf("[ERR] failed to create instance: %s", err)
// quota errors introduce new line after each missing quota, causing formatting issues:
return diag.Errorf("[ERR] failed to create instance: %s", strings.ReplaceAll(err.Error(), "\n", " "))
}

d.SetId(instance.ID)
Expand Down Expand Up @@ -400,6 +413,16 @@ func resourceInstanceRead(_ context.Context, d *schema.ResourceData, m interface
d.Set("attached_volume", volumes)
}

if resp.Script == "" {
d.Set("script", "")
}

decodedScript, err := base64.StdEncoding.DecodeString(resp.Script)
if err != nil {
return diag.Errorf("[ERR] failed to decode base64 script: %s", err)
}

d.Set("script", string(decodedScript))
d.Set("hostname", resp.Hostname)
d.Set("reverse_dns", resp.ReverseDNS)
d.Set("size", resp.Size)
Expand All @@ -416,10 +439,10 @@ func resourceInstanceRead(_ context.Context, d *schema.ResourceData, m interface
d.Set("network_id", resp.NetworkID)
d.Set("firewall_id", resp.FirewallID)
d.Set("status", resp.Status)
d.Set("script", resp.Script)
d.Set("created_at", resp.CreatedAt.UTC().String())
d.Set("notes", resp.Notes)
d.Set("disk_image", diskImg.ID)
d.Set("volume_type", resp.VolumeType)

if resp.PublicIP != "" {
d.Set("public_ip_required", "create")
Expand Down Expand Up @@ -456,7 +479,7 @@ func resourceInstanceUpdate(ctx context.Context, d *schema.ResourceData, m inter
}

createStateConf := &resource.StateChangeConf{
Pending: []string{"BUILDING"},
Pending: []string{"BUILDING", "REBOOTING"},
Target: []string{"ACTIVE"},
Refresh: func() (interface{}, string, error) {
resp, err := apiClient.GetInstance(d.Id())
Expand Down Expand Up @@ -639,3 +662,10 @@ func resourceInstanceDelete(ctx context.Context, d *schema.ResourceData, m inter

return nil
}

func customizeDiffInstance(ctx context.Context, d *schema.ResourceDiff, meta interface{}) error {
if d.Id() != "" && d.HasChange("script") {
return fmt.Errorf("the 'script' field is immutable")
}
return nil
}
3 changes: 2 additions & 1 deletion civo/kubernetes/resource_kubernetes_cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,8 @@ func resourceKubernetesClusterCreate(ctx context.Context, d *schema.ResourceData
log.Printf("[INFO] kubernertes config %+v", config)
resp, err := apiClient.NewKubernetesClusters(config)
if err != nil {
return diag.Errorf("[ERR] failed to create the kubernetes cluster: %s", err)
// quota errors introduce new line after each missing quota, causing formatting issues:
return diag.Errorf("[ERR] failed to create the kubernetes cluster: %s", strings.ReplaceAll(err.Error(), "\n", " "))
}

d.SetId(resp.ID)
Expand Down
2 changes: 1 addition & 1 deletion civo/kubernetes/resource_kubernetes_cluster_nodepool.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ func ResourceKubernetesClusterNodePool() *schema.Resource {
func resourceKubernetesClusterNodePoolCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
apiClient := m.(*civogo.Client)

// overwrite the region if is define in the datasource
// overwrite the region if is defined in the datasource
if region, ok := d.GetOk("region"); ok {
apiClient.Region = region.(string)
}
Expand Down
70 changes: 70 additions & 0 deletions civo/volume/datasource_volumetype.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package volume

import (
"context"
"github.com/civo/civogo"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

// DataSourceVolumeType function returns a schema.Resource that represents a Volume.
// This can be used to query and retrieve details about a specific Volume in the infrastructure using its id or name.
func DataSourceVolumeType() *schema.Resource {
return &schema.Resource{
ReadContext: dataSourceCivoVolumeTypeRead,

Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
},
"labels": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
},
}
}

func dataSourceCivoVolumeTypeRead(_ context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
client := m.(*civogo.Client)

// overwrite the region if is defined in the datasource
if region, ok := d.GetOk("region"); ok {
client.Region = region.(string)
}

// Get the name of the volume type from the Terraform configuration
volumeTypeName := d.Get("name").(string)

// Fetch all volume types
volumeTypes, err := client.ListVolumeTypes()
if err != nil {
return diag.Errorf("[ERR] failed to retrieve volume type: %s", err)
}

// Find the specific volume type by name
var foundVolumeType *civogo.VolumeType
for _, vt := range volumeTypes {
if vt.Name == volumeTypeName {
foundVolumeType = &vt
break
}
}

// If the volume type is not found, return an error
if foundVolumeType == nil {
return diag.Errorf("volume type with name '%s' not found", volumeTypeName)
}

// Set the data source's ID and output fields
d.SetId(foundVolumeType.Name)
if err := d.Set("labels", foundVolumeType.Labels); err != nil {
return diag.Errorf("[ERR] failed to set volume labels: %s", err)
}

return nil
}
13 changes: 12 additions & 1 deletion civo/volume/resource_volume.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ func ResourceVolume() *schema.Resource {
Computed: true,
Description: "The mount point of the volume (from instance's perspective)",
},
"volume_type": {
Type: schema.TypeString,
Optional: true,
Description: "The type of the volume",
},
},
CreateContext: resourceVolumeCreate,
ReadContext: resourceVolumeRead,
Expand All @@ -61,19 +66,24 @@ func ResourceVolume() *schema.Resource {
func resourceVolumeCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
apiClient := m.(*civogo.Client)

// overwrite the region if is define in the datasource
// overwrite the region if is defined in the datasource
if region, ok := d.GetOk("region"); ok {
apiClient.Region = region.(string)
}

log.Printf("[INFO] configuring the volume %s", d.Get("name").(string))

config := &civogo.VolumeConfig{
Name: d.Get("name").(string),
SizeGigabytes: d.Get("size_gb").(int),
NetworkID: d.Get("network_id").(string),
Region: apiClient.Region,
}

if v, ok := d.GetOk("volume_type"); ok {
config.VolumeType = v.(string)
}

_, err := apiClient.FindNetwork(config.NetworkID)
if err != nil {
return diag.Errorf("[ERR] Unable to find network ID %q in %q region", config.NetworkID, config.Region)
Expand Down Expand Up @@ -132,6 +142,7 @@ func resourceVolumeRead(_ context.Context, d *schema.ResourceData, m interface{}
d.Set("network_id", resp.NetworkID)
d.Set("size_gb", resp.SizeGigabytes)
d.Set("mount_point", resp.MountPoint)
d.Set("volume_type", resp.VolumeType)

return nil
}
Expand Down
18 changes: 18 additions & 0 deletions civo/volume/resource_volume_attachment.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ func ResourceVolumeAttachment() *schema.Resource {
func resourceVolumeAttachmentCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
apiClient := m.(*civogo.Client)
var diags diag.Diagnostics

// overwrite the region if it's defined
if region, ok := d.GetOk("region"); ok {
apiClient.Region = region.(string)
Expand All @@ -72,6 +73,23 @@ func resourceVolumeAttachmentCreate(ctx context.Context, d *schema.ResourceData,
}

if volume.InstanceID == "" || volume.InstanceID != instanceID {

vuc := civogo.VolumeAttachConfig{
InstanceID: instanceID,
Region: apiClient.Region,
}

if attachAtBoot {
// Notify the terminal
msg := fmt.Sprintf("To use the volume %s, The instance %s needs to be rebooted", volumeID, instanceID)
diags = append(diags, diag.Diagnostic{
Severity: diag.Warning,
Summary: msg,
})

vuc.AttachAtBoot = true
}

log.Printf("[INFO] attaching the volume %s to instance %s", volumeID, instanceID)
vuc := civogo.VolumeAttachConfig{

Check failure on line 94 in civo/volume/resource_volume_attachment.go

View workflow job for this annotation

GitHub Actions / build (1.20.x, ubuntu-latest)

no new variables on left side of :=
InstanceID: instanceID,
Expand Down
3 changes: 0 additions & 3 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,6 @@ provider "civo" {
region = "LON1"
}
```
~> **Note** currently only full path is supported on the `credentials_file` input, but in the future using tilde (~) will work as well.



## Argument Reference

Expand Down
1 change: 1 addition & 0 deletions docs/resources/database.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ resource "civo_database" "custom_database" {
- `port` (Number) The port of the database
- `status` (String) The status of the database
- `username` (String) The username of the database
- `private_ipv4` (String) The private IP assigned to the database

<a id="nestedblock--timeouts"></a>
### Nested Schema for `timeouts`
Expand Down
4 changes: 3 additions & 1 deletion docs/resources/instance.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ resource "civo_instance" "example" {
network_id = civo_network.example.id
size = "g3.xsmall"
disk_image = data.civo_disk_image.debian.diskimages[0].id
volume_type = "csi-s3"
}
```
Expand All @@ -139,12 +140,13 @@ resource "civo_instance" "example" {
- `region` (String) The region for the instance, if not declare we use the region in declared in the provider
- `reserved_ipv4` (String) Can be either the UUID, name, or the IP address of the reserved IP
- `reverse_dns` (String) A fully qualified domain name that should be used as the instance's IP's reverse DNS (optional, uses the hostname if unspecified)
- `script` (String) The contents of a script that will be uploaded to /usr/local/bin/civo-user-init-script on your instance, read/write/executable only by root and then will be executed at the end of the cloud initialization
- `script` (String) The contents of a script that will be uploaded to /usr/local/bin/civo-user-init-script on your instance, read/write/executable only by root and then will be executed at the end of the cloud initialization. To fetch from file: `file("${path.module}/script")` (this is an immutable field, meaning you can't change it after creation)
- `size` (String) The name of the size, from the current list, e.g. g3.xsmall
- `sshkey_id` (String) The ID of an already uploaded SSH public key to use for login to the default user (optional; if one isn't provided a random password will be set and returned in the initial_password field)
- `tags` (Set of String) An optional list of tags, represented as a key, value pair
- `timeouts` (Block, Optional) (see [below for nested schema](#nestedblock--timeouts)) defines timeouts for cluster creation, read and update, default is 30 minutes for all
- `write_password` (Boolean) If set to true then initial_password for the instance will be saved to terraform state file. (default: false)
- `volume_type` (string) Type of volume that instance should be created with, e.g: ms-xfs-2-replicas, px-csi-db (default: csi-s3)

<a id="nestedblock--timeouts"></a>
### Nested Schema for `timeouts`
Expand Down
Loading

0 comments on commit b410d8f

Please sign in to comment.