linode / linodego

Go client for Linode REST v4 API
MIT License
138 stars 81 forks source link

new: Add support for Images Gen. 2 #526

Closed lgarber-akamai closed 2 months ago

lgarber-akamai commented 3 months ago

📝 Description

This pull request adds support for the Images Gen. 2 project, including the following changes:

✔️ How to Test

The following test steps assume you have pulled down this PR locally and pointed your local environment to an API instance where Images Gen. 2 is available:

export LINODE_URL=...
export LINODE_TOKEN=...

Integration Testing

make ARGS="-run TestImage_CloudInit" fixtures
make ARGS="-run TestImage_CreateUpload" fixtures

# Not currently ready for testing
make ARGS="-run TestImage_Replicate" fixtures

Unit Testing

make testunit

Manual Testing

The following test steps are expected to be run in a linodego sandbox environment (e.g. dx-devenv).

Testing Manual Images

  1. Run the following:
package main

import (
    "context"
    "github.com/davecgh/go-spew/spew"
    "github.com/linode/linodego"
    "log"
    "os"
    "slices"
)

func main() {
    ctx := context.Background()

    client := linodego.NewClient(nil)
    client.SetToken(os.Getenv("LINODE_TOKEN"))

    // Create an instance for imaging
    booted := false

    inst, err := client.CreateInstance(ctx, linodego.InstanceCreateOptions{
        Region:   "us-east",
        Type:     "g6-nanode-1",
        Label:    "linodego-manual-test",
        RootPass: "f00b4r!!!!123123!!!!11",
        Image:    "linode/alpine3.19",
        Booted:   &booted,
    })
    if err != nil {
        log.Fatal(err)
    }

    if _, err := client.WaitForInstanceStatus(ctx, inst.ID, linodego.InstanceOffline, 240); err != nil {
        log.Fatal(err)
    }

    disks, err := client.ListInstanceDisks(ctx, inst.ID, nil)
    if err != nil {
        log.Fatal(err)
    }

    diskIdx := slices.IndexFunc(disks, func(disk linodego.InstanceDisk) bool {
        return disk.Filesystem == linodego.FilesystemExt4
    })

    // Image the instance
    image, err := client.CreateImage(ctx, linodego.ImageCreateOptions{
        DiskID: disks[diskIdx].ID,
        Label:  "linodego-test-image",
        Tags:   &[]string{"very", "cool"},
    })
    if err != nil {
        log.Fatal(err)
    }

    image, err = client.WaitForImageStatus(ctx, image.ID, linodego.ImageStatusAvailable, 240)
    if err != nil {
        log.Fatal(err)
    }

    spew.Dump(image)

    // NOTE: This section is not currently testable
    //image, err = client.ReplicateImage(
    //  ctx,
    //  image.ID,
    //  linodego.ImageReplicateOptions{
    //      Regions: []string{
    //          "us-southeast",
    //      },
    //  },
    //)
    //if err != nil {
    //  log.Fatal(err)
    //}
    //
    //spew.Dump(image)
}
  1. Ensure the output looks similar to the following:
(*linodego.Image)(0xc00018a000)({
 ID: (string) (len=16) "private/12345",
 Label: (string) (len=19) "linodego-test-image",
 TotalSize: (int) 358,
 Regions: ([]linodego.ImageRegion) {
 },
 Tags: ([]string) (len=2 cap=2) {
  (string) (len=4) "cool",
  (string) (len=4) "very"
 },
 ...
})

Testing Uploaded Images

  1. Run the following:
package main

import (
    "context"
    "github.com/davecgh/go-spew/spew"
    "github.com/linode/linodego"
    "log"
    "os"
)

// Minimal gzipped image for testing purposes
var minimalImageData = []byte{
    0x1f, 0x8b, 0x08, 0x08, 0xbd, 0x5c, 0x91, 0x60,
    0x00, 0x03, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x69, 0x6d, 0x67, 0x00, 0x03, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
}

func main() {
    ctx := context.Background()

    client := linodego.NewClient(nil)
    client.SetToken(os.Getenv("LINODE_TOKEN"))

    // Create & upload an image
    image, _, err := client.CreateImageUpload(ctx, linodego.ImageCreateUploadOptions{
        Region: "us-east",
        Label:  "linodego-upload-test",
        Tags:   &[]string{"very", "cool"},
    })
    if err != nil {
        log.Fatal(err)
    }

    image, err = client.WaitForImageStatus(ctx, image.ID, linodego.ImageStatusPendingUpload, 240)
    if err != nil {
        log.Fatal(err)
    }

    spew.Dump(image)
}
  1. Ensure the output looks similar to the following:

(*linodego.Image)(0xc00029a4b0)({
 ID: (string) (len=16) "private/1234",
 TotalSize: (int) 0,
 Regions: ([]linodego.ImageRegion) {
 },
 Tags: ([]string) (len=2 cap=2) {
  (string) (len=4) "cool",
  (string) (len=4) "very"
 },
 ...
})
lgarber-akamai commented 2 months ago

@yec-akamai Thanks for the feedback! I split up the ImageStatus and ImageRegionStatus types/consts and they should now match the API implementations 👍