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 }