├── .gitignore ├── .travis.yml ├── Dockerfile ├── Makefile ├── README.md ├── cmd └── example.go ├── doc.go ├── example_test.go ├── liblvm.go ├── macro_wrapper.c └── macro_wrapper.h /.gitignore: -------------------------------------------------------------------------------- 1 | example 2 | *.swp 3 | *.swo 4 | tmp-ref* 5 | test.go 6 | testrun 7 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | go: 3 | - 1.x 4 | dist: trusty 5 | sudo: required 6 | services: 7 | - docker 8 | env: 9 | - TARGET_CONTAINER_ID=container-go-lvm 10 | script: 11 | - docker build -t go-lvm . 12 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | ############################################## 2 | # This Dockerfile is created for the CI test # 3 | ############################################## 4 | FROM centos:latest 5 | RUN yum -y install golang device-mapper-devel lvm2-devel gcc git 6 | RUN go get -u github.com/nak3/go-lvm 7 | RUN cd ~/go/src/github.com/nak3/go-lvm && go build ./... 8 | #RUN go run cmd/example.go 9 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | go build -o example cmd/example.go 3 | go build -o testrun cmd/test.go 4 | run: 5 | sudo ./example 6 | test: 7 | sudo ./testrun 8 | clean: 9 | rm example 10 | 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | go-lvm 2 | ======================================================================= 3 | 4 | [![GoDoc](https://godoc.org/github.com/nak3/go-lvm?status.svg)](https://godoc.org/github.com/nak3/go-lvm) 5 | [![Build Status](https://travis-ci.org/nak3/go-lvm.svg?branch=master)](https://travis-ci.org/nak3/go-lvm) 6 | [![Go Report Card](https://goreportcard.com/badge/github.com/nak3/go-lvm)](https://goreportcard.com/report/github.com/nak3/go-lvm) 7 | 8 | ### Overview 9 | 10 | go-lvm is a go library to call liblvm API based on python-lvm developed in [LVM2](https://sourceware.org/lvm2/). 11 | 12 | ### Usage 13 | 14 | Please refer to [go-doc](https://godoc.org/github.com/nak3/go-lvm#example-LvObject--Createremove). 15 | 16 | ### Test run 17 | 18 | Let's create a available volume group and create and delete a LV. 19 | 20 | #### step-1. set up a free VG 21 | ~~~ 22 | sudo dd if=/dev/zero of=disk.img bs=1G count=1 23 | export LOOP=`sudo losetup -f` 24 | sudo losetup $LOOP disk.img 25 | sudo vgcreate vg-targetd $LOOP 26 | ~~~ 27 | 28 | #### step-2. Run an example script 29 | ~~~ 30 | go run cmd/example.go 31 | ~~~ 32 | -------------------------------------------------------------------------------- /cmd/example.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/nak3/go-lvm" 6 | ) 7 | 8 | func main() { 9 | // List volume group 10 | vglist := lvm.ListVgNames() 11 | availableVG := "" 12 | // Create a VG object 13 | vgo := &lvm.VgObject{} 14 | for i := 0; i < len(vglist); i++ { 15 | vgo.Vgt = lvm.VgOpen(vglist[i], "r") 16 | if vgo.GetFreeSize() > 0 { 17 | availableVG = vglist[i] 18 | vgo.Close() 19 | break 20 | } 21 | vgo.Close() 22 | } 23 | if availableVG == "" { 24 | fmt.Printf("no VG that has free space found\n") 25 | return 26 | } 27 | 28 | // Open VG in write mode 29 | vgo.Vgt = lvm.VgOpen(availableVG, "w") 30 | defer vgo.Close() 31 | 32 | // Output some data of the VG 33 | fmt.Printf("size: %d GiB\n", uint64(vgo.GetSize())/1024/1024/1024) 34 | fmt.Printf("pvlist: %v\n", vgo.ListPVs()) 35 | fmt.Printf("Free size: %d KiB\n", uint64(vgo.GetFreeSize())/1024/1024) 36 | 37 | // Create a LV object 38 | l := &lvm.LvObject{} 39 | 40 | // Create a LV 41 | l, err := vgo.CreateLvLinear("go-lvm-example-test-lv", int64(vgo.GetFreeSize())/1024/1024/2) 42 | if err != nil { 43 | fmt.Printf("error: %v") 44 | return 45 | } 46 | 47 | // Output uuid of LV 48 | fmt.Printf("Created\n\tuuid: %s\n\tname: %s\n\tattr: %s\n\torigin: %s\n", 49 | l.GetUuid(), l.GetName(), l.GetAttr(), l.GetOrigin()) 50 | 51 | // Output uuid of LV 52 | l.Remove() 53 | } 54 | -------------------------------------------------------------------------------- /doc.go: -------------------------------------------------------------------------------- 1 | // Package lvm provides API access to liblvm 2 | package lvm 3 | -------------------------------------------------------------------------------- /example_test.go: -------------------------------------------------------------------------------- 1 | package lvm_test 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/nak3/go-lvm" 7 | ) 8 | 9 | // This example demonstrates creating and removing a Logical Volume(LV). 10 | func ExampleLvObject_createremove() { 11 | // List volume group 12 | vglist := lvm.ListVgNames() 13 | availableVG := "" 14 | 15 | // Create a VG object 16 | vgo := &lvm.VgObject{} 17 | for i := 0; i < len(vglist); i++ { 18 | vgo.Vgt = lvm.VgOpen(vglist[i], "r") 19 | if vgo.GetFreeSize() > 0 { 20 | availableVG = vglist[i] 21 | vgo.Close() 22 | break 23 | } 24 | vgo.Close() 25 | } 26 | if availableVG == "" { 27 | fmt.Printf("no VG that has free space found\n") 28 | return 29 | } 30 | 31 | // Open VG in write mode 32 | vgo.Vgt = lvm.VgOpen(availableVG, "w") 33 | defer vgo.Close() 34 | 35 | // Create a LV object 36 | l := &lvm.LvObject{} 37 | 38 | // Create a LV 39 | l, err := vgo.CreateLvLinear("go-lvm-example-test-lv", int64(vgo.GetFreeSize())/1024/1024/2) 40 | if err != nil { 41 | fmt.Printf("error: %v") 42 | return 43 | } 44 | 45 | // Output uuid of LV 46 | fmt.Printf("Created\n\tuuid: %s\n\tname: %s\n\tattr: %s\n\torigin: %s\n", 47 | l.GetUuid(), l.GetName(), l.GetAttr(), l.GetOrigin()) 48 | // Output uuid of LV 49 | l.Remove() 50 | 51 | /* 52 | Created 53 | uuid: cn631J-J2GR-DL0l-3G38-MfGm-8ypc-iHskGI 54 | name: go-lvm-example-test-lv 55 | attr: -wi-a----- 56 | origin: 57 | */ 58 | } 59 | -------------------------------------------------------------------------------- /liblvm.go: -------------------------------------------------------------------------------- 1 | package lvm 2 | 3 | //#cgo LDFLAGS: -llvm2app 4 | //#include "macro_wrapper.h" 5 | import "C" 6 | import ( 7 | "fmt" 8 | "unsafe" 9 | ) 10 | 11 | var libh *C.struct_lvm 12 | 13 | func init() { 14 | libh = C.lvm_init(nil) 15 | } 16 | 17 | // ######################## LVM methods ####################### 18 | 19 | // GetVersion returns library version 20 | func GetVersion() *C.char { 21 | return C.lvm_library_get_version() 22 | } 23 | 24 | // GC cleans up libh 25 | func GC() { 26 | C.lvm_quit(libh) 27 | libh = nil 28 | } 29 | 30 | //VgOpen opens volume group 31 | func VgOpen(vgname string, mode string) C.vg_t { 32 | if mode == "" { 33 | mode = "r" 34 | } 35 | vg := C.lvm_vg_open(libh, C.CString(vgname), C.CString(mode), 0) 36 | return vg 37 | } 38 | 39 | //VgCreate creates VG 40 | func VgCreate(vgname string) C.vg_t { 41 | return C.lvm_vg_create(libh, C.CString(vgname)) 42 | } 43 | 44 | // ConfigFind checks if config could be found or not. 45 | func ConfigFind(config string) (bool, error) { 46 | rval := C.lvm_config_find_bool(libh, C.CString(config), -10) 47 | if rval == -10 { 48 | return false, fmt.Errorf("config path not found") 49 | } 50 | if C.int(rval) == 0 { 51 | return false, nil 52 | } 53 | return true, nil 54 | } 55 | 56 | // ConfigReload reloads config. 57 | func ConfigReload(config string) error { 58 | if C.lvm_config_reload(libh) == -1 { 59 | return getLastError() 60 | } 61 | return nil 62 | } 63 | 64 | // ConfigOverride overrides config. 65 | func ConfigOverride(config string) error { 66 | if C.lvm_config_override(libh, C.CString(config)) == -1 { 67 | return getLastError() 68 | } 69 | return nil 70 | } 71 | 72 | // Scan scans libh 73 | func Scan() { 74 | C.lvm_scan(libh) 75 | } 76 | 77 | // ListVgNames returns LVM name list 78 | func ListVgNames() []string { 79 | vgnames := C.lvm_list_vg_names(libh) 80 | if vgnames != nil { 81 | // TODO 82 | fmt.Printf("nil\n") 83 | } 84 | cargs := C.makeCharArray(C.int(0)) 85 | n := C.wrapper_dm_list_iterate_items(vgnames, cargs) 86 | gs := goStrings(n, cargs) 87 | return gs 88 | } 89 | 90 | // ListVgUUIDs returns LVM uuid list 91 | func ListVgUUIDs() []string { 92 | uuids := C.lvm_list_vg_uuids(libh) 93 | if uuids != nil { 94 | // TODO 95 | fmt.Printf("nil\n") 96 | } 97 | cargs := C.makeCharArray(C.int(0)) 98 | n := C.wrapper_dm_list_iterate_items(uuids, cargs) 99 | gs := goStrings(n, cargs) 100 | return gs 101 | } 102 | 103 | //PvCreate creates PV 104 | func PvCreate(pv_name string, size uint64, pvmetadatacopies uint64, pvmetadatasize uint64, 105 | data_alignment uint64, data_alignment_offset uint64, zero uint64) C.vg_t { 106 | pv_params := C.lvm_pv_params_create(libh, C.CString(pv_name)) 107 | if pv_params != nil { 108 | // TODO 109 | } 110 | 111 | // TODO return error 112 | C.wrapper_set_pv_prop(pv_params, C.CString("size"), C.longlong(size)) 113 | C.wrapper_set_pv_prop(pv_params, C.CString("size"), C.longlong(size)) 114 | C.wrapper_set_pv_prop(pv_params, C.CString("pvmetadatacopies"), C.longlong(pvmetadatacopies)) 115 | C.wrapper_set_pv_prop(pv_params, C.CString("pvmetadatasize"), C.longlong(pvmetadatasize)) 116 | C.wrapper_set_pv_prop(pv_params, C.CString("data_alignment"), C.longlong(data_alignment)) 117 | C.wrapper_set_pv_prop(pv_params, C.CString("data_alignment_offset"), C.longlong(data_alignment_offset)) 118 | C.wrapper_set_pv_prop(pv_params, C.CString("zero"), C.longlong(zero)) 119 | 120 | C.lvm_pv_create_adv(pv_params) 121 | // TODO 122 | return nil 123 | } 124 | 125 | // PvRemove removes PV. 126 | func PvRemove(pv_name string) { 127 | C.lvm_pv_remove(libh, C.CString(pv_name)) 128 | } 129 | 130 | // PercentToFloat converts percent to float. 131 | func PercentToFloat(percent C.percent_t) C.float { 132 | // TODO C.percent_t should be golang type. 133 | return C.lvm_percent_to_float(percent) 134 | } 135 | 136 | // VgNameValidate validates if the vg name is valid. 137 | func VgNameValidate(name string) error { 138 | ret := C.lvm_vg_name_validate(libh, C.CString(name)) 139 | if ret < 0 { 140 | return getLastError() 141 | } 142 | return nil 143 | } 144 | 145 | // VgNameFromPvID returns VG name from PVID. 146 | func VgNameFromPvID(pvid string) *C.char { 147 | ret := C.lvm_vgname_from_pvid(libh, C.CString(pvid)) 148 | // TODO 149 | msg := C.lvm_errmsg(libh) 150 | fmt.Printf("msg : %#v\n", C.GoString(msg)) 151 | return ret 152 | } 153 | 154 | // VgNameFromPvDevice returns VG name from PV device. 155 | func VgNameFromPvDevice(pvdevice string) string { 156 | ret := C.lvm_vgname_from_device(libh, C.CString(pvdevice)) 157 | if ret == nil { 158 | // TODO 159 | // return getLastError() 160 | } 161 | return C.GoString(ret) 162 | } 163 | 164 | // ######################## vg methods ####################### 165 | 166 | // VgObject is an object of VG. 167 | type VgObject struct { 168 | Vgt C.vg_t 169 | } 170 | 171 | // GetName gets name of VG. 172 | func (v *VgObject) GetName() string { 173 | return C.GoString(C.lvm_vg_get_name(v.Vgt)) 174 | } 175 | 176 | // GetUuid gets UUID of VG. 177 | func (v *VgObject) GetUuid() *C.char { 178 | return C.lvm_vg_get_uuid(v.Vgt) 179 | } 180 | 181 | // Close closes VG object. 182 | func (v *VgObject) Close() error { 183 | if C.lvm_vg_close(v.Vgt) == -1 { 184 | return getLastError() 185 | } 186 | return nil 187 | } 188 | 189 | // Remove removes VG. 190 | func (v *VgObject) Remove() error { 191 | if C.lvm_vg_remove(v.Vgt) == -1 { 192 | return getLastError() 193 | } 194 | if C.lvm_vg_write(v.Vgt) == -1 { 195 | return getLastError() 196 | } 197 | return v.Close() 198 | } 199 | 200 | // Extend extends PV by adding vg. 201 | func (v *VgObject) Extend(device string) error { 202 | if C.lvm_vg_extend(v.Vgt, C.CString(device)) == -1 { 203 | return getLastError() 204 | } 205 | if C.lvm_vg_write(v.Vgt) == -1 { 206 | return getLastError() 207 | } 208 | return nil 209 | } 210 | 211 | // Reduce reduces VG from PV. 212 | func (v *VgObject) Reduce(device string) error { 213 | if C.lvm_vg_reduce(v.Vgt, C.CString(device)) == -1 { 214 | return getLastError() 215 | } 216 | if C.lvm_vg_write(v.Vgt) == -1 { 217 | return getLastError() 218 | } 219 | return nil 220 | } 221 | 222 | // AddTag adds tag to VG. 223 | func (v *VgObject) AddTag(stag string) error { 224 | tag := C.CString(stag) 225 | if C.lvm_vg_add_tag(v.Vgt, tag) == -1 { 226 | return getLastError() 227 | } 228 | if C.lvm_vg_write(v.Vgt) == -1 { 229 | return getLastError() 230 | } 231 | return nil 232 | } 233 | 234 | // RemoveTag removes tag from VG. 235 | func (v *VgObject) RemoveTag(stag string) error { 236 | tag := C.CString(stag) 237 | if C.lvm_vg_remove_tag(v.Vgt, tag) == -1 { 238 | return getLastError() 239 | } 240 | if C.lvm_vg_write(v.Vgt) == -1 { 241 | return getLastError() 242 | } 243 | return nil 244 | } 245 | 246 | // SetExtentSize sets extent size. 247 | func (v *VgObject) SetExtentSize(size uint32) error { 248 | if C.lvm_vg_set_extent_size(v.Vgt, C.uint32_t(size)) == 1 { 249 | return getLastError() 250 | } 251 | return nil 252 | } 253 | 254 | // IsClustered checks clustered or not. 255 | func (v *VgObject) IsClustered() bool { 256 | if C.lvm_vg_is_clustered(v.Vgt) == 1 { 257 | return true 258 | } 259 | return false 260 | } 261 | 262 | // IsExported checks exported or not. 263 | func (v *VgObject) IsExported() bool { 264 | if C.lvm_vg_is_exported(v.Vgt) == 1 { 265 | return true 266 | } 267 | return false 268 | } 269 | 270 | // IsPartial checks partial or not. 271 | func (v *VgObject) IsPartial() bool { 272 | if C.lvm_vg_is_partial(v.Vgt) == 1 { 273 | return true 274 | } 275 | return false 276 | } 277 | 278 | // GetSeqno returns sequence number of VG. 279 | func (v *VgObject) GetSeqno() C.uint64_t { 280 | return C.lvm_vg_get_seqno(v.Vgt) 281 | } 282 | 283 | // GetSize returns size of VG 284 | func (v *VgObject) GetSize() C.uint64_t { 285 | return C.lvm_vg_get_size(v.Vgt) 286 | } 287 | 288 | // GetFreeSize returns free size of VG 289 | func (v *VgObject) GetFreeSize() C.uint64_t { 290 | return C.lvm_vg_get_free_size(v.Vgt) 291 | } 292 | 293 | // GetExtentSize returns extent size of VG. 294 | func (v *VgObject) GetExtentSize() C.uint64_t { 295 | return C.lvm_vg_get_extent_size(v.Vgt) 296 | } 297 | 298 | // GetExtentCount returns extent count of VG. 299 | func (v *VgObject) GetExtentCount() C.uint64_t { 300 | return C.lvm_vg_get_extent_count(v.Vgt) 301 | } 302 | 303 | // GetFreeExtentCount returns free extent count of VG. 304 | func (v *VgObject) GetFreeExtentCount() C.uint64_t { 305 | return C.lvm_vg_get_free_extent_count(v.Vgt) 306 | } 307 | 308 | // GetProperty returns properties of VG. 309 | func (v *VgObject) GetProperty(name string) (properties, error) { 310 | prop_value := C.lvm_vg_get_property(v.Vgt, C.CString(name)) 311 | return get_property(&prop_value) 312 | } 313 | 314 | // { "setProperty", (PyCFunction)_liblvm_lvm_vg_set_property, METH_VARARGS }, 315 | 316 | // GePvCount returns the number of PV. 317 | func (v *VgObject) GetPvCont() C.uint64_t { 318 | return C.lvm_vg_get_pv_count(v.Vgt) 319 | } 320 | 321 | // GetMaxPv returns maximum value of PV. 322 | func (v *VgObject) GetMaxPv() C.uint64_t { 323 | return C.lvm_vg_get_max_pv(v.Vgt) 324 | } 325 | 326 | // GetMaxPv returns maximum value of LV. 327 | func (v *VgObject) GetMaxLV() C.uint64_t { 328 | return C.lvm_vg_get_max_lv(v.Vgt) 329 | } 330 | 331 | // ListLVs lists of lvs from VG 332 | func (v *VgObject) ListLVs() []string { 333 | lvl := C.lvm_vg_list_lvs(v.Vgt) 334 | if lvl == nil { 335 | return []string{""} 336 | } 337 | cargs := C.makeCharArray(C.int(0)) 338 | n := C.wrapper_dm_list_iterate_items(lvl, cargs) 339 | gs := goStrings(n, cargs) 340 | fmt.Printf("(test)lvList: %#v\n", gs) 341 | return gs 342 | } 343 | 344 | // ListPVs lists of pvs from VG 345 | func (v *VgObject) ListPVs() []string { 346 | pvs := C.lvm_vg_list_pvs(v.Vgt) 347 | if pvs == nil { 348 | return []string{""} 349 | } 350 | cargs := C.makeCharArray(C.int(0)) 351 | n := C.wrapper_dm_list_iterate_items(pvs, cargs) 352 | gs := goStrings(n, cargs) 353 | fmt.Printf("(test)pvsList: %#v\n", gs) 354 | return gs 355 | } 356 | 357 | // pv_from_N returns PV. 358 | func lv_from_N(vg *C.struct_volume_group, id *C.char, pvg *VgObject, f func(*C.struct_volume_group, *C.char) C.lv_t) (*LvObject, error) { 359 | lv := f(vg, id) 360 | if lv == nil { 361 | return nil, getLastError() 362 | } 363 | return &LvObject{ 364 | Lvt: lv, 365 | parentVG: pvg, 366 | }, nil 367 | } 368 | 369 | // TODO: test 370 | // LvFromName returns LV object from name of VG. 371 | func (v *VgObject) LvFromName(sname string) (*LvObject, error) { 372 | name := C.CString(sname) 373 | return lv_from_N(v.Vgt, name, v, func(vg *C.struct_volume_group, id *C.char) C.lv_t { 374 | return C.lvm_lv_from_name(vg, name) 375 | }) 376 | } 377 | 378 | // LvFromUuid returns LV object from UUID of VG. 379 | func (v *VgObject) LvFromUuid(suuid string) (*LvObject, error) { 380 | uuid := C.CString(suuid) 381 | return lv_from_N(v.Vgt, uuid, v, func(vg *C.struct_volume_group, id *C.char) C.lv_t { 382 | return C.lvm_lv_from_uuid(vg, uuid) 383 | }) 384 | } 385 | 386 | // LvNameValidate validates if the lv name is valid inside VG. 387 | func (v *VgObject) LvNameValidate(name string) error { 388 | ret := C.lvm_lv_name_validate(v.Vgt, C.CString(name)) 389 | if ret < 0 { 390 | return getLastError() 391 | } 392 | return nil 393 | } 394 | 395 | // pv_from_N returns PV. 396 | func pv_from_N(vg *C.struct_volume_group, id *C.char, f func(*C.struct_volume_group, *C.char) C.pv_t) (*PvObject, error) { 397 | pv := f(vg, id) 398 | if pv == nil { 399 | return nil, getLastError() 400 | } 401 | return &PvObject{pv}, nil 402 | } 403 | 404 | // TODO: test 405 | // PvFromName returns PV object from VGName 406 | func (v *VgObject) PvFromName(sname string) (*PvObject, error) { 407 | name := C.CString(sname) 408 | return pv_from_N(v.Vgt, name, func(vg *C.struct_volume_group, id *C.char) C.pv_t { 409 | return C.lvm_pv_from_name(vg, name) 410 | }) 411 | } 412 | 413 | // PvFromUuid returns PV object from uuid. 414 | func (v *VgObject) PvFromUuid(sid string) (*PvObject, error) { 415 | id := C.CString(sid) 416 | return pv_from_N(v.Vgt, id, func(vg *C.struct_volume_group, id *C.char) C.pv_t { 417 | return C.lvm_pv_from_uuid(vg, id) 418 | }) 419 | } 420 | 421 | // GetTags returns tag list of LV. 422 | func (v *VgObject) GetTags() []string { 423 | tagsl := C.lvm_vg_get_tags(v.Vgt) 424 | // TODO: should check error? 425 | if tagsl == nil { 426 | return []string{""} 427 | } 428 | // TODO?: dm_list_size(vgnames?) 429 | cargs := C.makeCharArray(C.int(0)) 430 | n := C.wrapper_dm_list_iterate_items(tagsl, cargs) 431 | gs := goStrings(n, cargs) 432 | return gs 433 | } 434 | 435 | // createGoLv creats a LV Object 436 | func createGoLv(v *VgObject, lv C.lv_t) *LvObject { 437 | return &LvObject{ 438 | Lvt: lv, 439 | parentVG: v, 440 | } 441 | } 442 | 443 | // CreateLvLinear creates LV Object. 444 | func (v *VgObject) CreateLvLinear(n string, s int64) (*LvObject, error) { 445 | size := C.uint64_t(s) 446 | name := C.CString(n) 447 | 448 | lv := C.lvm_vg_create_lv_linear(v.Vgt, name, size) 449 | if lv == nil { 450 | return nil, getLastError() 451 | } 452 | return createGoLv(v, lv), nil 453 | } 454 | 455 | // { "createLvThinpool", (PyCFunction)_liblvm_lvm_vg_create_lv_thinpool, METH_VARARGS }, 456 | // { "createLvThin", (PyCFunction)_liblvm_lvm_vg_create_lv_thin, METH_VARARGS }, 457 | 458 | // ######################################## LV methods ################################### 459 | 460 | // LvObject represents LV. 461 | type LvObject struct { 462 | Lvt C.lv_t 463 | parentVG *VgObject 464 | } 465 | 466 | // GetAttr gets LV attr 467 | func (l *LvObject) GetAttr() string { 468 | return C.GoString(C.lvm_lv_get_attr(l.Lvt)) 469 | } 470 | 471 | // GetName gets LV name 472 | func (l *LvObject) GetName() string { 473 | return C.GoString(C.lvm_lv_get_name(l.Lvt)) 474 | } 475 | 476 | // GetOrigin gets LV origin 477 | func (l *LvObject) GetOrigin() string { 478 | return C.GoString(C.lvm_lv_get_origin(l.Lvt)) 479 | } 480 | 481 | // GetUuid gets LV uuid 482 | func (l *LvObject) GetUuid() string { 483 | return C.GoString(C.lvm_lv_get_uuid(l.Lvt)) 484 | } 485 | 486 | // Activate activates LV. 487 | func (l *LvObject) Activate() error { 488 | if C.lvm_lv_activate(l.Lvt) == -1 { 489 | return getLastError() 490 | } 491 | return nil 492 | } 493 | 494 | // Deactivate deactivates LV. 495 | func (l *LvObject) Deactivate() error { 496 | if C.lvm_lv_deactivate(l.Lvt) == -1 { 497 | return getLastError() 498 | } 499 | return nil 500 | } 501 | 502 | // Remove removes LV. 503 | func (l *LvObject) Remove() error { 504 | if C.lvm_vg_remove_lv(l.Lvt) == -1 { 505 | return getLastError() 506 | } 507 | return nil 508 | } 509 | 510 | // properties represents variety of properties. 511 | type properties struct { 512 | signed_integer int 513 | integer int 514 | str string 515 | } 516 | 517 | // get_property returns properties. 518 | func get_property(prop *C.struct_lvm_property_value) (properties, error) { 519 | var p properties 520 | if C.is_valid(unsafe.Pointer(prop)) == 0 { 521 | return p, getLastError() 522 | } 523 | 524 | if C.is_integer(unsafe.Pointer(prop)) != 0 { 525 | if C.is_signed(unsafe.Pointer(prop)) != 0 { 526 | // TODO 527 | } else { 528 | // TODO 529 | } 530 | } else { 531 | // TODO 532 | } 533 | return p, nil 534 | } 535 | 536 | // GetProperty returns properties of LV. 537 | func (l *LvObject) GetProperty(name string) (properties, error) { 538 | prop_value := C.lvm_lv_get_property(l.Lvt, C.CString(name)) 539 | return get_property(&prop_value) 540 | } 541 | 542 | // GetSize returns size of LV. 543 | func (l *LvObject) GetSize() C.uint64_t { 544 | return C.lvm_lv_get_size(l.Lvt) 545 | } 546 | 547 | // IsActive checks active LV or not. 548 | func (l *LvObject) IsActive() bool { 549 | if C.lvm_lv_is_active(l.Lvt) == 1 { 550 | return true 551 | } 552 | return false 553 | } 554 | 555 | // IsSuspended checks suspended LV or not. 556 | func (l *LvObject) IsSuspended() bool { 557 | if C.lvm_lv_is_suspended(l.Lvt) == 1 { 558 | return true 559 | } 560 | return false 561 | } 562 | 563 | // AddTag adds tag to LV. 564 | func (l *LvObject) AddTag(stag string) error { 565 | tag := C.CString(stag) 566 | if C.lvm_lv_add_tag(l.Lvt, tag) == -1 { 567 | return getLastError() 568 | } 569 | if C.lvm_vg_write(l.parentVG.Vgt) == -1 { 570 | return getLastError() 571 | } 572 | return nil 573 | } 574 | 575 | // RemoveTag removes tag from LV. 576 | func (l *LvObject) RemoveTag(stag string) error { 577 | tag := C.CString(stag) 578 | if C.lvm_lv_remove_tag(l.Lvt, tag) == -1 { 579 | return getLastError() 580 | } 581 | if C.lvm_vg_write(l.parentVG.Vgt) == -1 { 582 | return getLastError() 583 | } 584 | return nil 585 | } 586 | 587 | // GetTags returns tag list of LV. 588 | func (l *LvObject) GetTags() []string { 589 | tagsl := C.lvm_lv_get_tags(l.Lvt) 590 | // TODO: should check error? 591 | if tagsl == nil { 592 | return []string{""} 593 | } 594 | // TODO?: dm_list_size(vgnames?) 595 | cargs := C.makeCharArray(C.int(0)) 596 | n := C.wrapper_dm_list_iterate_items(tagsl, cargs) 597 | gs := goStrings(n, cargs) 598 | return gs 599 | } 600 | 601 | // Rename rename the name of LV. 602 | func (l *LvObject) Rename(name string) error { 603 | if C.lvm_lv_rename(l.Lvt, C.CString(name)) == -1 { 604 | return getLastError() 605 | } 606 | return nil 607 | } 608 | 609 | // Resize resizes the size of LV. 610 | func (l *LvObject) Resize(size uint64) error { 611 | if C.lvm_lv_resize(l.Lvt, C.uint64_t(size)) == -1 { 612 | return getLastError() 613 | } 614 | return nil 615 | } 616 | 617 | // { "listLVsegs", (PyCFunction)_liblvm_lvm_lv_list_lvsegs, METH_NOARGS }, 618 | 619 | // Snapshot creates a LV snapshot. 620 | func (l *LvObject) Snapshot(snapname string, size uint64) (*LvObject, error) { 621 | 622 | lvp := C.lvm_lv_params_create_snapshot(l.Lvt, C.CString(snapname), C.uint64_t(size)) 623 | if lvp == nil { 624 | return nil, getLastError() 625 | } 626 | lv := C.lvm_lv_create(lvp) 627 | if lv == nil { 628 | return nil, getLastError() 629 | } 630 | return createGoLv(l.parentVG, lv), nil 631 | } 632 | 633 | // ######################## pv list methods ####################### 634 | 635 | // Open lists PVs and get them as string array. 636 | func Open() []string { 637 | pvsList := C.lvm_list_pvs(libh) 638 | fmt.Printf("pvsList: %#v\n", pvsList) 639 | 640 | cargs := C.makeCharArray(C.int(0)) 641 | n := C.wrapper_dm_list_iterate_items(pvsList, cargs) 642 | gs := goStrings(n, cargs) 643 | return gs 644 | } 645 | 646 | // Close frees list of PVs. 647 | func Close(pvs []string) { 648 | // TODO 649 | if len(pvs) > 0 { 650 | //C.lvm_list_pvs_free(pvs) 651 | } 652 | } 653 | 654 | // ######################## pv methods ####################### 655 | 656 | // pvObject represents PV. 657 | type PvObject struct { 658 | Pvt C.pv_t 659 | } 660 | 661 | // GetName returns name of the PV. 662 | func (p *PvObject) GetName() string { 663 | return C.GoString(C.lvm_pv_get_name(p.Pvt)) 664 | } 665 | 666 | // GetUuid returns UUID of the PV. 667 | func (p *PvObject) GetUuid() string { 668 | return C.GoString(C.lvm_pv_get_uuid(p.Pvt)) 669 | } 670 | 671 | // GetMdaCount returns metadata count. 672 | func (p *PvObject) GetMdaCount() C.uint64_t { 673 | return C.lvm_pv_get_mda_count(p.Pvt) 674 | } 675 | 676 | // GetProperty returns properties of PV. 677 | func (p *PvObject) GetProperty(name string) (properties, error) { 678 | prop_value := C.lvm_pv_get_property(p.Pvt, C.CString(name)) 679 | return get_property(&prop_value) 680 | } 681 | 682 | // GetSize returns size of PV. 683 | func (p *PvObject) GetSize() C.uint64_t { 684 | return C.lvm_pv_get_size(p.Pvt) 685 | } 686 | 687 | // GetDevSize returns free size of PV. 688 | func (p *PvObject) GetDevSize() C.uint64_t { 689 | return C.lvm_pv_get_size(p.Pvt) 690 | } 691 | 692 | // GetFreeSize returns free size of PV. 693 | func (p *PvObject) GetFreeSize() C.uint64_t { 694 | return C.lvm_pv_get_free(p.Pvt) 695 | } 696 | 697 | // Resize resizes the size of PV. 698 | func (p *PvObject) Resize(size uint64) error { 699 | if C.lvm_pv_resize(p.Pvt, C.uint64_t(size)) == -1 { 700 | return getLastError() 701 | } 702 | return nil 703 | } 704 | 705 | // { "listPVsegs", (PyCFunction)_liblvm_lvm_pv_list_pvsegs, METH_NOARGS }, 706 | 707 | // ######################## utility methods ####################### 708 | func goStrings(argc C.int, argv **C.char) []string { 709 | // TODO nConstraint 710 | length := int(argc) 711 | tmpslice := (*[1 << 30]*C.char)(unsafe.Pointer(argv))[:length:length] 712 | gostrings := make([]string, length) 713 | for i, s := range tmpslice { 714 | gostrings[i] = C.GoString(s) 715 | } 716 | return gostrings 717 | } 718 | 719 | func getLastError() error { 720 | msg := C.GoString(C.lvm_errmsg(libh)) 721 | if msg == "" { 722 | return fmt.Errorf("unknown error") 723 | } 724 | return fmt.Errorf(msg) 725 | } 726 | -------------------------------------------------------------------------------- /macro_wrapper.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int wrapper_dm_list_iterate_items(struct dm_list *vgnames, char **r) 6 | { 7 | struct lvm_str_list *strl; 8 | int num = 0; 9 | dm_list_iterate_items(strl, vgnames) { 10 | printf("--> %s\n", strl->str); 11 | r[num] = (char*)strl->str; 12 | num++; 13 | } 14 | return num; 15 | } 16 | 17 | static int _set_pv_numeric_prop(pv_create_params_t pv_params, const char *name, 18 | unsigned long long value) 19 | { 20 | struct lvm_property_value prop_value = { 21 | .is_integer = 1, 22 | .value.integer = value, 23 | }; 24 | 25 | return lvm_pv_params_set_property(pv_params, name, &prop_value); 26 | } 27 | 28 | #define SET_PV_PROP(params, name, value) \ 29 | do { \ 30 | if (_set_pv_numeric_prop(params, name, value) == -1) \ 31 | goto error; \ 32 | } while(0)\ 33 | 34 | 35 | void wrapper_set_pv_prop(pv_create_params_t pv_params, char *name, long long value) { 36 | SET_PV_PROP(pv_params, name, value); 37 | error: 38 | // TODO 39 | return; 40 | } 41 | 42 | // C helper functions: 43 | char**makeCharArray(int size) { 44 | return calloc(sizeof(char*), size); 45 | } 46 | 47 | /* 48 | static void setArrayString(char **a, char *s, int n) { 49 | a[n] = s; 50 | } 51 | 52 | static void freeCharArray(char **a, int size) { 53 | int i; 54 | for (i = 0; i < size; i++) 55 | free(a[i]); 56 | free(a); 57 | } 58 | */ 59 | 60 | 61 | int is_valid(void* p) { 62 | lvm_property_value_t t = *(lvm_property_value_t *)p; 63 | return t.is_valid; 64 | } 65 | 66 | int is_integer(void* p) { 67 | lvm_property_value_t t = *(lvm_property_value_t *)p; 68 | return t.is_integer; 69 | } 70 | 71 | int is_signed(void* p) { 72 | lvm_property_value_t t = *(lvm_property_value_t *)p; 73 | return t.is_signed; 74 | } 75 | -------------------------------------------------------------------------------- /macro_wrapper.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | typedef char *names[]; 6 | 7 | struct result { 8 | char **namelist; 9 | }; 10 | 11 | int wrapper_dm_list_iterate_items(struct dm_list *vgnames, char **r); 12 | void wrapper_set_pv_prop(pv_create_params_t params, char *name, long long value); 13 | 14 | char**makeCharArray(int size); 15 | 16 | int is_valid(void* p); 17 | int is_integer(void* p); 18 | int is_signed(void* p); 19 | 20 | 21 | --------------------------------------------------------------------------------