@@ -22,6 +22,7 @@ import (
22
22
23
23
"github.com/coreos/pkg/capnslog"
24
24
"github.com/gophercloud/gophercloud"
25
+ "github.com/gophercloud/gophercloud/openstack/blockstorage/v3/volumes"
25
26
"github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/bootfromvolume"
26
27
"github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/floatingips"
27
28
"github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/keypairs"
@@ -76,10 +77,11 @@ type Server struct {
76
77
}
77
78
78
79
type 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
83
85
}
84
86
85
87
// LoadCloudsYAML defines how to load a clouds.yaml file.
@@ -143,11 +145,18 @@ func New(opts *Options) (*API, error) {
143
145
return nil , fmt .Errorf ("failed to create network client: %v" , err )
144
146
}
145
147
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
146
154
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 ,
151
160
}
152
161
153
162
if a .opts .Flavor != "" {
@@ -637,6 +646,24 @@ func (a *API) DeleteKey(name string) error {
637
646
return keypairs .Delete (a .computeClient , name , nil ).ExtractErr ()
638
647
}
639
648
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
+
640
667
func (a * API ) ListKeyPairs () ([]keypairs.KeyPair , error ) {
641
668
opts := keypairs.ListOpts {}
642
669
// Retrieve all pages of keypairs
@@ -710,5 +737,28 @@ func (a *API) GC(gracePeriod time.Duration) error {
710
737
}
711
738
}
712
739
}
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
+ }
713
763
return nil
714
764
}
0 commit comments