diff --git a/README.md b/README.md index 0add6a9..112fd5b 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,8 @@ The following parameters are supported: | `boot_time` | string | Optional. Maximum wait time for instance to boot up. During that time plugin check Cloud-Init signatures. | | `use_ignition` | string | Enable Fedora CoreOS / Flatcar Linux Ignition support | | `server_spec` | object | Server spec used to create instances. See: [Compute API](https://docs.openstack.org/api-ref/compute/#create-server) | +| `volume_type` | string | Optional. Volume type name, must be used in conjunction with `volume_size` | +| `volume_size` | int | Optional. Size of disk volume in gigabytes, must be used in conjunction with `volume_type` | ### Default connector config diff --git a/internal/openstackclient/openstackclient.go b/internal/openstackclient/openstackclient.go index 5b7e53d..ea78b6f 100644 --- a/internal/openstackclient/openstackclient.go +++ b/internal/openstackclient/openstackclient.go @@ -11,6 +11,7 @@ import ( "github.com/gophercloud/gophercloud/v2" "github.com/gophercloud/gophercloud/v2/openstack" "github.com/gophercloud/gophercloud/v2/openstack/compute/v2/servers" + "github.com/gophercloud/gophercloud/v2/openstack/blockstorage/v2/volumes" "github.com/gophercloud/gophercloud/v2/openstack/config" "github.com/gophercloud/gophercloud/v2/openstack/config/clouds" "github.com/gophercloud/gophercloud/v2/openstack/image/v2/images" @@ -81,11 +82,15 @@ type Client interface { ListServers(ctx context.Context) ([]servers.Server, error) CreateServer(ctx context.Context, spec servers.CreateOptsBuilder, hintOpts servers.SchedulerHintOptsBuilder) (*servers.Server, error) DeleteServer(ctx context.Context, serverId string) error + CreateVolume(ctx context.Context, opts volumes.CreateOpts) (*volumes.Volume, error) + GetVolume(ctx context.Context, volumeId string) (*volumes.Volume, error) + WaitForVolumeStatus(ctx context.Context, volumeId string, status string) error } type client struct { - compute *gophercloud.ServiceClient - image *gophercloud.ServiceClient + compute *gophercloud.ServiceClient + image *gophercloud.ServiceClient + blockStorage *gophercloud.ServiceClient } func New(ctx context.Context, authConfig AuthConfig, cloudOpts *CloudOpts) (Client, error) { @@ -118,10 +123,15 @@ func New(ctx context.Context, authConfig AuthConfig, cloudOpts *CloudOpts) (Clie if err != nil { return nil, err } + blockStorageClient, err := openstack.NewBlockStorageV3(providerClient, endpointOps) + if err != nil { + return nil, err + } return &client{ compute: computeClient, image: imageClient, + blockStorage: blockStorageClient, }, nil } @@ -315,3 +325,15 @@ func (c *client) CreateServer(ctx context.Context, spec servers.CreateOptsBuilde func (c *client) DeleteServer(ctx context.Context, serverId string) error { return servers.Delete(ctx, c.compute, serverId).ExtractErr() } + +func (c *client) CreateVolume(ctx context.Context, opts volumes.CreateOpts) (*volumes.Volume, error) { + return volumes.Create(ctx, c.blockStorage, opts, nil).Extract() +} + +func (c *client) GetVolume(ctx context.Context, volumeId string) (*volumes.Volume, error) { + return volumes.Get(ctx, c.blockStorage, volumeId).Extract() +} + +func (c *client) WaitForVolumeStatus(ctx context.Context, volumeId string, status string) error { + return volumes.WaitForStatus(ctx, c.blockStorage, volumeId, status) +} diff --git a/provider.go b/provider.go index 532b23b..cfb9901 100644 --- a/provider.go +++ b/provider.go @@ -8,6 +8,7 @@ import ( "sync/atomic" "time" + "github.com/gophercloud/gophercloud/v2/openstack/blockstorage/v2/volumes" "github.com/gophercloud/gophercloud/v2/openstack/compute/v2/servers" "github.com/hashicorp/go-hclog" "github.com/jinzhu/copier" @@ -29,6 +30,8 @@ type InstanceGroup struct { UseIgnition bool `json:"use_ignition"` // Configure keys via Ignition (Fedora CoreOS / Flatcar) BootTimeS string `json:"boot_time"` // optional: wait some time before report machine as available BootTime time.Duration + VolumeType string `json:"volume_type"` + VolumeSize int `json:"volume_size"` client openstackclient.Client settings provider.Settings @@ -242,6 +245,34 @@ func (g *InstanceGroup) createInstance(ctx context.Context) (string, error) { } } + if g.VolumeSize != 0 && g.VolumeType != "" { + volumeOpts := volumes.CreateOpts{ + Name: spec.Name, + Size: g.VolumeSize, + VolumeType: g.VolumeType, + ImageID: spec.ImageRef, + } + volume, err := g.client.CreateVolume(ctx, volumeOpts) + if err != nil { + return "", err + } + + err = g.client.WaitForVolumeStatus(ctx, volume.ID, "available") + if err != nil { + return "", err + } + + spec.BlockDevice = []servers.BlockDevice{ + { + BootIndex: 0, + DeleteOnTermination: true, + DestinationType: servers.DestinationVolume, + SourceType: servers.SourceVolume, + UUID: volume.ID, + }, + } + } + if spec.ImageName != "" { imageRef, imgProps, err := g.client.GetImageByName(ctx, spec.ImageName) if err != nil {