github.com/emc-advanced-dev/unik@v0.0.0-20190717152701-a58d3e8e33b7/pkg/providers/gcloud/run_instance.go (about)

     1  package gcloud
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"github.com/sirupsen/logrus"
     7  	"github.com/emc-advanced-dev/pkg/errors"
     8  	"github.com/solo-io/unik/pkg/providers/common"
     9  	"github.com/solo-io/unik/pkg/types"
    10  	"google.golang.org/api/compute/v1"
    11  	"time"
    12  )
    13  
    14  func (p *GcloudProvider) RunInstance(params types.RunInstanceParams) (_ *types.Instance, err error) {
    15  	logrus.WithFields(logrus.Fields{
    16  		"image-id": params.ImageId,
    17  		"mounts":   params.MntPointsToVolumeIds,
    18  		"env":      params.Env,
    19  	}).Infof("running instance %s", params.Name)
    20  
    21  	var instanceId string
    22  
    23  	defer func() {
    24  		if err != nil {
    25  			logrus.WithError(err).Errorf("gcloud running instance encountered an error")
    26  			if instanceId != "" {
    27  				if params.NoCleanup {
    28  					logrus.Warnf("because --no-cleanup flag was provided, not cleaning up failed instance %s0", instanceId)
    29  					return
    30  				}
    31  				logrus.Warnf("cleaning up instance %s", instanceId)
    32  				p.compute().Instances.Delete(p.config.ProjectID, p.config.Zone, instanceId)
    33  				if cleanupErr := p.state.ModifyInstances(func(instances map[string]*types.Instance) error {
    34  					delete(instances, instanceId)
    35  					return nil
    36  				}); cleanupErr != nil {
    37  					logrus.Error(errors.New("modifying instance map in state", cleanupErr))
    38  				}
    39  			}
    40  		}
    41  	}()
    42  
    43  	image, err := p.GetImage(params.ImageId)
    44  	if err != nil {
    45  		return nil, errors.New("getting image", err)
    46  	}
    47  
    48  	if err := common.VerifyMntsInput(p, image, params.MntPointsToVolumeIds); err != nil {
    49  		return nil, errors.New("invalid mapping for volume", err)
    50  	}
    51  
    52  	envData, err := json.Marshal(params.Env)
    53  	if err != nil {
    54  		return nil, errors.New("could not convert instance env to json", err)
    55  	}
    56  
    57  	//if not set, use default
    58  	if params.InstanceMemory <= 0 {
    59  		params.InstanceMemory = image.RunSpec.DefaultInstanceMemory
    60  	}
    61  
    62  	if len(envData) > 32768 {
    63  		return nil, errors.New("total length of env metadata must be <= 32768 bytes; have json string "+string(envData), nil)
    64  	}
    65  
    66  	disks := []*compute.AttachedDisk{
    67  		//boot disk
    68  		&compute.AttachedDisk{
    69  			AutoDelete: true,
    70  			Boot:       true,
    71  			//DeviceName: "sd0"
    72  			InitializeParams: &compute.AttachedDiskInitializeParams{
    73  				SourceImage: "global/images/" + image.Name,
    74  			},
    75  		},
    76  	}
    77  
    78  	for _, volumeId := range params.MntPointsToVolumeIds {
    79  		disks = append(disks, &compute.AttachedDisk{
    80  			AutoDelete: false,
    81  			Boot:       false,
    82  			Source:     volumeId,
    83  		})
    84  	}
    85  
    86  	instanceSpec := &compute.Instance{
    87  		Name: params.Name,
    88  		Metadata: &compute.Metadata{
    89  			Items: []*compute.MetadataItems{
    90  				&compute.MetadataItems{
    91  					Key:   "ENV_DATA",
    92  					Value: pointerTo(string(envData)),
    93  				},
    94  			},
    95  		},
    96  		Disks:       disks,
    97  		MachineType: fmt.Sprintf("zones/%s/machineTypes/%s", p.config.Zone, "g1-small"),
    98  		NetworkInterfaces: []*compute.NetworkInterface{
    99  			&compute.NetworkInterface{
   100  				AccessConfigs: []*compute.AccessConfig{
   101  					&compute.AccessConfig{
   102  						Type: "ONE_TO_ONE_NAT",
   103  						Name: "External NAT",
   104  					},
   105  				},
   106  				Network: "global/networks/default",
   107  			},
   108  		},
   109  	}
   110  
   111  	gInstance, err := p.compute().Instances.Insert(p.config.ProjectID, p.config.Zone, instanceSpec).Do()
   112  	if err != nil {
   113  		return nil, errors.New("creating instance on gcloud failed", err)
   114  	}
   115  	logrus.Infof("gcloud instance created: %+v", gInstance)
   116  
   117  	instanceId = params.Name
   118  
   119  	//must add instance to state before attaching volumes
   120  	instance := &types.Instance{
   121  		Id:             instanceId,
   122  		Name:           params.Name,
   123  		State:          types.InstanceState_Pending,
   124  		Infrastructure: types.Infrastructure_GCLOUD,
   125  		ImageId:        image.Id,
   126  		Created:        time.Now(),
   127  	}
   128  
   129  	if err := p.state.ModifyInstances(func(instances map[string]*types.Instance) error {
   130  		instances[instance.Id] = instance
   131  		return nil
   132  	}); err != nil {
   133  		return nil, errors.New("modifying instance map in state", err)
   134  	}
   135  
   136  	logrus.WithFields(logrus.Fields{"instance": instance}).Infof("instance created succesfully")
   137  
   138  	return instance, nil
   139  }
   140  
   141  func pointerTo(v string) *string {
   142  	return &v
   143  }