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  }