@@ -22,6 +22,7 @@ import (
2222
2323 "github.com/coreos/pkg/capnslog"
2424 "github.com/gophercloud/gophercloud"
25+ "github.com/gophercloud/gophercloud/openstack/blockstorage/v3/volumes"
2526 "github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/bootfromvolume"
2627 "github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/floatingips"
2728 "github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/keypairs"
@@ -76,10 +77,11 @@ type Server struct {
7677}
7778
7879type API struct {
79- opts * Options
80- computeClient * gophercloud.ServiceClient
81- imageClient * gophercloud.ServiceClient
82- networkClient * gophercloud.ServiceClient
80+ opts * Options
81+ computeClient * gophercloud.ServiceClient
82+ imageClient * gophercloud.ServiceClient
83+ networkClient * gophercloud.ServiceClient
84+ blockStorageClient * gophercloud.ServiceClient
8385}
8486
8587// LoadCloudsYAML defines how to load a clouds.yaml file.
@@ -143,11 +145,18 @@ func New(opts *Options) (*API, error) {
143145 return nil , fmt .Errorf ("failed to create network client: %v" , err )
144146 }
145147
148+ blockStorageClient , err := clientconfig .NewServiceClient ("volume" , osOpts )
149+ if err != nil {
150+ return nil , fmt .Errorf ("failed to create block storage client: %v" , err )
151+ }
152+
153+ // Initialize the API struct
146154 a := & API {
147- opts : opts ,
148- computeClient : computeClient ,
149- imageClient : imageClient ,
150- networkClient : networkClient ,
155+ opts : opts ,
156+ computeClient : computeClient ,
157+ imageClient : imageClient ,
158+ networkClient : networkClient ,
159+ blockStorageClient : blockStorageClient ,
151160 }
152161
153162 if a .opts .Flavor != "" {
@@ -637,6 +646,24 @@ func (a *API) DeleteKey(name string) error {
637646 return keypairs .Delete (a .computeClient , name , nil ).ExtractErr ()
638647}
639648
649+ func (a * API ) DeleteVolume (volumeID string ) error {
650+ return volumes .Delete (a .blockStorageClient , volumeID , volumes.DeleteOpts {}).ExtractErr ()
651+ }
652+
653+ func (a * API ) ListVolumes () ([]volumes.Volume , error ) {
654+ opts := volumes.ListOpts {}
655+ allPages , err := volumes .List (a .blockStorageClient , opts ).AllPages ()
656+ if err != nil {
657+ return nil , fmt .Errorf ("failed to fetch volume pages: %w" , err )
658+ }
659+
660+ allVolumes , err := volumes .ExtractVolumes (allPages )
661+ if err != nil {
662+ return nil , fmt .Errorf ("failed to extract volumes: %w" , err )
663+ }
664+ return allVolumes , nil
665+ }
666+
640667func (a * API ) ListKeyPairs () ([]keypairs.KeyPair , error ) {
641668 opts := keypairs.ListOpts {}
642669 // Retrieve all pages of keypairs
@@ -710,5 +737,28 @@ func (a *API) GC(gracePeriod time.Duration) error {
710737 }
711738 }
712739 }
740+ // Clean up volumes
741+ volumes , err := a .ListVolumes ()
742+ if err != nil {
743+ return err
744+ }
745+
746+ for _ , volume := range volumes {
747+ // Skip volumes that are not in "available" state and don't start with "error"
748+ if volume .Status != "available" && ! strings .HasPrefix (volume .Status , "error" ) {
749+ continue
750+ }
751+ // Skip volumes created after the threshold
752+ if volume .CreatedAt .After (threshold ) {
753+ continue
754+ }
755+ // Skip volumes with names that do not start with "kola"
756+ if ! strings .HasPrefix (volume .Name , "kola" ) {
757+ continue
758+ }
759+ if err := a .DeleteVolume (volume .ID ); err != nil {
760+ return fmt .Errorf ("couldn't delete volume %s: %v" , volume .ID , err )
761+ }
762+ }
713763 return nil
714764}
0 commit comments