yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/esxi/storagecache.go (about)

     1  // Copyright 2019 Yunion
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package esxi
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  	"path"
    21  	"regexp"
    22  
    23  	"yunion.io/x/jsonutils"
    24  	"yunion.io/x/log"
    25  	"yunion.io/x/pkg/errors"
    26  
    27  	"yunion.io/x/cloudmux/pkg/cloudprovider"
    28  	"yunion.io/x/onecloud/pkg/mcclient"
    29  	"yunion.io/x/cloudmux/pkg/multicloud"
    30  )
    31  
    32  const (
    33  	IMAGE_CACHE_DIR_NAME = "image_cache"
    34  )
    35  
    36  type SDatastoreImageCache struct {
    37  	multicloud.SResourceBase
    38  	multicloud.STagBase
    39  	datastore *SDatastore
    40  	host      *SHost
    41  }
    42  
    43  type EsxiOptions struct {
    44  	ReasonableCIDREsxi string `help:"Reasonable CIDR in esxi, such as '10.0.0.0/8'" defautl:""`
    45  	TemplateNameRegex  string `help:"Regex of template name"`
    46  }
    47  
    48  var tempalteNameRegex *regexp.Regexp
    49  
    50  func InitEsxiConfig(opt EsxiOptions) error {
    51  	var err error
    52  	if len(opt.TemplateNameRegex) != 0 {
    53  		tempalteNameRegex, err = regexp.Compile(opt.TemplateNameRegex)
    54  		if err != nil {
    55  			return errors.Wrap(err, "regexp.Compile")
    56  		}
    57  	}
    58  	return initVMIPV4Filter(opt.ReasonableCIDREsxi)
    59  }
    60  
    61  func (self *SDatastoreImageCache) GetId() string {
    62  	if self.host != nil {
    63  		return self.host.GetGlobalId()
    64  	} else {
    65  		return self.datastore.GetGlobalId()
    66  	}
    67  }
    68  
    69  func (self *SDatastoreImageCache) GetName() string {
    70  	if self.host != nil {
    71  		return fmt.Sprintf("storage-cache-%s", self.host.GetName())
    72  	} else {
    73  		return fmt.Sprintf("storage-cache-%s", self.datastore.GetName())
    74  	}
    75  }
    76  
    77  func (self *SDatastoreImageCache) GetGlobalId() string {
    78  	return self.GetId()
    79  }
    80  
    81  func (self *SDatastoreImageCache) GetStatus() string {
    82  	return "available"
    83  }
    84  
    85  func (self *SDatastoreImageCache) Refresh() error {
    86  	return nil
    87  }
    88  
    89  func (self *SDatastoreImageCache) IsEmulated() bool {
    90  	return false
    91  }
    92  
    93  func (self *SDatastoreImageCache) GetPath() string {
    94  	return path.Join(self.datastore.GetMountPoint(), IMAGE_CACHE_DIR_NAME)
    95  }
    96  
    97  func (self *SDatastoreImageCache) getTempalteVMs() ([]*SVirtualMachine, error) {
    98  	return self.datastore.FetchTemplateVMs()
    99  }
   100  
   101  func (self *SDatastoreImageCache) getFakeTempateVMs() ([]*SVirtualMachine, error) {
   102  	if tempalteNameRegex == nil {
   103  		return nil, nil
   104  	}
   105  	return self.datastore.FetchFakeTempateVMs("")
   106  }
   107  
   108  func (self *SDatastoreImageCache) GetIImageInImagecache() ([]cloudprovider.ICloudImage, error) {
   109  	ctx := context.Background()
   110  	ret := make([]cloudprovider.ICloudImage, 0, 2)
   111  	files, err := self.datastore.ListDir(ctx, IMAGE_CACHE_DIR_NAME)
   112  	if errors.Cause(err) == errors.ErrNotFound {
   113  		return ret, nil
   114  	}
   115  	if err != nil {
   116  		log.Errorf("GetIImages ListDir fail %s", err)
   117  		return ret, nil
   118  	}
   119  
   120  	validFilenames := make(map[string]bool)
   121  
   122  	for i := 0; i < len(files); i += 1 {
   123  		filename := path.Join(IMAGE_CACHE_DIR_NAME, files[i].Name)
   124  		if err := self.datastore.CheckVmdk(ctx, filename); err != nil {
   125  			continue
   126  		}
   127  		vmdkInfo, err := self.datastore.GetVmdkInfo(ctx, filename)
   128  		if err != nil {
   129  			continue
   130  		}
   131  		image := SImage{
   132  			cache:    self,
   133  			filename: filename,
   134  			size:     vmdkInfo.Size(),
   135  			createAt: files[i].Date,
   136  		}
   137  		ret = append(ret, &image)
   138  		vmdkName := files[i].Name
   139  		vmdkExtName := fmt.Sprintf("%s-flat.vmdk", vmdkName[:len(vmdkName)-5])
   140  		validFilenames[vmdkName] = true
   141  		validFilenames[vmdkExtName] = true
   142  	}
   143  
   144  	log.Debugf("storage cache contains %#v", validFilenames)
   145  	// cleanup storage cache!!!
   146  	for i := 0; i < len(files); i += 1 {
   147  		if _, ok := validFilenames[files[i].Name]; !ok {
   148  			log.Debugf("delete invalid vmdk file %s!!!", files[i].Name)
   149  			self.datastore.Delete(ctx, path.Join(IMAGE_CACHE_DIR_NAME, files[i].Name))
   150  		}
   151  	}
   152  
   153  	return ret, nil
   154  }
   155  
   156  var ErrTimeConsuming = errors.Error("time consuming")
   157  
   158  func (self *SDatastoreImageCache) getTemplateVMsFromCache() ([]*SVirtualMachine, error) {
   159  	ihosts, err := self.datastore.datacenter.GetIHosts()
   160  	if err != nil {
   161  		return nil, err
   162  	}
   163  	dsRef := self.datastore.getDatastore().Self
   164  	ret := make([]*SVirtualMachine, 0)
   165  	for i := range ihosts {
   166  		tvms := ihosts[i].(*SHost).tempalteVMs
   167  		if tvms == nil {
   168  			return nil, ErrTimeConsuming
   169  		}
   170  		for _, vm := range tvms {
   171  			dss := vm.getVirtualMachine().Datastore
   172  			for _, ds := range dss {
   173  				if ds == dsRef {
   174  					ret = append(ret, vm)
   175  					break
   176  				}
   177  			}
   178  		}
   179  	}
   180  	return ret, nil
   181  }
   182  
   183  func (self *SDatastoreImageCache) GetIImageInTemplateVMs() ([]cloudprovider.ICloudImage, error) {
   184  	ret := make([]cloudprovider.ICloudImage, 0, 2)
   185  	log.Infof("start to GetIImages")
   186  
   187  	datastore := self.datastore
   188  	if datastore.datacenter.ihosts != nil {
   189  		vms, err := self.getTemplateVMsFromCache()
   190  		if err == nil {
   191  			for i := range vms {
   192  				ret = append(ret, NewVMTemplate(vms[i], self))
   193  			}
   194  			return ret, nil
   195  		}
   196  	}
   197  	realTemplates, err := self.getTempalteVMs()
   198  	if err != nil {
   199  		return nil, errors.Wrap(err, "getTemplateVMs")
   200  	}
   201  	fakeTemplates, err := self.getFakeTempateVMs()
   202  	if err != nil {
   203  		return nil, errors.Wrap(err, "getFakeTempateVMs")
   204  	}
   205  
   206  	for i := range realTemplates {
   207  		ret = append(ret, NewVMTemplate(realTemplates[i], self))
   208  	}
   209  	for i := range fakeTemplates {
   210  		ret = append(ret, NewVMTemplate(fakeTemplates[i], self))
   211  	}
   212  
   213  	log.Infof("get templates successfully")
   214  	log.Debugf("fake template name: ")
   215  	for i := range fakeTemplates {
   216  		log.Debugf("%s ", fakeTemplates[i].GetName())
   217  	}
   218  	log.Debugf("real template name: ")
   219  	for i := range realTemplates {
   220  		log.Debugf("%s ", realTemplates[i].GetName())
   221  	}
   222  	return ret, nil
   223  }
   224  
   225  func (self *SDatastoreImageCache) GetIImageInTemplateVMsById(id string) (cloudprovider.ICloudImage, error) {
   226  	if tempalteNameRegex != nil {
   227  		vm, err := self.datastore.FetchFakeTempateVMById(id, "")
   228  		log.Infof("FetchFakeTempateVMById: %v, %v", vm, err)
   229  		if err == nil {
   230  			return NewVMTemplate(vm, self), nil
   231  		}
   232  		if errors.Cause(err) != errors.ErrNotFound {
   233  			return nil, err
   234  		}
   235  	}
   236  	vm, err := self.datastore.FetchTemplateVMById(id)
   237  	if err == nil {
   238  		return NewVMTemplate(vm, self), nil
   239  	}
   240  	return nil, err
   241  }
   242  
   243  func (self *SDatastoreImageCache) GetICustomizedCloudImages() ([]cloudprovider.ICloudImage, error) {
   244  	return nil, cloudprovider.ErrNotImplemented
   245  }
   246  
   247  func (self *SDatastoreImageCache) GetICloudImages() ([]cloudprovider.ICloudImage, error) {
   248  	images1, err := self.GetIImageInTemplateVMs()
   249  	if err != nil {
   250  		return nil, err
   251  	}
   252  	return images1, nil
   253  	// images2, err := self.GetIImageInImagecache()
   254  	// if err != nil {
   255  	// 	return nil, err
   256  	// }
   257  	// return append(images1, images2...), nil
   258  }
   259  
   260  func (self *SDatastoreImageCache) GetIImageById(extId string) (cloudprovider.ICloudImage, error) {
   261  	// check templatevms
   262  	image, err := self.GetIImageInTemplateVMsById(extId)
   263  	if err == nil {
   264  		return image, nil
   265  	}
   266  	if errors.Cause(err) != errors.ErrNotFound {
   267  		return nil, err
   268  	}
   269  	log.Infof("start to GetIImageInImagecache")
   270  	images, err := self.GetIImageInImagecache()
   271  	if err != nil {
   272  		return nil, err
   273  	}
   274  	for i := 0; i < len(images); i += 1 {
   275  		if images[i].GetGlobalId() == extId {
   276  			return images[i], nil
   277  		}
   278  	}
   279  	return nil, cloudprovider.ErrNotFound
   280  }
   281  
   282  func (self *SDatastoreImageCache) CreateIImage(snapshotId, imageName, osType, imageDesc string) (cloudprovider.ICloudImage, error) {
   283  	return nil, cloudprovider.ErrNotImplemented
   284  }
   285  
   286  func (self *SDatastoreImageCache) DownloadImage(userCred mcclient.TokenCredential, imageId string, extId string, path string) (jsonutils.JSONObject, error) {
   287  	return nil, cloudprovider.ErrNotImplemented
   288  }
   289  
   290  func (self *SDatastoreImageCache) UploadImage(ctx context.Context, userCred mcclient.TokenCredential, image *cloudprovider.SImageCreateOption, callback func(progress float32)) (string, error) {
   291  	return "", cloudprovider.ErrNotImplemented
   292  }