github.com/mirantis/virtlet@v1.5.2-0.20191204181327-1659b8a48e9b/pkg/libvirttools/disklist.go (about) 1 /* 2 Copyright 2016-2017 Mirantis 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package libvirttools 18 19 import ( 20 "fmt" 21 "strings" 22 23 "github.com/golang/glog" 24 libvirtxml "github.com/libvirt/libvirt-go-xml" 25 26 "github.com/Mirantis/virtlet/pkg/metadata/types" 27 "github.com/Mirantis/virtlet/pkg/virt" 28 ) 29 30 type diskItem struct { 31 driver diskDriver 32 volume VMVolume 33 } 34 35 func (di *diskItem) setup(config *types.VMConfig) (*libvirtxml.DomainDisk, *libvirtxml.DomainFilesystem, error) { 36 diskDef, fsDef, err := di.volume.Setup() 37 if err != nil { 38 return nil, nil, err 39 } 40 if di.volume.IsDisk() { 41 if diskDef == nil { 42 panic("no disk for disk volume") 43 } 44 if fsDef != nil { 45 panic("got fsDef for disk volume") 46 } 47 } else { 48 if diskDef != nil { 49 panic("got disk for fs volume") 50 } 51 if fsDef == nil { 52 panic("no fsDef for fs volume") 53 } 54 } 55 if diskDef != nil { 56 diskDef.Target = di.driver.target() 57 diskDef.Address = di.driver.address() 58 } 59 return diskDef, fsDef, nil 60 } 61 62 type diskList struct { 63 config *types.VMConfig 64 items []*diskItem 65 } 66 67 // newDiskList creates a diskList for the specified types.VMConfig, volume 68 // source and volume owner 69 func newDiskList(config *types.VMConfig, source VMVolumeSource, owner volumeOwner) (*diskList, error) { 70 vmVols, err := source(config, owner) 71 if err != nil { 72 return nil, err 73 } 74 75 diskDriverFactory, err := getDiskDriverFactory(config.ParsedAnnotations.DiskDriver) 76 if err != nil { 77 return nil, err 78 } 79 var items []*diskItem 80 n := 0 81 for _, volume := range vmVols { 82 var driver diskDriver 83 if volume.IsDisk() { 84 driver, err = diskDriverFactory(n) 85 if err != nil { 86 return nil, err 87 } 88 n++ 89 } 90 items = append(items, &diskItem{driver, volume}) 91 } 92 93 return &diskList{config, items}, nil 94 } 95 96 // setup performs the setup procedure on each volume in the diskList 97 // and returns a list of libvirtxml DomainDisk and domainFileSystems structs 98 func (dl *diskList) setup() ([]libvirtxml.DomainDisk, []libvirtxml.DomainFilesystem, error) { 99 var domainDisks []libvirtxml.DomainDisk 100 var domainFileSystems []libvirtxml.DomainFilesystem 101 for n, item := range dl.items { 102 diskDef, fsDef, err := item.setup(dl.config) 103 if err != nil { 104 // try to tear down volumes that were already set up 105 for _, item := range dl.items[:n] { 106 if err := item.volume.Teardown(); err != nil { 107 glog.Warningf("Failed to tear down a volume on error: %v", err) 108 } 109 } 110 return nil, nil, err 111 } 112 if diskDef != nil { 113 domainDisks = append(domainDisks, *diskDef) 114 } 115 if fsDef != nil { 116 domainFileSystems = append(domainFileSystems, *fsDef) 117 } 118 } 119 return domainDisks, domainFileSystems, nil 120 } 121 122 // writeImages writes images for volumes that are based on generated 123 // images (such as cloud-init nocloud datasource). It must be passed 124 // a Domain for which images are being generated. 125 func (dl *diskList) writeImages(domain virt.Domain) error { 126 domainDesc, err := domain.XML() 127 if err != nil { 128 return fmt.Errorf("couldn't get domain xml: %v", err) 129 } 130 131 volumeMap := make(diskPathMap) 132 for _, item := range dl.items { 133 uuid := item.volume.UUID() 134 if uuid != "" && item.driver != nil { 135 diskPath, err := item.driver.diskPath(domainDesc) 136 if err != nil { 137 return err 138 } 139 volumeMap[uuid] = *diskPath 140 } 141 } 142 143 for _, item := range dl.items { 144 if err := item.volume.WriteImage(volumeMap); err != nil { 145 return err 146 } 147 } 148 149 return nil 150 } 151 152 func (dl *diskList) teardown() error { 153 var errs []string 154 for _, item := range dl.items { 155 if err := item.volume.Teardown(); err != nil { 156 errs = append(errs, err.Error()) 157 } 158 } 159 if errs != nil { 160 return fmt.Errorf("failed to tear down some of the volumes:\n%s", strings.Join(errs, "\n")) 161 } 162 return nil 163 }