Skip to content

Commit a6b7c08

Browse files
committed
libvirt: Use static libvirt library to destroy cluster
When we create the cluster, the terraform provider uses a static pure-golang library to communicate with libvirt. Use the same library to destroy the cluster, instead of using one that has to dynamically link with the C library.
1 parent 8013ca0 commit a6b7c08

File tree

2 files changed

+61
-69
lines changed

2 files changed

+61
-69
lines changed

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ require (
3333
github.com/coreos/ignition/v2 v2.18.0
3434
github.com/coreos/stream-metadata-go v0.1.8
3535
github.com/daixiang0/gci v0.10.1
36+
github.com/digitalocean/go-libvirt v0.0.0-20240220204746-fcabe97a6eed
3637
github.com/diskfs/go-diskfs v1.4.0
3738
github.com/form3tech-oss/jwt-go v3.2.3+incompatible
3839
github.com/go-openapi/errors v0.21.1
@@ -153,7 +154,6 @@ require (
153154
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
154155
github.com/coreos/vcontext v0.0.0-20230201181013-d72178a18687 // indirect
155156
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
156-
github.com/digitalocean/go-libvirt v0.0.0-20240220204746-fcabe97a6eed // indirect
157157
github.com/dimchansky/utfbom v1.1.1 // indirect
158158
github.com/dougm/pretty v0.0.0-20171025230240-2ee9d7453c02 // indirect
159159
github.com/elliotwutingfeng/asciiset v0.0.0-20230602022725-51bbb787efab // indirect

pkg/destroy/libvirt/libvirt.go

Lines changed: 60 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@
44
package libvirt
55

66
import (
7+
"net/url"
78
"strings"
89

9-
"github.com/libvirt/libvirt-go"
10+
libvirt "github.com/digitalocean/go-libvirt"
1011
"github.com/pkg/errors"
1112
"github.com/sirupsen/logrus"
1213

@@ -39,7 +40,7 @@ var AlwaysTrueFilter = func() filterFunc {
3940
}
4041

4142
// deleteFunc is the interface a function needs to implement to be delete resources.
42-
type deleteFunc func(conn *libvirt.Connect, filter filterFunc, logger logrus.FieldLogger) error
43+
type deleteFunc func(conn *libvirt.Libvirt, filter filterFunc, logger logrus.FieldLogger) error
4344

4445
// ClusterUninstaller holds the various options for the cluster we want to delete.
4546
type ClusterUninstaller struct {
@@ -59,17 +60,29 @@ func New(logger logrus.FieldLogger, metadata *types.ClusterMetadata) (providers.
5960

6061
// Run is the entrypoint to start the uninstall process.
6162
func (o *ClusterUninstaller) Run() (*types.ClusterQuota, error) {
62-
conn, err := libvirt.NewConnect(o.LibvirtURI)
63+
uri, err := url.Parse(o.LibvirtURI)
6364
if err != nil {
64-
return nil, errors.Wrap(err, "failed to connect to Libvirt daemon")
65+
return nil, err
6566
}
6667

68+
virt, err := libvirt.ConnectToURI(uri)
69+
if err != nil {
70+
return nil, err
71+
}
72+
defer func() {
73+
if err := virt.Disconnect(); err != nil {
74+
if o.Logger != nil {
75+
o.Logger.Warn("failed to disconnect from libvirt", err)
76+
}
77+
}
78+
}()
79+
6780
for _, del := range []deleteFunc{
6881
deleteDomains,
6982
deleteNetwork,
7083
deleteStoragePool,
7184
} {
72-
err = del(conn, o.Filter, o.Logger)
85+
err = del(virt, o.Filter, o.Logger)
7386
if err != nil {
7487
return nil, err
7588
}
@@ -83,145 +96,124 @@ func (o *ClusterUninstaller) Run() (*types.ClusterQuota, error) {
8396
// additional nodes after the initial list call. We continue deleting
8497
// domains until we either hit an error or we have a list call with no
8598
// matching domains.
86-
func deleteDomains(conn *libvirt.Connect, filter filterFunc, logger logrus.FieldLogger) error {
99+
func deleteDomains(virt *libvirt.Libvirt, filter filterFunc, logger logrus.FieldLogger) error {
87100
logger.Debug("Deleting libvirt domains")
88101
var err error
89102
nothingToDelete := false
90103
for !nothingToDelete {
91-
nothingToDelete, err = deleteDomainsSinglePass(conn, filter, logger)
104+
nothingToDelete, err = deleteDomainsSinglePass(virt, filter, logger)
92105
if err != nil {
93106
return err
94107
}
95108
}
96109
return nil
97110
}
98111

99-
func deleteDomainsSinglePass(conn *libvirt.Connect, filter filterFunc, logger logrus.FieldLogger) (nothingToDelete bool, err error) {
100-
domains, err := conn.ListAllDomains(0)
112+
func deleteDomainsSinglePass(virt *libvirt.Libvirt, filter filterFunc, logger logrus.FieldLogger) (nothingToDelete bool, err error) {
113+
domains, _, err := virt.ConnectListAllDomains(1, 0)
101114
if err != nil {
102115
return false, errors.Wrap(err, "list domains")
103116
}
104117

105118
nothingToDelete = true
106119
for _, domain := range domains {
107-
defer domain.Free()
108-
dName, err := domain.GetName()
109-
if err != nil {
110-
return false, errors.Wrap(err, "get domain name")
111-
}
112-
if !filter(dName) {
120+
if !filter(domain.Name) {
113121
continue
114122
}
115123

116124
nothingToDelete = false
117-
dState, _, err := domain.GetState()
125+
dState, _, err := virt.DomainGetState(domain, 0)
118126
if err != nil {
119-
return false, errors.Wrapf(err, "get domain state %d", dName)
127+
return false, errors.Wrapf(err, "get domain state %d", domain.Name)
120128
}
121129

122-
if dState != libvirt.DOMAIN_SHUTOFF && dState != libvirt.DOMAIN_SHUTDOWN {
123-
if err := domain.Destroy(); err != nil {
124-
return false, errors.Wrapf(err, "destroy domain %q", dName)
130+
if libvirt.DomainState(dState) != libvirt.DomainShutoff && libvirt.DomainState(dState) != libvirt.DomainShutdown {
131+
if err := virt.DomainDestroy(domain); err != nil {
132+
return false, errors.Wrapf(err, "destroy domain %q", domain.Name)
125133
}
126134
}
127-
if err := domain.UndefineFlags(libvirt.DOMAIN_UNDEFINE_NVRAM); err != nil {
128-
if e := err.(libvirt.Error); e.Code == libvirt.ERR_NO_SUPPORT || e.Code == libvirt.ERR_INVALID_ARG {
129-
logger.WithField("domain", dName).Info("libvirt does not support undefine flags: will try again without flags")
130-
if err := domain.Undefine(); err != nil {
131-
return false, errors.Wrapf(err, "could not undefine libvirt domain: %q", dName)
135+
if err := virt.DomainUndefineFlags(domain, libvirt.DomainUndefineNvram); err != nil {
136+
if e, ok := err.(libvirt.Error); ok && (libvirt.ErrorNumber(e.Code) == libvirt.ErrNoSupport || libvirt.ErrorNumber(e.Code) == libvirt.ErrInvalidArg) {
137+
logger.WithField("domain", domain.Name).Info("libvirt does not support undefine flags: will try again without flags")
138+
if err := virt.DomainUndefine(domain); err != nil {
139+
return false, errors.Wrapf(err, "could not undefine libvirt domain: %q", domain.Name)
132140
}
133141
} else {
134-
return false, errors.Wrapf(err, "could not undefine libvirt domain %q with flags", dName)
142+
return false, errors.Wrapf(err, "could not undefine libvirt domain %q with flags", domain.Name)
135143
}
136144
}
137-
logger.WithField("domain", dName).Info("Deleted domain")
145+
logger.WithField("domain", domain.Name).Info("Deleted domain")
138146
}
139147

140148
return nothingToDelete, nil
141149
}
142150

143-
func deleteStoragePool(conn *libvirt.Connect, filter filterFunc, logger logrus.FieldLogger) error {
151+
func deleteStoragePool(virt *libvirt.Libvirt, filter filterFunc, logger logrus.FieldLogger) error {
144152
logger.Debug("Deleting libvirt volumes")
145153

146-
pools, err := conn.ListStoragePools()
154+
pools, _, err := virt.ConnectListAllStoragePools(1, 0)
147155
if err != nil {
148156
return errors.Wrap(err, "list storage pools")
149157
}
150158

151-
for _, pname := range pools {
159+
for _, pool := range pools {
152160
// pool name that returns true from filter
153-
if !filter(pname) {
161+
if !filter(pool.Name) {
154162
continue
155163
}
156164

157-
pool, err := conn.LookupStoragePoolByName(pname)
158-
if err != nil {
159-
return errors.Wrapf(err, "get storage pool %q", pname)
160-
}
161-
defer pool.Free()
162-
163165
// delete all vols that return true from filter.
164-
vols, err := pool.ListAllStorageVolumes(0)
166+
vols, _, err := virt.StoragePoolListAllVolumes(pool, 1, 0)
165167
if err != nil {
166-
return errors.Wrapf(err, "list volumes in %q", pname)
168+
return errors.Wrapf(err, "list volumes in %q", pool.Name)
167169
}
168170

169171
for _, vol := range vols {
170-
defer vol.Free()
171-
vName, err := vol.GetName()
172-
if err != nil {
173-
return errors.Wrapf(err, "get volume names in %q", pname)
172+
if err := virt.StorageVolDelete(vol, 0); err != nil {
173+
return errors.Wrapf(err, "delete volume %q from %q", vol.Name, pool.Name)
174174
}
175-
if err := vol.Delete(0); err != nil {
176-
return errors.Wrapf(err, "delete volume %q from %q", vName, pname)
177-
}
178-
logger.WithField("volume", vName).Info("Deleted volume")
175+
logger.WithField("volume", vol.Name).Info("Deleted volume")
179176
}
180177

181178
// blow away entire pool.
182-
if err := pool.Destroy(); err != nil {
183-
return errors.Wrapf(err, "destroy pool %q", pname)
179+
if err := virt.StoragePoolDestroy(pool); err != nil {
180+
return errors.Wrapf(err, "destroy pool %q", pool.Name)
184181
}
185182

186-
if err := pool.Delete(0); err != nil {
187-
return errors.Wrapf(err, "delete pool %q", pname)
183+
if err := virt.StoragePoolDelete(pool, 0); err != nil {
184+
return errors.Wrapf(err, "delete pool %q", pool.Name)
188185
}
189186

190-
if err := pool.Undefine(); err != nil {
191-
return errors.Wrapf(err, "undefine pool %q", pname)
187+
if err := virt.StoragePoolUndefine(pool); err != nil {
188+
return errors.Wrapf(err, "undefine pool %q", pool.Name)
192189
}
193-
logger.WithField("pool", pname).Info("Deleted pool")
190+
logger.WithField("pool", pool.Name).Info("Deleted pool")
194191
}
195192

196193
return nil
197194
}
198195

199-
func deleteNetwork(conn *libvirt.Connect, filter filterFunc, logger logrus.FieldLogger) error {
196+
func deleteNetwork(virt *libvirt.Libvirt, filter filterFunc, logger logrus.FieldLogger) error {
200197
logger.Debug("Deleting libvirt network")
201198

202-
networks, err := conn.ListNetworks()
199+
networks, _, err := virt.ConnectListAllNetworks(1, 0)
203200
if err != nil {
204201
return errors.Wrap(err, "list networks")
205202
}
206203

207-
for _, nName := range networks {
208-
if !filter(nName) {
204+
for _, network := range networks {
205+
if !filter(network.Name) {
209206
continue
210207
}
211-
network, err := conn.LookupNetworkByName(nName)
212-
if err != nil {
213-
return errors.Wrapf(err, "get network %q", nName)
214-
}
215-
defer network.Free()
216208

217-
if err := network.Destroy(); err != nil {
218-
return errors.Wrapf(err, "destroy network %q", nName)
209+
if err := virt.NetworkDestroy(network); err != nil {
210+
return errors.Wrapf(err, "destroy network %q", network.Name)
219211
}
220212

221-
if err := network.Undefine(); err != nil {
222-
return errors.Wrapf(err, "undefine network %q", nName)
213+
if err := virt.NetworkUndefine(network); err != nil {
214+
return errors.Wrapf(err, "undefine network %q", network.Name)
223215
}
224-
logger.WithField("network", nName).Info("Deleted network")
216+
logger.WithField("network", network.Name).Info("Deleted network")
225217
}
226218
return nil
227219
}

0 commit comments

Comments
 (0)