github.com/solo-io/unik@v0.0.0-20190717152701-a58d3e8e33b7/pkg/providers/gcloud/stage.go (about)

     1  package gcloud
     2  
     3  import (
     4  	"github.com/sirupsen/logrus"
     5  	"github.com/emc-advanced-dev/pkg/errors"
     6  	"github.com/solo-io/unik/pkg/providers/common"
     7  	"github.com/solo-io/unik/pkg/types"
     8  	"github.com/solo-io/unik/pkg/util"
     9  	"github.com/pborman/uuid"
    10  	"google.golang.org/api/compute/v1"
    11  	"google.golang.org/api/storage/v1"
    12  	"io/ioutil"
    13  	"os"
    14  	"os/exec"
    15  	"path/filepath"
    16  	"runtime"
    17  	"time"
    18  )
    19  
    20  func (p *GcloudProvider) Stage(params types.StageImageParams) (_ *types.Image, err error) {
    21  	images, err := p.ListImages()
    22  	if err != nil {
    23  		return nil, errors.New("retrieving image list for existing image", err)
    24  	}
    25  
    26  	for _, image := range images {
    27  		if image.Name == params.Name {
    28  			if !params.Force {
    29  				return nil, errors.New("an image already exists with name '"+params.Name+"', try again with --force", nil)
    30  			} else {
    31  				logrus.WithField("image", image).Warnf("force: deleting previous image with name " + params.Name)
    32  				err = p.DeleteImage(image.Id, true)
    33  				if err != nil {
    34  					return nil, errors.New("removing previously existing image", err)
    35  				}
    36  			}
    37  		}
    38  	}
    39  
    40  	logrus.WithField("raw-image", params.RawImage).WithField("project id", p.config.ProjectID).Infof("creating google image from raw image")
    41  
    42  	rawImageFile, err := os.Stat(params.RawImage.LocalImagePath)
    43  	if err != nil {
    44  		return nil, errors.New("statting raw image file", err)
    45  	}
    46  
    47  	imageSize := rawImageFile.Size()
    48  
    49  	//need to convert image to raw & name it disk.raw before uploading
    50  	if params.RawImage.StageSpec.ImageFormat != types.ImageFormat_RAW {
    51  		rawImage, err := ioutil.TempFile("", "converted.raw.image.")
    52  		if err != nil {
    53  			return nil, errors.New("creating tmp file for raw image", err)
    54  		}
    55  		defer os.Remove(rawImage.Name())
    56  		logrus.Debugf("need to convert %v to image format RAW", params.RawImage.StageSpec.ImageFormat)
    57  		if err := common.ConvertRawImage(params.RawImage.StageSpec.ImageFormat, types.ImageFormat_RAW, params.RawImage.LocalImagePath, rawImage.Name()); err != nil {
    58  			return nil, errors.New("converting qcow2 to vhd image", err)
    59  		}
    60  		os.Remove(params.RawImage.LocalImagePath)
    61  		//point at the new image
    62  		params.RawImage.LocalImagePath = rawImage.Name()
    63  		params.RawImage.StageSpec.ImageFormat = types.ImageFormat_RAW
    64  		imageSize, err = common.GetVirtualImageSize(params.RawImage.LocalImagePath, params.RawImage.StageSpec.ImageFormat)
    65  		if err != nil {
    66  			return nil, errors.New("getting virtual image size", err)
    67  		}
    68  	}
    69  	destDir, err := ioutil.TempDir("", "gcloud.raw.image.dir.")
    70  	if err != nil {
    71  		return nil, errors.New("creating tmp dir for gcloud image upload", err)
    72  	}
    73  	if !params.NoCleanup {
    74  		defer os.RemoveAll(destDir)
    75  	}
    76  	gcloudImageName := filepath.Join(destDir, "disk.raw")
    77  	if err := os.Rename(params.RawImage.LocalImagePath, gcloudImageName); err != nil {
    78  		return nil, errors.New("renaming image to disk.raw ", err)
    79  	}
    80  	//if we're on OSX, we need to tar with gtar
    81  	tarBin := "tar"
    82  	if runtime.GOOS == "darwin" {
    83  		tarBin = "gtar"
    84  		if _, err := exec.LookPath(tarBin); err != nil {
    85  			return nil, errors.New("gtar was not found in your system path. GNU Tar is required for running google cloud provider; try installing with 'brew install gtar'", err)
    86  		}
    87  	}
    88  	tarCmd := exec.Command(tarBin, "-Sczf", "raw-disk.tar.gz", "disk.raw")
    89  	tarCmd.Dir = destDir
    90  	util.LogCommand(tarCmd, true)
    91  	if err := tarCmd.Run(); err != nil {
    92  		return nil, errors.New("running tar command ", err)
    93  	}
    94  	objectName := "raw-disk.tar.gz"
    95  
    96  	//create tmp bucket
    97  	bucketName := "unik-tmp-bucket-" + uuid.New()
    98  
    99  	if !params.NoCleanup {
   100  		defer func() {
   101  			if err := p.storage().Objects.Delete(bucketName, objectName).Do(); err != nil {
   102  				logrus.Warnf("failed to clean up object %v: %v", objectName, err)
   103  			}
   104  			if err := p.storage().Buckets.Delete(bucketName).Do(); err != nil {
   105  				logrus.Warnf("failed to clean up buket %v: %v", bucketName, err)
   106  			}
   107  		}()
   108  	}
   109  
   110  	bucket, err := p.storage().Buckets.Insert(p.config.ProjectID, &storage.Bucket{Name: bucketName}).Do()
   111  	if err != nil {
   112  		return nil, errors.New("creating bucket "+bucketName, err)
   113  	}
   114  	logrus.Debug("created bucket ", bucket)
   115  
   116  	imageTar := filepath.Join(destDir, objectName)
   117  	file, err := os.Open(imageTar)
   118  	if err != nil {
   119  		return nil, errors.New("opening file "+imageTar, err)
   120  	}
   121  	obj, err := p.storage().Objects.Insert(bucket.Name, &storage.Object{Name: objectName}).Media(file).Do()
   122  	if err != nil {
   123  		return nil, errors.New("uploading file "+imageTar, err)
   124  	}
   125  	logrus.Debug("uploaded object ", obj.Bucket)
   126  
   127  	imageSpec := &compute.Image{
   128  		Name: params.Name,
   129  		RawDisk: &compute.ImageRawDisk{
   130  			Source: obj.SelfLink,
   131  		},
   132  	}
   133  
   134  	logrus.Debugf("creating image from " + imageSpec.RawDisk.Source)
   135  
   136  	operation, err := p.compute().Images.Insert(p.config.ProjectID, imageSpec).Do()
   137  	if err != nil {
   138  		return nil, errors.New("creating gcloud image from storage", err)
   139  	}
   140  
   141  	if err := p.waitOperation(operation.Name, true); err != nil {
   142  		return nil, errors.New("waiting for image create operation to finish", err)
   143  	}
   144  
   145  	logrus.Infof("created google image successfully: %+v", operation)
   146  
   147  	sizeMb := imageSize >> 20
   148  
   149  	image := &types.Image{
   150  		Id:             params.Name,
   151  		Name:           params.Name,
   152  		RunSpec:        params.RawImage.RunSpec,
   153  		StageSpec:      params.RawImage.StageSpec,
   154  		SizeMb:         sizeMb,
   155  		Infrastructure: types.Infrastructure_GCLOUD,
   156  		Created:        time.Now(),
   157  	}
   158  	if err := p.state.ModifyImages(func(images map[string]*types.Image) error {
   159  		images[image.Id] = image
   160  		return nil
   161  	}); err != nil {
   162  		return nil, errors.New("modifying image map in state", err)
   163  	}
   164  
   165  	logrus.WithFields(logrus.Fields{"image": image}).Infof("image created succesfully")
   166  	return image, nil
   167  }