github.com/Mirantis/virtlet@v1.5.2-0.20191204181327-1659b8a48e9b/pkg/libvirttools/raw_flexvolume.go (about) 1 /* 2 Copyright 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 "path/filepath" 22 "strings" 23 24 libvirtxml "github.com/libvirt/libvirt-go-xml" 25 26 "github.com/Mirantis/virtlet/pkg/metadata/types" 27 "github.com/Mirantis/virtlet/pkg/utils" 28 ) 29 30 type rawVolumeOptions struct { 31 Path string `json:"path"` 32 UUID string `json:"uuid"` 33 } 34 35 func (vo *rawVolumeOptions) validate() error { 36 if !strings.HasPrefix(vo.Path, "/dev/") { 37 return fmt.Errorf("raw volume path needs to be prefixed by '/dev/', but it's whole value is: %s", vo.Path) 38 } 39 return nil 40 } 41 42 // rawDeviceVolume denotes a raw device that's made accessible for a VM 43 type rawDeviceVolume struct { 44 volumeBase 45 opts *rawVolumeOptions 46 } 47 48 var _ VMVolume = &rawDeviceVolume{} 49 50 func newRawDeviceVolume(volumeName, configPath string, config *types.VMConfig, owner volumeOwner) (VMVolume, error) { 51 var opts rawVolumeOptions 52 if err := utils.ReadJSON(configPath, &opts); err != nil { 53 return nil, fmt.Errorf("failed to parse raw volume config %q: %v", configPath, err) 54 } 55 if err := opts.validate(); err != nil { 56 return nil, err 57 } 58 return &rawDeviceVolume{ 59 volumeBase: volumeBase{config, owner}, 60 opts: &opts, 61 }, nil 62 } 63 64 func (v *rawDeviceVolume) verifyRawDeviceWhitelisted(path string) error { 65 for _, deviceTemplate := range v.owner.RawDevices() { 66 matches, err := filepath.Match("/dev/"+deviceTemplate, path) 67 if err != nil { 68 return fmt.Errorf("bad raw device whitelist glob pattern '%s': %v", deviceTemplate, err) 69 } 70 if matches { 71 return nil 72 } 73 } 74 return fmt.Errorf("device '%s' not whitelisted on this virtlet node", path) 75 } 76 77 func (v *rawDeviceVolume) IsDisk() bool { return true } 78 79 func (v *rawDeviceVolume) UUID() string { 80 return v.opts.UUID 81 } 82 83 func (v *rawDeviceVolume) Setup() (*libvirtxml.DomainDisk, *libvirtxml.DomainFilesystem, error) { 84 if err := v.verifyRawDeviceWhitelisted(v.opts.Path); err != nil { 85 return nil, nil, err 86 } 87 88 if err := verifyRawDeviceAccess(v.opts.Path); err != nil { 89 return nil, nil, err 90 } 91 return &libvirtxml.DomainDisk{ 92 Device: "disk", 93 Source: &libvirtxml.DomainDiskSource{Block: &libvirtxml.DomainDiskSourceBlock{Dev: v.opts.Path}}, 94 Driver: &libvirtxml.DomainDiskDriver{Name: "qemu", Type: "raw"}, 95 }, nil, nil 96 } 97 98 func init() { 99 addFlexvolumeSource("raw", newRawDeviceVolume) 100 } 101 102 // TODO: this file needs a test