-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
Type: `linode-image` | ||
|
||
The Linode Image data source matches or filters the ID or label of both public images on | ||
Linode and private images in your account using regular expression (regex) or an exact | ||
match. | ||
|
||
You can get the latest list of available public images on Linode via the | ||
[Linode Image List API](https://www.linode.com/docs/api/images/#images-list). | ||
|
||
## Examples | ||
|
||
```hcl | ||
data "linode-image" "latest_ubuntu" { | ||
id_regex = "linode/ubuntu.*" | ||
latest = true | ||
} | ||
source "linode" "example" { | ||
image = linode-image.latest_ubuntu.id | ||
image_description = "My Private Image" | ||
image_label = "my-packaer-private-linode-image-test" | ||
instance_label = "temporary-linode-image" | ||
instance_type = "g6-nanode-1" | ||
region = "us-mia" | ||
ssh_username = "root" | ||
} | ||
build { | ||
sources = ["source.linode.example"] | ||
} | ||
``` | ||
|
||
```hcl | ||
data "linode-image" "latest_ubuntu_lts" { | ||
label_regex = "Ubuntu [0-9]+\\.[0-9]+ LTS" | ||
latest = true | ||
} | ||
``` | ||
|
||
```hcl | ||
data "linode-image" "ubuntu22_lts" { | ||
id = "linode/ubuntu22.04" | ||
latest = true | ||
} | ||
``` | ||
|
||
## Configuration Reference: | ||
|
||
<!-- Code generated from the comments of the Config struct in datasource/image/data.go; DO NOT EDIT MANUALLY --> | ||
|
||
- `label` (string) - Matching the label of an image by exact label | ||
|
||
- `label_regex` (string) - Matching the label of an image by a regular expression | ||
|
||
- `id` (string) - Matching the ID of an image by exact ID | ||
|
||
- `id_regex` (string) - Matching the ID of an image by a regular expression | ||
|
||
- `latest` (bool) - Whether to use the latest created image when there are multiple matches | ||
|
||
<!-- End of code generated from the comments of the Config struct in datasource/image/data.go; --> | ||
|
||
<!-- Code generated from the comments of the LinodeCommon struct in helper/common.go; DO NOT EDIT MANUALLY --> | ||
|
||
- `linode_token` (string) - The Linode API token. This can also be specified in LINODE_TOKEN environment variable | ||
|
||
<!-- End of code generated from the comments of the LinodeCommon struct in helper/common.go; --> | ||
|
||
|
||
## Output: | ||
|
||
<!-- Code generated from the comments of the DatasourceOutput struct in datasource/image/data.go; DO NOT EDIT MANUALLY --> | ||
|
||
- `id` (string) - The unique ID of this Image. | ||
|
||
- `capabilities` ([]string) - A list containing the following possible capabilities of this Image: | ||
- cloud-init: This Image supports cloud-init with Metadata. Only applies to public Images. | ||
|
||
- `created` (string) - When this Image was created. | ||
|
||
- `created_by` (string) - The name of the User who created this Image, or “linode” for public Images. | ||
|
||
- `deprecated` (bool) - Whether or not this Image is deprecated. Will only be true for deprecated public Images. | ||
|
||
- `description` (string) - A detailed description of this Image. | ||
|
||
- `eol` (string) - The date of the public Image’s planned end of life. `null` for private Images. | ||
|
||
- `expiry` (string) - Expiry date of the image. | ||
Only Images created automatically from a deleted Linode (type=automatic) will expire. | ||
|
||
- `is_public` (bool) - True if the Image is a public distribution image. | ||
False if Image is private Account-specific Image. | ||
|
||
- `label` (string) - A short description of the Image. | ||
|
||
- `size` (int) - The minimum size this Image needs to deploy. Size is in MB. | ||
|
||
- `type` (string) - Enum: `manual` `automatic` | ||
How the Image was created. | ||
"Manual" Images can be created at any time. | ||
"Automatic" Images are created automatically from a deleted Linode. | ||
|
||
- `updated` (string) - When this Image was last updated. | ||
|
||
- `vendor` (string) - The upstream distribution vendor. `null` for private Images. | ||
|
||
<!-- End of code generated from the comments of the DatasourceOutput struct in datasource/image/data.go; --> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,190 @@ | ||
package image | ||
|
||
//go:generate packer-sdc struct-markdown | ||
//go:generate packer-sdc mapstructure-to-hcl2 -type DatasourceOutput,Config | ||
import ( | ||
"context" | ||
"errors" | ||
"os" | ||
"time" | ||
|
||
"github.com/hashicorp/hcl/v2/hcldec" | ||
"github.com/hashicorp/packer-plugin-sdk/common" | ||
"github.com/hashicorp/packer-plugin-sdk/hcl2helper" | ||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer" | ||
"github.com/hashicorp/packer-plugin-sdk/template/config" | ||
"github.com/linode/linodego" | ||
"github.com/linode/packer-plugin-linode/helper" | ||
"github.com/zclconf/go-cty/cty" | ||
) | ||
|
||
type Datasource struct { | ||
config Config | ||
} | ||
|
||
type Config struct { | ||
common.PackerConfig `mapstructure:",squash"` | ||
helper.LinodeCommon `mapstructure:",squash"` | ||
|
||
// Matching the label of an image by exact label | ||
Label string `mapstructure:"label"` | ||
|
||
// Matching the label of an image by a regular expression | ||
LabelRegex string `mapstructure:"label_regex"` | ||
|
||
// Matching the ID of an image by exact ID | ||
ID string `mapstructure:"id"` | ||
|
||
// Matching the ID of an image by a regular expression | ||
IDRegex string `mapstructure:"id_regex"` | ||
|
||
// Whether to use the latest created image when there are multiple matches | ||
Latest bool `mapstructure:"latest"` | ||
} | ||
|
||
func (d *Datasource) ConfigSpec() hcldec.ObjectSpec { | ||
return d.config.FlatMapstructure().HCL2Spec() | ||
} | ||
|
||
func (d *Datasource) Configure(raws ...interface{}) error { | ||
err := config.Decode(&d.config, nil, raws...) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
var errs *packersdk.MultiError | ||
|
||
if d.config.PersonalAccessToken == "" { | ||
token := os.Getenv("LINODE_TOKEN") | ||
if token == "" { | ||
errs = packersdk.MultiErrorAppend(errs, errors.New( | ||
"A Linode API token is required. You can specify it in an "+ | ||
"environment variable LINODE_TOKEN or set linode_token "+ | ||
"attribute in the datasource block.", | ||
)) | ||
} | ||
d.config.PersonalAccessToken = token | ||
} | ||
|
||
if errs != nil && len(errs.Errors) > 0 { | ||
return errs | ||
} | ||
|
||
return nil | ||
} | ||
|
||
type DatasourceOutput struct { | ||
// The unique ID of this Image. | ||
ID string `mapstructure:"id"` | ||
|
||
// A list containing the following possible capabilities of this Image: | ||
// - cloud-init: This Image supports cloud-init with Metadata. Only applies to public Images. | ||
Capabilities []string `mapstructure:"capabilities"` | ||
|
||
// When this Image was created. | ||
Created string `mapstructure:"created"` | ||
|
||
// The name of the User who created this Image, or “linode” for public Images. | ||
CreatedBy string `mapstructure:"created_by"` | ||
|
||
// Whether or not this Image is deprecated. Will only be true for deprecated public Images. | ||
Deprecated bool `mapstructure:"deprecated"` | ||
|
||
// A detailed description of this Image. | ||
Description string `mapstructure:"description"` | ||
|
||
// The date of the public Image’s planned end of life. `null` for private Images. | ||
EOL string `mapstructure:"eol"` | ||
|
||
// Expiry date of the image. | ||
// Only Images created automatically from a deleted Linode (type=automatic) will expire. | ||
Expiry string `mapstructure:"expiry"` | ||
|
||
// True if the Image is a public distribution image. | ||
// False if Image is private Account-specific Image. | ||
IsPublic bool `mapstructure:"is_public"` | ||
|
||
// A short description of the Image. | ||
Label string `mapstructure:"label"` | ||
|
||
// The minimum size this Image needs to deploy. Size is in MB. | ||
Size int `mapstructure:"size"` | ||
|
||
// Enum: `manual` `automatic` | ||
// How the Image was created. | ||
// "Manual" Images can be created at any time. | ||
// "Automatic" Images are created automatically from a deleted Linode. | ||
Type string `mapstructure:"type"` | ||
|
||
// When this Image was last updated. | ||
Updated string `mapstructure:"updated"` | ||
|
||
// The upstream distribution vendor. `null` for private Images. | ||
Vendor string `mapstructure:"vendor"` | ||
} | ||
|
||
func (d *Datasource) OutputSpec() hcldec.ObjectSpec { | ||
return (&DatasourceOutput{}).FlatMapstructure().HCL2Spec() | ||
} | ||
|
||
func (d *Datasource) Execute() (cty.Value, error) { | ||
client := helper.NewLinodeClient(d.config.PersonalAccessToken) | ||
|
||
filters := linodego.Filter{} | ||
|
||
// Label is API filterable | ||
if d.config.Label != "" { | ||
filters.AddField(linodego.Eq, "label", d.config.Label) | ||
} | ||
|
||
// we only want available images for the obvious reason | ||
filters.AddField(linodego.Eq, "status", "available") | ||
|
||
filterString, err := filters.MarshalJSON() | ||
if err != nil { | ||
return cty.NullVal(cty.EmptyObject), err | ||
} | ||
|
||
images, err := client.ListImages( | ||
context.Background(), | ||
linodego.NewListOptions(0, string(filterString)), | ||
) | ||
if err != nil { | ||
return cty.NullVal(cty.EmptyObject), err | ||
} | ||
|
||
// filtering non-API filterable attributes | ||
image, err := filterImageResults(images, d.config) | ||
if err != nil { | ||
return cty.NullVal(cty.EmptyObject), err | ||
} | ||
|
||
return hcl2helper.HCL2ValueFromConfig(getOutput(image), d.OutputSpec()), nil | ||
} | ||
|
||
func getOutput(image linodego.Image) DatasourceOutput { | ||
output := DatasourceOutput{ | ||
ID: image.ID, | ||
Capabilities: image.Capabilities, | ||
CreatedBy: image.CreatedBy, | ||
Deprecated: image.Deprecated, | ||
Description: image.Description, | ||
IsPublic: image.IsPublic, | ||
Label: image.Label, | ||
Size: image.Size, | ||
Type: image.Type, | ||
Vendor: image.Vendor, | ||
Created: image.Created.Format(time.RFC3339), | ||
Updated: image.Updated.Format(time.RFC3339), | ||
Check failure on line 178 in datasource/image/data.go
|
||
} | ||
|
||
if image.EOL != nil { | ||
Check failure on line 181 in datasource/image/data.go
|
||
output.EOL = image.EOL.Format(time.RFC3339) | ||
Check failure on line 182 in datasource/image/data.go
|
||
} | ||
|
||
if image.Expiry != nil { | ||
output.Expiry = image.Expiry.Format(time.RFC3339) | ||
} | ||
|
||
return output | ||
} |