@@ -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