github.phpd.cn/hashicorp/packer@v1.3.2/builder/triton/driver_triton.go (about)

     1  package triton
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"net/http"
     7  	"sort"
     8  	"time"
     9  
    10  	"github.com/hashicorp/packer/packer"
    11  	"github.com/joyent/triton-go/compute"
    12  	terrors "github.com/joyent/triton-go/errors"
    13  )
    14  
    15  type driverTriton struct {
    16  	client *Client
    17  	ui     packer.Ui
    18  }
    19  
    20  func NewDriverTriton(ui packer.Ui, config Config) (Driver, error) {
    21  	client, err := config.AccessConfig.CreateTritonClient()
    22  	if err != nil {
    23  		return nil, err
    24  	}
    25  
    26  	return &driverTriton{
    27  		client: client,
    28  		ui:     ui,
    29  	}, nil
    30  }
    31  
    32  func (d *driverTriton) GetImage(config Config) (string, error) {
    33  	computeClient, _ := d.client.Compute()
    34  	images, err := computeClient.Images().List(context.Background(), &compute.ListImagesInput{
    35  		Name:    config.MachineImageFilters.Name,
    36  		OS:      config.MachineImageFilters.OS,
    37  		Version: config.MachineImageFilters.Version,
    38  		Public:  config.MachineImageFilters.Public,
    39  		Type:    config.MachineImageFilters.Type,
    40  		State:   config.MachineImageFilters.State,
    41  		Owner:   config.MachineImageFilters.Owner,
    42  	})
    43  	if err != nil {
    44  		return "", err
    45  	}
    46  
    47  	if len(images) == 0 {
    48  		return "", errors.New("No images found in your search. Please refine your search criteria")
    49  	}
    50  
    51  	if len(images) > 1 {
    52  		if !config.MachineImageFilters.MostRecent {
    53  			return "", errors.New("More than 1 machine image was found in your search. Please refine your search criteria")
    54  		} else {
    55  			return mostRecentImages(images).ID, nil
    56  		}
    57  	} else {
    58  		return images[0].ID, nil
    59  	}
    60  }
    61  
    62  func (d *driverTriton) CreateImageFromMachine(machineId string, config Config) (string, error) {
    63  	computeClient, _ := d.client.Compute()
    64  	image, err := computeClient.Images().CreateFromMachine(context.Background(), &compute.CreateImageFromMachineInput{
    65  		MachineID:   machineId,
    66  		Name:        config.ImageName,
    67  		Version:     config.ImageVersion,
    68  		Description: config.ImageDescription,
    69  		HomePage:    config.ImageHomepage,
    70  		EULA:        config.ImageEULA,
    71  		ACL:         config.ImageACL,
    72  		Tags:        config.ImageTags,
    73  	})
    74  	if err != nil {
    75  		return "", err
    76  	}
    77  
    78  	return image.ID, err
    79  }
    80  
    81  func (d *driverTriton) CreateMachine(config Config) (string, error) {
    82  	computeClient, _ := d.client.Compute()
    83  	input := &compute.CreateInstanceInput{
    84  		Package:         config.MachinePackage,
    85  		Image:           config.MachineImage,
    86  		Metadata:        config.MachineMetadata,
    87  		Tags:            config.MachineTags,
    88  		FirewallEnabled: config.MachineFirewallEnabled,
    89  	}
    90  
    91  	if config.MachineName == "" {
    92  		// If not supplied generate a name for the source VM: "packer-builder-[image_name]".
    93  		// The version is not used because it can contain characters invalid for a VM name.
    94  		input.Name = "packer-builder-" + config.ImageName
    95  	} else {
    96  		input.Name = config.MachineName
    97  	}
    98  
    99  	if len(config.MachineNetworks) > 0 {
   100  		input.Networks = config.MachineNetworks
   101  	}
   102  
   103  	machine, err := computeClient.Instances().Create(context.Background(), input)
   104  	if err != nil {
   105  		return "", err
   106  	}
   107  
   108  	return machine.ID, nil
   109  }
   110  
   111  func (d *driverTriton) DeleteImage(imageId string) error {
   112  	computeClient, _ := d.client.Compute()
   113  	return computeClient.Images().Delete(context.Background(), &compute.DeleteImageInput{
   114  		ImageID: imageId,
   115  	})
   116  }
   117  
   118  func (d *driverTriton) DeleteMachine(machineId string) error {
   119  	computeClient, _ := d.client.Compute()
   120  	return computeClient.Instances().Delete(context.Background(), &compute.DeleteInstanceInput{
   121  		ID: machineId,
   122  	})
   123  }
   124  
   125  func (d *driverTriton) GetMachineIP(machineId string) (string, error) {
   126  	computeClient, _ := d.client.Compute()
   127  	machine, err := computeClient.Instances().Get(context.Background(), &compute.GetInstanceInput{
   128  		ID: machineId,
   129  	})
   130  	if err != nil {
   131  		return "", err
   132  	}
   133  
   134  	return machine.PrimaryIP, nil
   135  }
   136  
   137  func (d *driverTriton) StopMachine(machineId string) error {
   138  	computeClient, _ := d.client.Compute()
   139  	return computeClient.Instances().Stop(context.Background(), &compute.StopInstanceInput{
   140  		InstanceID: machineId,
   141  	})
   142  }
   143  
   144  // waitForMachineState uses the supplied client to wait for the state of
   145  // the machine with the given ID to reach the state described in state.
   146  // If timeout is reached before the machine reaches the required state, an
   147  // error is returned. If the machine reaches the target state within the
   148  // timeout, nil is returned.
   149  func (d *driverTriton) WaitForMachineState(machineId string, state string, timeout time.Duration) error {
   150  	return waitFor(
   151  		func() (bool, error) {
   152  			computeClient, _ := d.client.Compute()
   153  			machine, err := computeClient.Instances().Get(context.Background(), &compute.GetInstanceInput{
   154  				ID: machineId,
   155  			})
   156  			if machine == nil {
   157  				return false, err
   158  			}
   159  			return machine.State == state, err
   160  		},
   161  		3*time.Second,
   162  		timeout,
   163  	)
   164  }
   165  
   166  // waitForMachineDeletion uses the supplied client to wait for the machine
   167  // with the given ID to be deleted. It is expected that the API call to delete
   168  // the machine has already been issued at this point.
   169  func (d *driverTriton) WaitForMachineDeletion(machineId string, timeout time.Duration) error {
   170  	return waitFor(
   171  		func() (bool, error) {
   172  			computeClient, _ := d.client.Compute()
   173  			_, err := computeClient.Instances().Get(context.Background(), &compute.GetInstanceInput{
   174  				ID: machineId,
   175  			})
   176  			if err != nil {
   177  				// Return true only when we receive a 410 (Gone) response.  A 404
   178  				// indicates that the machine is being deleted whereas a 410 indicates
   179  				// that this process has completed.
   180  				if terrors.IsSpecificStatusCode(err, http.StatusGone) {
   181  					return true, nil
   182  				}
   183  			}
   184  
   185  			return false, err
   186  		},
   187  		3*time.Second,
   188  		timeout,
   189  	)
   190  }
   191  
   192  func (d *driverTriton) WaitForImageCreation(imageId string, timeout time.Duration) error {
   193  	return waitFor(
   194  		func() (bool, error) {
   195  			computeClient, _ := d.client.Compute()
   196  			image, err := computeClient.Images().Get(context.Background(), &compute.GetImageInput{
   197  				ImageID: imageId,
   198  			})
   199  			if image == nil {
   200  				return false, err
   201  			}
   202  			return image.State == "active", err
   203  		},
   204  		3*time.Second,
   205  		timeout,
   206  	)
   207  }
   208  
   209  func waitFor(f func() (bool, error), every, timeout time.Duration) error {
   210  	start := time.Now()
   211  
   212  	for time.Since(start) <= timeout {
   213  		stop, err := f()
   214  		if err != nil {
   215  			return err
   216  		}
   217  
   218  		if stop {
   219  			return nil
   220  		}
   221  
   222  		time.Sleep(every)
   223  	}
   224  
   225  	return errors.New("Timed out while waiting for resource change")
   226  }
   227  
   228  func mostRecentImages(images []*compute.Image) *compute.Image {
   229  	return sortImages(images)[0]
   230  }
   231  
   232  type imageSort []*compute.Image
   233  
   234  func sortImages(images []*compute.Image) []*compute.Image {
   235  	sortedImages := images
   236  	sort.Sort(sort.Reverse(imageSort(sortedImages)))
   237  	return sortedImages
   238  }
   239  
   240  func (a imageSort) Len() int {
   241  	return len(a)
   242  }
   243  
   244  func (a imageSort) Swap(i, j int) {
   245  	a[i], a[j] = a[j], a[i]
   246  }
   247  
   248  func (a imageSort) Less(i, j int) bool {
   249  	itime := a[i].PublishedAt
   250  	jtime := a[j].PublishedAt
   251  	return itime.Unix() < jtime.Unix()
   252  }