From 10bd11d950416af153bf7b17d352eb22ba827c63 Mon Sep 17 00:00:00 2001 From: Vishal Anarase Date: Thu, 29 Aug 2024 15:24:59 +0530 Subject: [PATCH 1/2] Support attaching/detaching volumes on create/update instance and detach volume Signed-off-by: Vishal Anarase --- fake_client.go | 6 +-- instance.go | 130 ++++++++++++++++++++++++++----------------------- volume.go | 13 +++-- volume_test.go | 5 +- 4 files changed, 84 insertions(+), 70 deletions(-) diff --git a/fake_client.go b/fake_client.go index 3776cac..ba3bb92 100644 --- a/fake_client.go +++ b/fake_client.go @@ -161,7 +161,7 @@ type Clienter interface { FindVolume(search string) (*Volume, error) NewVolume(v *VolumeConfig) (*VolumeResult, error) ResizeVolume(id string, size int) (*SimpleResponse, error) - AttachVolume(id string, instance string) (*SimpleResponse, error) + AttachVolume(id string, cfg VolumeAttachConfig) (*SimpleResponse, error) DetachVolume(id string) (*SimpleResponse, error) DeleteVolume(id string) (*SimpleResponse, error) @@ -1283,10 +1283,10 @@ func (c *FakeClient) ResizeVolume(id string, size int) (*SimpleResponse, error) } // AttachVolume implemented in a fake way for automated tests -func (c *FakeClient) AttachVolume(id string, instance string) (*SimpleResponse, error) { +func (c *FakeClient) AttachVolume(id string, cfg VolumeAttachConfig) (*SimpleResponse, error) { for i, volume := range c.Volumes { if volume.ID == id { - c.Volumes[i].InstanceID = instance + c.Volumes[i].InstanceID = cfg.InstanceID c.Volumes[i].Status = "attached" return &SimpleResponse{Result: "success"}, nil } diff --git a/instance.go b/instance.go index 55342c9..0fd1ff2 100644 --- a/instance.go +++ b/instance.go @@ -12,47 +12,48 @@ import ( // Instance represents a virtual server within Civo's infrastructure type Instance struct { - ID string `json:"id,omitempty"` - OpenstackServerID string `json:"openstack_server_id,omitempty"` - Hostname string `json:"hostname,omitempty"` - ReverseDNS string `json:"reverse_dns,omitempty"` - Size string `json:"size,omitempty"` - Region string `json:"region,omitempty"` - NetworkID string `json:"network_id,omitempty"` - PrivateIP string `json:"private_ip,omitempty"` - PublicIP string `json:"public_ip,omitempty"` - IPv6 string `json:"ipv6,omitempty"` - PseudoIP string `json:"pseudo_ip,omitempty"` - TemplateID string `json:"template_id,omitempty"` - SourceType string `json:"source_type,omitempty"` - SourceID string `json:"source_id,omitempty"` - SnapshotID string `json:"snapshot_id,omitempty"` - InitialUser string `json:"initial_user,omitempty"` - InitialPassword string `json:"initial_password,omitempty"` - SSHKey string `json:"ssh_key,omitempty"` - SSHKeyID string `json:"ssh_key_id,omitempty"` - Status string `json:"status,omitempty"` - Notes string `json:"notes,omitempty"` - FirewallID string `json:"firewall_id,omitempty"` - Tags []string `json:"tags,omitempty"` - CivostatsdToken string `json:"civostatsd_token,omitempty"` - CivostatsdStats string `json:"civostatsd_stats,omitempty"` - CivostatsdStatsPerMinute []string `json:"civostatsd_stats_per_minute,omitempty"` - CivostatsdStatsPerHour []string `json:"civostatsd_stats_per_hour,omitempty"` - OpenstackImageID string `json:"openstack_image_id,omitempty"` - RescuePassword string `json:"rescue_password,omitempty"` - VolumeBacked bool `json:"volume_backed,omitempty"` - CPUCores int `json:"cpu_cores,omitempty"` - RAMMegabytes int `json:"ram_mb,omitempty"` - DiskGigabytes int `json:"disk_gb,omitempty"` - GPUCount int `json:"gpu_count,omitempty"` - GPUType string `json:"gpu_type,omitempty"` - Script string `json:"script,omitempty"` - CreatedAt time.Time `json:"created_at,omitempty"` - ReservedIPID string `json:"reserved_ip_id,omitempty"` - ReservedIPName string `json:"reserved_ip_name,omitempty"` - ReservedIP string `json:"reserved_ip,omitempty"` - Subnets []Subnet `json:"subnets,omitempty"` + ID string `json:"id,omitempty"` + OpenstackServerID string `json:"openstack_server_id,omitempty"` + Hostname string `json:"hostname,omitempty"` + ReverseDNS string `json:"reverse_dns,omitempty"` + Size string `json:"size,omitempty"` + Region string `json:"region,omitempty"` + NetworkID string `json:"network_id,omitempty"` + PrivateIP string `json:"private_ip,omitempty"` + PublicIP string `json:"public_ip,omitempty"` + IPv6 string `json:"ipv6,omitempty"` + PseudoIP string `json:"pseudo_ip,omitempty"` + TemplateID string `json:"template_id,omitempty"` + SourceType string `json:"source_type,omitempty"` + SourceID string `json:"source_id,omitempty"` + SnapshotID string `json:"snapshot_id,omitempty"` + InitialUser string `json:"initial_user,omitempty"` + InitialPassword string `json:"initial_password,omitempty"` + SSHKey string `json:"ssh_key,omitempty"` + SSHKeyID string `json:"ssh_key_id,omitempty"` + Status string `json:"status,omitempty"` + Notes string `json:"notes,omitempty"` + FirewallID string `json:"firewall_id,omitempty"` + Tags []string `json:"tags,omitempty"` + CivostatsdToken string `json:"civostatsd_token,omitempty"` + CivostatsdStats string `json:"civostatsd_stats,omitempty"` + CivostatsdStatsPerMinute []string `json:"civostatsd_stats_per_minute,omitempty"` + CivostatsdStatsPerHour []string `json:"civostatsd_stats_per_hour,omitempty"` + OpenstackImageID string `json:"openstack_image_id,omitempty"` + RescuePassword string `json:"rescue_password,omitempty"` + VolumeBacked bool `json:"volume_backed,omitempty"` + CPUCores int `json:"cpu_cores,omitempty"` + RAMMegabytes int `json:"ram_mb,omitempty"` + DiskGigabytes int `json:"disk_gb,omitempty"` + GPUCount int `json:"gpu_count,omitempty"` + GPUType string `json:"gpu_type,omitempty"` + Script string `json:"script,omitempty"` + CreatedAt time.Time `json:"created_at,omitempty"` + ReservedIPID string `json:"reserved_ip_id,omitempty"` + ReservedIPName string `json:"reserved_ip_name,omitempty"` + ReservedIP string `json:"reserved_ip,omitempty"` + Subnets []Subnet `json:"subnets,omitempty"` + AttachedVolume []AttachedVolume `json:"attached_volume,omitempty"` } //"cpu_cores":1,"ram_mb":2048,"disk_gb":25 @@ -70,30 +71,37 @@ type PaginatedInstanceList struct { Items []Instance `json:"items"` } +// AttachedVolume disk information +type AttachedVolume struct { + // ID of the volume to attach + ID string `json:"id"` +} + // InstanceConfig describes the parameters for a new instance // none of the fields are mandatory and will be automatically // set with default values type InstanceConfig struct { - Count int `json:"count"` - Hostname string `json:"hostname"` - ReverseDNS string `json:"reverse_dns"` - Size string `json:"size"` - Region string `json:"region"` - PublicIPRequired string `json:"public_ip"` - ReservedIPv4 string `json:"reserved_ipv4"` - PrivateIPv4 string `json:"private_ipv4"` - NetworkID string `json:"network_id"` - TemplateID string `json:"template_id"` - SourceType string `json:"source_type"` - SourceID string `json:"source_id"` - SnapshotID string `json:"snapshot_id"` - Subnets []string `json:"subnets,omitempty"` - InitialUser string `json:"initial_user"` - SSHKeyID string `json:"ssh_key_id"` - Script string `json:"script"` - Tags []string `json:"-"` - TagsList string `json:"tags"` - FirewallID string `json:"firewall_id"` + Count int `json:"count"` + Hostname string `json:"hostname"` + ReverseDNS string `json:"reverse_dns"` + Size string `json:"size"` + Region string `json:"region"` + PublicIPRequired string `json:"public_ip"` + ReservedIPv4 string `json:"reserved_ipv4"` + PrivateIPv4 string `json:"private_ipv4"` + NetworkID string `json:"network_id"` + TemplateID string `json:"template_id"` + SourceType string `json:"source_type"` + SourceID string `json:"source_id"` + SnapshotID string `json:"snapshot_id"` + Subnets []string `json:"subnets,omitempty"` + InitialUser string `json:"initial_user"` + SSHKeyID string `json:"ssh_key_id"` + Script string `json:"script"` + Tags []string `json:"-"` + TagsList string `json:"tags"` + FirewallID string `json:"firewall_id"` + AttachedVolume []AttachedVolume `json:"attached_volume"` } // ListInstances returns a page of Instances owned by the calling API account diff --git a/volume.go b/volume.go index f55515d..ebc1673 100644 --- a/volume.go +++ b/volume.go @@ -41,6 +41,12 @@ type VolumeConfig struct { Bootable bool `json:"bootable"` } +type VolumeAttachConfig struct { + InstanceID string `json:"instance_id"` + AttachAtBoot bool `json:"attach_at_boot"` + Region string `json:"region"` +} + // ListVolumes returns all volumes owned by the calling API account // https://www.civo.com/api/volumes#list-volumes func (c *Client) ListVolumes() ([]Volume, error) { @@ -199,11 +205,8 @@ func (c *Client) ResizeVolume(id string, size int) (*SimpleResponse, error) { // AttachVolume attaches a volume to an instance // https://www.civo.com/api/volumes#attach-a-volume-to-an-instance -func (c *Client) AttachVolume(id string, instance string) (*SimpleResponse, error) { - resp, err := c.SendPutRequest(fmt.Sprintf("/v2/volumes/%s/attach", id), map[string]string{ - "instance_id": instance, - "region": c.Region, - }) +func (c *Client) AttachVolume(id string, v VolumeAttachConfig) (*SimpleResponse, error) { + resp, err := c.SendPutRequest(fmt.Sprintf("/v2/volumes/%s/attach", id), v) if err != nil { return nil, decodeError(err) } diff --git a/volume_test.go b/volume_test.go index 53d4480..f65bbf9 100644 --- a/volume_test.go +++ b/volume_test.go @@ -195,7 +195,10 @@ func TestAttachVolumes(t *testing.T) { "/v2/volumes/12346/attach": `{"result": "success"}`, }) defer server.Close() - got, err := client.AttachVolume("12346", "123456") + cfg := VolumeAttachConfig{ + InstanceID: "123456", + } + got, err := client.AttachVolume("12346", cfg) if err != nil { t.Errorf("Request returned an error: %s", err) return From 2b6369ec99ae0aaaf262d2299f27da6874928282 Mon Sep 17 00:00:00 2001 From: Vishal Anarase Date: Thu, 29 Aug 2024 15:26:48 +0530 Subject: [PATCH 2/2] Fix lint Signed-off-by: Vishal Anarase --- volume.go | 1 + 1 file changed, 1 insertion(+) diff --git a/volume.go b/volume.go index ebc1673..c5d6c33 100644 --- a/volume.go +++ b/volume.go @@ -41,6 +41,7 @@ type VolumeConfig struct { Bootable bool `json:"bootable"` } +// VolumeAttachConfig is the configuration used to attach volume type VolumeAttachConfig struct { InstanceID string `json:"instance_id"` AttachAtBoot bool `json:"attach_at_boot"`