Vendor amazon plugin (#10800)
* remove amazon from core * vendor amazon plugin * remove website content * Add amazon to docs-remote-plugins * update amazon reference links in the documentation * update amazon docs version to latest Co-authored-by: Adrien Delorme <adrien.delorme@icloud.com>
This commit is contained in:
parent
25fddf3199
commit
505cbd2591
|
@ -1,251 +0,0 @@
|
|||
package chroot
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
)
|
||||
|
||||
func testConfig() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"ami_name": "foo",
|
||||
"source_ami": "foo",
|
||||
"region": "us-east-1",
|
||||
// region validation logic is checked in ami_config_test
|
||||
"skip_region_validation": true,
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilder_ImplementsBuilder(t *testing.T) {
|
||||
var raw interface{}
|
||||
raw = &Builder{}
|
||||
if _, ok := raw.(packersdk.Builder); !ok {
|
||||
t.Fatalf("Builder should be a builder")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderPrepare_AMIName(t *testing.T) {
|
||||
var b Builder
|
||||
config := testConfig()
|
||||
|
||||
// Test good
|
||||
config["ami_name"] = "foo"
|
||||
config["skip_region_validation"] = true
|
||||
_, warnings, err := b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
|
||||
// Test bad
|
||||
config["ami_name"] = "foo {{"
|
||||
b = Builder{}
|
||||
_, warnings, err = b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
|
||||
// Test bad
|
||||
delete(config, "ami_name")
|
||||
b = Builder{}
|
||||
_, warnings, err = b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderPrepare_ChrootMounts(t *testing.T) {
|
||||
b := &Builder{}
|
||||
config := testConfig()
|
||||
|
||||
config["chroot_mounts"] = nil
|
||||
_, warnings, err := b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err != nil {
|
||||
t.Errorf("err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderPrepare_ChrootMountsBadDefaults(t *testing.T) {
|
||||
b := &Builder{}
|
||||
config := testConfig()
|
||||
|
||||
config["chroot_mounts"] = [][]string{
|
||||
{"bad"},
|
||||
}
|
||||
_, warnings, err := b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
}
|
||||
func TestBuilderPrepare_SourceAmi(t *testing.T) {
|
||||
b := &Builder{}
|
||||
config := testConfig()
|
||||
|
||||
config["source_ami"] = ""
|
||||
_, warnings, err := b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
|
||||
config["source_ami"] = "foo"
|
||||
_, warnings, err = b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err != nil {
|
||||
t.Errorf("err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderPrepare_CommandWrapper(t *testing.T) {
|
||||
b := &Builder{}
|
||||
config := testConfig()
|
||||
|
||||
config["command_wrapper"] = "echo hi; {{.Command}}"
|
||||
_, warnings, err := b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err != nil {
|
||||
t.Errorf("err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderPrepare_CopyFiles(t *testing.T) {
|
||||
b := &Builder{}
|
||||
config := testConfig()
|
||||
|
||||
_, warnings, err := b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err != nil {
|
||||
t.Errorf("err: %s", err)
|
||||
}
|
||||
|
||||
if len(b.config.CopyFiles) != 1 && b.config.CopyFiles[0] != "/etc/resolv.conf" {
|
||||
t.Errorf("Was expecting default value for copy_files.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderPrepare_CopyFilesNoDefault(t *testing.T) {
|
||||
b := &Builder{}
|
||||
config := testConfig()
|
||||
|
||||
config["copy_files"] = []string{}
|
||||
_, warnings, err := b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err != nil {
|
||||
t.Errorf("err: %s", err)
|
||||
}
|
||||
|
||||
if len(b.config.CopyFiles) > 0 {
|
||||
t.Errorf("Was expecting no default value for copy_files. Found %v",
|
||||
b.config.CopyFiles)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderPrepare_RootDeviceNameAndAMIMappings(t *testing.T) {
|
||||
var b Builder
|
||||
config := testConfig()
|
||||
|
||||
config["root_device_name"] = "/dev/sda"
|
||||
config["ami_block_device_mappings"] = []interface{}{map[string]string{}}
|
||||
config["root_volume_size"] = 15
|
||||
_, warnings, err := b.Prepare(config)
|
||||
if len(warnings) == 0 {
|
||||
t.Fatal("Missing warning, stating block device mappings will be overwritten")
|
||||
} else if len(warnings) > 1 {
|
||||
t.Fatalf("excessive warnings: %#v", warnings)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderPrepare_AMIMappingsNoRootDeviceName(t *testing.T) {
|
||||
var b Builder
|
||||
config := testConfig()
|
||||
|
||||
config["ami_block_device_mappings"] = []interface{}{map[string]string{}}
|
||||
_, warnings, err := b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatalf("should have error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderPrepare_RootDeviceNameNoAMIMappings(t *testing.T) {
|
||||
var b Builder
|
||||
config := testConfig()
|
||||
|
||||
config["root_device_name"] = "/dev/sda"
|
||||
_, warnings, err := b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatalf("should have error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderPrepare_ReturnGeneratedData(t *testing.T) {
|
||||
var b Builder
|
||||
config := testConfig()
|
||||
|
||||
generatedData, warnings, err := b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
if len(generatedData) == 0 {
|
||||
t.Fatalf("Generated data should not be empty")
|
||||
}
|
||||
if generatedData[0] != "SourceAMIName" {
|
||||
t.Fatalf("Generated data should contain SourceAMIName")
|
||||
}
|
||||
if generatedData[1] != "BuildRegion" {
|
||||
t.Fatalf("Generated data should contain BuildRegion")
|
||||
}
|
||||
if generatedData[2] != "SourceAMI" {
|
||||
t.Fatalf("Generated data should contain SourceAMI")
|
||||
}
|
||||
if generatedData[3] != "SourceAMICreationDate" {
|
||||
t.Fatalf("Generated data should contain SourceAMICreationDate")
|
||||
}
|
||||
if generatedData[4] != "SourceAMIOwner" {
|
||||
t.Fatalf("Generated data should contain SourceAMIOwner")
|
||||
}
|
||||
if generatedData[5] != "SourceAMIOwnerName" {
|
||||
t.Fatalf("Generated data should contain SourceAMIOwnerName")
|
||||
}
|
||||
if generatedData[6] != "Device" {
|
||||
t.Fatalf("Generated data should contain Device")
|
||||
}
|
||||
if generatedData[7] != "MountPath" {
|
||||
t.Fatalf("Generated data should contain MountPath")
|
||||
}
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
package chroot
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/packer-plugin-sdk/common"
|
||||
)
|
||||
|
||||
func TestCopyFile(t *testing.T) {
|
||||
if runtime.GOOS == "windows" {
|
||||
return
|
||||
}
|
||||
|
||||
first, err := ioutil.TempFile("", "copy_files_test")
|
||||
if err != nil {
|
||||
t.Fatalf("couldn't create temp file.")
|
||||
}
|
||||
defer os.Remove(first.Name())
|
||||
newName := first.Name() + "-new"
|
||||
|
||||
payload := "copy_files_test.go payload"
|
||||
if _, err = first.WriteString(payload); err != nil {
|
||||
t.Fatalf("Couldn't write payload to first file.")
|
||||
}
|
||||
first.Sync()
|
||||
|
||||
cmd := common.ShellCommand(fmt.Sprintf("cp %s %s", first.Name(), newName))
|
||||
if err := cmd.Run(); err != nil {
|
||||
t.Fatalf("Couldn't copy file")
|
||||
}
|
||||
defer os.Remove(newName)
|
||||
|
||||
second, err := os.Open(newName)
|
||||
if err != nil {
|
||||
t.Fatalf("Couldn't open copied file.")
|
||||
}
|
||||
defer second.Close()
|
||||
|
||||
var copiedPayload = make([]byte, len(payload))
|
||||
if _, err := second.Read(copiedPayload); err != nil {
|
||||
t.Fatalf("Couldn't open copied file for reading.")
|
||||
}
|
||||
|
||||
if string(copiedPayload) != payload {
|
||||
t.Fatalf("payload not copied.")
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
package chroot
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestDevicePrefixMatch(t *testing.T) {
|
||||
/*
|
||||
if devicePrefixMatch("nvme0n1") != "" {
|
||||
}
|
||||
*/
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
package chroot
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/packer-plugin-sdk/chroot"
|
||||
)
|
||||
|
||||
func TestAttachVolumeCleanupFunc_ImplementsCleanupFunc(t *testing.T) {
|
||||
var raw interface{}
|
||||
raw = new(StepAttachVolume)
|
||||
if _, ok := raw.(chroot.Cleanup); !ok {
|
||||
t.Fatalf("cleanup func should be a CleanupFunc")
|
||||
}
|
||||
}
|
|
@ -1,97 +0,0 @@
|
|||
package chroot
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
confighelper "github.com/hashicorp/packer-plugin-sdk/template/config"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func buildTestRootDevice() *ec2.BlockDeviceMapping {
|
||||
return &ec2.BlockDeviceMapping{
|
||||
Ebs: &ec2.EbsBlockDevice{
|
||||
VolumeSize: aws.Int64(10),
|
||||
SnapshotId: aws.String("snap-1234"),
|
||||
VolumeType: aws.String("gp2"),
|
||||
Encrypted: aws.Bool(false),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateVolume_Default(t *testing.T) {
|
||||
stepCreateVolume := new(StepCreateVolume)
|
||||
_, err := stepCreateVolume.buildCreateVolumeInput("test-az", buildTestRootDevice())
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestCreateVolume_Shrink(t *testing.T) {
|
||||
stepCreateVolume := StepCreateVolume{RootVolumeSize: 1}
|
||||
testRootDevice := buildTestRootDevice()
|
||||
ret, err := stepCreateVolume.buildCreateVolumeInput("test-az", testRootDevice)
|
||||
assert.NoError(t, err)
|
||||
// Ensure that the new value is equal to the size of the old root device
|
||||
assert.Equal(t, *ret.Size, *testRootDevice.Ebs.VolumeSize)
|
||||
}
|
||||
|
||||
func TestCreateVolume_Expand(t *testing.T) {
|
||||
stepCreateVolume := StepCreateVolume{RootVolumeSize: 25}
|
||||
testRootDevice := buildTestRootDevice()
|
||||
ret, err := stepCreateVolume.buildCreateVolumeInput("test-az", testRootDevice)
|
||||
assert.NoError(t, err)
|
||||
// Ensure that the new value is equal to the size of the value passed in
|
||||
assert.Equal(t, *ret.Size, stepCreateVolume.RootVolumeSize)
|
||||
}
|
||||
|
||||
func TestCreateVolume_io1_to_io1(t *testing.T) {
|
||||
stepCreateVolume := StepCreateVolume{RootVolumeType: "io1"}
|
||||
testRootDevice := buildTestRootDevice()
|
||||
testRootDevice.Ebs.VolumeType = aws.String("io1")
|
||||
testRootDevice.Ebs.Iops = aws.Int64(1000)
|
||||
ret, err := stepCreateVolume.buildCreateVolumeInput("test-az", testRootDevice)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, *ret.VolumeType, stepCreateVolume.RootVolumeType)
|
||||
assert.Equal(t, *ret.Iops, *testRootDevice.Ebs.Iops)
|
||||
}
|
||||
|
||||
func TestCreateVolume_io1_to_gp2(t *testing.T) {
|
||||
stepCreateVolume := StepCreateVolume{RootVolumeType: "gp2"}
|
||||
testRootDevice := buildTestRootDevice()
|
||||
testRootDevice.Ebs.VolumeType = aws.String("io1")
|
||||
testRootDevice.Ebs.Iops = aws.Int64(1000)
|
||||
|
||||
ret, err := stepCreateVolume.buildCreateVolumeInput("test-az", testRootDevice)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, *ret.VolumeType, stepCreateVolume.RootVolumeType)
|
||||
assert.Nil(t, ret.Iops)
|
||||
}
|
||||
|
||||
func TestCreateVolume_gp2_to_io1(t *testing.T) {
|
||||
stepCreateVolume := StepCreateVolume{RootVolumeType: "io1"}
|
||||
testRootDevice := buildTestRootDevice()
|
||||
|
||||
_, err := stepCreateVolume.buildCreateVolumeInput("test-az", testRootDevice)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestCreateVolume_Encrypted(t *testing.T) {
|
||||
stepCreateVolume := StepCreateVolume{RootVolumeEncryptBoot: confighelper.TrileanFromBool(true)}
|
||||
testRootDevice := buildTestRootDevice()
|
||||
ret, err := stepCreateVolume.buildCreateVolumeInput("test-az", testRootDevice)
|
||||
assert.NoError(t, err)
|
||||
// Ensure that the new value is equal to the the value passed in
|
||||
assert.Equal(t, confighelper.TrileanFromBool(*ret.Encrypted), stepCreateVolume.RootVolumeEncryptBoot)
|
||||
}
|
||||
|
||||
func TestCreateVolume_Custom_KMS_Key_Encrypted(t *testing.T) {
|
||||
stepCreateVolume := StepCreateVolume{
|
||||
RootVolumeEncryptBoot: confighelper.TrileanFromBool(true),
|
||||
RootVolumeKmsKeyId: "alias/1234",
|
||||
}
|
||||
testRootDevice := buildTestRootDevice()
|
||||
ret, err := stepCreateVolume.buildCreateVolumeInput("test-az", testRootDevice)
|
||||
assert.NoError(t, err)
|
||||
// Ensure that the new value is equal to the value passed in
|
||||
assert.Equal(t, *ret.KmsKeyId, stepCreateVolume.RootVolumeKmsKeyId)
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
package chroot
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/packer-plugin-sdk/chroot"
|
||||
)
|
||||
|
||||
func TestFlockCleanupFunc_ImplementsCleanupFunc(t *testing.T) {
|
||||
var raw interface{}
|
||||
raw = new(StepFlock)
|
||||
if _, ok := raw.(chroot.Cleanup); !ok {
|
||||
t.Fatalf("cleanup func should be a CleanupFunc")
|
||||
}
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
package chroot
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/packer-plugin-sdk/chroot"
|
||||
)
|
||||
|
||||
func TestMountDeviceCleanupFunc_ImplementsCleanupFunc(t *testing.T) {
|
||||
var raw interface{}
|
||||
raw = new(StepMountDevice)
|
||||
if _, ok := raw.(chroot.Cleanup); !ok {
|
||||
t.Fatalf("cleanup func should be a CleanupFunc")
|
||||
}
|
||||
}
|
|
@ -1,216 +0,0 @@
|
|||
package chroot
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/packer-plugin-sdk/common"
|
||||
amazon "github.com/hashicorp/packer/builder/amazon/common"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
)
|
||||
|
||||
func testImage() ec2.Image {
|
||||
return ec2.Image{
|
||||
ImageId: aws.String("ami-abcd1234"),
|
||||
Name: aws.String("ami_test_name"),
|
||||
Architecture: aws.String("x86_64"),
|
||||
KernelId: aws.String("aki-abcd1234"),
|
||||
}
|
||||
}
|
||||
|
||||
func TestStepRegisterAmi_buildRegisterOpts_pv(t *testing.T) {
|
||||
config := Config{}
|
||||
config.AMIName = "test_ami_name"
|
||||
config.AMIDescription = "test_ami_description"
|
||||
config.AMIVirtType = "paravirtual"
|
||||
rootDeviceName := "foo"
|
||||
|
||||
image := testImage()
|
||||
|
||||
blockDevices := []*ec2.BlockDeviceMapping{}
|
||||
|
||||
opts := buildRegisterOptsFromExistingImage(&config, &image, blockDevices, rootDeviceName, config.AMIName)
|
||||
|
||||
expected := config.AMIVirtType
|
||||
if *opts.VirtualizationType != expected {
|
||||
t.Fatalf("Unexpected VirtType value: expected %s got %s\n", expected, *opts.VirtualizationType)
|
||||
}
|
||||
|
||||
expected = config.AMIName
|
||||
if *opts.Name != expected {
|
||||
t.Fatalf("Unexpected Name value: expected %s got %s\n", expected, *opts.Name)
|
||||
}
|
||||
|
||||
expected = *image.KernelId
|
||||
if *opts.KernelId != expected {
|
||||
t.Fatalf("Unexpected KernelId value: expected %s got %s\n", expected, *opts.KernelId)
|
||||
}
|
||||
|
||||
expected = rootDeviceName
|
||||
if *opts.RootDeviceName != expected {
|
||||
t.Fatalf("Unexpected RootDeviceName value: expected %s got %s\n", expected, *opts.RootDeviceName)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStepRegisterAmi_buildRegisterOpts_hvm(t *testing.T) {
|
||||
config := Config{}
|
||||
config.AMIName = "test_ami_name"
|
||||
config.AMIDescription = "test_ami_description"
|
||||
config.AMIVirtType = "hvm"
|
||||
rootDeviceName := "foo"
|
||||
|
||||
image := testImage()
|
||||
|
||||
blockDevices := []*ec2.BlockDeviceMapping{}
|
||||
|
||||
opts := buildRegisterOptsFromExistingImage(&config, &image, blockDevices, rootDeviceName, config.AMIName)
|
||||
|
||||
expected := config.AMIVirtType
|
||||
if *opts.VirtualizationType != expected {
|
||||
t.Fatalf("Unexpected VirtType value: expected %s got %s\n", expected, *opts.VirtualizationType)
|
||||
}
|
||||
|
||||
expected = config.AMIName
|
||||
if *opts.Name != expected {
|
||||
t.Fatalf("Unexpected Name value: expected %s got %s\n", expected, *opts.Name)
|
||||
}
|
||||
|
||||
if opts.KernelId != nil {
|
||||
t.Fatalf("Unexpected KernelId value: expected nil got %s\n", *opts.KernelId)
|
||||
}
|
||||
|
||||
expected = rootDeviceName
|
||||
if *opts.RootDeviceName != expected {
|
||||
t.Fatalf("Unexpected RootDeviceName value: expected %s got %s\n", expected, *opts.RootDeviceName)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStepRegisterAmi_buildRegisterOptsFromScratch(t *testing.T) {
|
||||
rootDeviceName := "/dev/sda"
|
||||
snapshotID := "foo"
|
||||
config := Config{
|
||||
FromScratch: true,
|
||||
PackerConfig: common.PackerConfig{},
|
||||
AMIMappings: []amazon.BlockDevice{
|
||||
{
|
||||
DeviceName: rootDeviceName,
|
||||
},
|
||||
},
|
||||
RootDeviceName: rootDeviceName,
|
||||
}
|
||||
registerOpts := buildBaseRegisterOpts(&config, nil, 10, snapshotID, config.AMIName)
|
||||
|
||||
if len(registerOpts.BlockDeviceMappings) != 1 {
|
||||
t.Fatal("Expected block device mapping of length 1")
|
||||
}
|
||||
|
||||
if *registerOpts.BlockDeviceMappings[0].Ebs.SnapshotId != snapshotID {
|
||||
t.Fatalf("Snapshot ID of root disk not set to snapshot id %s", rootDeviceName)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStepRegisterAmi_buildRegisterOptFromExistingImage(t *testing.T) {
|
||||
rootDeviceName := "/dev/sda"
|
||||
snapshotID := "foo"
|
||||
|
||||
config := Config{
|
||||
FromScratch: false,
|
||||
PackerConfig: common.PackerConfig{},
|
||||
}
|
||||
sourceImage := ec2.Image{
|
||||
RootDeviceName: &rootDeviceName,
|
||||
BlockDeviceMappings: []*ec2.BlockDeviceMapping{
|
||||
{
|
||||
DeviceName: &rootDeviceName,
|
||||
Ebs: &ec2.EbsBlockDevice{
|
||||
VolumeSize: aws.Int64(10),
|
||||
},
|
||||
},
|
||||
// Throw in an ephemeral device, it seems like all devices in the return struct in a source AMI have
|
||||
// a size, even if it's for ephemeral
|
||||
{
|
||||
DeviceName: aws.String("/dev/sdb"),
|
||||
VirtualName: aws.String("ephemeral0"),
|
||||
Ebs: &ec2.EbsBlockDevice{
|
||||
VolumeSize: aws.Int64(0),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
registerOpts := buildBaseRegisterOpts(&config, &sourceImage, 15, snapshotID, config.AMIName)
|
||||
|
||||
if len(registerOpts.BlockDeviceMappings) != 2 {
|
||||
t.Fatal("Expected block device mapping of length 2")
|
||||
}
|
||||
|
||||
for _, dev := range registerOpts.BlockDeviceMappings {
|
||||
if dev.Ebs.SnapshotId != nil && *dev.Ebs.SnapshotId == snapshotID {
|
||||
// Even though root volume size is in config, it isn't used, instead we use the root volume size
|
||||
// that's derived when we build the step
|
||||
if *dev.Ebs.VolumeSize != 15 {
|
||||
t.Fatalf("Root volume size not 15 GB instead %d", *dev.Ebs.VolumeSize)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
t.Fatalf("Could not find device with snapshot ID %s", snapshotID)
|
||||
}
|
||||
|
||||
func TestStepRegisterAmi_buildRegisterOptFromExistingImageWithBlockDeviceMappings(t *testing.T) {
|
||||
const (
|
||||
rootDeviceName = "/dev/xvda"
|
||||
oldRootDevice = "/dev/sda1"
|
||||
)
|
||||
snapshotId := "foo"
|
||||
|
||||
config := Config{
|
||||
FromScratch: false,
|
||||
PackerConfig: common.PackerConfig{},
|
||||
AMIMappings: []amazon.BlockDevice{
|
||||
{
|
||||
DeviceName: rootDeviceName,
|
||||
},
|
||||
},
|
||||
RootDeviceName: rootDeviceName,
|
||||
}
|
||||
|
||||
// Intentionally try to use a different root devicename
|
||||
sourceImage := ec2.Image{
|
||||
RootDeviceName: aws.String(oldRootDevice),
|
||||
BlockDeviceMappings: []*ec2.BlockDeviceMapping{
|
||||
{
|
||||
DeviceName: aws.String(oldRootDevice),
|
||||
Ebs: &ec2.EbsBlockDevice{
|
||||
VolumeSize: aws.Int64(10),
|
||||
},
|
||||
},
|
||||
// Throw in an ephemeral device, it seems like all devices in the return struct in a source AMI have
|
||||
// a size, even if it's for ephemeral
|
||||
{
|
||||
DeviceName: aws.String("/dev/sdb"),
|
||||
VirtualName: aws.String("ephemeral0"),
|
||||
Ebs: &ec2.EbsBlockDevice{
|
||||
VolumeSize: aws.Int64(0),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
registerOpts := buildBaseRegisterOpts(&config, &sourceImage, 15, snapshotId, config.AMIName)
|
||||
|
||||
if len(registerOpts.BlockDeviceMappings) != 1 {
|
||||
t.Fatal("Expected block device mapping of length 1")
|
||||
}
|
||||
|
||||
if *registerOpts.BlockDeviceMappings[0].Ebs.SnapshotId != snapshotId {
|
||||
t.Fatalf("Snapshot ID of root disk set to '%s' expected '%s'", *registerOpts.BlockDeviceMappings[0].Ebs.SnapshotId, rootDeviceName)
|
||||
}
|
||||
|
||||
if *registerOpts.RootDeviceName != rootDeviceName {
|
||||
t.Fatalf("Root device set to '%s' expected %s", *registerOpts.RootDeviceName, rootDeviceName)
|
||||
}
|
||||
|
||||
if *registerOpts.BlockDeviceMappings[0].Ebs.VolumeSize != 15 {
|
||||
t.Fatalf("Size of root disk not set to 15 GB, instead %d", *registerOpts.BlockDeviceMappings[0].Ebs.VolumeSize)
|
||||
}
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
)
|
||||
|
||||
func TestAccessConfigPrepare_Region(t *testing.T) {
|
||||
c := FakeAccessConfig()
|
||||
|
||||
c.RawRegion = "us-east-12"
|
||||
err := c.ValidateRegion(c.RawRegion)
|
||||
if err == nil {
|
||||
t.Fatalf("should have region validation err: %s", c.RawRegion)
|
||||
}
|
||||
|
||||
c.RawRegion = "us-east-1"
|
||||
err = c.ValidateRegion(c.RawRegion)
|
||||
if err != nil {
|
||||
t.Fatalf("shouldn't have region validation err: %s", c.RawRegion)
|
||||
}
|
||||
|
||||
c.RawRegion = "custom"
|
||||
err = c.ValidateRegion(c.RawRegion)
|
||||
if err == nil {
|
||||
t.Fatalf("should have region validation err: %s", c.RawRegion)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAccessConfigPrepare_RegionRestricted(t *testing.T) {
|
||||
c := FakeAccessConfig()
|
||||
|
||||
// Create a Session with a custom region
|
||||
c.session = session.Must(session.NewSession(&aws.Config{
|
||||
Region: aws.String("us-gov-west-1"),
|
||||
}))
|
||||
|
||||
if err := c.Prepare(); err != nil {
|
||||
t.Fatalf("shouldn't have err: %s", err)
|
||||
}
|
||||
|
||||
if !c.IsGovCloud() {
|
||||
t.Fatal("We should be in gov region.")
|
||||
}
|
||||
}
|
|
@ -1,244 +0,0 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
"github.com/hashicorp/packer-plugin-sdk/template/config"
|
||||
)
|
||||
|
||||
func testAMIConfig() *AMIConfig {
|
||||
return &AMIConfig{
|
||||
AMIName: "foo",
|
||||
}
|
||||
}
|
||||
|
||||
func getFakeAccessConfig(region string) *AccessConfig {
|
||||
c := FakeAccessConfig()
|
||||
c.RawRegion = region
|
||||
return c
|
||||
}
|
||||
|
||||
func TestAMIConfigPrepare_name(t *testing.T) {
|
||||
c := testAMIConfig()
|
||||
accessConf := FakeAccessConfig()
|
||||
if err := c.Prepare(accessConf, nil); err != nil {
|
||||
t.Fatalf("shouldn't have err: %s", err)
|
||||
}
|
||||
|
||||
c.AMIName = ""
|
||||
if err := c.Prepare(accessConf, nil); err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
}
|
||||
|
||||
func (m *mockEC2Client) DescribeRegions(*ec2.DescribeRegionsInput) (*ec2.DescribeRegionsOutput, error) {
|
||||
return &ec2.DescribeRegionsOutput{
|
||||
Regions: []*ec2.Region{
|
||||
{RegionName: aws.String("us-east-1")},
|
||||
{RegionName: aws.String("us-east-2")},
|
||||
{RegionName: aws.String("us-west-1")},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func TestAMIConfigPrepare_regions(t *testing.T) {
|
||||
c := testAMIConfig()
|
||||
c.AMIRegions = nil
|
||||
|
||||
var errs []error
|
||||
var err error
|
||||
accessConf := FakeAccessConfig()
|
||||
mockConn := &mockEC2Client{}
|
||||
if errs = c.prepareRegions(accessConf); len(errs) > 0 {
|
||||
t.Fatalf("shouldn't have err: %#v", errs)
|
||||
}
|
||||
|
||||
c.AMIRegions, err = listEC2Regions(mockConn)
|
||||
if err != nil {
|
||||
t.Fatalf("shouldn't have err: %s", err.Error())
|
||||
}
|
||||
if errs = c.prepareRegions(accessConf); len(errs) > 0 {
|
||||
t.Fatalf("shouldn't have err: %#v", errs)
|
||||
}
|
||||
|
||||
c.AMIRegions = []string{"us-east-1", "us-west-1", "us-east-1"}
|
||||
if errs = c.prepareRegions(accessConf); len(errs) > 0 {
|
||||
t.Fatalf("bad: %s", errs[0])
|
||||
}
|
||||
|
||||
expected := []string{"us-east-1", "us-west-1"}
|
||||
if !reflect.DeepEqual(c.AMIRegions, expected) {
|
||||
t.Fatalf("bad: %#v", c.AMIRegions)
|
||||
}
|
||||
|
||||
c.AMIRegions = []string{"custom"}
|
||||
if errs = c.prepareRegions(accessConf); len(errs) > 0 {
|
||||
t.Fatal("shouldn't have error")
|
||||
}
|
||||
|
||||
c.AMIRegions = []string{"us-east-1", "us-east-2", "us-west-1"}
|
||||
c.AMIRegionKMSKeyIDs = map[string]string{
|
||||
"us-east-1": "123-456-7890",
|
||||
"us-west-1": "789-012-3456",
|
||||
"us-east-2": "456-789-0123",
|
||||
}
|
||||
if errs = c.prepareRegions(accessConf); len(errs) > 0 {
|
||||
t.Fatal(fmt.Sprintf("shouldn't have error: %s", errs[0]))
|
||||
}
|
||||
|
||||
c.AMIRegions = []string{"us-east-1", "us-east-2", "us-west-1"}
|
||||
c.AMIRegionKMSKeyIDs = map[string]string{
|
||||
"us-east-1": "123-456-7890",
|
||||
"us-west-1": "789-012-3456",
|
||||
"us-east-2": "",
|
||||
}
|
||||
if errs = c.prepareRegions(accessConf); len(errs) > 0 {
|
||||
t.Fatal("should have passed; we are able to use default KMS key if not sharing")
|
||||
}
|
||||
|
||||
c.SnapshotUsers = []string{"user-foo", "user-bar"}
|
||||
c.AMIRegions = []string{"us-east-1", "us-east-2", "us-west-1"}
|
||||
c.AMIRegionKMSKeyIDs = map[string]string{
|
||||
"us-east-1": "123-456-7890",
|
||||
"us-west-1": "789-012-3456",
|
||||
"us-east-2": "",
|
||||
}
|
||||
if errs = c.prepareRegions(accessConf); len(errs) > 0 {
|
||||
t.Fatal("should have an error b/c can't use default KMS key if sharing")
|
||||
}
|
||||
|
||||
c.AMIRegions = []string{"us-east-1", "us-west-1"}
|
||||
c.AMIRegionKMSKeyIDs = map[string]string{
|
||||
"us-east-1": "123-456-7890",
|
||||
"us-west-1": "789-012-3456",
|
||||
"us-east-2": "456-789-0123",
|
||||
}
|
||||
if errs = c.prepareRegions(accessConf); len(errs) > 0 {
|
||||
t.Fatal("should have error b/c theres a region in the key map that isn't in ami_regions")
|
||||
}
|
||||
|
||||
c.AMIRegions = []string{"us-east-1", "us-west-1", "us-east-2"}
|
||||
c.AMIRegionKMSKeyIDs = map[string]string{
|
||||
"us-east-1": "123-456-7890",
|
||||
"us-west-1": "789-012-3456",
|
||||
}
|
||||
|
||||
if err := c.Prepare(accessConf, nil); err == nil {
|
||||
t.Fatal("should have error b/c theres a region in in ami_regions that isn't in the key map")
|
||||
}
|
||||
|
||||
c.SnapshotUsers = []string{"foo", "bar"}
|
||||
c.AMIKmsKeyId = "123-abc-456"
|
||||
c.AMIEncryptBootVolume = config.TriTrue
|
||||
c.AMIRegions = []string{"us-east-1", "us-west-1"}
|
||||
c.AMIRegionKMSKeyIDs = map[string]string{
|
||||
"us-east-1": "123-456-7890",
|
||||
"us-west-1": "",
|
||||
}
|
||||
if errs = c.prepareRegions(accessConf); len(errs) > 0 {
|
||||
t.Fatal("should have error b/c theres a region in in ami_regions that isn't in the key map")
|
||||
}
|
||||
|
||||
// allow rawregion to exist in ami_regions list.
|
||||
accessConf = getFakeAccessConfig("us-east-1")
|
||||
c.AMIRegions = []string{"us-east-1", "us-west-1", "us-east-2"}
|
||||
c.AMIRegionKMSKeyIDs = nil
|
||||
if errs = c.prepareRegions(accessConf); len(errs) > 0 {
|
||||
t.Fatal("should allow user to have the raw region in ami_regions")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestAMIConfigPrepare_Share_EncryptedBoot(t *testing.T) {
|
||||
c := testAMIConfig()
|
||||
c.AMIUsers = []string{"testAccountID"}
|
||||
c.AMIEncryptBootVolume = config.TriTrue
|
||||
|
||||
accessConf := FakeAccessConfig()
|
||||
|
||||
c.AMIKmsKeyId = ""
|
||||
if err := c.Prepare(accessConf, nil); err == nil {
|
||||
t.Fatal("shouldn't be able to share ami with encrypted boot volume")
|
||||
}
|
||||
c.AMIKmsKeyId = "89c3fb9a-de87-4f2a-aedc-fddc5138193c"
|
||||
if err := c.Prepare(accessConf, nil); err != nil {
|
||||
t.Fatal("should be able to share ami with encrypted boot volume")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAMIConfigPrepare_ValidateKmsKey(t *testing.T) {
|
||||
c := testAMIConfig()
|
||||
c.AMIEncryptBootVolume = config.TriTrue
|
||||
|
||||
accessConf := FakeAccessConfig()
|
||||
|
||||
validCases := []string{
|
||||
"abcd1234-e567-890f-a12b-a123b4cd56ef",
|
||||
"alias/foo/bar",
|
||||
"arn:aws:kms:us-east-1:012345678910:key/abcd1234-a123-456a-a12b-a123b4cd56ef",
|
||||
"arn:aws:kms:us-east-1:012345678910:alias/foo/bar",
|
||||
"arn:aws-us-gov:kms:us-gov-east-1:123456789012:key/12345678-1234-abcd-0000-123456789012",
|
||||
}
|
||||
for _, validCase := range validCases {
|
||||
c.AMIKmsKeyId = validCase
|
||||
if err := c.Prepare(accessConf, nil); err != nil {
|
||||
t.Fatalf("%s should not have failed KMS key validation", validCase)
|
||||
}
|
||||
}
|
||||
|
||||
invalidCases := []string{
|
||||
"ABCD1234-e567-890f-a12b-a123b4cd56ef",
|
||||
"ghij1234-e567-890f-a12b-a123b4cd56ef",
|
||||
"ghij1234+e567_890f-a12b-a123b4cd56ef",
|
||||
"foo/bar",
|
||||
"arn:aws:kms:us-east-1:012345678910:foo/bar",
|
||||
"arn:foo:kms:us-east-1:012345678910:key/abcd1234-a123-456a-a12b-a123b4cd56ef",
|
||||
}
|
||||
for _, invalidCase := range invalidCases {
|
||||
c.AMIKmsKeyId = invalidCase
|
||||
if err := c.Prepare(accessConf, nil); err == nil {
|
||||
t.Fatalf("%s should have failed KMS key validation", invalidCase)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestAMINameValidation(t *testing.T) {
|
||||
c := testAMIConfig()
|
||||
|
||||
accessConf := FakeAccessConfig()
|
||||
|
||||
c.AMIName = "aa"
|
||||
if err := c.Prepare(accessConf, nil); err == nil {
|
||||
t.Fatal("shouldn't be able to have an ami name with less than 3 characters")
|
||||
}
|
||||
|
||||
var longAmiName string
|
||||
for i := 0; i < 129; i++ {
|
||||
longAmiName += "a"
|
||||
}
|
||||
c.AMIName = longAmiName
|
||||
if err := c.Prepare(accessConf, nil); err == nil {
|
||||
t.Fatal("shouldn't be able to have an ami name with great than 128 characters")
|
||||
}
|
||||
|
||||
c.AMIName = "+aaa"
|
||||
if err := c.Prepare(accessConf, nil); err == nil {
|
||||
t.Fatal("shouldn't be able to have an ami name with invalid characters")
|
||||
}
|
||||
|
||||
c.AMIName = "fooBAR1()[] ./-'@_"
|
||||
if err := c.Prepare(accessConf, nil); err != nil {
|
||||
t.Fatal("should be able to use all of the allowed AMI characters")
|
||||
}
|
||||
|
||||
c.AMIName = `xyz-base-2017-04-05-1934`
|
||||
if err := c.Prepare(accessConf, nil); err != nil {
|
||||
t.Fatalf("expected `xyz-base-2017-04-05-1934` to pass validation.")
|
||||
}
|
||||
|
||||
}
|
|
@ -1,90 +0,0 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
)
|
||||
|
||||
func TestArtifact_Impl(t *testing.T) {
|
||||
var _ packersdk.Artifact = new(Artifact)
|
||||
}
|
||||
|
||||
func TestArtifactId(t *testing.T) {
|
||||
expected := `east:foo,west:bar`
|
||||
|
||||
amis := make(map[string]string)
|
||||
amis["east"] = "foo"
|
||||
amis["west"] = "bar"
|
||||
|
||||
a := &Artifact{
|
||||
Amis: amis,
|
||||
}
|
||||
|
||||
result := a.Id()
|
||||
if result != expected {
|
||||
t.Fatalf("bad: %s", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestArtifactState_atlasMetadata(t *testing.T) {
|
||||
a := &Artifact{
|
||||
Amis: map[string]string{
|
||||
"east": "foo",
|
||||
"west": "bar",
|
||||
},
|
||||
}
|
||||
|
||||
actual := a.State("atlas.artifact.metadata")
|
||||
expected := map[string]string{
|
||||
"region.east": "foo",
|
||||
"region.west": "bar",
|
||||
}
|
||||
if !reflect.DeepEqual(actual, expected) {
|
||||
t.Fatalf("bad: %#v", actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestArtifactString(t *testing.T) {
|
||||
expected := `AMIs were created:
|
||||
east: foo
|
||||
west: bar
|
||||
`
|
||||
|
||||
amis := make(map[string]string)
|
||||
amis["east"] = "foo"
|
||||
amis["west"] = "bar"
|
||||
|
||||
a := &Artifact{Amis: amis}
|
||||
result := a.String()
|
||||
if result != expected {
|
||||
t.Fatalf("bad: %s", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestArtifactState(t *testing.T) {
|
||||
expectedData := "this is the data"
|
||||
artifact := &Artifact{
|
||||
StateData: map[string]interface{}{"state_data": expectedData},
|
||||
}
|
||||
|
||||
// Valid state
|
||||
result := artifact.State("state_data")
|
||||
if result != expectedData {
|
||||
t.Fatalf("Bad: State data was %s instead of %s", result, expectedData)
|
||||
}
|
||||
|
||||
// Invalid state
|
||||
result = artifact.State("invalid_key")
|
||||
if result != nil {
|
||||
t.Fatalf("Bad: State should be nil for invalid state data name")
|
||||
}
|
||||
|
||||
// Nil StateData should not fail and should return nil
|
||||
artifact = &Artifact{}
|
||||
result = artifact.State("key")
|
||||
if result != nil {
|
||||
t.Fatalf("Bad: State should be nil for nil StateData")
|
||||
}
|
||||
}
|
|
@ -1,401 +0,0 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/hashicorp/packer-plugin-sdk/template/config"
|
||||
"github.com/hashicorp/packer-plugin-sdk/template/interpolate"
|
||||
)
|
||||
|
||||
func TestBlockDevice(t *testing.T) {
|
||||
cases := []struct {
|
||||
Config *BlockDevice
|
||||
Result *ec2.BlockDeviceMapping
|
||||
}{
|
||||
{
|
||||
Config: &BlockDevice{
|
||||
DeviceName: "/dev/sdb",
|
||||
SnapshotId: "snap-1234",
|
||||
VolumeType: "standard",
|
||||
VolumeSize: 8,
|
||||
DeleteOnTermination: true,
|
||||
},
|
||||
|
||||
Result: &ec2.BlockDeviceMapping{
|
||||
DeviceName: aws.String("/dev/sdb"),
|
||||
Ebs: &ec2.EbsBlockDevice{
|
||||
SnapshotId: aws.String("snap-1234"),
|
||||
VolumeType: aws.String("standard"),
|
||||
VolumeSize: aws.Int64(8),
|
||||
DeleteOnTermination: aws.Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Config: &BlockDevice{
|
||||
DeviceName: "/dev/sdb",
|
||||
VolumeSize: 8,
|
||||
},
|
||||
|
||||
Result: &ec2.BlockDeviceMapping{
|
||||
DeviceName: aws.String("/dev/sdb"),
|
||||
Ebs: &ec2.EbsBlockDevice{
|
||||
VolumeSize: aws.Int64(8),
|
||||
DeleteOnTermination: aws.Bool(false),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Config: &BlockDevice{
|
||||
DeviceName: "/dev/sdb",
|
||||
VolumeType: "io1",
|
||||
VolumeSize: 8,
|
||||
DeleteOnTermination: true,
|
||||
IOPS: aws.Int64(1000),
|
||||
},
|
||||
|
||||
Result: &ec2.BlockDeviceMapping{
|
||||
DeviceName: aws.String("/dev/sdb"),
|
||||
Ebs: &ec2.EbsBlockDevice{
|
||||
VolumeType: aws.String("io1"),
|
||||
VolumeSize: aws.Int64(8),
|
||||
DeleteOnTermination: aws.Bool(true),
|
||||
Iops: aws.Int64(1000),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Config: &BlockDevice{
|
||||
DeviceName: "/dev/sdb",
|
||||
VolumeType: "io2",
|
||||
VolumeSize: 8,
|
||||
DeleteOnTermination: true,
|
||||
IOPS: aws.Int64(1000),
|
||||
},
|
||||
|
||||
Result: &ec2.BlockDeviceMapping{
|
||||
DeviceName: aws.String("/dev/sdb"),
|
||||
Ebs: &ec2.EbsBlockDevice{
|
||||
VolumeType: aws.String("io2"),
|
||||
VolumeSize: aws.Int64(8),
|
||||
DeleteOnTermination: aws.Bool(true),
|
||||
Iops: aws.Int64(1000),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Config: &BlockDevice{
|
||||
DeviceName: "/dev/sdb",
|
||||
VolumeType: "gp2",
|
||||
VolumeSize: 8,
|
||||
DeleteOnTermination: true,
|
||||
Encrypted: config.TriTrue,
|
||||
},
|
||||
|
||||
Result: &ec2.BlockDeviceMapping{
|
||||
DeviceName: aws.String("/dev/sdb"),
|
||||
Ebs: &ec2.EbsBlockDevice{
|
||||
VolumeType: aws.String("gp2"),
|
||||
VolumeSize: aws.Int64(8),
|
||||
DeleteOnTermination: aws.Bool(true),
|
||||
Encrypted: aws.Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Config: &BlockDevice{
|
||||
DeviceName: "/dev/sdb",
|
||||
VolumeType: "gp2",
|
||||
VolumeSize: 8,
|
||||
DeleteOnTermination: true,
|
||||
Encrypted: config.TriTrue,
|
||||
KmsKeyId: "2Fa48a521f-3aff-4b34-a159-376ac5d37812",
|
||||
},
|
||||
|
||||
Result: &ec2.BlockDeviceMapping{
|
||||
DeviceName: aws.String("/dev/sdb"),
|
||||
Ebs: &ec2.EbsBlockDevice{
|
||||
VolumeType: aws.String("gp2"),
|
||||
VolumeSize: aws.Int64(8),
|
||||
DeleteOnTermination: aws.Bool(true),
|
||||
Encrypted: aws.Bool(true),
|
||||
KmsKeyId: aws.String("2Fa48a521f-3aff-4b34-a159-376ac5d37812"),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Config: &BlockDevice{
|
||||
DeviceName: "/dev/sdb",
|
||||
VolumeType: "standard",
|
||||
DeleteOnTermination: true,
|
||||
},
|
||||
|
||||
Result: &ec2.BlockDeviceMapping{
|
||||
DeviceName: aws.String("/dev/sdb"),
|
||||
Ebs: &ec2.EbsBlockDevice{
|
||||
VolumeType: aws.String("standard"),
|
||||
DeleteOnTermination: aws.Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Config: &BlockDevice{
|
||||
DeviceName: "/dev/sdb",
|
||||
VirtualName: "ephemeral0",
|
||||
},
|
||||
|
||||
Result: &ec2.BlockDeviceMapping{
|
||||
DeviceName: aws.String("/dev/sdb"),
|
||||
VirtualName: aws.String("ephemeral0"),
|
||||
},
|
||||
},
|
||||
{
|
||||
Config: &BlockDevice{
|
||||
DeviceName: "/dev/sdb",
|
||||
NoDevice: true,
|
||||
},
|
||||
|
||||
Result: &ec2.BlockDeviceMapping{
|
||||
DeviceName: aws.String("/dev/sdb"),
|
||||
NoDevice: aws.String(""),
|
||||
},
|
||||
},
|
||||
{
|
||||
Config: &BlockDevice{
|
||||
DeviceName: "/dev/sdb",
|
||||
VolumeType: "gp3",
|
||||
VolumeSize: 8,
|
||||
Throughput: aws.Int64(125),
|
||||
IOPS: aws.Int64(3000),
|
||||
DeleteOnTermination: true,
|
||||
Encrypted: config.TriTrue,
|
||||
},
|
||||
|
||||
Result: &ec2.BlockDeviceMapping{
|
||||
DeviceName: aws.String("/dev/sdb"),
|
||||
Ebs: &ec2.EbsBlockDevice{
|
||||
VolumeType: aws.String("gp3"),
|
||||
VolumeSize: aws.Int64(8),
|
||||
Throughput: aws.Int64(125),
|
||||
Iops: aws.Int64(3000),
|
||||
DeleteOnTermination: aws.Bool(true),
|
||||
Encrypted: aws.Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
var amiBlockDevices BlockDevices = []BlockDevice{*tc.Config}
|
||||
|
||||
var launchBlockDevices BlockDevices = []BlockDevice{*tc.Config}
|
||||
|
||||
expected := []*ec2.BlockDeviceMapping{tc.Result}
|
||||
|
||||
amiResults := amiBlockDevices.BuildEC2BlockDeviceMappings()
|
||||
if diff := cmp.Diff(expected, amiResults); diff != "" {
|
||||
t.Fatalf("Bad block device: %s", diff)
|
||||
}
|
||||
|
||||
launchResults := launchBlockDevices.BuildEC2BlockDeviceMappings()
|
||||
if diff := cmp.Diff(expected, launchResults); diff != "" {
|
||||
t.Fatalf("Bad block device: %s", diff)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIOPSValidation(t *testing.T) {
|
||||
|
||||
cases := []struct {
|
||||
device BlockDevice
|
||||
ok bool
|
||||
msg string
|
||||
}{
|
||||
// volume size unknown
|
||||
{
|
||||
device: BlockDevice{
|
||||
DeviceName: "/dev/sdb",
|
||||
VolumeType: "io1",
|
||||
IOPS: aws.Int64(1000),
|
||||
},
|
||||
ok: true,
|
||||
},
|
||||
{
|
||||
device: BlockDevice{
|
||||
DeviceName: "/dev/sdb",
|
||||
VolumeType: "io2",
|
||||
IOPS: aws.Int64(1000),
|
||||
},
|
||||
ok: true,
|
||||
},
|
||||
// ratio requirement satisfied
|
||||
{
|
||||
device: BlockDevice{
|
||||
DeviceName: "/dev/sdb",
|
||||
VolumeType: "io1",
|
||||
VolumeSize: 50,
|
||||
IOPS: aws.Int64(1000),
|
||||
},
|
||||
ok: true,
|
||||
},
|
||||
{
|
||||
device: BlockDevice{
|
||||
DeviceName: "/dev/sdb",
|
||||
VolumeType: "io2",
|
||||
VolumeSize: 100,
|
||||
IOPS: aws.Int64(1000),
|
||||
},
|
||||
ok: true,
|
||||
},
|
||||
// ratio requirement not satisfied
|
||||
{
|
||||
device: BlockDevice{
|
||||
DeviceName: "/dev/sdb",
|
||||
VolumeType: "io1",
|
||||
VolumeSize: 10,
|
||||
IOPS: aws.Int64(2000),
|
||||
},
|
||||
ok: false,
|
||||
msg: "/dev/sdb: the maximum ratio of provisioned IOPS to requested volume size (in GiB) is 50:1 for io1 volumes",
|
||||
},
|
||||
{
|
||||
device: BlockDevice{
|
||||
DeviceName: "/dev/sdb",
|
||||
VolumeType: "io2",
|
||||
VolumeSize: 50,
|
||||
IOPS: aws.Int64(30000),
|
||||
},
|
||||
ok: false,
|
||||
msg: "/dev/sdb: the maximum ratio of provisioned IOPS to requested volume size (in GiB) is 500:1 for io2 volumes",
|
||||
},
|
||||
// exceed max iops
|
||||
{
|
||||
device: BlockDevice{
|
||||
DeviceName: "/dev/sdb",
|
||||
VolumeType: "io2",
|
||||
VolumeSize: 500,
|
||||
IOPS: aws.Int64(99999),
|
||||
},
|
||||
ok: false,
|
||||
msg: "IOPS must be between 100 and 64000 for device /dev/sdb",
|
||||
},
|
||||
// lower than min iops
|
||||
{
|
||||
device: BlockDevice{
|
||||
DeviceName: "/dev/sdb",
|
||||
VolumeType: "io2",
|
||||
VolumeSize: 50,
|
||||
IOPS: aws.Int64(10),
|
||||
},
|
||||
ok: false,
|
||||
msg: "IOPS must be between 100 and 64000 for device /dev/sdb",
|
||||
},
|
||||
// exceed max iops
|
||||
{
|
||||
device: BlockDevice{
|
||||
DeviceName: "/dev/sdb",
|
||||
VolumeType: "gp3",
|
||||
VolumeSize: 50,
|
||||
Throughput: aws.Int64(125),
|
||||
IOPS: aws.Int64(99999),
|
||||
},
|
||||
ok: false,
|
||||
msg: "IOPS must be between 3000 and 16000 for device /dev/sdb",
|
||||
},
|
||||
// lower than min iops
|
||||
{
|
||||
device: BlockDevice{
|
||||
DeviceName: "/dev/sdb",
|
||||
VolumeType: "gp3",
|
||||
VolumeSize: 50,
|
||||
Throughput: aws.Int64(125),
|
||||
IOPS: aws.Int64(10),
|
||||
},
|
||||
ok: false,
|
||||
msg: "IOPS must be between 3000 and 16000 for device /dev/sdb",
|
||||
},
|
||||
}
|
||||
|
||||
ctx := interpolate.Context{}
|
||||
for _, testCase := range cases {
|
||||
err := testCase.device.Prepare(&ctx)
|
||||
if testCase.ok && err != nil {
|
||||
t.Fatalf("should not error, but: %v", err)
|
||||
}
|
||||
if !testCase.ok {
|
||||
if err == nil {
|
||||
t.Fatalf("should error")
|
||||
} else if err.Error() != testCase.msg {
|
||||
t.Fatalf("wrong error: expected %s, found: %v", testCase.msg, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestThroughputValidation(t *testing.T) {
|
||||
|
||||
cases := []struct {
|
||||
device BlockDevice
|
||||
ok bool
|
||||
msg string
|
||||
}{
|
||||
{
|
||||
device: BlockDevice{
|
||||
DeviceName: "/dev/sdb",
|
||||
VolumeType: "gp3",
|
||||
Throughput: aws.Int64(125),
|
||||
IOPS: aws.Int64(3000),
|
||||
},
|
||||
ok: true,
|
||||
},
|
||||
{
|
||||
device: BlockDevice{
|
||||
DeviceName: "/dev/sdb",
|
||||
VolumeType: "gp3",
|
||||
Throughput: aws.Int64(1000),
|
||||
IOPS: aws.Int64(3000),
|
||||
},
|
||||
ok: true,
|
||||
},
|
||||
// exceed max Throughput
|
||||
{
|
||||
device: BlockDevice{
|
||||
DeviceName: "/dev/sdb",
|
||||
VolumeType: "gp3",
|
||||
Throughput: aws.Int64(1001),
|
||||
IOPS: aws.Int64(3000),
|
||||
},
|
||||
ok: false,
|
||||
msg: "Throughput must be between 125 and 1000 for device /dev/sdb",
|
||||
},
|
||||
// lower than min Throughput
|
||||
{
|
||||
device: BlockDevice{
|
||||
DeviceName: "/dev/sdb",
|
||||
VolumeType: "gp3",
|
||||
Throughput: aws.Int64(124),
|
||||
IOPS: aws.Int64(3000),
|
||||
},
|
||||
ok: false,
|
||||
msg: "Throughput must be between 125 and 1000 for device /dev/sdb",
|
||||
},
|
||||
}
|
||||
|
||||
ctx := interpolate.Context{}
|
||||
for _, testCase := range cases {
|
||||
err := testCase.device.Prepare(&ctx)
|
||||
if testCase.ok && err != nil {
|
||||
t.Fatalf("should not error, but: %v", err)
|
||||
}
|
||||
if !testCase.ok {
|
||||
if err == nil {
|
||||
t.Fatalf("should error")
|
||||
} else if err.Error() != testCase.msg {
|
||||
t.Fatalf("wrong error: expected %s, found: %v", testCase.msg, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestStepSourceAmiInfo_BuildFilter(t *testing.T) {
|
||||
filter_key := "name"
|
||||
filter_value := "foo"
|
||||
filter_key2 := "name2"
|
||||
filter_value2 := "foo2"
|
||||
|
||||
inputFilter := map[string]string{filter_key: filter_value, filter_key2: filter_value2}
|
||||
outputFilter := buildEc2Filters(inputFilter)
|
||||
|
||||
// deconstruct filter back into things we can test
|
||||
foundMap := map[string]bool{filter_key: false, filter_key2: false}
|
||||
for _, filter := range outputFilter {
|
||||
for key, value := range inputFilter {
|
||||
if *filter.Name == key && *filter.Values[0] == value {
|
||||
foundMap[key] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for k, v := range foundMap {
|
||||
if !v {
|
||||
t.Fatalf("Fail: should have found value for key: %s", k)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,70 +0,0 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/sts"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
)
|
||||
|
||||
type mockSTS struct {
|
||||
}
|
||||
|
||||
func (m *mockSTS) DecodeAuthorizationMessage(input *sts.DecodeAuthorizationMessageInput) (*sts.DecodeAuthorizationMessageOutput, error) {
|
||||
return &sts.DecodeAuthorizationMessageOutput{
|
||||
DecodedMessage: aws.String(`{
|
||||
"allowed": false,
|
||||
"explicitDeny": true,
|
||||
"matchedStatements": {}
|
||||
}`),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func TestErrorsParsing_RequestFailure(t *testing.T) {
|
||||
|
||||
ae := awserr.New("UnauthorizedOperation",
|
||||
`You are not authorized to perform this operation. Encoded authorization failure message: D9Q7oicjOMr9l2CC-NPP1FiZXK9Ijia1k-3l0siBFCcrK3oSuMFMkBIO5TNj0HdXE-WfwnAcdycFOohfKroNO6toPJEns8RFVfy_M_IjNGmrEFJ6E62pnmBW0OLrMsXxR9FQE4gB4gJzSM0AD6cV6S3FOfqYzWBRX-sQdOT4HryGkFNRoFBr9Xbp-tRwiadwkbdHdfnV9fbRkXmnwCdULml16NBSofC4ZPepLMKmIB5rKjwk-m179UUh2XA-J5no0si6XcRo5GbHQB5QfCIwSHL4vsro2wLZUd16-8OWKyr3tVlTbQe0ERZskqRqRQ5E28QuiBCVV6XstUyo-T4lBSr75Fgnyr3wCO-dS3b_5Ns3WzA2JD4E2AJOAStXIU8IH5YuKkAg7C-dJMuBMPpmKCBEXhNoHDwCyOo5PsV3xMlc0jSb0qYGpfst_TDDtejcZfn7NssUjxVq9qkdH-OXz2gPoQB-hX8ycmZCL5UZwKc3TCLUr7TGnudHjmnMrE9cUo-yTCWfyHPLprhiYhTCKW18EikJ0O1EKI3FJ_b4F19_jFBPARjSwQc7Ut6MNCVzrPdZGYSF6acj5gPaxdy9uSkVQwWXK7Pd5MFP7EBDE1_DgYbzodgwDO2PXeVFUbSLBHKWo_ebZS9ZX2nYPcGss_sYaly0ZVSIJXp7G58B5BoFVhvVH6jYnF9XiAOjMltuP_ycu1pQP1lki500RY3baLvfeYeAsB38XZHKEgWZzq7Fei-uh89q0cjJTmlVyrfRU3q6`,
|
||||
fmt.Errorf("You can't do it!!"))
|
||||
rf := awserr.NewRequestFailure(ae, 400, "abc-def-123-456")
|
||||
|
||||
result := decodeAWSError(&mockSTS{}, rf)
|
||||
if result == nil {
|
||||
t.Error("Expected resulting error")
|
||||
}
|
||||
if !strings.Contains(result.Error(), "Authorization failure message:") {
|
||||
t.Error("Expected authorization failure message")
|
||||
}
|
||||
}
|
||||
|
||||
func TestErrorsParsing_NonAuthorizationFailure(t *testing.T) {
|
||||
|
||||
ae := awserr.New("BadRequest",
|
||||
`You did something wrong. Try again`,
|
||||
fmt.Errorf("Request was no good."))
|
||||
rf := awserr.NewRequestFailure(ae, 400, "abc-def-123-456")
|
||||
|
||||
result := decodeAWSError(&mockSTS{}, rf)
|
||||
if result == nil {
|
||||
t.Error("Expected resulting error")
|
||||
}
|
||||
if result != rf {
|
||||
t.Error("Expected original error to be returned unchanged")
|
||||
}
|
||||
}
|
||||
|
||||
func TestErrorsParsing_NonAWSError(t *testing.T) {
|
||||
|
||||
err := fmt.Errorf("Random error occurred")
|
||||
|
||||
result := decodeAWSError(&mockSTS{}, err)
|
||||
if result == nil {
|
||||
t.Error("Expected resulting error")
|
||||
}
|
||||
if result != err {
|
||||
t.Error("Expected original error to be returned unchanged")
|
||||
}
|
||||
}
|
|
@ -1,91 +0,0 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
"github.com/hashicorp/packer-plugin-sdk/packerbuilderdata"
|
||||
)
|
||||
|
||||
func testImage() *ec2.Image {
|
||||
return &ec2.Image{
|
||||
ImageId: aws.String("ami-abcd1234"),
|
||||
CreationDate: aws.String("ami_test_creation_date"),
|
||||
Name: aws.String("ami_test_name"),
|
||||
OwnerId: aws.String("ami_test_owner_id"),
|
||||
ImageOwnerAlias: aws.String("ami_test_owner_alias"),
|
||||
RootDeviceType: aws.String("ebs"),
|
||||
Tags: []*ec2.Tag{
|
||||
{
|
||||
Key: aws.String("key-1"),
|
||||
Value: aws.String("value-1"),
|
||||
},
|
||||
{
|
||||
Key: aws.String("key-2"),
|
||||
Value: aws.String("value-2"),
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func testState() multistep.StateBag {
|
||||
state := new(multistep.BasicStateBag)
|
||||
return state
|
||||
}
|
||||
|
||||
func testGeneratedData(state multistep.StateBag) packerbuilderdata.GeneratedData {
|
||||
generatedData := packerbuilderdata.GeneratedData{State: state}
|
||||
return generatedData
|
||||
}
|
||||
|
||||
func TestInterpolateBuildInfo_extractBuildInfo_noSourceImage(t *testing.T) {
|
||||
state := testState()
|
||||
generatedData := testGeneratedData(state)
|
||||
buildInfo := extractBuildInfo("foo", state, &generatedData)
|
||||
|
||||
expected := BuildInfoTemplate{
|
||||
BuildRegion: "foo",
|
||||
}
|
||||
if !reflect.DeepEqual(*buildInfo, expected) {
|
||||
t.Fatalf("Unexpected BuildInfoTemplate: expected %#v got %#v\n", expected, *buildInfo)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInterpolateBuildInfo_extractBuildInfo_withSourceImage(t *testing.T) {
|
||||
state := testState()
|
||||
state.Put("source_image", testImage())
|
||||
generatedData := testGeneratedData(state)
|
||||
buildInfo := extractBuildInfo("foo", state, &generatedData)
|
||||
|
||||
expected := BuildInfoTemplate{
|
||||
BuildRegion: "foo",
|
||||
SourceAMI: "ami-abcd1234",
|
||||
SourceAMICreationDate: "ami_test_creation_date",
|
||||
SourceAMIName: "ami_test_name",
|
||||
SourceAMIOwner: "ami_test_owner_id",
|
||||
SourceAMIOwnerName: "ami_test_owner_alias",
|
||||
SourceAMITags: map[string]string{
|
||||
"key-1": "value-1",
|
||||
"key-2": "value-2",
|
||||
},
|
||||
}
|
||||
if !reflect.DeepEqual(*buildInfo, expected) {
|
||||
t.Fatalf("Unexpected BuildInfoTemplate: expected %#v got %#v\n", expected, *buildInfo)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInterpolateBuildInfo_extractBuildInfo_GeneratedDataWithSourceImageName(t *testing.T) {
|
||||
state := testState()
|
||||
state.Put("source_image", testImage())
|
||||
generatedData := testGeneratedData(state)
|
||||
extractBuildInfo("foo", state, &generatedData)
|
||||
|
||||
generatedDataState := state.Get("generated_data").(map[string]interface{})
|
||||
|
||||
if generatedDataState["SourceAMIName"] != "ami_test_name" {
|
||||
t.Fatalf("Unexpected state SourceAMIName: expected %#v got %#v\n", "ami_test_name", generatedDataState["SourceAMIName"])
|
||||
}
|
||||
}
|
|
@ -1,251 +0,0 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"regexp"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/packer-plugin-sdk/communicator"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// Clear out the AWS access key env vars so they don't
|
||||
// affect our tests.
|
||||
os.Setenv("AWS_ACCESS_KEY_ID", "")
|
||||
os.Setenv("AWS_ACCESS_KEY", "")
|
||||
os.Setenv("AWS_SECRET_ACCESS_KEY", "")
|
||||
os.Setenv("AWS_SECRET_KEY", "")
|
||||
}
|
||||
|
||||
func testConfig() *RunConfig {
|
||||
return &RunConfig{
|
||||
SourceAmi: "abcd",
|
||||
InstanceType: "m1.small",
|
||||
|
||||
Comm: communicator.Config{
|
||||
SSH: communicator.SSH{
|
||||
SSHUsername: "foo",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func testConfigFilter() *RunConfig {
|
||||
config := testConfig()
|
||||
config.SourceAmi = ""
|
||||
config.SourceAmiFilter = AmiFilterOptions{}
|
||||
return config
|
||||
}
|
||||
|
||||
func TestRunConfigPrepare(t *testing.T) {
|
||||
c := testConfig()
|
||||
err := c.Prepare(nil)
|
||||
if len(err) > 0 {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunConfigPrepare_InstanceType(t *testing.T) {
|
||||
c := testConfig()
|
||||
c.InstanceType = ""
|
||||
if err := c.Prepare(nil); len(err) != 1 {
|
||||
t.Fatalf("Should error if an instance_type is not specified")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunConfigPrepare_SourceAmi(t *testing.T) {
|
||||
c := testConfig()
|
||||
c.SourceAmi = ""
|
||||
if err := c.Prepare(nil); len(err) != 2 {
|
||||
t.Fatalf("Should error if a source_ami (or source_ami_filter) is not specified")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunConfigPrepare_SourceAmiFilterBlank(t *testing.T) {
|
||||
c := testConfigFilter()
|
||||
if err := c.Prepare(nil); len(err) != 2 {
|
||||
t.Fatalf("Should error if source_ami_filter is empty or not specified (and source_ami is not specified)")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunConfigPrepare_SourceAmiFilterOwnersBlank(t *testing.T) {
|
||||
c := testConfigFilter()
|
||||
filter_key := "name"
|
||||
filter_value := "foo"
|
||||
c.SourceAmiFilter.Filters = map[string]string{filter_key: filter_value}
|
||||
if err := c.Prepare(nil); len(err) != 1 {
|
||||
t.Fatalf("Should error if Owners is not specified)")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunConfigPrepare_SourceAmiFilterGood(t *testing.T) {
|
||||
c := testConfigFilter()
|
||||
owner := "123"
|
||||
filter_key := "name"
|
||||
filter_value := "foo"
|
||||
goodFilter := AmiFilterOptions{
|
||||
Owners: []string{owner},
|
||||
Filters: map[string]string{filter_key: filter_value},
|
||||
}
|
||||
c.SourceAmiFilter = goodFilter
|
||||
if err := c.Prepare(nil); len(err) != 0 {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunConfigPrepare_EnableT2UnlimitedGood(t *testing.T) {
|
||||
c := testConfig()
|
||||
// Must have a T2 instance type if T2 Unlimited is enabled
|
||||
c.InstanceType = "t2.micro"
|
||||
c.EnableT2Unlimited = true
|
||||
err := c.Prepare(nil)
|
||||
if len(err) > 0 {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunConfigPrepare_EnableT2UnlimitedBadInstanceType(t *testing.T) {
|
||||
c := testConfig()
|
||||
// T2 Unlimited cannot be used with instance types other than T2
|
||||
c.InstanceType = "m5.large"
|
||||
c.EnableT2Unlimited = true
|
||||
err := c.Prepare(nil)
|
||||
if len(err) != 1 {
|
||||
t.Fatalf("Should error if T2 Unlimited is enabled with non-T2 instance_type")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunConfigPrepare_EnableT2UnlimitedBadWithSpotInstanceRequest(t *testing.T) {
|
||||
c := testConfig()
|
||||
// T2 Unlimited cannot be used with Spot Instances
|
||||
c.InstanceType = "t2.micro"
|
||||
c.EnableT2Unlimited = true
|
||||
c.SpotPrice = "auto"
|
||||
err := c.Prepare(nil)
|
||||
if len(err) != 1 {
|
||||
t.Fatalf("Should error if T2 Unlimited has been used in conjuntion with a Spot Price request")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunConfigPrepare_SpotAuto(t *testing.T) {
|
||||
c := testConfig()
|
||||
c.SpotPrice = "auto"
|
||||
if err := c.Prepare(nil); len(err) != 0 {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
// Shouldn't error (YET) even though SpotPriceAutoProduct is deprecated
|
||||
c.SpotPriceAutoProduct = "Linux/Unix"
|
||||
if err := c.Prepare(nil); len(err) != 0 {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunConfigPrepare_SSHPort(t *testing.T) {
|
||||
c := testConfig()
|
||||
c.Comm.SSHPort = 0
|
||||
if err := c.Prepare(nil); len(err) != 0 {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
if c.Comm.SSHPort != 22 {
|
||||
t.Fatalf("invalid value: %d", c.Comm.SSHPort)
|
||||
}
|
||||
|
||||
c.Comm.SSHPort = 44
|
||||
if err := c.Prepare(nil); len(err) != 0 {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
if c.Comm.SSHPort != 44 {
|
||||
t.Fatalf("invalid value: %d", c.Comm.SSHPort)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunConfigPrepare_UserData(t *testing.T) {
|
||||
c := testConfig()
|
||||
tf, err := ioutil.TempFile("", "packer")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
defer os.Remove(tf.Name())
|
||||
defer tf.Close()
|
||||
|
||||
c.UserData = "foo"
|
||||
c.UserDataFile = tf.Name()
|
||||
if err := c.Prepare(nil); len(err) != 1 {
|
||||
t.Fatalf("Should error if user_data string and user_data_file have both been specified")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunConfigPrepare_UserDataFile(t *testing.T) {
|
||||
c := testConfig()
|
||||
if err := c.Prepare(nil); len(err) != 0 {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
c.UserDataFile = "idontexistidontthink"
|
||||
if err := c.Prepare(nil); len(err) != 1 {
|
||||
t.Fatalf("Should error if the file specified by user_data_file does not exist")
|
||||
}
|
||||
|
||||
tf, err := ioutil.TempFile("", "packer")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
defer os.Remove(tf.Name())
|
||||
defer tf.Close()
|
||||
|
||||
c.UserDataFile = tf.Name()
|
||||
if err := c.Prepare(nil); len(err) != 0 {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunConfigPrepare_TemporaryKeyPairName(t *testing.T) {
|
||||
c := testConfig()
|
||||
c.Comm.SSHTemporaryKeyPairName = ""
|
||||
if err := c.Prepare(nil); len(err) != 0 {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
if c.Comm.SSHTemporaryKeyPairName == "" {
|
||||
t.Fatal("keypair name is empty")
|
||||
}
|
||||
|
||||
// Match prefix and UUID, e.g. "packer_5790d491-a0b8-c84c-c9d2-2aea55086550".
|
||||
r := regexp.MustCompile(`\Apacker_(?:(?i)[a-f\d]{8}(?:-[a-f\d]{4}){3}-[a-f\d]{12}?)\z`)
|
||||
if !r.MatchString(c.Comm.SSHTemporaryKeyPairName) {
|
||||
t.Fatal("keypair name is not valid")
|
||||
}
|
||||
|
||||
c.Comm.SSHTemporaryKeyPairName = "ssh-key-123"
|
||||
if err := c.Prepare(nil); len(err) != 0 {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
if c.Comm.SSHTemporaryKeyPairName != "ssh-key-123" {
|
||||
t.Fatal("keypair name does not match")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunConfigPrepare_TenancyBad(t *testing.T) {
|
||||
c := testConfig()
|
||||
c.Tenancy = "not_real"
|
||||
|
||||
if err := c.Prepare(nil); len(err) != 1 {
|
||||
t.Fatal("Should error if tenancy is set to an invalid type")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunConfigPrepare_TenancyGood(t *testing.T) {
|
||||
validTenancy := []string{"", "default", "dedicated", "host"}
|
||||
for _, vt := range validTenancy {
|
||||
c := testConfig()
|
||||
c.Tenancy = vt
|
||||
if err := c.Prepare(nil); len(err) != 0 {
|
||||
t.Fatalf("Should not error if tenancy is set to %s", vt)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,141 +0,0 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
)
|
||||
|
||||
const (
|
||||
privateIP = "10.0.0.1"
|
||||
publicIP = "192.168.1.1"
|
||||
privateDNS = "private.dns.test"
|
||||
publicDNS = "public.dns.test"
|
||||
localhost = "localhost"
|
||||
sshHostTemplate = "custom.host.value"
|
||||
)
|
||||
|
||||
func TestSSHHost(t *testing.T) {
|
||||
origSshHostSleepDuration := sshHostSleepDuration
|
||||
defer func() { sshHostSleepDuration = origSshHostSleepDuration }()
|
||||
sshHostSleepDuration = 0
|
||||
|
||||
var cases = []struct {
|
||||
allowTries int
|
||||
vpcId string
|
||||
sshInterface string
|
||||
|
||||
ok bool
|
||||
wantHost string
|
||||
sshHostOverride string
|
||||
}{
|
||||
{1, "", "", true, publicDNS, ""},
|
||||
{1, "", "private_ip", true, privateIP, ""},
|
||||
{1, "", "session_manager", true, localhost, ""},
|
||||
{1, "vpc-id", "", true, publicIP, ""},
|
||||
{1, "vpc-id", "private_ip", true, privateIP, ""},
|
||||
{1, "vpc-id", "private_dns", true, privateDNS, ""},
|
||||
{1, "vpc-id", "public_dns", true, publicDNS, ""},
|
||||
{1, "vpc-id", "public_ip", true, publicIP, ""},
|
||||
{1, "vpc-id", "session_manager", true, localhost, ""},
|
||||
{2, "", "", true, publicDNS, ""},
|
||||
{2, "", "private_ip", true, privateIP, ""},
|
||||
{2, "vpc-id", "", true, publicIP, ""},
|
||||
{2, "vpc-id", "private_ip", true, privateIP, ""},
|
||||
{2, "vpc-id", "private_dns", true, privateDNS, ""},
|
||||
{2, "vpc-id", "public_dns", true, publicDNS, ""},
|
||||
{2, "vpc-id", "public_ip", true, publicIP, ""},
|
||||
{3, "", "", false, "", ""},
|
||||
{3, "", "private_ip", false, "", ""},
|
||||
{3, "vpc-id", "", false, "", ""},
|
||||
{3, "vpc-id", "private_ip", false, "", ""},
|
||||
{3, "vpc-id", "private_dns", false, "", ""},
|
||||
{3, "vpc-id", "public_dns", false, "", ""},
|
||||
{3, "vpc-id", "public_ip", false, "", ""},
|
||||
{1, "", "", true, sshHostTemplate, sshHostTemplate},
|
||||
{1, "vpc-id", "", true, sshHostTemplate, sshHostTemplate},
|
||||
{2, "vpc-id", "private_dns", true, sshHostTemplate, sshHostTemplate},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
testSSHHost(t, c.allowTries, c.vpcId, c.sshInterface, c.ok, c.wantHost,
|
||||
c.sshHostOverride)
|
||||
}
|
||||
}
|
||||
|
||||
func testSSHHost(t *testing.T, allowTries int, vpcId string, sshInterface string,
|
||||
ok bool, wantHost string, sshHostOverride string) {
|
||||
t.Logf("allowTries=%d vpcId=%s sshInterface=%s ok=%t wantHost=%q sshHostOverride=%s",
|
||||
allowTries, vpcId, sshInterface, ok, wantHost, sshHostOverride)
|
||||
|
||||
e := &fakeEC2Describer{
|
||||
allowTries: allowTries,
|
||||
vpcId: vpcId,
|
||||
privateIP: privateIP,
|
||||
publicIP: publicIP,
|
||||
privateDNS: privateDNS,
|
||||
publicDNS: publicDNS,
|
||||
}
|
||||
|
||||
f := SSHHost(e, sshInterface, sshHostOverride)
|
||||
st := &multistep.BasicStateBag{}
|
||||
st.Put("instance", &ec2.Instance{
|
||||
InstanceId: aws.String("instance-id"),
|
||||
})
|
||||
|
||||
host, err := f(st)
|
||||
|
||||
if e.tries > allowTries {
|
||||
t.Fatalf("got %d ec2 DescribeInstances tries, want %d", e.tries, allowTries)
|
||||
}
|
||||
|
||||
switch {
|
||||
case ok && err != nil:
|
||||
t.Fatalf("expected no error, got %+v", err)
|
||||
case !ok && err == nil:
|
||||
t.Fatalf("expected error, got none and host %s", host)
|
||||
}
|
||||
|
||||
if host != wantHost {
|
||||
t.Fatalf("got host %s, want %s", host, wantHost)
|
||||
}
|
||||
}
|
||||
|
||||
type fakeEC2Describer struct {
|
||||
allowTries int
|
||||
tries int
|
||||
|
||||
vpcId string
|
||||
privateIP, publicIP, privateDNS, publicDNS string
|
||||
}
|
||||
|
||||
func (d *fakeEC2Describer) DescribeInstances(in *ec2.DescribeInstancesInput) (*ec2.DescribeInstancesOutput, error) {
|
||||
d.tries++
|
||||
|
||||
instance := &ec2.Instance{
|
||||
InstanceId: aws.String("instance-id"),
|
||||
}
|
||||
|
||||
if d.vpcId != "" {
|
||||
instance.VpcId = aws.String(d.vpcId)
|
||||
}
|
||||
|
||||
if d.tries >= d.allowTries {
|
||||
instance.PublicIpAddress = aws.String(d.publicIP)
|
||||
instance.PrivateIpAddress = aws.String(d.privateIP)
|
||||
instance.PublicDnsName = aws.String(d.publicDNS)
|
||||
instance.PrivateDnsName = aws.String(d.privateDNS)
|
||||
}
|
||||
|
||||
out := &ec2.DescribeInstancesOutput{
|
||||
Reservations: []*ec2.Reservation{
|
||||
{
|
||||
Instances: []*ec2.Instance{instance},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
|
@ -1,66 +0,0 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
)
|
||||
|
||||
func testGetWaiterOptions(t *testing.T) {
|
||||
// no vars are set
|
||||
envValues := overridableWaitVars{
|
||||
envInfo{"AWS_POLL_DELAY_SECONDS", 2, false},
|
||||
envInfo{"AWS_MAX_ATTEMPTS", 0, false},
|
||||
envInfo{"AWS_TIMEOUT_SECONDS", 300, false},
|
||||
}
|
||||
options := applyEnvOverrides(envValues)
|
||||
if len(options) > 0 {
|
||||
t.Fatalf("Did not expect any waiter options to be generated; actual: %#v", options)
|
||||
}
|
||||
|
||||
// all vars are set
|
||||
envValues = overridableWaitVars{
|
||||
envInfo{"AWS_POLL_DELAY_SECONDS", 1, true},
|
||||
envInfo{"AWS_MAX_ATTEMPTS", 800, true},
|
||||
envInfo{"AWS_TIMEOUT_SECONDS", 20, true},
|
||||
}
|
||||
options = applyEnvOverrides(envValues)
|
||||
expected := []request.WaiterOption{
|
||||
request.WithWaiterDelay(request.ConstantWaiterDelay(time.Duration(1) * time.Second)),
|
||||
request.WithWaiterMaxAttempts(800),
|
||||
}
|
||||
if !reflect.DeepEqual(options, expected) {
|
||||
t.Fatalf("expected != actual!! Expected: %#v; Actual: %#v.", expected, options)
|
||||
}
|
||||
|
||||
// poll delay is not set
|
||||
envValues = overridableWaitVars{
|
||||
envInfo{"AWS_POLL_DELAY_SECONDS", 2, false},
|
||||
envInfo{"AWS_MAX_ATTEMPTS", 800, true},
|
||||
envInfo{"AWS_TIMEOUT_SECONDS", 300, false},
|
||||
}
|
||||
options = applyEnvOverrides(envValues)
|
||||
expected = []request.WaiterOption{
|
||||
request.WithWaiterMaxAttempts(800),
|
||||
}
|
||||
if !reflect.DeepEqual(options, expected) {
|
||||
t.Fatalf("expected != actual!! Expected: %#v; Actual: %#v.", expected, options)
|
||||
}
|
||||
|
||||
// poll delay is not set but timeout seconds is
|
||||
envValues = overridableWaitVars{
|
||||
envInfo{"AWS_POLL_DELAY_SECONDS", 2, false},
|
||||
envInfo{"AWS_MAX_ATTEMPTS", 0, false},
|
||||
envInfo{"AWS_TIMEOUT_SECONDS", 20, true},
|
||||
}
|
||||
options = applyEnvOverrides(envValues)
|
||||
expected = []request.WaiterOption{
|
||||
request.WithWaiterDelay(request.ConstantWaiterDelay(time.Duration(2) * time.Second)),
|
||||
request.WithWaiterMaxAttempts(10),
|
||||
}
|
||||
if !reflect.DeepEqual(options, expected) {
|
||||
t.Fatalf("expected != actual!! Expected: %#v; Actual: %#v.", expected, options)
|
||||
}
|
||||
}
|
|
@ -1,404 +0,0 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
"github.com/aws/aws-sdk-go/service/ec2/ec2iface"
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
"github.com/hashicorp/packer-plugin-sdk/template/config"
|
||||
)
|
||||
|
||||
// Define a mock struct to be used in unit tests for common aws steps.
|
||||
type mockEC2Conn struct {
|
||||
ec2iface.EC2API
|
||||
Config *aws.Config
|
||||
|
||||
// Counters to figure out what code path was taken
|
||||
copyImageCount int
|
||||
describeImagesCount int
|
||||
deregisterImageCount int
|
||||
deleteSnapshotCount int
|
||||
waitCount int
|
||||
|
||||
lock sync.Mutex
|
||||
}
|
||||
|
||||
func (m *mockEC2Conn) CopyImage(copyInput *ec2.CopyImageInput) (*ec2.CopyImageOutput, error) {
|
||||
m.lock.Lock()
|
||||
m.copyImageCount++
|
||||
m.lock.Unlock()
|
||||
copiedImage := fmt.Sprintf("%s-copied-%d", *copyInput.SourceImageId, m.copyImageCount)
|
||||
output := &ec2.CopyImageOutput{
|
||||
ImageId: &copiedImage,
|
||||
}
|
||||
return output, nil
|
||||
}
|
||||
|
||||
// functions we have to create mock responses for in order for test to run
|
||||
func (m *mockEC2Conn) DescribeImages(*ec2.DescribeImagesInput) (*ec2.DescribeImagesOutput, error) {
|
||||
m.lock.Lock()
|
||||
m.describeImagesCount++
|
||||
m.lock.Unlock()
|
||||
output := &ec2.DescribeImagesOutput{
|
||||
Images: []*ec2.Image{{}},
|
||||
}
|
||||
return output, nil
|
||||
}
|
||||
|
||||
func (m *mockEC2Conn) DeregisterImage(*ec2.DeregisterImageInput) (*ec2.DeregisterImageOutput, error) {
|
||||
m.lock.Lock()
|
||||
m.deregisterImageCount++
|
||||
m.lock.Unlock()
|
||||
output := &ec2.DeregisterImageOutput{}
|
||||
return output, nil
|
||||
}
|
||||
|
||||
func (m *mockEC2Conn) DeleteSnapshot(*ec2.DeleteSnapshotInput) (*ec2.DeleteSnapshotOutput, error) {
|
||||
m.lock.Lock()
|
||||
m.deleteSnapshotCount++
|
||||
m.lock.Unlock()
|
||||
output := &ec2.DeleteSnapshotOutput{}
|
||||
return output, nil
|
||||
}
|
||||
|
||||
func (m *mockEC2Conn) WaitUntilImageAvailableWithContext(aws.Context, *ec2.DescribeImagesInput, ...request.WaiterOption) error {
|
||||
m.lock.Lock()
|
||||
m.waitCount++
|
||||
m.lock.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
func getMockConn(config *AccessConfig, target string) (ec2iface.EC2API, error) {
|
||||
mockConn := &mockEC2Conn{
|
||||
Config: aws.NewConfig(),
|
||||
}
|
||||
|
||||
return mockConn, nil
|
||||
}
|
||||
|
||||
// Create statebag for running test
|
||||
func tState() multistep.StateBag {
|
||||
state := new(multistep.BasicStateBag)
|
||||
state.Put("ui", &packersdk.BasicUi{
|
||||
Reader: new(bytes.Buffer),
|
||||
Writer: new(bytes.Buffer),
|
||||
})
|
||||
state.Put("amis", map[string]string{"us-east-1": "ami-12345"})
|
||||
state.Put("snapshots", map[string][]string{"us-east-1": {"snap-0012345"}})
|
||||
conn, _ := getMockConn(&AccessConfig{}, "us-east-2")
|
||||
state.Put("ec2", conn)
|
||||
return state
|
||||
}
|
||||
|
||||
func TestStepAMIRegionCopy_duplicates(t *testing.T) {
|
||||
// ------------------------------------------------------------------------
|
||||
// Test that if the original region is added to both Regions and Region,
|
||||
// the ami is only copied once (with encryption).
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
stepAMIRegionCopy := StepAMIRegionCopy{
|
||||
AccessConfig: FakeAccessConfig(),
|
||||
Regions: []string{"us-east-1"},
|
||||
AMIKmsKeyId: "12345",
|
||||
// Original region key in regionkeyids is different than in amikmskeyid
|
||||
RegionKeyIds: map[string]string{"us-east-1": "12345"},
|
||||
EncryptBootVolume: config.TriTrue,
|
||||
Name: "fake-ami-name",
|
||||
OriginalRegion: "us-east-1",
|
||||
}
|
||||
// mock out the region connection code
|
||||
stepAMIRegionCopy.getRegionConn = getMockConn
|
||||
|
||||
state := tState()
|
||||
state.Put("intermediary_image", true)
|
||||
stepAMIRegionCopy.Run(context.Background(), state)
|
||||
|
||||
if len(stepAMIRegionCopy.Regions) != 1 {
|
||||
t.Fatalf("Should have added original ami to Regions one time only")
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Both Region and Regions set, but no encryption - shouldn't copy anything
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
// the ami is only copied once.
|
||||
stepAMIRegionCopy = StepAMIRegionCopy{
|
||||
AccessConfig: FakeAccessConfig(),
|
||||
Regions: []string{"us-east-1"},
|
||||
Name: "fake-ami-name",
|
||||
OriginalRegion: "us-east-1",
|
||||
}
|
||||
// mock out the region connection code
|
||||
state.Put("intermediary_image", false)
|
||||
stepAMIRegionCopy.getRegionConn = getMockConn
|
||||
stepAMIRegionCopy.Run(context.Background(), state)
|
||||
|
||||
if len(stepAMIRegionCopy.Regions) != 0 {
|
||||
t.Fatalf("Should not have added original ami to Regions; not encrypting")
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Both Region and Regions set, but no encryption - shouldn't copy anything,
|
||||
// this tests false as opposed to nil value above.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
// the ami is only copied once.
|
||||
stepAMIRegionCopy = StepAMIRegionCopy{
|
||||
AccessConfig: FakeAccessConfig(),
|
||||
Regions: []string{"us-east-1"},
|
||||
EncryptBootVolume: config.TriFalse,
|
||||
Name: "fake-ami-name",
|
||||
OriginalRegion: "us-east-1",
|
||||
}
|
||||
// mock out the region connection code
|
||||
state.Put("intermediary_image", false)
|
||||
stepAMIRegionCopy.getRegionConn = getMockConn
|
||||
stepAMIRegionCopy.Run(context.Background(), state)
|
||||
|
||||
if len(stepAMIRegionCopy.Regions) != 0 {
|
||||
t.Fatalf("Should not have added original ami to Regions once; not" +
|
||||
"encrypting")
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Multiple regions, many duplicates, and encryption (this shouldn't ever
|
||||
// happen because of our template validation, but good to test it.)
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
stepAMIRegionCopy = StepAMIRegionCopy{
|
||||
AccessConfig: FakeAccessConfig(),
|
||||
// Many duplicates for only 3 actual values
|
||||
Regions: []string{"us-east-1", "us-west-2", "us-west-2", "ap-east-1", "ap-east-1", "ap-east-1"},
|
||||
AMIKmsKeyId: "IlikePancakes",
|
||||
// Original region key in regionkeyids is different than in amikmskeyid
|
||||
RegionKeyIds: map[string]string{"us-east-1": "12345", "us-west-2": "abcde", "ap-east-1": "xyz"},
|
||||
EncryptBootVolume: config.TriTrue,
|
||||
Name: "fake-ami-name",
|
||||
OriginalRegion: "us-east-1",
|
||||
}
|
||||
// mock out the region connection code
|
||||
stepAMIRegionCopy.getRegionConn = getMockConn
|
||||
state.Put("intermediary_image", true)
|
||||
stepAMIRegionCopy.Run(context.Background(), state)
|
||||
|
||||
if len(stepAMIRegionCopy.Regions) != 3 {
|
||||
t.Fatalf("Each AMI should have been added to Regions one time only.")
|
||||
}
|
||||
|
||||
// Also verify that we respect RegionKeyIds over AMIKmsKeyIds:
|
||||
if stepAMIRegionCopy.RegionKeyIds["us-east-1"] != "12345" {
|
||||
t.Fatalf("RegionKeyIds should take precedence over AmiKmsKeyIds")
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Multiple regions, many duplicates, NO encryption
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
stepAMIRegionCopy = StepAMIRegionCopy{
|
||||
AccessConfig: FakeAccessConfig(),
|
||||
// Many duplicates for only 3 actual values
|
||||
Regions: []string{"us-east-1", "us-west-2", "us-west-2", "ap-east-1", "ap-east-1", "ap-east-1"},
|
||||
Name: "fake-ami-name",
|
||||
OriginalRegion: "us-east-1",
|
||||
}
|
||||
// mock out the region connection code
|
||||
stepAMIRegionCopy.getRegionConn = getMockConn
|
||||
state.Put("intermediary_image", false)
|
||||
stepAMIRegionCopy.Run(context.Background(), state)
|
||||
|
||||
if len(stepAMIRegionCopy.Regions) != 2 {
|
||||
t.Fatalf("Each AMI should have been added to Regions one time only, " +
|
||||
"and original region shouldn't be added at all")
|
||||
}
|
||||
}
|
||||
|
||||
func TestStepAmiRegionCopy_nil_encryption(t *testing.T) {
|
||||
// create step
|
||||
stepAMIRegionCopy := StepAMIRegionCopy{
|
||||
AccessConfig: FakeAccessConfig(),
|
||||
Regions: make([]string, 0),
|
||||
AMIKmsKeyId: "",
|
||||
RegionKeyIds: make(map[string]string),
|
||||
EncryptBootVolume: config.TriUnset,
|
||||
Name: "fake-ami-name",
|
||||
OriginalRegion: "us-east-1",
|
||||
}
|
||||
// mock out the region connection code
|
||||
stepAMIRegionCopy.getRegionConn = getMockConn
|
||||
|
||||
state := tState()
|
||||
state.Put("intermediary_image", false)
|
||||
stepAMIRegionCopy.Run(context.Background(), state)
|
||||
|
||||
if stepAMIRegionCopy.toDelete != "" {
|
||||
t.Fatalf("Shouldn't have an intermediary ami if encrypt is nil")
|
||||
}
|
||||
if len(stepAMIRegionCopy.Regions) != 0 {
|
||||
t.Fatalf("Should not have added original ami to original region")
|
||||
}
|
||||
}
|
||||
|
||||
func TestStepAmiRegionCopy_true_encryption(t *testing.T) {
|
||||
// create step
|
||||
stepAMIRegionCopy := StepAMIRegionCopy{
|
||||
AccessConfig: FakeAccessConfig(),
|
||||
Regions: make([]string, 0),
|
||||
AMIKmsKeyId: "",
|
||||
RegionKeyIds: make(map[string]string),
|
||||
EncryptBootVolume: config.TriTrue,
|
||||
Name: "fake-ami-name",
|
||||
OriginalRegion: "us-east-1",
|
||||
}
|
||||
// mock out the region connection code
|
||||
stepAMIRegionCopy.getRegionConn = getMockConn
|
||||
|
||||
state := tState()
|
||||
state.Put("intermediary_image", true)
|
||||
stepAMIRegionCopy.Run(context.Background(), state)
|
||||
|
||||
if stepAMIRegionCopy.toDelete == "" {
|
||||
t.Fatalf("Should delete original AMI if encrypted=true")
|
||||
}
|
||||
if len(stepAMIRegionCopy.Regions) == 0 {
|
||||
t.Fatalf("Should have added original ami to Regions")
|
||||
}
|
||||
}
|
||||
|
||||
func TestStepAmiRegionCopy_nil_intermediary(t *testing.T) {
|
||||
// create step
|
||||
stepAMIRegionCopy := StepAMIRegionCopy{
|
||||
AccessConfig: FakeAccessConfig(),
|
||||
Regions: make([]string, 0),
|
||||
AMIKmsKeyId: "",
|
||||
RegionKeyIds: make(map[string]string),
|
||||
EncryptBootVolume: config.TriFalse,
|
||||
Name: "fake-ami-name",
|
||||
OriginalRegion: "us-east-1",
|
||||
}
|
||||
// mock out the region connection code
|
||||
stepAMIRegionCopy.getRegionConn = getMockConn
|
||||
|
||||
state := tState()
|
||||
stepAMIRegionCopy.Run(context.Background(), state)
|
||||
|
||||
if stepAMIRegionCopy.toDelete != "" {
|
||||
t.Fatalf("Should not delete original AMI if no intermediary")
|
||||
}
|
||||
if len(stepAMIRegionCopy.Regions) != 0 {
|
||||
t.Fatalf("Should not have added original ami to Regions")
|
||||
}
|
||||
}
|
||||
|
||||
func TestStepAmiRegionCopy_AMISkipBuildRegion(t *testing.T) {
|
||||
// ------------------------------------------------------------------------
|
||||
// skip build region is true
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
stepAMIRegionCopy := StepAMIRegionCopy{
|
||||
AccessConfig: FakeAccessConfig(),
|
||||
Regions: []string{"us-west-1"},
|
||||
AMIKmsKeyId: "",
|
||||
RegionKeyIds: map[string]string{"us-west-1": "abcde"},
|
||||
Name: "fake-ami-name",
|
||||
OriginalRegion: "us-east-1",
|
||||
AMISkipBuildRegion: true,
|
||||
}
|
||||
// mock out the region connection code
|
||||
stepAMIRegionCopy.getRegionConn = getMockConn
|
||||
|
||||
state := tState()
|
||||
state.Put("intermediary_image", true)
|
||||
stepAMIRegionCopy.Run(context.Background(), state)
|
||||
|
||||
if stepAMIRegionCopy.toDelete == "" {
|
||||
t.Fatalf("Should delete original AMI if skip_save_build_region=true")
|
||||
}
|
||||
if len(stepAMIRegionCopy.Regions) != 1 {
|
||||
t.Fatalf("Should not have added original ami to Regions; Regions: %#v", stepAMIRegionCopy.Regions)
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// skip build region is false.
|
||||
// ------------------------------------------------------------------------
|
||||
stepAMIRegionCopy = StepAMIRegionCopy{
|
||||
AccessConfig: FakeAccessConfig(),
|
||||
Regions: []string{"us-west-1"},
|
||||
AMIKmsKeyId: "",
|
||||
RegionKeyIds: make(map[string]string),
|
||||
Name: "fake-ami-name",
|
||||
OriginalRegion: "us-east-1",
|
||||
AMISkipBuildRegion: false,
|
||||
}
|
||||
// mock out the region connection code
|
||||
stepAMIRegionCopy.getRegionConn = getMockConn
|
||||
|
||||
state.Put("intermediary_image", false) // not encrypted
|
||||
stepAMIRegionCopy.Run(context.Background(), state)
|
||||
|
||||
if stepAMIRegionCopy.toDelete != "" {
|
||||
t.Fatalf("Shouldn't have an intermediary AMI, so dont delete original ami")
|
||||
}
|
||||
if len(stepAMIRegionCopy.Regions) != 1 {
|
||||
t.Fatalf("Should not have added original ami to Regions; Regions: %#v", stepAMIRegionCopy.Regions)
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// skip build region is false, but encrypt is true
|
||||
// ------------------------------------------------------------------------
|
||||
stepAMIRegionCopy = StepAMIRegionCopy{
|
||||
AccessConfig: FakeAccessConfig(),
|
||||
Regions: []string{"us-west-1"},
|
||||
AMIKmsKeyId: "",
|
||||
RegionKeyIds: map[string]string{"us-west-1": "abcde"},
|
||||
Name: "fake-ami-name",
|
||||
OriginalRegion: "us-east-1",
|
||||
AMISkipBuildRegion: false,
|
||||
EncryptBootVolume: config.TriTrue,
|
||||
}
|
||||
// mock out the region connection code
|
||||
stepAMIRegionCopy.getRegionConn = getMockConn
|
||||
|
||||
state.Put("intermediary_image", true) //encrypted
|
||||
stepAMIRegionCopy.Run(context.Background(), state)
|
||||
|
||||
if stepAMIRegionCopy.toDelete == "" {
|
||||
t.Fatalf("Have to delete intermediary AMI")
|
||||
}
|
||||
if len(stepAMIRegionCopy.Regions) != 2 {
|
||||
t.Fatalf("Should have added original ami to Regions; Regions: %#v", stepAMIRegionCopy.Regions)
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// skip build region is true, and encrypt is true
|
||||
// ------------------------------------------------------------------------
|
||||
stepAMIRegionCopy = StepAMIRegionCopy{
|
||||
AccessConfig: FakeAccessConfig(),
|
||||
Regions: []string{"us-west-1"},
|
||||
AMIKmsKeyId: "",
|
||||
RegionKeyIds: map[string]string{"us-west-1": "abcde"},
|
||||
Name: "fake-ami-name",
|
||||
OriginalRegion: "us-east-1",
|
||||
AMISkipBuildRegion: true,
|
||||
EncryptBootVolume: config.TriTrue,
|
||||
}
|
||||
// mock out the region connection code
|
||||
stepAMIRegionCopy.getRegionConn = getMockConn
|
||||
|
||||
state.Put("intermediary_image", true) //encrypted
|
||||
stepAMIRegionCopy.Run(context.Background(), state)
|
||||
|
||||
if stepAMIRegionCopy.toDelete == "" {
|
||||
t.Fatalf("Have to delete intermediary AMI")
|
||||
}
|
||||
if len(stepAMIRegionCopy.Regions) != 1 {
|
||||
t.Fatalf("Should not have added original ami to Regions; Regions: %#v", stepAMIRegionCopy.Regions)
|
||||
}
|
||||
}
|
|
@ -1,70 +0,0 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
)
|
||||
|
||||
//DescribeVpcs mocks an ec2.DescribeVpcsOutput for a given input
|
||||
func (m *mockEC2Conn) DescribeVpcs(input *ec2.DescribeVpcsInput) (*ec2.DescribeVpcsOutput, error) {
|
||||
|
||||
if input == nil || aws.StringValue(input.VpcIds[0]) == "" {
|
||||
return nil, fmt.Errorf("oops looks like we need more input")
|
||||
}
|
||||
|
||||
var isDefault bool
|
||||
vpcID := aws.StringValue(input.VpcIds[0])
|
||||
|
||||
//only one default VPC per region
|
||||
if strings.Contains("vpc-default-id", vpcID) {
|
||||
isDefault = true
|
||||
}
|
||||
|
||||
output := &ec2.DescribeVpcsOutput{
|
||||
Vpcs: []*ec2.Vpc{
|
||||
{IsDefault: aws.Bool(isDefault),
|
||||
VpcId: aws.String(vpcID),
|
||||
},
|
||||
},
|
||||
}
|
||||
return output, nil
|
||||
}
|
||||
|
||||
func TestStepPreValidate_checkVpc(t *testing.T) {
|
||||
tt := []struct {
|
||||
name string
|
||||
step StepPreValidate
|
||||
errorExpected bool
|
||||
}{
|
||||
{"DefaultVpc", StepPreValidate{VpcId: "vpc-default-id"}, false},
|
||||
{"NonDefaultVpcNoSubnet", StepPreValidate{VpcId: "vpc-1234567890"}, true},
|
||||
{"NonDefaultVpcWithSubnet", StepPreValidate{VpcId: "vpc-1234567890", SubnetId: "subnet-1234567890"}, false},
|
||||
{"SubnetWithNoVpc", StepPreValidate{SubnetId: "subnet-1234567890"}, false},
|
||||
{"NoVpcInformation", StepPreValidate{}, false},
|
||||
{"NonDefaultVpcWithSubnetFilter", StepPreValidate{VpcId: "vpc-1234567890", HasSubnetFilter: true}, false},
|
||||
}
|
||||
|
||||
mockConn, err := getMockConn(nil, "")
|
||||
if err != nil {
|
||||
t.Fatal("unable to get a mock connection")
|
||||
}
|
||||
|
||||
for _, tc := range tt {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
err := tc.step.checkVpc(mockConn)
|
||||
|
||||
if tc.errorExpected && err == nil {
|
||||
t.Errorf("expected a validation error for %q but got %q", tc.name, err)
|
||||
}
|
||||
|
||||
if !tc.errorExpected && err != nil {
|
||||
t.Errorf("expected a validation to pass for %q but got %q", tc.name, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
|
@ -1,366 +0,0 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
"github.com/aws/aws-sdk-go/service/ec2/ec2iface"
|
||||
"github.com/hashicorp/packer-plugin-sdk/communicator"
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
)
|
||||
|
||||
// Create statebag for running test
|
||||
func tStateSpot() multistep.StateBag {
|
||||
state := new(multistep.BasicStateBag)
|
||||
state.Put("ui", &packersdk.BasicUi{
|
||||
Reader: new(bytes.Buffer),
|
||||
Writer: new(bytes.Buffer),
|
||||
})
|
||||
state.Put("availability_zone", "us-east-1c")
|
||||
state.Put("securityGroupIds", []string{"sg-0b8984db72f213dc3"})
|
||||
state.Put("iamInstanceProfile", "packer-123")
|
||||
state.Put("subnet_id", "subnet-077fde4e")
|
||||
state.Put("source_image", "")
|
||||
return state
|
||||
}
|
||||
|
||||
func getBasicStep() *StepRunSpotInstance {
|
||||
stepRunSpotInstance := StepRunSpotInstance{
|
||||
PollingConfig: new(AWSPollingConfig),
|
||||
AssociatePublicIpAddress: false,
|
||||
LaunchMappings: BlockDevices{},
|
||||
BlockDurationMinutes: 0,
|
||||
Debug: false,
|
||||
Comm: &communicator.Config{
|
||||
SSH: communicator.SSH{
|
||||
SSHKeyPairName: "foo",
|
||||
},
|
||||
},
|
||||
EbsOptimized: false,
|
||||
ExpectedRootDevice: "ebs",
|
||||
InstanceInitiatedShutdownBehavior: "stop",
|
||||
InstanceType: "t2.micro",
|
||||
Region: "us-east-1",
|
||||
SourceAMI: "",
|
||||
SpotPrice: "auto",
|
||||
SpotTags: nil,
|
||||
Tags: map[string]string{},
|
||||
VolumeTags: nil,
|
||||
UserData: "",
|
||||
UserDataFile: "",
|
||||
}
|
||||
|
||||
return &stepRunSpotInstance
|
||||
}
|
||||
|
||||
func TestCreateTemplateData(t *testing.T) {
|
||||
state := tStateSpot()
|
||||
stepRunSpotInstance := getBasicStep()
|
||||
template := stepRunSpotInstance.CreateTemplateData(aws.String("userdata"), "az", state,
|
||||
&ec2.LaunchTemplateInstanceMarketOptionsRequest{})
|
||||
|
||||
// expected := []*ec2.LaunchTemplateInstanceNetworkInterfaceSpecificationRequest{
|
||||
// &ec2.LaunchTemplateInstanceNetworkInterfaceSpecificationRequest{
|
||||
// DeleteOnTermination: aws.Bool(true),
|
||||
// DeviceIndex: aws.Int64(0),
|
||||
// Groups: aws.StringSlice([]string{"sg-0b8984db72f213dc3"}),
|
||||
// SubnetId: aws.String("subnet-077fde4e"),
|
||||
// },
|
||||
// }
|
||||
// if expected != template.NetworkInterfaces {
|
||||
if template.NetworkInterfaces == nil {
|
||||
t.Fatalf("Template should have contained a networkInterface object: recieved %#v", template.NetworkInterfaces)
|
||||
}
|
||||
|
||||
if *template.IamInstanceProfile.Name != state.Get("iamInstanceProfile") {
|
||||
t.Fatalf("Template should have contained a InstanceProfile name: recieved %#v", template.IamInstanceProfile.Name)
|
||||
}
|
||||
|
||||
// Rerun, this time testing that we set security group IDs
|
||||
state.Put("subnet_id", "")
|
||||
template = stepRunSpotInstance.CreateTemplateData(aws.String("userdata"), "az", state,
|
||||
&ec2.LaunchTemplateInstanceMarketOptionsRequest{})
|
||||
if template.NetworkInterfaces != nil {
|
||||
t.Fatalf("Template shouldn't contain network interfaces object if subnet_id is unset.")
|
||||
}
|
||||
|
||||
// Rerun, this time testing that instance doesn't have instance profile is iamInstanceProfile is unset
|
||||
state.Put("iamInstanceProfile", "")
|
||||
template = stepRunSpotInstance.CreateTemplateData(aws.String("userdata"), "az", state,
|
||||
&ec2.LaunchTemplateInstanceMarketOptionsRequest{})
|
||||
fmt.Println(template.IamInstanceProfile)
|
||||
if *template.IamInstanceProfile.Name != "" {
|
||||
t.Fatalf("Template shouldn't contain instance profile if iamInstanceProfile is unset.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateTemplateData_NoEphemeral(t *testing.T) {
|
||||
state := tStateSpot()
|
||||
stepRunSpotInstance := getBasicStep()
|
||||
stepRunSpotInstance.NoEphemeral = true
|
||||
template := stepRunSpotInstance.CreateTemplateData(aws.String("userdata"), "az", state,
|
||||
&ec2.LaunchTemplateInstanceMarketOptionsRequest{})
|
||||
if len(template.BlockDeviceMappings) != 26 {
|
||||
t.Fatalf("Should have created 26 mappings to keep ephemeral drives from appearing.")
|
||||
}
|
||||
|
||||
// Now check that noEphemeral doesn't mess with the mappings in real life.
|
||||
// state = tStateSpot()
|
||||
// stepRunSpotInstance = getBasicStep()
|
||||
// stepRunSpotInstance.NoEphemeral = true
|
||||
// mappings := []*ec2.InstanceBlockDeviceMapping{
|
||||
// &ec2.InstanceBlockDeviceMapping{
|
||||
// DeviceName: "xvda",
|
||||
// Ebs: {
|
||||
// DeleteOnTermination: true,
|
||||
// Status: "attaching",
|
||||
// VolumeId: "vol-044cd49c330f21c05",
|
||||
// },
|
||||
// },
|
||||
// &ec2.InstanceBlockDeviceMapping{
|
||||
// DeviceName: "/dev/xvdf",
|
||||
// Ebs: {
|
||||
// DeleteOnTermination: false,
|
||||
// Status: "attaching",
|
||||
// VolumeId: "vol-0eefaf2d6ae35827e",
|
||||
// },
|
||||
// },
|
||||
// }
|
||||
// template = stepRunSpotInstance.CreateTemplateData(aws.String("userdata"), "az", state,
|
||||
// &ec2.LaunchTemplateInstanceMarketOptionsRequest{})
|
||||
// if len(*template.BlockDeviceMappings) != 26 {
|
||||
// t.Fatalf("Should have created 26 mappings to keep ephemeral drives from appearing.")
|
||||
// }
|
||||
}
|
||||
|
||||
type runSpotEC2ConnMock struct {
|
||||
ec2iface.EC2API
|
||||
|
||||
CreateLaunchTemplateParams []*ec2.CreateLaunchTemplateInput
|
||||
CreateLaunchTemplateFn func(*ec2.CreateLaunchTemplateInput) (*ec2.CreateLaunchTemplateOutput, error)
|
||||
|
||||
CreateFleetParams []*ec2.CreateFleetInput
|
||||
CreateFleetFn func(*ec2.CreateFleetInput) (*ec2.CreateFleetOutput, error)
|
||||
|
||||
CreateTagsParams []*ec2.CreateTagsInput
|
||||
CreateTagsFn func(*ec2.CreateTagsInput) (*ec2.CreateTagsOutput, error)
|
||||
|
||||
DescribeInstancesParams []*ec2.DescribeInstancesInput
|
||||
DescribeInstancesFn func(input *ec2.DescribeInstancesInput) (*ec2.DescribeInstancesOutput, error)
|
||||
}
|
||||
|
||||
func (m *runSpotEC2ConnMock) CreateLaunchTemplate(req *ec2.CreateLaunchTemplateInput) (*ec2.CreateLaunchTemplateOutput, error) {
|
||||
m.CreateLaunchTemplateParams = append(m.CreateLaunchTemplateParams, req)
|
||||
resp, err := m.CreateLaunchTemplateFn(req)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
func (m *runSpotEC2ConnMock) CreateFleet(req *ec2.CreateFleetInput) (*ec2.CreateFleetOutput, error) {
|
||||
m.CreateFleetParams = append(m.CreateFleetParams, req)
|
||||
if m.CreateFleetFn != nil {
|
||||
resp, err := m.CreateFleetFn(req)
|
||||
return resp, err
|
||||
} else {
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (m *runSpotEC2ConnMock) DescribeInstances(req *ec2.DescribeInstancesInput) (*ec2.DescribeInstancesOutput, error) {
|
||||
m.DescribeInstancesParams = append(m.DescribeInstancesParams, req)
|
||||
if m.DescribeInstancesFn != nil {
|
||||
resp, err := m.DescribeInstancesFn(req)
|
||||
return resp, err
|
||||
} else {
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (m *runSpotEC2ConnMock) CreateTags(req *ec2.CreateTagsInput) (*ec2.CreateTagsOutput, error) {
|
||||
m.CreateTagsParams = append(m.CreateTagsParams, req)
|
||||
if m.CreateTagsFn != nil {
|
||||
resp, err := m.CreateTagsFn(req)
|
||||
return resp, err
|
||||
} else {
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
func defaultEc2Mock(instanceId, spotRequestId, volumeId, launchTemplateId *string) *runSpotEC2ConnMock {
|
||||
instance := &ec2.Instance{
|
||||
InstanceId: instanceId,
|
||||
SpotInstanceRequestId: spotRequestId,
|
||||
BlockDeviceMappings: []*ec2.InstanceBlockDeviceMapping{
|
||||
{
|
||||
Ebs: &ec2.EbsInstanceBlockDevice{
|
||||
VolumeId: volumeId,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
return &runSpotEC2ConnMock{
|
||||
CreateLaunchTemplateFn: func(in *ec2.CreateLaunchTemplateInput) (*ec2.CreateLaunchTemplateOutput, error) {
|
||||
return &ec2.CreateLaunchTemplateOutput{
|
||||
LaunchTemplate: &ec2.LaunchTemplate{
|
||||
LaunchTemplateId: launchTemplateId,
|
||||
},
|
||||
Warning: nil,
|
||||
}, nil
|
||||
},
|
||||
CreateFleetFn: func(*ec2.CreateFleetInput) (*ec2.CreateFleetOutput, error) {
|
||||
return &ec2.CreateFleetOutput{
|
||||
Errors: nil,
|
||||
FleetId: nil,
|
||||
Instances: []*ec2.CreateFleetInstance{
|
||||
{
|
||||
InstanceIds: []*string{instanceId},
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
},
|
||||
DescribeInstancesFn: func(input *ec2.DescribeInstancesInput) (*ec2.DescribeInstancesOutput, error) {
|
||||
return &ec2.DescribeInstancesOutput{
|
||||
NextToken: nil,
|
||||
Reservations: []*ec2.Reservation{
|
||||
{
|
||||
Instances: []*ec2.Instance{instance},
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestRun(t *testing.T) {
|
||||
instanceId := aws.String("test-instance-id")
|
||||
spotRequestId := aws.String("spot-id")
|
||||
volumeId := aws.String("volume-id")
|
||||
launchTemplateId := aws.String("launchTemplateId")
|
||||
ec2Mock := defaultEc2Mock(instanceId, spotRequestId, volumeId, launchTemplateId)
|
||||
|
||||
uiMock := packersdk.TestUi(t)
|
||||
|
||||
state := tStateSpot()
|
||||
state.Put("ec2", ec2Mock)
|
||||
state.Put("ui", uiMock)
|
||||
state.Put("source_image", testImage())
|
||||
|
||||
stepRunSpotInstance := getBasicStep()
|
||||
stepRunSpotInstance.Tags["Name"] = "Packer Builder"
|
||||
stepRunSpotInstance.Tags["test-tag"] = "test-value"
|
||||
stepRunSpotInstance.SpotTags = map[string]string{
|
||||
"spot-tag": "spot-tag-value",
|
||||
}
|
||||
stepRunSpotInstance.VolumeTags = map[string]string{
|
||||
"volume-tag": "volume-tag-value",
|
||||
}
|
||||
|
||||
ctx := context.TODO()
|
||||
action := stepRunSpotInstance.Run(ctx, state)
|
||||
|
||||
if err := state.Get("error"); err != nil {
|
||||
t.Fatalf("should not error, but: %v", err)
|
||||
}
|
||||
|
||||
if action != multistep.ActionContinue {
|
||||
t.Fatalf("shoul continue, but: %v", action)
|
||||
}
|
||||
|
||||
if len(ec2Mock.CreateLaunchTemplateParams) != 1 {
|
||||
t.Fatalf("createLaunchTemplate should be invoked once, but invoked %v", len(ec2Mock.CreateLaunchTemplateParams))
|
||||
}
|
||||
launchTemplateName := ec2Mock.CreateLaunchTemplateParams[0].LaunchTemplateName
|
||||
|
||||
if len(ec2Mock.CreateLaunchTemplateParams[0].TagSpecifications) != 1 {
|
||||
t.Fatalf("exactly one launch template tag specification expected")
|
||||
}
|
||||
if *ec2Mock.CreateLaunchTemplateParams[0].TagSpecifications[0].ResourceType != "launch-template" {
|
||||
t.Fatalf("resource type 'launch-template' expected")
|
||||
}
|
||||
if len(ec2Mock.CreateLaunchTemplateParams[0].TagSpecifications[0].Tags) != 1 {
|
||||
t.Fatalf("1 launch template tag expected")
|
||||
}
|
||||
|
||||
nameTag := ec2Mock.CreateLaunchTemplateParams[0].TagSpecifications[0].Tags[0]
|
||||
if *nameTag.Key != "spot-tag" || *nameTag.Value != "spot-tag-value" {
|
||||
t.Fatalf("expected spot-tag: spot-tag-value")
|
||||
}
|
||||
|
||||
if len(ec2Mock.CreateFleetParams) != 1 {
|
||||
t.Fatalf("createFleet should be invoked once, but invoked %v", len(ec2Mock.CreateLaunchTemplateParams))
|
||||
}
|
||||
if *ec2Mock.CreateFleetParams[0].TargetCapacitySpecification.DefaultTargetCapacityType != "spot" {
|
||||
t.Fatalf("capacity type should be spot")
|
||||
}
|
||||
if *ec2Mock.CreateFleetParams[0].TargetCapacitySpecification.TotalTargetCapacity != 1 {
|
||||
t.Fatalf("target capacity should be 1")
|
||||
}
|
||||
if len(ec2Mock.CreateFleetParams[0].LaunchTemplateConfigs) != 1 {
|
||||
t.Fatalf("exactly one launch config template expected")
|
||||
}
|
||||
if *ec2Mock.CreateFleetParams[0].LaunchTemplateConfigs[0].LaunchTemplateSpecification.LaunchTemplateName != *launchTemplateName {
|
||||
t.Fatalf("launchTemplateName should match in createLaunchTemplate and createFleet requests")
|
||||
}
|
||||
|
||||
if len(ec2Mock.DescribeInstancesParams) != 1 {
|
||||
t.Fatalf("describeInstancesParams should be invoked once, but invoked %v", len(ec2Mock.DescribeInstancesParams))
|
||||
}
|
||||
if *ec2Mock.DescribeInstancesParams[0].InstanceIds[0] != *instanceId {
|
||||
t.Fatalf("instanceId should match from createFleet response")
|
||||
}
|
||||
|
||||
uiMock.Say(fmt.Sprintf("%v", ec2Mock.CreateTagsParams))
|
||||
if len(ec2Mock.CreateTagsParams) != 3 {
|
||||
t.Fatalf("createTags should be invoked 3 times")
|
||||
}
|
||||
if len(ec2Mock.CreateTagsParams[0].Resources) != 1 || *ec2Mock.CreateTagsParams[0].Resources[0] != *spotRequestId {
|
||||
t.Fatalf("should create tags for spot request")
|
||||
}
|
||||
if len(ec2Mock.CreateTagsParams[1].Resources) != 1 || *ec2Mock.CreateTagsParams[1].Resources[0] != *instanceId {
|
||||
t.Fatalf("should create tags for instance")
|
||||
}
|
||||
if len(ec2Mock.CreateTagsParams[2].Resources) != 1 || ec2Mock.CreateTagsParams[2].Resources[0] != volumeId {
|
||||
t.Fatalf("should create tags for volume")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRun_NoSpotTags(t *testing.T) {
|
||||
instanceId := aws.String("test-instance-id")
|
||||
spotRequestId := aws.String("spot-id")
|
||||
volumeId := aws.String("volume-id")
|
||||
launchTemplateId := aws.String("lt-id")
|
||||
ec2Mock := defaultEc2Mock(instanceId, spotRequestId, volumeId, launchTemplateId)
|
||||
|
||||
uiMock := packersdk.TestUi(t)
|
||||
|
||||
state := tStateSpot()
|
||||
state.Put("ec2", ec2Mock)
|
||||
state.Put("ui", uiMock)
|
||||
state.Put("source_image", testImage())
|
||||
|
||||
stepRunSpotInstance := getBasicStep()
|
||||
stepRunSpotInstance.Tags["Name"] = "Packer Builder"
|
||||
stepRunSpotInstance.Tags["test-tag"] = "test-value"
|
||||
stepRunSpotInstance.VolumeTags = map[string]string{
|
||||
"volume-tag": "volume-tag-value",
|
||||
}
|
||||
|
||||
ctx := context.TODO()
|
||||
action := stepRunSpotInstance.Run(ctx, state)
|
||||
|
||||
if err := state.Get("error"); err != nil {
|
||||
t.Fatalf("should not error, but: %v", err)
|
||||
}
|
||||
|
||||
if action != multistep.ActionContinue {
|
||||
t.Fatalf("shoul continue, but: %v", action)
|
||||
}
|
||||
|
||||
if len(ec2Mock.CreateLaunchTemplateParams[0].TagSpecifications) != 0 {
|
||||
t.Fatalf("0 launch template tags expected")
|
||||
}
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestStepSourceAmiInfo_PVImage(t *testing.T) {
|
||||
err := new(StepSourceAMIInfo).canEnableEnhancedNetworking(&ec2.Image{
|
||||
VirtualizationType: aws.String("paravirtual"),
|
||||
})
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestStepSourceAmiInfo_HVMImage(t *testing.T) {
|
||||
err := new(StepSourceAMIInfo).canEnableEnhancedNetworking(&ec2.Image{
|
||||
VirtualizationType: aws.String("hvm"),
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestStepSourceAmiInfo_PVImageWithAMIVirtPV(t *testing.T) {
|
||||
stepSourceAMIInfo := StepSourceAMIInfo{
|
||||
AMIVirtType: "paravirtual",
|
||||
}
|
||||
err := stepSourceAMIInfo.canEnableEnhancedNetworking(&ec2.Image{
|
||||
VirtualizationType: aws.String("paravirtual"),
|
||||
})
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestStepSourceAmiInfo_PVImageWithAMIVirtHVM(t *testing.T) {
|
||||
stepSourceAMIInfo := StepSourceAMIInfo{
|
||||
AMIVirtType: "hvm",
|
||||
}
|
||||
err := stepSourceAMIInfo.canEnableEnhancedNetworking(&ec2.Image{
|
||||
VirtualizationType: aws.String("paravirtual"),
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestAMITemplatePrepare_clean(t *testing.T) {
|
||||
origName := "AMZamz09()./-_:&^ $%[]#'@"
|
||||
expected := "AMZamz09()./-_--- --[]-'@"
|
||||
|
||||
name := templateCleanAMIName(origName)
|
||||
|
||||
if name != expected {
|
||||
t.Fatalf("template names do not match: expected %s got %s\n", expected, name)
|
||||
}
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
package amazon_acc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
awscommon "github.com/hashicorp/packer/builder/amazon/common"
|
||||
)
|
||||
|
||||
type AWSHelper struct {
|
||||
Region string
|
||||
AMIName string
|
||||
}
|
||||
|
||||
func (a *AWSHelper) CleanUpAmi() error {
|
||||
accessConfig := &awscommon.AccessConfig{}
|
||||
session, err := accessConfig.Session()
|
||||
if err != nil {
|
||||
return fmt.Errorf("AWSAMICleanUp: Unable to create aws session %s", err.Error())
|
||||
}
|
||||
|
||||
regionconn := ec2.New(session.Copy(&aws.Config{
|
||||
Region: aws.String(a.Region),
|
||||
}))
|
||||
|
||||
resp, err := regionconn.DescribeImages(&ec2.DescribeImagesInput{
|
||||
Owners: aws.StringSlice([]string{"self"}),
|
||||
Filters: []*ec2.Filter{{
|
||||
Name: aws.String("name"),
|
||||
Values: aws.StringSlice([]string{a.AMIName}),
|
||||
}}})
|
||||
if err != nil {
|
||||
return fmt.Errorf("AWSAMICleanUp: Unable to find Image %s: %s", a.AMIName, err.Error())
|
||||
}
|
||||
|
||||
if resp != nil && len(resp.Images) > 0 {
|
||||
_, err = regionconn.DeregisterImage(&ec2.DeregisterImageInput{
|
||||
ImageId: resp.Images[0].ImageId,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("AWSAMICleanUp: Unable to Deregister Image %s", err.Error())
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
package amazon_acc
|
||||
|
||||
// This is the code necessary for running the provisioner acceptance tests.
|
||||
// It provides the builder config and cleans up created resource.
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
amazonebsbuilder "github.com/hashicorp/packer/builder/amazon/ebs"
|
||||
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
)
|
||||
|
||||
type AmazonEBSAccTest struct{}
|
||||
|
||||
func (s *AmazonEBSAccTest) GetConfigs() (map[string]string, error) {
|
||||
fixtures := map[string]string{
|
||||
"linux": "amazon-ebs.txt",
|
||||
"windows": "amazon-ebs_windows.txt",
|
||||
}
|
||||
|
||||
configs := make(map[string]string)
|
||||
|
||||
for distro, fixture := range fixtures {
|
||||
fileName := fixture
|
||||
filePath := filepath.Join("../../builder/amazon/ebs/acceptance/test-fixtures/", fileName)
|
||||
config, err := os.Open(filePath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Expected to find %s", filePath)
|
||||
}
|
||||
defer config.Close()
|
||||
|
||||
file, err := ioutil.ReadAll(config)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Unable to read %s", filePath)
|
||||
}
|
||||
|
||||
configs[distro] = string(file)
|
||||
|
||||
}
|
||||
return configs, nil
|
||||
}
|
||||
|
||||
func (s *AmazonEBSAccTest) CleanUp() error {
|
||||
helper := AWSHelper{
|
||||
Region: "us-east-1",
|
||||
AMIName: "packer-acc-test",
|
||||
}
|
||||
return helper.CleanUpAmi()
|
||||
}
|
||||
|
||||
func (s *AmazonEBSAccTest) GetBuilderStore() packersdk.MapOfBuilder {
|
||||
return packersdk.MapOfBuilder{
|
||||
"amazon-ebs": func() (packersdk.Builder, error) { return &amazonebsbuilder.Builder{}, nil },
|
||||
}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
{
|
||||
"type": "amazon-ebs",
|
||||
"ami_name": "packer-acc-test",
|
||||
"instance_type": "m1.small",
|
||||
"region": "us-east-1",
|
||||
"ssh_username": "ubuntu",
|
||||
"source_ami": "ami-0568456c",
|
||||
"force_deregister" : true,
|
||||
"tags": {
|
||||
"packer-test": "true"
|
||||
}
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
{
|
||||
"type": "amazon-ebs",
|
||||
"region": "us-east-1",
|
||||
"instance_type": "t2.micro",
|
||||
"source_ami_filter": {
|
||||
"filters": {
|
||||
"virtualization-type": "hvm",
|
||||
"name": "*Windows_Server-2012-R2*English-64Bit-Base*",
|
||||
"root-device-type": "ebs"
|
||||
},
|
||||
"most_recent": true,
|
||||
"owners": "amazon"
|
||||
},
|
||||
"ami_name": "packer-acc-test",
|
||||
"user_data_file": "../../builder/amazon/ebs/acceptance/test-fixtures/scripts/bootstrap_win.txt",
|
||||
"communicator": "winrm",
|
||||
"winrm_username": "Administrator",
|
||||
"winrm_password": "SuperS3cr3t!!!!",
|
||||
"force_deregister" : true,
|
||||
"tags": {
|
||||
"packer-test": "true"
|
||||
}
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
<powershell>
|
||||
# Set administrator password
|
||||
net user Administrator SuperS3cr3t!!!!
|
||||
wmic useraccount where "name='Administrator'" set PasswordExpires=FALSE
|
||||
|
||||
# First, make sure WinRM can't be connected to
|
||||
netsh advfirewall firewall set rule name="Windows Remote Management (HTTP-In)" new enable=yes action=block
|
||||
|
||||
# Delete any existing WinRM listeners
|
||||
winrm delete winrm/config/listener?Address=*+Transport=HTTP 2>$Null
|
||||
winrm delete winrm/config/listener?Address=*+Transport=HTTPS 2>$Null
|
||||
|
||||
# Disable group policies which block basic authentication and unencrypted login
|
||||
|
||||
Set-ItemProperty -Path HKLM:\Software\Policies\Microsoft\Windows\WinRM\Client -Name AllowBasic -Value 1
|
||||
Set-ItemProperty -Path HKLM:\Software\Policies\Microsoft\Windows\WinRM\Client -Name AllowUnencryptedTraffic -Value 1
|
||||
Set-ItemProperty -Path HKLM:\Software\Policies\Microsoft\Windows\WinRM\Service -Name AllowBasic -Value 1
|
||||
Set-ItemProperty -Path HKLM:\Software\Policies\Microsoft\Windows\WinRM\Service -Name AllowUnencryptedTraffic -Value 1
|
||||
|
||||
|
||||
# Create a new WinRM listener and configure
|
||||
winrm create winrm/config/listener?Address=*+Transport=HTTP
|
||||
winrm set winrm/config/winrs '@{MaxMemoryPerShellMB="0"}'
|
||||
winrm set winrm/config '@{MaxTimeoutms="7200000"}'
|
||||
winrm set winrm/config/service '@{AllowUnencrypted="true"}'
|
||||
winrm set winrm/config/service '@{MaxConcurrentOperationsPerUser="12000"}'
|
||||
winrm set winrm/config/service/auth '@{Basic="true"}'
|
||||
winrm set winrm/config/client/auth '@{Basic="true"}'
|
||||
|
||||
# Configure UAC to allow privilege elevation in remote shells
|
||||
$Key = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System'
|
||||
$Setting = 'LocalAccountTokenFilterPolicy'
|
||||
Set-ItemProperty -Path $Key -Name $Setting -Value 1 -Force
|
||||
|
||||
# Configure and restart the WinRM Service; Enable the required firewall exception
|
||||
Stop-Service -Name WinRM
|
||||
Set-Service -Name WinRM -StartupType Automatic
|
||||
netsh advfirewall firewall set rule name="Windows Remote Management (HTTP-In)" new action=allow localip=any remoteip=any
|
||||
Start-Service -Name WinRM
|
||||
</powershell>
|
|
@ -1,396 +0,0 @@
|
|||
/*
|
||||
Deregister the test image with
|
||||
aws ec2 deregister-image --image-id $(aws ec2 describe-images --output text --filters "Name=name,Values=packer-test-packer-test-dereg" --query 'Images[*].{ID:ImageId}')
|
||||
*/
|
||||
package ebs
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
builderT "github.com/hashicorp/packer-plugin-sdk/acctest"
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
"github.com/hashicorp/packer/builder/amazon/common"
|
||||
)
|
||||
|
||||
func TestBuilderAcc_basic(t *testing.T) {
|
||||
builderT.Test(t, builderT.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Builder: &Builder{},
|
||||
Template: testBuilderAccBasic,
|
||||
})
|
||||
}
|
||||
|
||||
func TestBuilderAcc_regionCopy(t *testing.T) {
|
||||
builderT.Test(t, builderT.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Builder: &Builder{},
|
||||
Template: testBuilderAccRegionCopy,
|
||||
Check: checkRegionCopy([]string{"us-east-1", "us-west-2"}),
|
||||
})
|
||||
}
|
||||
|
||||
func TestBuilderAcc_forceDeregister(t *testing.T) {
|
||||
// Build the same AMI name twice, with force_deregister on the second run
|
||||
builderT.Test(t, builderT.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Builder: &Builder{},
|
||||
Template: buildForceDeregisterConfig("false", "dereg"),
|
||||
SkipArtifactTeardown: true,
|
||||
})
|
||||
|
||||
builderT.Test(t, builderT.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Builder: &Builder{},
|
||||
Template: buildForceDeregisterConfig("true", "dereg"),
|
||||
})
|
||||
}
|
||||
|
||||
func TestBuilderAcc_forceDeleteSnapshot(t *testing.T) {
|
||||
amiName := "packer-test-dereg"
|
||||
|
||||
// Build the same AMI name twice, with force_delete_snapshot on the second run
|
||||
builderT.Test(t, builderT.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Builder: &Builder{},
|
||||
Template: buildForceDeleteSnapshotConfig("false", amiName),
|
||||
SkipArtifactTeardown: true,
|
||||
})
|
||||
|
||||
// Get image data by AMI name
|
||||
ec2conn, _ := testEC2Conn()
|
||||
describeInput := &ec2.DescribeImagesInput{Filters: []*ec2.Filter{
|
||||
{
|
||||
Name: aws.String("name"),
|
||||
Values: []*string{aws.String(amiName)},
|
||||
},
|
||||
}}
|
||||
ec2conn.WaitUntilImageExists(describeInput)
|
||||
imageResp, _ := ec2conn.DescribeImages(describeInput)
|
||||
image := imageResp.Images[0]
|
||||
|
||||
// Get snapshot ids for image
|
||||
snapshotIds := []*string{}
|
||||
for _, device := range image.BlockDeviceMappings {
|
||||
if device.Ebs != nil && device.Ebs.SnapshotId != nil {
|
||||
snapshotIds = append(snapshotIds, device.Ebs.SnapshotId)
|
||||
}
|
||||
}
|
||||
|
||||
builderT.Test(t, builderT.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Builder: &Builder{},
|
||||
Template: buildForceDeleteSnapshotConfig("true", amiName),
|
||||
Check: checkSnapshotsDeleted(snapshotIds),
|
||||
})
|
||||
}
|
||||
|
||||
func checkSnapshotsDeleted(snapshotIds []*string) builderT.TestCheckFunc {
|
||||
return func(artifacts []packersdk.Artifact) error {
|
||||
// Verify the snapshots are gone
|
||||
ec2conn, _ := testEC2Conn()
|
||||
snapshotResp, _ := ec2conn.DescribeSnapshots(
|
||||
&ec2.DescribeSnapshotsInput{SnapshotIds: snapshotIds},
|
||||
)
|
||||
|
||||
if len(snapshotResp.Snapshots) > 0 {
|
||||
return fmt.Errorf("Snapshots weren't successfully deleted by `force_delete_snapshot`")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderAcc_amiSharing(t *testing.T) {
|
||||
builderT.Test(t, builderT.TestCase{
|
||||
PreCheck: func() { testAccSharingPreCheck(t) },
|
||||
Builder: &Builder{},
|
||||
Template: buildSharingConfig(os.Getenv("TESTACC_AWS_ACCOUNT_ID")),
|
||||
Check: checkAMISharing(2, os.Getenv("TESTACC_AWS_ACCOUNT_ID"), "all"),
|
||||
})
|
||||
}
|
||||
|
||||
func TestBuilderAcc_encryptedBoot(t *testing.T) {
|
||||
builderT.Test(t, builderT.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Builder: &Builder{},
|
||||
Template: testBuilderAccEncrypted,
|
||||
Check: checkBootEncrypted(),
|
||||
})
|
||||
}
|
||||
|
||||
func checkAMISharing(count int, uid, group string) builderT.TestCheckFunc {
|
||||
return func(artifacts []packersdk.Artifact) error {
|
||||
if len(artifacts) > 1 {
|
||||
return fmt.Errorf("more than 1 artifact")
|
||||
}
|
||||
|
||||
// Get the actual *Artifact pointer so we can access the AMIs directly
|
||||
artifactRaw := artifacts[0]
|
||||
artifact, ok := artifactRaw.(*common.Artifact)
|
||||
if !ok {
|
||||
return fmt.Errorf("unknown artifact: %#v", artifactRaw)
|
||||
}
|
||||
|
||||
// describe the image, get block devices with a snapshot
|
||||
ec2conn, _ := testEC2Conn()
|
||||
imageResp, err := ec2conn.DescribeImageAttribute(&ec2.DescribeImageAttributeInput{
|
||||
Attribute: aws.String("launchPermission"),
|
||||
ImageId: aws.String(artifact.Amis["us-east-1"]),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error retrieving Image Attributes for AMI Artifact (%#v) in AMI Sharing Test: %s", artifact, err)
|
||||
}
|
||||
|
||||
// Launch Permissions are in addition to the userid that created it, so if
|
||||
// you add 3 additional ami_users, you expect 2 Launch Permissions here
|
||||
if len(imageResp.LaunchPermissions) != count {
|
||||
return fmt.Errorf("Error in Image Attributes, expected (%d) Launch Permissions, got (%d)", count, len(imageResp.LaunchPermissions))
|
||||
}
|
||||
|
||||
userFound := false
|
||||
for _, lp := range imageResp.LaunchPermissions {
|
||||
if lp.UserId != nil && uid == *lp.UserId {
|
||||
userFound = true
|
||||
}
|
||||
}
|
||||
|
||||
if !userFound {
|
||||
return fmt.Errorf("Error in Image Attributes, expected User ID (%s) to have Launch Permissions, but was not found", uid)
|
||||
}
|
||||
|
||||
groupFound := false
|
||||
for _, lp := range imageResp.LaunchPermissions {
|
||||
if lp.Group != nil && group == *lp.Group {
|
||||
groupFound = true
|
||||
}
|
||||
}
|
||||
|
||||
if !groupFound {
|
||||
return fmt.Errorf("Error in Image Attributes, expected Group ID (%s) to have Launch Permissions, but was not found", group)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func checkRegionCopy(regions []string) builderT.TestCheckFunc {
|
||||
return func(artifacts []packersdk.Artifact) error {
|
||||
if len(artifacts) > 1 {
|
||||
return fmt.Errorf("more than 1 artifact")
|
||||
}
|
||||
|
||||
// Get the actual *Artifact pointer so we can access the AMIs directly
|
||||
artifactRaw := artifacts[0]
|
||||
artifact, ok := artifactRaw.(*common.Artifact)
|
||||
if !ok {
|
||||
return fmt.Errorf("unknown artifact: %#v", artifactRaw)
|
||||
}
|
||||
|
||||
// Verify that we copied to only the regions given
|
||||
regionSet := make(map[string]struct{})
|
||||
for _, r := range regions {
|
||||
regionSet[r] = struct{}{}
|
||||
}
|
||||
for r := range artifact.Amis {
|
||||
if _, ok := regionSet[r]; !ok {
|
||||
return fmt.Errorf("unknown region: %s", r)
|
||||
}
|
||||
|
||||
delete(regionSet, r)
|
||||
}
|
||||
if len(regionSet) > 0 {
|
||||
return fmt.Errorf("didn't copy to: %#v", regionSet)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func checkBootEncrypted() builderT.TestCheckFunc {
|
||||
return func(artifacts []packersdk.Artifact) error {
|
||||
|
||||
// Get the actual *Artifact pointer so we can access the AMIs directly
|
||||
artifactRaw := artifacts[0]
|
||||
artifact, ok := artifactRaw.(*common.Artifact)
|
||||
if !ok {
|
||||
return fmt.Errorf("unknown artifact: %#v", artifactRaw)
|
||||
}
|
||||
|
||||
// describe the image, get block devices with a snapshot
|
||||
ec2conn, _ := testEC2Conn()
|
||||
imageResp, err := ec2conn.DescribeImages(&ec2.DescribeImagesInput{
|
||||
ImageIds: []*string{aws.String(artifact.Amis["us-east-1"])},
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error retrieving Image Attributes for AMI (%s) in AMI Encrypted Boot Test: %s", artifact, err)
|
||||
}
|
||||
|
||||
image := imageResp.Images[0] // Only requested a single AMI ID
|
||||
|
||||
rootDeviceName := image.RootDeviceName
|
||||
|
||||
for _, bd := range image.BlockDeviceMappings {
|
||||
if *bd.DeviceName == *rootDeviceName {
|
||||
if *bd.Ebs.Encrypted != true {
|
||||
return fmt.Errorf("volume not encrypted: %s", *bd.Ebs.SnapshotId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderAcc_SessionManagerInterface(t *testing.T) {
|
||||
builderT.Test(t, builderT.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Builder: &Builder{},
|
||||
Template: testBuilderAccSessionManagerInterface,
|
||||
})
|
||||
}
|
||||
|
||||
func testAccPreCheck(t *testing.T) {
|
||||
}
|
||||
|
||||
func testAccSharingPreCheck(t *testing.T) {
|
||||
if v := os.Getenv("TESTACC_AWS_ACCOUNT_ID"); v == "" {
|
||||
t.Fatal(fmt.Sprintf("TESTACC_AWS_ACCOUNT_ID must be set for acceptance tests"))
|
||||
}
|
||||
}
|
||||
|
||||
func testEC2Conn() (*ec2.EC2, error) {
|
||||
access := &common.AccessConfig{RawRegion: "us-east-1"}
|
||||
session, err := access.Session()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ec2.New(session), nil
|
||||
}
|
||||
|
||||
const testBuilderAccBasic = `
|
||||
{
|
||||
"builders": [{
|
||||
"type": "test",
|
||||
"region": "us-east-1",
|
||||
"instance_type": "m3.medium",
|
||||
"source_ami": "ami-76b2a71e",
|
||||
"ssh_username": "ubuntu",
|
||||
"ami_name": "packer-test {{timestamp}}"
|
||||
}]
|
||||
}
|
||||
`
|
||||
|
||||
const testBuilderAccRegionCopy = `
|
||||
{
|
||||
"builders": [{
|
||||
"type": "test",
|
||||
"region": "us-east-1",
|
||||
"instance_type": "m3.medium",
|
||||
"source_ami": "ami-76b2a71e",
|
||||
"ssh_username": "ubuntu",
|
||||
"ami_name": "packer-test {{timestamp}}",
|
||||
"ami_regions": ["us-east-1", "us-west-2"]
|
||||
}]
|
||||
}
|
||||
`
|
||||
|
||||
const testBuilderAccForceDeregister = `
|
||||
{
|
||||
"builders": [{
|
||||
"type": "test",
|
||||
"region": "us-east-1",
|
||||
"instance_type": "m3.medium",
|
||||
"source_ami": "ami-76b2a71e",
|
||||
"ssh_username": "ubuntu",
|
||||
"force_deregister": "%s",
|
||||
"ami_name": "%s"
|
||||
}]
|
||||
}
|
||||
`
|
||||
|
||||
const testBuilderAccForceDeleteSnapshot = `
|
||||
{
|
||||
"builders": [{
|
||||
"type": "test",
|
||||
"region": "us-east-1",
|
||||
"instance_type": "m3.medium",
|
||||
"source_ami": "ami-76b2a71e",
|
||||
"ssh_username": "ubuntu",
|
||||
"force_deregister": "%s",
|
||||
"force_delete_snapshot": "%s",
|
||||
"ami_name": "%s"
|
||||
}]
|
||||
}
|
||||
`
|
||||
|
||||
const testBuilderAccSharing = `
|
||||
{
|
||||
"builders": [{
|
||||
"type": "test",
|
||||
"region": "us-east-1",
|
||||
"instance_type": "m3.medium",
|
||||
"source_ami": "ami-76b2a71e",
|
||||
"ssh_username": "ubuntu",
|
||||
"ami_name": "packer-test {{timestamp}}",
|
||||
"ami_users":["%s"],
|
||||
"ami_groups":["all"]
|
||||
}]
|
||||
}
|
||||
`
|
||||
|
||||
const testBuilderAccEncrypted = `
|
||||
{
|
||||
"builders": [{
|
||||
"type": "test",
|
||||
"region": "us-east-1",
|
||||
"instance_type": "m3.medium",
|
||||
"source_ami":"ami-c15bebaa",
|
||||
"ssh_username": "ubuntu",
|
||||
"ami_name": "packer-enc-test {{timestamp}}",
|
||||
"encrypt_boot": true
|
||||
}]
|
||||
}
|
||||
`
|
||||
|
||||
const testBuilderAccSessionManagerInterface = `
|
||||
{
|
||||
"builders": [{
|
||||
"type": "test",
|
||||
"region": "us-east-1",
|
||||
"instance_type": "m3.medium",
|
||||
"source_ami_filter": {
|
||||
"filters": {
|
||||
"virtualization-type": "hvm",
|
||||
"name": "ubuntu/images/*ubuntu-xenial-16.04-amd64-server-*",
|
||||
"root-device-type": "ebs"
|
||||
},
|
||||
"owners": [
|
||||
"099720109477"
|
||||
],
|
||||
"most_recent": true
|
||||
},
|
||||
"ssh_username": "ubuntu",
|
||||
"ssh_interface": "session_manager",
|
||||
"iam_instance_profile": "SSMInstanceProfile",
|
||||
"ami_name": "packer-ssm-test-{{timestamp}}"
|
||||
}]
|
||||
}
|
||||
`
|
||||
|
||||
func buildForceDeregisterConfig(val, name string) string {
|
||||
return fmt.Sprintf(testBuilderAccForceDeregister, val, name)
|
||||
}
|
||||
|
||||
func buildForceDeleteSnapshotConfig(val, name string) string {
|
||||
return fmt.Sprintf(testBuilderAccForceDeleteSnapshot, val, val, name)
|
||||
}
|
||||
|
||||
func buildSharingConfig(val string) string {
|
||||
return fmt.Sprintf(testBuilderAccSharing, val)
|
||||
}
|
|
@ -1,166 +0,0 @@
|
|||
package ebs
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
)
|
||||
|
||||
func testConfig() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"access_key": "foo",
|
||||
"secret_key": "bar",
|
||||
"source_ami": "foo",
|
||||
"instance_type": "foo",
|
||||
"region": "us-east-1",
|
||||
"ssh_username": "root",
|
||||
"ami_name": "foo",
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilder_ImplementsBuilder(t *testing.T) {
|
||||
var raw interface{}
|
||||
raw = &Builder{}
|
||||
if _, ok := raw.(packersdk.Builder); !ok {
|
||||
t.Fatalf("Builder should be a builder")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilder_Prepare_BadType(t *testing.T) {
|
||||
b := &Builder{}
|
||||
c := map[string]interface{}{
|
||||
"access_key": []string{},
|
||||
}
|
||||
|
||||
_, warnings, err := b.Prepare(c)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatalf("prepare should fail")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderPrepare_AMIName(t *testing.T) {
|
||||
var b Builder
|
||||
config := testConfig()
|
||||
|
||||
// Test good
|
||||
config["ami_name"] = "foo"
|
||||
_, warnings, err := b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
|
||||
// Test bad
|
||||
config["ami_name"] = "foo {{"
|
||||
b = Builder{}
|
||||
_, warnings, err = b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
|
||||
// Test bad
|
||||
delete(config, "ami_name")
|
||||
b = Builder{}
|
||||
_, warnings, err = b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderPrepare_InvalidKey(t *testing.T) {
|
||||
var b Builder
|
||||
config := testConfig()
|
||||
|
||||
// Add a random key
|
||||
config["i_should_not_be_valid"] = true
|
||||
_, warnings, err := b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderPrepare_InvalidShutdownBehavior(t *testing.T) {
|
||||
var b Builder
|
||||
config := testConfig()
|
||||
|
||||
// Test good
|
||||
config["shutdown_behavior"] = "terminate"
|
||||
_, warnings, err := b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
|
||||
// Test good
|
||||
config["shutdown_behavior"] = "stop"
|
||||
_, warnings, err = b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
|
||||
// Test bad
|
||||
config["shutdown_behavior"] = "foobar"
|
||||
_, warnings, err = b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderPrepare_ReturnGeneratedData(t *testing.T) {
|
||||
var b Builder
|
||||
config := testConfig()
|
||||
|
||||
generatedData, warnings, err := b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
if len(generatedData) == 0 {
|
||||
t.Fatalf("Generated data should not be empty")
|
||||
}
|
||||
if len(generatedData) == 0 {
|
||||
t.Fatalf("Generated data should not be empty")
|
||||
}
|
||||
if generatedData[0] != "SourceAMIName" {
|
||||
t.Fatalf("Generated data should contain SourceAMIName")
|
||||
}
|
||||
if generatedData[1] != "BuildRegion" {
|
||||
t.Fatalf("Generated data should contain BuildRegion")
|
||||
}
|
||||
if generatedData[2] != "SourceAMI" {
|
||||
t.Fatalf("Generated data should contain SourceAMI")
|
||||
}
|
||||
if generatedData[3] != "SourceAMICreationDate" {
|
||||
t.Fatalf("Generated data should contain SourceAMICreationDate")
|
||||
}
|
||||
if generatedData[4] != "SourceAMIOwner" {
|
||||
t.Fatalf("Generated data should contain SourceAMIOwner")
|
||||
}
|
||||
if generatedData[5] != "SourceAMIOwnerName" {
|
||||
t.Fatalf("Generated data should contain SourceAMIOwnerName")
|
||||
}
|
||||
}
|
|
@ -1,137 +0,0 @@
|
|||
package ebs
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
builderT "github.com/hashicorp/packer-plugin-sdk/acctest"
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
"github.com/hashicorp/packer/builder/amazon/common"
|
||||
)
|
||||
|
||||
type TFBuilder struct {
|
||||
Type string `json:"type"`
|
||||
Region string `json:"region"`
|
||||
SourceAmi string `json:"source_ami"`
|
||||
InstanceType string `json:"instance_type"`
|
||||
SshUsername string `json:"ssh_username"`
|
||||
AmiName string `json:"ami_name"`
|
||||
Tags map[string]string `json:"tags"`
|
||||
SnapshotTags map[string]string `json:"snapshot_tags"`
|
||||
}
|
||||
|
||||
type TFConfig struct {
|
||||
Builders []TFBuilder `json:"builders"`
|
||||
}
|
||||
|
||||
func TestBuilderTagsAcc_basic(t *testing.T) {
|
||||
builderT.Test(t, builderT.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Builder: &Builder{},
|
||||
Template: testBuilderTagsAccBasic,
|
||||
Check: checkTags(),
|
||||
})
|
||||
}
|
||||
|
||||
func checkTags() builderT.TestCheckFunc {
|
||||
return func(artifacts []packersdk.Artifact) error {
|
||||
if len(artifacts) > 1 {
|
||||
return fmt.Errorf("more than 1 artifact")
|
||||
}
|
||||
|
||||
config := TFConfig{}
|
||||
json.Unmarshal([]byte(testBuilderTagsAccBasic), &config)
|
||||
tags := config.Builders[0].Tags
|
||||
snapshotTags := config.Builders[0].SnapshotTags
|
||||
|
||||
// Get the actual *Artifact pointer so we can access the AMIs directly
|
||||
artifactRaw := artifacts[0]
|
||||
artifact, ok := artifactRaw.(*common.Artifact)
|
||||
if !ok {
|
||||
return fmt.Errorf("unknown artifact: %#v", artifactRaw)
|
||||
}
|
||||
|
||||
// Describe the image, get block devices with a snapshot
|
||||
ec2conn, _ := testEC2Conn()
|
||||
imageResp, err := ec2conn.DescribeImages(&ec2.DescribeImagesInput{
|
||||
ImageIds: []*string{aws.String(artifact.Amis["us-east-1"])},
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error retrieving details for AMI Artifact (%#v) in Tags Test: %s", artifact, err)
|
||||
}
|
||||
|
||||
if len(imageResp.Images) == 0 {
|
||||
return fmt.Errorf("No images found for AMI Artifact (%#v) in Tags Test: %s", artifact, err)
|
||||
}
|
||||
|
||||
image := imageResp.Images[0]
|
||||
|
||||
// Check only those with a Snapshot ID, i.e. not Ephemeral
|
||||
var snapshots []*string
|
||||
for _, device := range image.BlockDeviceMappings {
|
||||
if device.Ebs != nil && device.Ebs.SnapshotId != nil {
|
||||
snapshots = append(snapshots, device.Ebs.SnapshotId)
|
||||
}
|
||||
}
|
||||
|
||||
// Grab matching snapshot info
|
||||
resp, err := ec2conn.DescribeSnapshots(&ec2.DescribeSnapshotsInput{
|
||||
SnapshotIds: snapshots,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error retrieving Snapshots for AMI Artifact (%#v) in Tags Test: %s", artifact, err)
|
||||
}
|
||||
|
||||
if len(resp.Snapshots) == 0 {
|
||||
return fmt.Errorf("No Snapshots found for AMI Artifact (%#v) in Tags Test", artifact)
|
||||
}
|
||||
|
||||
// Grab the snapshots, check the tags
|
||||
for _, s := range resp.Snapshots {
|
||||
expected := len(tags)
|
||||
for _, t := range s.Tags {
|
||||
for key, value := range tags {
|
||||
if val, ok := snapshotTags[key]; ok && val == *t.Value {
|
||||
expected--
|
||||
} else if key == *t.Key && value == *t.Value {
|
||||
expected--
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if expected > 0 {
|
||||
return fmt.Errorf("Not all tags found")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
const testBuilderTagsAccBasic = `
|
||||
{
|
||||
"builders": [
|
||||
{
|
||||
"type": "test",
|
||||
"region": "us-east-1",
|
||||
"source_ami": "ami-9eaa1cf6",
|
||||
"instance_type": "t2.micro",
|
||||
"ssh_username": "ubuntu",
|
||||
"ami_name": "packer-tags-testing-{{timestamp}}",
|
||||
"tags": {
|
||||
"OS_Version": "Ubuntu",
|
||||
"Release": "Latest",
|
||||
"Name": "Bleep"
|
||||
},
|
||||
"snapshot_tags": {
|
||||
"Name": "Foobar"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
`
|
|
@ -1,110 +0,0 @@
|
|||
package ebssurrogate
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/packer/builder/amazon/common"
|
||||
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
)
|
||||
|
||||
func testConfig() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"access_key": "foo",
|
||||
"secret_key": "bar",
|
||||
"source_ami": "foo",
|
||||
"instance_type": "foo",
|
||||
"region": "us-east-1",
|
||||
"ssh_username": "root",
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilder_ImplementsBuilder(t *testing.T) {
|
||||
var raw interface{}
|
||||
raw = &Builder{}
|
||||
if _, ok := raw.(packersdk.Builder); !ok {
|
||||
t.Fatal("Builder should be a builder")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilder_Prepare_BadType(t *testing.T) {
|
||||
b := &Builder{}
|
||||
c := map[string]interface{}{
|
||||
"access_key": []string{},
|
||||
}
|
||||
|
||||
_, warnings, err := b.Prepare(c)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("prepare should fail")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderPrepare_InvalidKey(t *testing.T) {
|
||||
var b Builder
|
||||
config := testConfig()
|
||||
|
||||
// Add a random key
|
||||
config["i_should_not_be_valid"] = true
|
||||
_, warnings, err := b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderPrepare_ReturnGeneratedData(t *testing.T) {
|
||||
var b Builder
|
||||
// Basic configuration
|
||||
b.config.RootDevice = RootBlockDevice{
|
||||
SourceDeviceName: "device name",
|
||||
DeviceName: "device name",
|
||||
}
|
||||
b.config.LaunchMappings = BlockDevices{
|
||||
BlockDevice{
|
||||
BlockDevice: common.BlockDevice{
|
||||
DeviceName: "device name",
|
||||
},
|
||||
OmitFromArtifact: false,
|
||||
},
|
||||
}
|
||||
b.config.AMIVirtType = "type"
|
||||
config := testConfig()
|
||||
config["ami_name"] = "name"
|
||||
|
||||
generatedData, warnings, err := b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
if len(generatedData) == 0 {
|
||||
t.Fatalf("Generated data should not be empty")
|
||||
}
|
||||
if len(generatedData) == 0 {
|
||||
t.Fatalf("Generated data should not be empty")
|
||||
}
|
||||
if generatedData[0] != "SourceAMIName" {
|
||||
t.Fatalf("Generated data should contain SourceAMIName")
|
||||
}
|
||||
if generatedData[1] != "BuildRegion" {
|
||||
t.Fatalf("Generated data should contain BuildRegion")
|
||||
}
|
||||
if generatedData[2] != "SourceAMI" {
|
||||
t.Fatalf("Generated data should contain SourceAMI")
|
||||
}
|
||||
if generatedData[3] != "SourceAMICreationDate" {
|
||||
t.Fatalf("Generated data should contain SourceAMICreationDate")
|
||||
}
|
||||
if generatedData[4] != "SourceAMIOwner" {
|
||||
t.Fatalf("Generated data should contain SourceAMIOwner")
|
||||
}
|
||||
if generatedData[5] != "SourceAMIOwnerName" {
|
||||
t.Fatalf("Generated data should contain SourceAMIOwnerName")
|
||||
}
|
||||
}
|
|
@ -1,249 +0,0 @@
|
|||
package ebssurrogate
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
"github.com/hashicorp/packer/builder/amazon/common"
|
||||
)
|
||||
|
||||
const sourceDeviceName = "/dev/xvdf"
|
||||
const rootDeviceName = "/dev/xvda"
|
||||
|
||||
func newStepRegisterAMI(amiDevices, launchDevices []*ec2.BlockDeviceMapping) *StepRegisterAMI {
|
||||
return &StepRegisterAMI{
|
||||
RootDevice: RootBlockDevice{
|
||||
SourceDeviceName: sourceDeviceName,
|
||||
DeviceName: rootDeviceName,
|
||||
DeleteOnTermination: true,
|
||||
VolumeType: "ebs",
|
||||
VolumeSize: 10,
|
||||
},
|
||||
AMIDevices: amiDevices,
|
||||
LaunchDevices: launchDevices,
|
||||
PollingConfig: new(common.AWSPollingConfig),
|
||||
}
|
||||
}
|
||||
|
||||
func sorted(devices []*ec2.BlockDeviceMapping) []*ec2.BlockDeviceMapping {
|
||||
sort.SliceStable(devices, func(i, j int) bool {
|
||||
return *devices[i].DeviceName < *devices[j].DeviceName
|
||||
})
|
||||
return devices
|
||||
}
|
||||
|
||||
func TestStepRegisterAmi_combineDevices(t *testing.T) {
|
||||
cases := []struct {
|
||||
snapshotIds map[string]string
|
||||
amiDevices []*ec2.BlockDeviceMapping
|
||||
launchDevices []*ec2.BlockDeviceMapping
|
||||
allDevices []*ec2.BlockDeviceMapping
|
||||
}{
|
||||
{
|
||||
snapshotIds: map[string]string{},
|
||||
amiDevices: []*ec2.BlockDeviceMapping{},
|
||||
launchDevices: []*ec2.BlockDeviceMapping{},
|
||||
allDevices: []*ec2.BlockDeviceMapping{},
|
||||
},
|
||||
{
|
||||
snapshotIds: map[string]string{},
|
||||
amiDevices: []*ec2.BlockDeviceMapping{},
|
||||
launchDevices: []*ec2.BlockDeviceMapping{
|
||||
{
|
||||
Ebs: &ec2.EbsBlockDevice{},
|
||||
DeviceName: aws.String(sourceDeviceName),
|
||||
},
|
||||
},
|
||||
allDevices: []*ec2.BlockDeviceMapping{
|
||||
{
|
||||
Ebs: &ec2.EbsBlockDevice{},
|
||||
DeviceName: aws.String(rootDeviceName),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
// Minimal single device
|
||||
snapshotIds: map[string]string{
|
||||
sourceDeviceName: "snap-0123456789abcdef1",
|
||||
},
|
||||
amiDevices: []*ec2.BlockDeviceMapping{},
|
||||
launchDevices: []*ec2.BlockDeviceMapping{
|
||||
{
|
||||
Ebs: &ec2.EbsBlockDevice{},
|
||||
DeviceName: aws.String(sourceDeviceName),
|
||||
},
|
||||
},
|
||||
allDevices: []*ec2.BlockDeviceMapping{
|
||||
{
|
||||
Ebs: &ec2.EbsBlockDevice{
|
||||
SnapshotId: aws.String("snap-0123456789abcdef1"),
|
||||
},
|
||||
DeviceName: aws.String(rootDeviceName),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
// Single launch device with AMI device
|
||||
snapshotIds: map[string]string{
|
||||
sourceDeviceName: "snap-0123456789abcdef1",
|
||||
},
|
||||
amiDevices: []*ec2.BlockDeviceMapping{
|
||||
{
|
||||
Ebs: &ec2.EbsBlockDevice{},
|
||||
DeviceName: aws.String("/dev/xvdg"),
|
||||
},
|
||||
},
|
||||
launchDevices: []*ec2.BlockDeviceMapping{
|
||||
{
|
||||
Ebs: &ec2.EbsBlockDevice{},
|
||||
DeviceName: aws.String(sourceDeviceName),
|
||||
},
|
||||
},
|
||||
allDevices: []*ec2.BlockDeviceMapping{
|
||||
{
|
||||
Ebs: &ec2.EbsBlockDevice{
|
||||
SnapshotId: aws.String("snap-0123456789abcdef1"),
|
||||
},
|
||||
DeviceName: aws.String(rootDeviceName),
|
||||
},
|
||||
{
|
||||
Ebs: &ec2.EbsBlockDevice{},
|
||||
DeviceName: aws.String("/dev/xvdg"),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
// Multiple launch devices
|
||||
snapshotIds: map[string]string{
|
||||
sourceDeviceName: "snap-0123456789abcdef1",
|
||||
"/dev/xvdg": "snap-0123456789abcdef2",
|
||||
},
|
||||
amiDevices: []*ec2.BlockDeviceMapping{},
|
||||
launchDevices: []*ec2.BlockDeviceMapping{
|
||||
{
|
||||
Ebs: &ec2.EbsBlockDevice{},
|
||||
DeviceName: aws.String(sourceDeviceName),
|
||||
},
|
||||
{
|
||||
Ebs: &ec2.EbsBlockDevice{},
|
||||
DeviceName: aws.String("/dev/xvdg"),
|
||||
},
|
||||
},
|
||||
allDevices: []*ec2.BlockDeviceMapping{
|
||||
{
|
||||
Ebs: &ec2.EbsBlockDevice{
|
||||
SnapshotId: aws.String("snap-0123456789abcdef1"),
|
||||
},
|
||||
DeviceName: aws.String(rootDeviceName),
|
||||
},
|
||||
{
|
||||
Ebs: &ec2.EbsBlockDevice{
|
||||
SnapshotId: aws.String("snap-0123456789abcdef2"),
|
||||
},
|
||||
DeviceName: aws.String("/dev/xvdg"),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
// Multiple launch devices with encryption
|
||||
snapshotIds: map[string]string{
|
||||
sourceDeviceName: "snap-0123456789abcdef1",
|
||||
"/dev/xvdg": "snap-0123456789abcdef2",
|
||||
},
|
||||
amiDevices: []*ec2.BlockDeviceMapping{},
|
||||
launchDevices: []*ec2.BlockDeviceMapping{
|
||||
{
|
||||
Ebs: &ec2.EbsBlockDevice{
|
||||
Encrypted: aws.Bool(true),
|
||||
},
|
||||
DeviceName: aws.String(sourceDeviceName),
|
||||
},
|
||||
{
|
||||
Ebs: &ec2.EbsBlockDevice{
|
||||
Encrypted: aws.Bool(true),
|
||||
},
|
||||
DeviceName: aws.String("/dev/xvdg"),
|
||||
},
|
||||
},
|
||||
allDevices: []*ec2.BlockDeviceMapping{
|
||||
{
|
||||
Ebs: &ec2.EbsBlockDevice{
|
||||
SnapshotId: aws.String("snap-0123456789abcdef1"),
|
||||
// Encrypted: true stripped from snapshotted devices
|
||||
},
|
||||
DeviceName: aws.String(rootDeviceName),
|
||||
},
|
||||
{
|
||||
Ebs: &ec2.EbsBlockDevice{
|
||||
SnapshotId: aws.String("snap-0123456789abcdef2"),
|
||||
},
|
||||
DeviceName: aws.String("/dev/xvdg"),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
// Multiple launch devices and AMI devices with encryption
|
||||
snapshotIds: map[string]string{
|
||||
sourceDeviceName: "snap-0123456789abcdef1",
|
||||
"/dev/xvdg": "snap-0123456789abcdef2",
|
||||
},
|
||||
amiDevices: []*ec2.BlockDeviceMapping{
|
||||
{
|
||||
Ebs: &ec2.EbsBlockDevice{
|
||||
Encrypted: aws.Bool(true),
|
||||
KmsKeyId: aws.String("keyId"),
|
||||
},
|
||||
// Source device name can be used in AMI devices
|
||||
// since launch device of same name gets renamed
|
||||
// to root device name
|
||||
DeviceName: aws.String(sourceDeviceName),
|
||||
},
|
||||
},
|
||||
launchDevices: []*ec2.BlockDeviceMapping{
|
||||
{
|
||||
Ebs: &ec2.EbsBlockDevice{
|
||||
Encrypted: aws.Bool(true),
|
||||
},
|
||||
DeviceName: aws.String(sourceDeviceName),
|
||||
},
|
||||
{
|
||||
Ebs: &ec2.EbsBlockDevice{
|
||||
Encrypted: aws.Bool(true),
|
||||
},
|
||||
DeviceName: aws.String("/dev/xvdg"),
|
||||
},
|
||||
},
|
||||
allDevices: []*ec2.BlockDeviceMapping{
|
||||
{
|
||||
Ebs: &ec2.EbsBlockDevice{
|
||||
Encrypted: aws.Bool(true),
|
||||
KmsKeyId: aws.String("keyId"),
|
||||
},
|
||||
DeviceName: aws.String(sourceDeviceName),
|
||||
},
|
||||
{
|
||||
Ebs: &ec2.EbsBlockDevice{
|
||||
SnapshotId: aws.String("snap-0123456789abcdef1"),
|
||||
},
|
||||
DeviceName: aws.String(rootDeviceName),
|
||||
},
|
||||
{
|
||||
Ebs: &ec2.EbsBlockDevice{
|
||||
SnapshotId: aws.String("snap-0123456789abcdef2"),
|
||||
},
|
||||
DeviceName: aws.String("/dev/xvdg"),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
stepRegisterAmi := newStepRegisterAMI(tc.amiDevices, tc.launchDevices)
|
||||
allDevices := stepRegisterAmi.combineDevices(tc.snapshotIds)
|
||||
if !reflect.DeepEqual(sorted(allDevices), sorted(tc.allDevices)) {
|
||||
t.Fatalf("Unexpected output from combineDevices")
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
package ebsvolume
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestArtifactState(t *testing.T) {
|
||||
expectedData := "this is the data"
|
||||
artifact := &Artifact{
|
||||
StateData: map[string]interface{}{"state_data": expectedData},
|
||||
}
|
||||
|
||||
// Valid state
|
||||
result := artifact.State("state_data")
|
||||
if result != expectedData {
|
||||
t.Fatalf("Bad: State data was %s instead of %s", result, expectedData)
|
||||
}
|
||||
|
||||
// Invalid state
|
||||
result = artifact.State("invalid_key")
|
||||
if result != nil {
|
||||
t.Fatalf("Bad: State should be nil for invalid state data name")
|
||||
}
|
||||
|
||||
// Nil StateData should not fail and should return nil
|
||||
artifact = &Artifact{}
|
||||
result = artifact.State("key")
|
||||
if result != nil {
|
||||
t.Fatalf("Bad: State should be nil for nil StateData")
|
||||
}
|
||||
}
|
|
@ -1,166 +0,0 @@
|
|||
package ebsvolume
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
)
|
||||
|
||||
func testConfig() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"access_key": "foo",
|
||||
"secret_key": "bar",
|
||||
"source_ami": "foo",
|
||||
"instance_type": "foo",
|
||||
"region": "us-east-1",
|
||||
"ssh_username": "root",
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilder_ImplementsBuilder(t *testing.T) {
|
||||
var raw interface{}
|
||||
raw = &Builder{}
|
||||
if _, ok := raw.(packersdk.Builder); !ok {
|
||||
t.Fatalf("Builder should be a builder")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilder_Prepare_BadType(t *testing.T) {
|
||||
b := &Builder{}
|
||||
c := map[string]interface{}{
|
||||
"access_key": []string{},
|
||||
}
|
||||
|
||||
_, warnings, err := b.Prepare(c)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatalf("prepare should fail")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderPrepare_InvalidKey(t *testing.T) {
|
||||
var b Builder
|
||||
config := testConfig()
|
||||
|
||||
// Add a random key
|
||||
config["i_should_not_be_valid"] = true
|
||||
_, warnings, err := b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderPrepare_InvalidShutdownBehavior(t *testing.T) {
|
||||
var b Builder
|
||||
config := testConfig()
|
||||
|
||||
// Test good
|
||||
config["shutdown_behavior"] = "terminate"
|
||||
_, warnings, err := b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
|
||||
// Test good
|
||||
config["shutdown_behavior"] = "stop"
|
||||
_, warnings, err = b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
|
||||
// Test bad
|
||||
config["shutdown_behavior"] = "foobar"
|
||||
_, warnings, err = b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderPrepare_ReturnGeneratedData(t *testing.T) {
|
||||
var b Builder
|
||||
config := testConfig()
|
||||
|
||||
generatedData, warnings, err := b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
if len(generatedData) == 0 {
|
||||
t.Fatalf("Generated data should not be empty")
|
||||
}
|
||||
if generatedData[0] != "SourceAMIName" {
|
||||
t.Fatalf("Generated data should contain SourceAMIName")
|
||||
}
|
||||
if generatedData[1] != "BuildRegion" {
|
||||
t.Fatalf("Generated data should contain BuildRegion")
|
||||
}
|
||||
if generatedData[2] != "SourceAMI" {
|
||||
t.Fatalf("Generated data should contain SourceAMI")
|
||||
}
|
||||
if generatedData[3] != "SourceAMICreationDate" {
|
||||
t.Fatalf("Generated data should contain SourceAMICreationDate")
|
||||
}
|
||||
if generatedData[4] != "SourceAMIOwner" {
|
||||
t.Fatalf("Generated data should contain SourceAMIOwner")
|
||||
}
|
||||
if generatedData[5] != "SourceAMIOwnerName" {
|
||||
t.Fatalf("Generated data should contain SourceAMIOwnerName")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuidler_ConfigBlockdevicemapping(t *testing.T) {
|
||||
var b Builder
|
||||
config := testConfig()
|
||||
|
||||
//Set some snapshot settings
|
||||
config["ebs_volumes"] = []map[string]interface{}{
|
||||
{
|
||||
"device_name": "/dev/xvdb",
|
||||
"volume_size": "32",
|
||||
"delete_on_termination": true,
|
||||
},
|
||||
{
|
||||
"device_name": "/dev/xvdc",
|
||||
"volume_size": "32",
|
||||
"delete_on_termination": true,
|
||||
"snapshot_tags": map[string]string{
|
||||
"Test_Tag": "tag_value",
|
||||
"another tag": "another value",
|
||||
},
|
||||
"snapshot_users": []string{
|
||||
"123", "456",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
generatedData, warnings, err := b.Prepare(config)
|
||||
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
if len(generatedData) == 0 {
|
||||
t.Fatalf("Generated data should not be empty")
|
||||
}
|
||||
|
||||
t.Logf("Test gen %+v", b.config.VolumeMappings)
|
||||
|
||||
}
|
|
@ -1,170 +0,0 @@
|
|||
package ebsvolume
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
|
||||
//"github.com/aws/aws-sdk-go/service/ec2"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
"github.com/aws/aws-sdk-go/service/ec2/ec2iface"
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
"github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
"github.com/hashicorp/packer/builder/amazon/common"
|
||||
)
|
||||
|
||||
// Define a mock struct to be used in unit tests for common aws steps.
|
||||
type mockEC2Conn struct {
|
||||
ec2iface.EC2API
|
||||
Config *aws.Config
|
||||
}
|
||||
|
||||
func (m *mockEC2Conn) CreateSnapshot(input *ec2.CreateSnapshotInput) (*ec2.Snapshot, error) {
|
||||
snap := &ec2.Snapshot{
|
||||
// This isn't typical amazon format, but injecting the volume id into
|
||||
// this field lets us verify that the right volume was snapshotted with
|
||||
// a simple string comparison
|
||||
SnapshotId: aws.String(fmt.Sprintf("snap-of-%s", *input.VolumeId)),
|
||||
}
|
||||
|
||||
return snap, nil
|
||||
}
|
||||
|
||||
func (m *mockEC2Conn) WaitUntilSnapshotCompletedWithContext(aws.Context, *ec2.DescribeSnapshotsInput, ...request.WaiterOption) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func getMockConn(config *common.AccessConfig, target string) (ec2iface.EC2API, error) {
|
||||
mockConn := &mockEC2Conn{
|
||||
Config: aws.NewConfig(),
|
||||
}
|
||||
return mockConn, nil
|
||||
}
|
||||
|
||||
// Create statebag for running test
|
||||
func tState(t *testing.T) multistep.StateBag {
|
||||
state := new(multistep.BasicStateBag)
|
||||
state.Put("ui", &packer.BasicUi{
|
||||
Reader: new(bytes.Buffer),
|
||||
Writer: new(bytes.Buffer),
|
||||
})
|
||||
// state.Put("amis", map[string]string{"us-east-1": "ami-12345"})
|
||||
// state.Put("snapshots", map[string][]string{"us-east-1": {"snap-0012345"}})
|
||||
conn, _ := getMockConn(&common.AccessConfig{}, "us-east-2")
|
||||
|
||||
state.Put("ec2", conn)
|
||||
// Store a fake instance that contains a block device that matches the
|
||||
// volumes defined in the config above
|
||||
state.Put("instance", &ec2.Instance{
|
||||
InstanceId: aws.String("instance-id"),
|
||||
BlockDeviceMappings: []*ec2.InstanceBlockDeviceMapping{
|
||||
{
|
||||
DeviceName: aws.String("/dev/xvda"),
|
||||
Ebs: &ec2.EbsInstanceBlockDevice{
|
||||
VolumeId: aws.String("vol-1234"),
|
||||
},
|
||||
},
|
||||
{
|
||||
DeviceName: aws.String("/dev/xvdb"),
|
||||
Ebs: &ec2.EbsInstanceBlockDevice{
|
||||
VolumeId: aws.String("vol-5678"),
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
return state
|
||||
}
|
||||
|
||||
func TestStepSnapshot_run_simple(t *testing.T) {
|
||||
var b Builder
|
||||
config := testConfig() //from builder_test
|
||||
|
||||
//Set some snapshot settings
|
||||
config["ebs_volumes"] = []map[string]interface{}{
|
||||
{
|
||||
"device_name": "/dev/xvdb",
|
||||
"volume_size": "32",
|
||||
"delete_on_termination": true,
|
||||
"snapshot_volume": true,
|
||||
},
|
||||
}
|
||||
|
||||
generatedData, warnings, err := b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
if len(generatedData) == 0 {
|
||||
t.Fatalf("Generated data should not be empty")
|
||||
}
|
||||
|
||||
state := tState(t)
|
||||
|
||||
accessConfig := common.FakeAccessConfig()
|
||||
|
||||
step := stepSnapshotEBSVolumes{
|
||||
PollingConfig: new(common.AWSPollingConfig),
|
||||
AccessConfig: accessConfig,
|
||||
VolumeMapping: b.config.VolumeMappings,
|
||||
Ctx: b.config.ctx,
|
||||
}
|
||||
|
||||
step.Run(context.Background(), state)
|
||||
|
||||
if len(step.snapshotMap) != 1 {
|
||||
t.Fatalf("Missing Snapshot from step")
|
||||
}
|
||||
|
||||
if volmapping := step.snapshotMap["snap-of-vol-5678"]; volmapping == nil {
|
||||
t.Fatalf("Didn't snapshot correct volume: Map is %#v", step.snapshotMap)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStepSnapshot_run_no_snaps(t *testing.T) {
|
||||
var b Builder
|
||||
config := testConfig() //from builder_test
|
||||
|
||||
//Set some snapshot settings
|
||||
config["ebs_volumes"] = []map[string]interface{}{
|
||||
{
|
||||
"device_name": "/dev/xvdb",
|
||||
"volume_size": "32",
|
||||
"delete_on_termination": true,
|
||||
"snapshot_volume": false,
|
||||
},
|
||||
}
|
||||
|
||||
generatedData, warnings, err := b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
if len(generatedData) == 0 {
|
||||
t.Fatalf("Generated data should not be empty")
|
||||
}
|
||||
|
||||
state := tState(t)
|
||||
|
||||
accessConfig := common.FakeAccessConfig()
|
||||
|
||||
step := stepSnapshotEBSVolumes{
|
||||
PollingConfig: new(common.AWSPollingConfig),
|
||||
AccessConfig: accessConfig,
|
||||
VolumeMapping: b.config.VolumeMappings,
|
||||
Ctx: b.config.ctx,
|
||||
}
|
||||
|
||||
step.Run(context.Background(), state)
|
||||
|
||||
if len(step.snapshotMap) != 0 {
|
||||
t.Fatalf("Shouldn't have snapshotted any volumes")
|
||||
}
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
command: packer build -var "accesskey=*" -var "secretkey=" -var "shellpath=packages.sh" .\apache.json
|
|
@ -1,31 +0,0 @@
|
|||
{
|
||||
"variables":
|
||||
{
|
||||
"accesskey": "",
|
||||
"secretkey": "",
|
||||
"shellpath": "packages.sh"
|
||||
},
|
||||
"builders":[
|
||||
{
|
||||
"type": "amazon-ebs",
|
||||
"access_key": "{{user `accesskey`}}",
|
||||
"secret_key": "{{user `secretkey`}}",
|
||||
"region": "ap-south-1",
|
||||
"source_ami": "ami-sa7608343426b",
|
||||
"instance_type": "t2.micro",
|
||||
"ssh_username": "ubuntu",
|
||||
"ami_name": "apache",
|
||||
"tags": {
|
||||
"OS_Version": "Ubuntu",
|
||||
"Release": "Latest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"provisioners":[
|
||||
{
|
||||
"type": "shell",
|
||||
"script": "{{user `shellpath`}}"
|
||||
}
|
||||
]
|
||||
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
echo "installing apache "
|
||||
sudo apt-get update
|
||||
sudo apt-get install apache2 -y
|
||||
sudo apt-get update
|
||||
sudo service apache2 restart
|
||||
sudo apache2 --version
|
|
@ -1 +0,0 @@
|
|||
command: packer build -var "accesskey=*" -var "secretkey=" -var "shellpath=packages.sh" .\nginx.json
|
|
@ -1,31 +0,0 @@
|
|||
{
|
||||
"variables":
|
||||
{
|
||||
"accesskey": "",
|
||||
"secretkey": "",
|
||||
"shellpath": "packages.sh"
|
||||
},
|
||||
"builders":[
|
||||
{
|
||||
"type": "amazon-ebs",
|
||||
"access_key": "{{user `accesskey`}}",
|
||||
"secret_key": "{{user `secretkey`}}",
|
||||
"region": "ap-south-1",
|
||||
"source_ami": "ami-sa7608343426b",
|
||||
"instance_type": "t2.micro",
|
||||
"ssh_username": "ubuntu",
|
||||
"ami_name": "nginx",
|
||||
"tags": {
|
||||
"OS_Version": "Ubuntu",
|
||||
"Release": "Latest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"provisioners":[
|
||||
{
|
||||
"type": "shell",
|
||||
"script": "{{user `shellpath`}}"
|
||||
}
|
||||
]
|
||||
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
echo "installing nginx "
|
||||
sudo apt-get update
|
||||
sudo apt-get install nginx -y
|
||||
sudo service nginx restart
|
|
@ -1,343 +0,0 @@
|
|||
package instance
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
)
|
||||
|
||||
func testConfig() (config map[string]interface{}, tf *os.File) {
|
||||
tf, err := ioutil.TempFile("", "packer")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
config = map[string]interface{}{
|
||||
"account_id": "foo",
|
||||
"ami_name": "foo",
|
||||
"instance_type": "m1.small",
|
||||
"region": "us-east-1",
|
||||
"s3_bucket": "foo",
|
||||
"source_ami": "foo",
|
||||
"ssh_username": "bob",
|
||||
"x509_cert_path": tf.Name(),
|
||||
"x509_key_path": tf.Name(),
|
||||
"x509_upload_path": "/foo",
|
||||
}
|
||||
|
||||
return config, tf
|
||||
}
|
||||
|
||||
func TestBuilder_ImplementsBuilder(t *testing.T) {
|
||||
var raw interface{}
|
||||
raw = &Builder{}
|
||||
if _, ok := raw.(packersdk.Builder); !ok {
|
||||
t.Fatalf("Builder should be a builder")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderPrepare_AccountId(t *testing.T) {
|
||||
b := &Builder{}
|
||||
config, tempfile := testConfig()
|
||||
config["skip_region_validation"] = true
|
||||
|
||||
defer os.Remove(tempfile.Name())
|
||||
defer tempfile.Close()
|
||||
|
||||
config["account_id"] = ""
|
||||
_, warnings, err := b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
|
||||
config["account_id"] = "foo"
|
||||
_, warnings, err = b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err != nil {
|
||||
t.Errorf("err: %s", err)
|
||||
}
|
||||
|
||||
config["account_id"] = "0123-0456-7890"
|
||||
_, warnings, err = b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
if b.config.AccountId != "012304567890" {
|
||||
t.Errorf("should strip hyphens: %s", b.config.AccountId)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderPrepare_AMIName(t *testing.T) {
|
||||
var b Builder
|
||||
config, tempfile := testConfig()
|
||||
defer os.Remove(tempfile.Name())
|
||||
defer tempfile.Close()
|
||||
|
||||
// Test good
|
||||
config["ami_name"] = "foo"
|
||||
config["skip_region_validation"] = true
|
||||
_, warnings, err := b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
|
||||
// Test bad
|
||||
config["ami_name"] = "foo {{"
|
||||
b = Builder{}
|
||||
_, warnings, err = b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
|
||||
// Test bad
|
||||
delete(config, "ami_name")
|
||||
b = Builder{}
|
||||
_, warnings, err = b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderPrepare_BundleDestination(t *testing.T) {
|
||||
b := &Builder{}
|
||||
config, tempfile := testConfig()
|
||||
config["skip_region_validation"] = true
|
||||
defer os.Remove(tempfile.Name())
|
||||
defer tempfile.Close()
|
||||
|
||||
config["bundle_destination"] = ""
|
||||
_, warnings, err := b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
if b.config.BundleDestination != "/tmp" {
|
||||
t.Fatalf("bad: %s", b.config.BundleDestination)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderPrepare_BundlePrefix(t *testing.T) {
|
||||
b := &Builder{}
|
||||
config, tempfile := testConfig()
|
||||
config["skip_region_validation"] = true
|
||||
defer os.Remove(tempfile.Name())
|
||||
defer tempfile.Close()
|
||||
|
||||
_, warnings, err := b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
if b.config.BundlePrefix == "" {
|
||||
t.Fatalf("bad: %s", b.config.BundlePrefix)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderPrepare_InvalidKey(t *testing.T) {
|
||||
var b Builder
|
||||
config, tempfile := testConfig()
|
||||
defer os.Remove(tempfile.Name())
|
||||
defer tempfile.Close()
|
||||
|
||||
// Add a random key
|
||||
config["i_should_not_be_valid"] = true
|
||||
_, warnings, err := b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderPrepare_S3Bucket(t *testing.T) {
|
||||
b := &Builder{}
|
||||
config, tempfile := testConfig()
|
||||
config["skip_region_validation"] = true
|
||||
defer os.Remove(tempfile.Name())
|
||||
defer tempfile.Close()
|
||||
|
||||
config["s3_bucket"] = ""
|
||||
_, warnings, err := b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
|
||||
config["s3_bucket"] = "foo"
|
||||
_, warnings, err = b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err != nil {
|
||||
t.Errorf("err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderPrepare_X509CertPath(t *testing.T) {
|
||||
b := &Builder{}
|
||||
config, tempfile := testConfig()
|
||||
config["skip_region_validation"] = true
|
||||
defer os.Remove(tempfile.Name())
|
||||
defer tempfile.Close()
|
||||
|
||||
config["x509_cert_path"] = ""
|
||||
_, warnings, err := b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
|
||||
config["x509_cert_path"] = "i/am/a/file/that/doesnt/exist"
|
||||
_, warnings, err = b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err == nil {
|
||||
t.Error("should have error")
|
||||
}
|
||||
|
||||
tf, err := ioutil.TempFile("", "packer")
|
||||
if err != nil {
|
||||
t.Fatalf("error tempfile: %s", err)
|
||||
}
|
||||
defer os.Remove(tf.Name())
|
||||
defer tf.Close()
|
||||
|
||||
config["x509_cert_path"] = tf.Name()
|
||||
_, warnings, err = b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderPrepare_X509KeyPath(t *testing.T) {
|
||||
b := &Builder{}
|
||||
config, tempfile := testConfig()
|
||||
config["skip_region_validation"] = true
|
||||
defer os.Remove(tempfile.Name())
|
||||
defer tempfile.Close()
|
||||
|
||||
config["x509_key_path"] = ""
|
||||
_, warnings, err := b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
|
||||
config["x509_key_path"] = "i/am/a/file/that/doesnt/exist"
|
||||
_, warnings, err = b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err == nil {
|
||||
t.Error("should have error")
|
||||
}
|
||||
|
||||
tf, err := ioutil.TempFile("", "packer")
|
||||
if err != nil {
|
||||
t.Fatalf("error tempfile: %s", err)
|
||||
}
|
||||
defer os.Remove(tf.Name())
|
||||
defer tf.Close()
|
||||
|
||||
config["x509_key_path"] = tf.Name()
|
||||
_, warnings, err = b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderPrepare_X509UploadPath(t *testing.T) {
|
||||
b := &Builder{}
|
||||
config, tempfile := testConfig()
|
||||
config["skip_region_validation"] = true
|
||||
defer os.Remove(tempfile.Name())
|
||||
defer tempfile.Close()
|
||||
|
||||
config["x509_upload_path"] = ""
|
||||
_, warnings, err := b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderPrepare_ReturnGeneratedData(t *testing.T) {
|
||||
var b Builder
|
||||
config, tempfile := testConfig()
|
||||
defer os.Remove(tempfile.Name())
|
||||
defer tempfile.Close()
|
||||
|
||||
generatedData, warnings, err := b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
if len(generatedData) == 0 {
|
||||
t.Fatalf("Generated data should not be empty")
|
||||
}
|
||||
if len(generatedData) == 0 {
|
||||
t.Fatalf("Generated data should not be empty")
|
||||
}
|
||||
if generatedData[0] != "SourceAMIName" {
|
||||
t.Fatalf("Generated data should contain SourceAMIName")
|
||||
}
|
||||
if generatedData[1] != "BuildRegion" {
|
||||
t.Fatalf("Generated data should contain BuildRegion")
|
||||
}
|
||||
if generatedData[2] != "SourceAMI" {
|
||||
t.Fatalf("Generated data should contain SourceAMI")
|
||||
}
|
||||
if generatedData[3] != "SourceAMICreationDate" {
|
||||
t.Fatalf("Generated data should contain SourceAMICreationDate")
|
||||
}
|
||||
if generatedData[4] != "SourceAMIOwner" {
|
||||
t.Fatalf("Generated data should contain SourceAMIOwner")
|
||||
}
|
||||
if generatedData[5] != "SourceAMIOwnerName" {
|
||||
t.Fatalf("Generated data should contain SourceAMIOwnerName")
|
||||
}
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
package version
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/packer-plugin-sdk/version"
|
||||
packerVersion "github.com/hashicorp/packer/version"
|
||||
)
|
||||
|
||||
var AWSPluginVersion *version.PluginVersion
|
||||
|
||||
func init() {
|
||||
AWSPluginVersion = version.InitializePluginVersion(
|
||||
packerVersion.Version, packerVersion.VersionPrerelease)
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/hashicorp/packer-plugin-sdk/plugin"
|
||||
"github.com/hashicorp/packer/builder/amazon/ebs"
|
||||
"github.com/hashicorp/packer/builder/amazon/ebssurrogate"
|
||||
"github.com/hashicorp/packer/builder/amazon/ebsvolume"
|
||||
"github.com/hashicorp/packer/builder/osc/chroot"
|
||||
amazonami "github.com/hashicorp/packer/datasource/amazon/ami"
|
||||
"github.com/hashicorp/packer/datasource/amazon/secretsmanager"
|
||||
amazonimport "github.com/hashicorp/packer/post-processor/amazon-import"
|
||||
)
|
||||
|
||||
func main() {
|
||||
pps := plugin.NewSet()
|
||||
pps.RegisterBuilder("ebs", new(ebs.Builder))
|
||||
pps.RegisterBuilder("chroot", new(chroot.Builder))
|
||||
pps.RegisterBuilder("ebssurrogate", new(ebssurrogate.Builder))
|
||||
pps.RegisterBuilder("ebsvolume", new(ebsvolume.Builder))
|
||||
pps.RegisterPostProcessor("import", new(amazonimport.PostProcessor))
|
||||
pps.RegisterDatasource("ami", new(amazonami.Datasource))
|
||||
pps.RegisterDatasource("secretsmanager", new(secretsmanager.Datasource))
|
||||
err := pps.Run()
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
|
@ -8,8 +8,8 @@ import (
|
|||
"runtime"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/packer-plugin-amazon/builder/ebs"
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
"github.com/hashicorp/packer/builder/amazon/ebs"
|
||||
"github.com/hashicorp/packer/builder/file"
|
||||
"github.com/hashicorp/packer/builder/null"
|
||||
"github.com/hashicorp/packer/packer"
|
||||
|
|
|
@ -16,9 +16,9 @@ import (
|
|||
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/hashicorp/hcl/v2/hclwrite"
|
||||
awscommon "github.com/hashicorp/packer-plugin-amazon/builder/common"
|
||||
hcl2shim "github.com/hashicorp/packer-plugin-sdk/hcl2helper"
|
||||
"github.com/hashicorp/packer-plugin-sdk/template"
|
||||
awscommon "github.com/hashicorp/packer/builder/amazon/common"
|
||||
"github.com/hashicorp/packer/packer"
|
||||
"github.com/mitchellh/mapstructure"
|
||||
"github.com/posener/complete"
|
||||
|
@ -107,7 +107,7 @@ const (
|
|||
# Read the documentation for data blocks here:
|
||||
# https://www.packer.io/docs/templates/hcl_templates/blocks/data
|
||||
# Read the documentation for the Amazon AMI Data Source here:
|
||||
# https://www.packer.io/docs/datasources/amazon/ami`
|
||||
# https://www.packer.io/docs/datasources/amazon/ami.mdx`
|
||||
|
||||
amazonSecretsManagerDataHeader = `
|
||||
# The amazon-secretsmanager data block is generated from your aws_secretsmanager template function; a data
|
||||
|
@ -115,7 +115,7 @@ const (
|
|||
# Read the documentation for data blocks here:
|
||||
# https://www.packer.io/docs/templates/hcl_templates/blocks/data
|
||||
# Read the documentation for the Amazon Secrets Manager Data Source here:
|
||||
# https://www.packer.io/docs/datasources/amazon/secretsmanager`
|
||||
# https://www.packer.io/docs/datasources/amazon/secretsmanager.mdx`
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
|
@ -14,11 +14,6 @@ import (
|
|||
"github.com/hashicorp/packer-plugin-sdk/plugin"
|
||||
|
||||
alicloudecsbuilder "github.com/hashicorp/packer/builder/alicloud/ecs"
|
||||
amazonchrootbuilder "github.com/hashicorp/packer/builder/amazon/chroot"
|
||||
amazonebsbuilder "github.com/hashicorp/packer/builder/amazon/ebs"
|
||||
amazonebssurrogatebuilder "github.com/hashicorp/packer/builder/amazon/ebssurrogate"
|
||||
amazonebsvolumebuilder "github.com/hashicorp/packer/builder/amazon/ebsvolume"
|
||||
amazoninstancebuilder "github.com/hashicorp/packer/builder/amazon/instance"
|
||||
azurearmbuilder "github.com/hashicorp/packer/builder/azure/arm"
|
||||
azurechrootbuilder "github.com/hashicorp/packer/builder/azure/chroot"
|
||||
azuredtlbuilder "github.com/hashicorp/packer/builder/azure/dtl"
|
||||
|
@ -64,10 +59,7 @@ import (
|
|||
vsphereclonebuilder "github.com/hashicorp/packer/builder/vsphere/clone"
|
||||
vsphereisobuilder "github.com/hashicorp/packer/builder/vsphere/iso"
|
||||
yandexbuilder "github.com/hashicorp/packer/builder/yandex"
|
||||
amazonamidatasource "github.com/hashicorp/packer/datasource/amazon/ami"
|
||||
amazonsecretsmanagerdatasource "github.com/hashicorp/packer/datasource/amazon/secretsmanager"
|
||||
alicloudimportpostprocessor "github.com/hashicorp/packer/post-processor/alicloud-import"
|
||||
amazonimportpostprocessor "github.com/hashicorp/packer/post-processor/amazon-import"
|
||||
artificepostprocessor "github.com/hashicorp/packer/post-processor/artifice"
|
||||
checksumpostprocessor "github.com/hashicorp/packer/post-processor/checksum"
|
||||
compresspostprocessor "github.com/hashicorp/packer/post-processor/compress"
|
||||
|
@ -108,57 +100,52 @@ type PluginCommand struct {
|
|||
}
|
||||
|
||||
var Builders = map[string]packersdk.Builder{
|
||||
"alicloud-ecs": new(alicloudecsbuilder.Builder),
|
||||
"amazon-chroot": new(amazonchrootbuilder.Builder),
|
||||
"amazon-ebs": new(amazonebsbuilder.Builder),
|
||||
"amazon-ebssurrogate": new(amazonebssurrogatebuilder.Builder),
|
||||
"amazon-ebsvolume": new(amazonebsvolumebuilder.Builder),
|
||||
"amazon-instance": new(amazoninstancebuilder.Builder),
|
||||
"azure-arm": new(azurearmbuilder.Builder),
|
||||
"azure-chroot": new(azurechrootbuilder.Builder),
|
||||
"azure-dtl": new(azuredtlbuilder.Builder),
|
||||
"cloudstack": new(cloudstackbuilder.Builder),
|
||||
"digitalocean": new(digitaloceanbuilder.Builder),
|
||||
"file": new(filebuilder.Builder),
|
||||
"googlecompute": new(googlecomputebuilder.Builder),
|
||||
"hcloud": new(hcloudbuilder.Builder),
|
||||
"hyperone": new(hyperonebuilder.Builder),
|
||||
"hyperv-iso": new(hypervisobuilder.Builder),
|
||||
"hyperv-vmcx": new(hypervvmcxbuilder.Builder),
|
||||
"jdcloud": new(jdcloudbuilder.Builder),
|
||||
"linode": new(linodebuilder.Builder),
|
||||
"lxc": new(lxcbuilder.Builder),
|
||||
"lxd": new(lxdbuilder.Builder),
|
||||
"ncloud": new(ncloudbuilder.Builder),
|
||||
"null": new(nullbuilder.Builder),
|
||||
"oneandone": new(oneandonebuilder.Builder),
|
||||
"openstack": new(openstackbuilder.Builder),
|
||||
"oracle-classic": new(oracleclassicbuilder.Builder),
|
||||
"oracle-oci": new(oracleocibuilder.Builder),
|
||||
"osc-bsu": new(oscbsubuilder.Builder),
|
||||
"osc-bsusurrogate": new(oscbsusurrogatebuilder.Builder),
|
||||
"osc-bsuvolume": new(oscbsuvolumebuilder.Builder),
|
||||
"osc-chroot": new(oscchrootbuilder.Builder),
|
||||
"parallels-iso": new(parallelsisobuilder.Builder),
|
||||
"parallels-pvm": new(parallelspvmbuilder.Builder),
|
||||
"profitbricks": new(profitbricksbuilder.Builder),
|
||||
"proxmox": new(proxmoxbuilder.Builder),
|
||||
"proxmox-clone": new(proxmoxclonebuilder.Builder),
|
||||
"proxmox-iso": new(proxmoxisobuilder.Builder),
|
||||
"qemu": new(qemubuilder.Builder),
|
||||
"scaleway": new(scalewaybuilder.Builder),
|
||||
"tencentcloud-cvm": new(tencentcloudcvmbuilder.Builder),
|
||||
"triton": new(tritonbuilder.Builder),
|
||||
"ucloud-uhost": new(uclouduhostbuilder.Builder),
|
||||
"vagrant": new(vagrantbuilder.Builder),
|
||||
"virtualbox-iso": new(virtualboxisobuilder.Builder),
|
||||
"virtualbox-ovf": new(virtualboxovfbuilder.Builder),
|
||||
"virtualbox-vm": new(virtualboxvmbuilder.Builder),
|
||||
"vmware-iso": new(vmwareisobuilder.Builder),
|
||||
"vmware-vmx": new(vmwarevmxbuilder.Builder),
|
||||
"vsphere-clone": new(vsphereclonebuilder.Builder),
|
||||
"vsphere-iso": new(vsphereisobuilder.Builder),
|
||||
"yandex": new(yandexbuilder.Builder),
|
||||
"alicloud-ecs": new(alicloudecsbuilder.Builder),
|
||||
"azure-arm": new(azurearmbuilder.Builder),
|
||||
"azure-chroot": new(azurechrootbuilder.Builder),
|
||||
"azure-dtl": new(azuredtlbuilder.Builder),
|
||||
"cloudstack": new(cloudstackbuilder.Builder),
|
||||
"digitalocean": new(digitaloceanbuilder.Builder),
|
||||
"file": new(filebuilder.Builder),
|
||||
"googlecompute": new(googlecomputebuilder.Builder),
|
||||
"hcloud": new(hcloudbuilder.Builder),
|
||||
"hyperone": new(hyperonebuilder.Builder),
|
||||
"hyperv-iso": new(hypervisobuilder.Builder),
|
||||
"hyperv-vmcx": new(hypervvmcxbuilder.Builder),
|
||||
"jdcloud": new(jdcloudbuilder.Builder),
|
||||
"linode": new(linodebuilder.Builder),
|
||||
"lxc": new(lxcbuilder.Builder),
|
||||
"lxd": new(lxdbuilder.Builder),
|
||||
"ncloud": new(ncloudbuilder.Builder),
|
||||
"null": new(nullbuilder.Builder),
|
||||
"oneandone": new(oneandonebuilder.Builder),
|
||||
"openstack": new(openstackbuilder.Builder),
|
||||
"oracle-classic": new(oracleclassicbuilder.Builder),
|
||||
"oracle-oci": new(oracleocibuilder.Builder),
|
||||
"osc-bsu": new(oscbsubuilder.Builder),
|
||||
"osc-bsusurrogate": new(oscbsusurrogatebuilder.Builder),
|
||||
"osc-bsuvolume": new(oscbsuvolumebuilder.Builder),
|
||||
"osc-chroot": new(oscchrootbuilder.Builder),
|
||||
"parallels-iso": new(parallelsisobuilder.Builder),
|
||||
"parallels-pvm": new(parallelspvmbuilder.Builder),
|
||||
"profitbricks": new(profitbricksbuilder.Builder),
|
||||
"proxmox": new(proxmoxbuilder.Builder),
|
||||
"proxmox-clone": new(proxmoxclonebuilder.Builder),
|
||||
"proxmox-iso": new(proxmoxisobuilder.Builder),
|
||||
"qemu": new(qemubuilder.Builder),
|
||||
"scaleway": new(scalewaybuilder.Builder),
|
||||
"tencentcloud-cvm": new(tencentcloudcvmbuilder.Builder),
|
||||
"triton": new(tritonbuilder.Builder),
|
||||
"ucloud-uhost": new(uclouduhostbuilder.Builder),
|
||||
"vagrant": new(vagrantbuilder.Builder),
|
||||
"virtualbox-iso": new(virtualboxisobuilder.Builder),
|
||||
"virtualbox-ovf": new(virtualboxovfbuilder.Builder),
|
||||
"virtualbox-vm": new(virtualboxvmbuilder.Builder),
|
||||
"vmware-iso": new(vmwareisobuilder.Builder),
|
||||
"vmware-vmx": new(vmwarevmxbuilder.Builder),
|
||||
"vsphere-clone": new(vsphereclonebuilder.Builder),
|
||||
"vsphere-iso": new(vsphereisobuilder.Builder),
|
||||
"yandex": new(yandexbuilder.Builder),
|
||||
}
|
||||
|
||||
var Provisioners = map[string]packersdk.Provisioner{
|
||||
|
@ -184,7 +171,6 @@ var Provisioners = map[string]packersdk.Provisioner{
|
|||
|
||||
var PostProcessors = map[string]packersdk.PostProcessor{
|
||||
"alicloud-import": new(alicloudimportpostprocessor.PostProcessor),
|
||||
"amazon-import": new(amazonimportpostprocessor.PostProcessor),
|
||||
"artifice": new(artificepostprocessor.PostProcessor),
|
||||
"checksum": new(checksumpostprocessor.PostProcessor),
|
||||
"compress": new(compresspostprocessor.PostProcessor),
|
||||
|
@ -202,10 +188,7 @@ var PostProcessors = map[string]packersdk.PostProcessor{
|
|||
"yandex-import": new(yandeximportpostprocessor.PostProcessor),
|
||||
}
|
||||
|
||||
var Datasources = map[string]packersdk.Datasource{
|
||||
"amazon-ami": new(amazonamidatasource.Datasource),
|
||||
"amazon-secretsmanager": new(amazonsecretsmanagerdatasource.Datasource),
|
||||
}
|
||||
var Datasources = map[string]packersdk.Datasource{}
|
||||
|
||||
var pluginRegexp = regexp.MustCompile("packer-(builder|post-processor|provisioner|datasource)-(.+)")
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@ variable "secret_account" {
|
|||
# Read the documentation for data blocks here:
|
||||
# https://www.packer.io/docs/templates/hcl_templates/blocks/data
|
||||
# Read the documentation for the Amazon Secrets Manager Data Source here:
|
||||
# https://www.packer.io/docs/datasources/amazon/secretsmanager
|
||||
# https://www.packer.io/docs/datasources/amazon/secretsmanager.mdx
|
||||
data "amazon-secretsmanager" "autogenerated_1" {
|
||||
name = "sample/app/password"
|
||||
}
|
||||
|
@ -76,7 +76,7 @@ data "amazon-secretsmanager" "autogenerated_4" {
|
|||
# Read the documentation for data blocks here:
|
||||
# https://www.packer.io/docs/templates/hcl_templates/blocks/data
|
||||
# Read the documentation for the Amazon AMI Data Source here:
|
||||
# https://www.packer.io/docs/datasources/amazon/ami
|
||||
# https://www.packer.io/docs/datasources/amazon/ami.mdx
|
||||
data "amazon-ami" "autogenerated_1" {
|
||||
access_key = "${var.aws_access_key}"
|
||||
filters = {
|
||||
|
|
|
@ -7,6 +7,14 @@ import (
|
|||
// still vendored with Packer for now. Importing as library instead of
|
||||
// forcing use of packer init, until packer v1.8.0
|
||||
exoscaleimportpostprocessor "github.com/exoscale/packer-plugin-exoscale/post-processor/exoscale-import"
|
||||
amazonchrootbuilder "github.com/hashicorp/packer-plugin-amazon/builder/chroot"
|
||||
amazonebsbuilder "github.com/hashicorp/packer-plugin-amazon/builder/ebs"
|
||||
amazonebssurrogatebuilder "github.com/hashicorp/packer-plugin-amazon/builder/ebssurrogate"
|
||||
amazonebsvolumebuilder "github.com/hashicorp/packer-plugin-amazon/builder/ebsvolume"
|
||||
amazoninstancebuilder "github.com/hashicorp/packer-plugin-amazon/builder/instance"
|
||||
amazonamidatasource "github.com/hashicorp/packer-plugin-amazon/datasource/ami"
|
||||
amazonsecretsmanagerdatasource "github.com/hashicorp/packer-plugin-amazon/datasource/secretsmanager"
|
||||
anazibimportpostprocessor "github.com/hashicorp/packer-plugin-amazon/post-processor/import"
|
||||
dockerbuilder "github.com/hashicorp/packer-plugin-docker/builder/docker"
|
||||
dockerimportpostprocessor "github.com/hashicorp/packer-plugin-docker/post-processor/docker-import"
|
||||
dockerpushpostprocessor "github.com/hashicorp/packer-plugin-docker/post-processor/docker-push"
|
||||
|
@ -14,10 +22,22 @@ import (
|
|||
dockertagpostprocessor "github.com/hashicorp/packer-plugin-docker/post-processor/docker-tag"
|
||||
)
|
||||
|
||||
// VendoredDatasources are datasource components that were once bundled with the
|
||||
// Packer core, but are now being imported from their counterpart plugin repos
|
||||
var VendoredDatasources = map[string]packersdk.Datasource{
|
||||
"amazon-ami": new(amazonamidatasource.Datasource),
|
||||
"amazon-secretsmanager": new(amazonsecretsmanagerdatasource.Datasource),
|
||||
}
|
||||
|
||||
// VendoredBuilders are builder components that were once bundled with the
|
||||
// Packer core, but are now being imported from their counterpart plugin repos
|
||||
var VendoredBuilders = map[string]packersdk.Builder{
|
||||
"docker": new(dockerbuilder.Builder),
|
||||
"docker": new(dockerbuilder.Builder),
|
||||
"amazon-ebs": new(amazonebsbuilder.Builder),
|
||||
"amazon-chroot": new(amazonchrootbuilder.Builder),
|
||||
"amazon-ebssurrogate": new(amazonebssurrogatebuilder.Builder),
|
||||
"amazon-ebsvolume": new(amazonebsvolumebuilder.Builder),
|
||||
"amazon-instance": new(amazoninstancebuilder.Builder),
|
||||
}
|
||||
|
||||
// VendoredProvisioners are provisioner components that were once bundled with the
|
||||
|
@ -32,11 +52,19 @@ var VendoredPostProcessors = map[string]packersdk.PostProcessor{
|
|||
"docker-save": new(dockersavepostprocessor.PostProcessor),
|
||||
"docker-tag": new(dockertagpostprocessor.PostProcessor),
|
||||
"exoscale-import": new(exoscaleimportpostprocessor.PostProcessor),
|
||||
"amazon-import": new(anazibimportpostprocessor.PostProcessor),
|
||||
}
|
||||
|
||||
// Upon init lets load up any plugins that were vendored manually into the default
|
||||
// set of plugins.
|
||||
func init() {
|
||||
for k, v := range VendoredDatasources {
|
||||
if _, ok := Datasources[k]; ok {
|
||||
continue
|
||||
}
|
||||
Datasources[k] = v
|
||||
}
|
||||
|
||||
for k, v := range VendoredBuilders {
|
||||
if _, ok := Builders[k]; ok {
|
||||
continue
|
||||
|
|
|
@ -1,64 +0,0 @@
|
|||
package ami
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/packer-plugin-sdk/acctest"
|
||||
amazonacc "github.com/hashicorp/packer/builder/amazon/ebs/acceptance"
|
||||
)
|
||||
|
||||
func TestAmazonAmi(t *testing.T) {
|
||||
testCase := &acctest.DatasourceTestCase{
|
||||
Name: "amazon_ami_datasource_basic_test",
|
||||
Teardown: func() error {
|
||||
helper := amazonacc.AWSHelper{
|
||||
Region: "us-west-2",
|
||||
AMIName: "packer-amazon-ami-test",
|
||||
}
|
||||
return helper.CleanUpAmi()
|
||||
},
|
||||
Template: testDatasourceBasic,
|
||||
Type: "amazon-ami",
|
||||
Check: func(buildCommand *exec.Cmd, logfile string) error {
|
||||
if buildCommand.ProcessState != nil {
|
||||
if buildCommand.ProcessState.ExitCode() != 0 {
|
||||
return fmt.Errorf("Bad exit code. Logfile: %s", logfile)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
acctest.TestDatasource(t, testCase)
|
||||
}
|
||||
|
||||
const testDatasourceBasic = `
|
||||
data "amazon-ami" "test" {
|
||||
filters = {
|
||||
virtualization-type = "hvm"
|
||||
name = "Windows_Server-2016-English-Full-Base-*"
|
||||
root-device-type = "ebs"
|
||||
}
|
||||
most_recent = true
|
||||
owners = ["801119661308"]
|
||||
}
|
||||
|
||||
source "amazon-ebs" "basic-example" {
|
||||
user_data_file = "./test-fixtures/configure-source-ssh.ps1"
|
||||
region = "us-west-2"
|
||||
source_ami = data.amazon-ami.test.id
|
||||
instance_type = "t2.small"
|
||||
ssh_agent_auth = false
|
||||
ami_name = "packer-amazon-ami-test"
|
||||
communicator = "ssh"
|
||||
ssh_timeout = "10m"
|
||||
ssh_username = "Administrator"
|
||||
}
|
||||
|
||||
build {
|
||||
sources = [
|
||||
"source.amazon-ebs.basic-example"
|
||||
]
|
||||
}
|
||||
`
|
|
@ -1,45 +0,0 @@
|
|||
package ami
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
awscommon "github.com/hashicorp/packer/builder/amazon/common"
|
||||
)
|
||||
|
||||
func TestDatasourceConfigure_FilterBlank(t *testing.T) {
|
||||
datasource := Datasource{
|
||||
config: Config{
|
||||
AmiFilterOptions: awscommon.AmiFilterOptions{},
|
||||
},
|
||||
}
|
||||
if err := datasource.Configure(nil); err == nil {
|
||||
t.Fatalf("Should error if filters map is empty or not specified")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunConfigPrepare_SourceAmiFilterOwnersBlank(t *testing.T) {
|
||||
datasource := Datasource{
|
||||
config: Config{
|
||||
AmiFilterOptions: awscommon.AmiFilterOptions{
|
||||
Filters: map[string]string{"foo": "bar"},
|
||||
},
|
||||
},
|
||||
}
|
||||
if err := datasource.Configure(nil); err == nil {
|
||||
t.Fatalf("Should error if Owners is not specified)")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunConfigPrepare_SourceAmiFilterGood(t *testing.T) {
|
||||
datasource := Datasource{
|
||||
config: Config{
|
||||
AmiFilterOptions: awscommon.AmiFilterOptions{
|
||||
Owners: []string{"1234567"},
|
||||
Filters: map[string]string{"foo": "bar"},
|
||||
},
|
||||
},
|
||||
}
|
||||
if err := datasource.Configure(nil); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
}
|
|
@ -1,161 +0,0 @@
|
|||
<powershell>
|
||||
# Version and download URL
|
||||
$openSSHVersion = "8.1.0.0p1-Beta"
|
||||
$openSSHURL = "https://github.com/PowerShell/Win32-OpenSSH/releases/download/v$openSSHVersion/OpenSSH-Win64.zip"
|
||||
|
||||
Set-ExecutionPolicy Unrestricted
|
||||
|
||||
# GitHub became TLS 1.2 only on Feb 22, 2018
|
||||
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12;
|
||||
|
||||
# Function to unzip an archive to a given destination
|
||||
Add-Type -AssemblyName System.IO.Compression.FileSystem
|
||||
Function Unzip
|
||||
{
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory=$true, Position=0)]
|
||||
[string] $ZipFile,
|
||||
[Parameter(Mandatory=$true, Position=1)]
|
||||
[string] $OutPath
|
||||
)
|
||||
|
||||
[System.IO.Compression.ZipFile]::ExtractToDirectory($zipFile, $outPath)
|
||||
}
|
||||
|
||||
# Set various known paths
|
||||
$openSSHZip = Join-Path $env:TEMP 'OpenSSH.zip'
|
||||
$openSSHInstallDir = Join-Path $env:ProgramFiles 'OpenSSH'
|
||||
$openSSHInstallScript = Join-Path $openSSHInstallDir 'install-sshd.ps1'
|
||||
$openSSHDownloadKeyScript = Join-Path $openSSHInstallDir 'download-key-pair.ps1'
|
||||
$openSSHDaemon = Join-Path $openSSHInstallDir 'sshd.exe'
|
||||
$openSSHDaemonConfig = [io.path]::combine($env:ProgramData, 'ssh', 'sshd_config')
|
||||
|
||||
# Download and unpack the binary distribution of OpenSSH
|
||||
Invoke-WebRequest -Uri $openSSHURL `
|
||||
-OutFile $openSSHZip `
|
||||
-ErrorAction Stop
|
||||
|
||||
Unzip -ZipFile $openSSHZip `
|
||||
-OutPath "$env:TEMP" `
|
||||
-ErrorAction Stop
|
||||
|
||||
Remove-Item $openSSHZip `
|
||||
-ErrorAction SilentlyContinue
|
||||
|
||||
# Move into Program Files
|
||||
Move-Item -Path (Join-Path $env:TEMP 'OpenSSH-Win64') `
|
||||
-Destination $openSSHInstallDir `
|
||||
-ErrorAction Stop
|
||||
|
||||
# Run the install script, terminate if it fails
|
||||
& Powershell.exe -ExecutionPolicy Bypass -File $openSSHInstallScript
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw("Failed to install OpenSSH Server")
|
||||
}
|
||||
|
||||
# Add a firewall rule to allow inbound SSH connections to sshd.exe
|
||||
New-NetFirewallRule -Name sshd `
|
||||
-DisplayName "OpenSSH Server (sshd)" `
|
||||
-Group "Remote Access" `
|
||||
-Description "Allow access via TCP port 22 to the OpenSSH Daemon" `
|
||||
-Enabled True `
|
||||
-Direction Inbound `
|
||||
-Protocol TCP `
|
||||
-LocalPort 22 `
|
||||
-Program "$openSSHDaemon" `
|
||||
-Action Allow `
|
||||
-ErrorAction Stop
|
||||
|
||||
# Ensure sshd automatically starts on boot
|
||||
Set-Service sshd -StartupType Automatic `
|
||||
-ErrorAction Stop
|
||||
|
||||
# Set the default login shell for SSH connections to Powershell
|
||||
New-Item -Path HKLM:\SOFTWARE\OpenSSH -Force
|
||||
New-ItemProperty -Path HKLM:\SOFTWARE\OpenSSH `
|
||||
-Name DefaultShell `
|
||||
-Value "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" `
|
||||
-ErrorAction Stop
|
||||
|
||||
$keyDownloadScript = @'
|
||||
# Download the instance key pair and authorize Administrator logins using it
|
||||
$openSSHAdminUser = 'c:\ProgramData\ssh'
|
||||
$openSSHAuthorizedKeys = Join-Path $openSSHAdminUser 'authorized_keys'
|
||||
|
||||
If (-Not (Test-Path $openSSHAdminUser)) {
|
||||
New-Item -Path $openSSHAdminUser -Type Directory
|
||||
}
|
||||
|
||||
$keyUrl = "http://169.254.169.254/latest/meta-data/public-keys/0/openssh-key"
|
||||
$keyReq = [System.Net.WebRequest]::Create($keyUrl)
|
||||
$keyResp = $keyReq.GetResponse()
|
||||
$keyRespStream = $keyResp.GetResponseStream()
|
||||
$streamReader = New-Object System.IO.StreamReader $keyRespStream
|
||||
$keyMaterial = $streamReader.ReadToEnd()
|
||||
|
||||
$keyMaterial | Out-File -Append -FilePath $openSSHAuthorizedKeys -Encoding ASCII
|
||||
|
||||
# Ensure access control on authorized_keys meets the requirements
|
||||
$acl = Get-ACL -Path $openSSHAuthorizedKeys
|
||||
$acl.SetAccessRuleProtection($True, $True)
|
||||
Set-Acl -Path $openSSHAuthorizedKeys -AclObject $acl
|
||||
|
||||
$acl = Get-ACL -Path $openSSHAuthorizedKeys
|
||||
$ar = New-Object System.Security.AccessControl.FileSystemAccessRule( `
|
||||
"NT Authority\Authenticated Users", "ReadAndExecute", "Allow")
|
||||
$acl.RemoveAccessRule($ar)
|
||||
$ar = New-Object System.Security.AccessControl.FileSystemAccessRule( `
|
||||
"BUILTIN\Administrators", "FullControl", "Allow")
|
||||
$acl.RemoveAccessRule($ar)
|
||||
$ar = New-Object System.Security.AccessControl.FileSystemAccessRule( `
|
||||
"BUILTIN\Users", "FullControl", "Allow")
|
||||
$acl.RemoveAccessRule($ar)
|
||||
Set-Acl -Path $openSSHAuthorizedKeys -AclObject $acl
|
||||
|
||||
Disable-ScheduledTask -TaskName "Download Key Pair"
|
||||
|
||||
$sshdConfigContent = @"
|
||||
# Modified sshd_config, created by Packer provisioner
|
||||
|
||||
PasswordAuthentication yes
|
||||
PubKeyAuthentication yes
|
||||
PidFile __PROGRAMDATA__/ssh/logs/sshd.pid
|
||||
AuthorizedKeysFile __PROGRAMDATA__/ssh/authorized_keys
|
||||
AllowUsers Administrator
|
||||
|
||||
Subsystem sftp sftp-server.exe
|
||||
"@
|
||||
|
||||
Set-Content -Path C:\ProgramData\ssh\sshd_config `
|
||||
-Value $sshdConfigContent
|
||||
|
||||
'@
|
||||
$keyDownloadScript | Out-File $openSSHDownloadKeyScript
|
||||
|
||||
# Create Task - Ensure the name matches the verbatim version above
|
||||
$taskName = "Download Key Pair"
|
||||
$principal = New-ScheduledTaskPrincipal `
|
||||
-UserID "NT AUTHORITY\SYSTEM" `
|
||||
-LogonType ServiceAccount `
|
||||
-RunLevel Highest
|
||||
$action = New-ScheduledTaskAction -Execute 'Powershell.exe' `
|
||||
-Argument "-NoProfile -File ""$openSSHDownloadKeyScript"""
|
||||
$trigger = New-ScheduledTaskTrigger -AtStartup
|
||||
Register-ScheduledTask -Action $action `
|
||||
-Trigger $trigger `
|
||||
-Principal $principal `
|
||||
-TaskName $taskName `
|
||||
-Description $taskName
|
||||
Disable-ScheduledTask -TaskName $taskName
|
||||
|
||||
# Run the install script, terminate if it fails
|
||||
& Powershell.exe -ExecutionPolicy Bypass -File $openSSHDownloadKeyScript
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw("Failed to download key pair")
|
||||
}
|
||||
|
||||
# Restart to ensure public key authentication works and SSH comes up
|
||||
Restart-Computer
|
||||
</powershell>
|
||||
<runAsLocalSystem>true</runAsLocalSystem>
|
|
@ -1,179 +0,0 @@
|
|||
package secretsmanager
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/secretsmanager"
|
||||
"github.com/hashicorp/packer-plugin-sdk/acctest"
|
||||
"github.com/hashicorp/packer-plugin-sdk/retry"
|
||||
awscommon "github.com/hashicorp/packer/builder/amazon/common"
|
||||
"github.com/hashicorp/packer/builder/amazon/common/awserrors"
|
||||
)
|
||||
|
||||
func TestAmazonSecretsManager(t *testing.T) {
|
||||
secret := &AmazonSecret{
|
||||
Name: "packer_datasource_secretsmanager_test_secret",
|
||||
Key: "packer_test_key",
|
||||
Value: "this_is_the_packer_test_secret_value",
|
||||
Description: "this is a secret used in a packer acc test",
|
||||
}
|
||||
|
||||
testCase := &acctest.DatasourceTestCase{
|
||||
Name: "amazon_secretsmanager_datasource_basic_test",
|
||||
Setup: func() error {
|
||||
return secret.Create()
|
||||
},
|
||||
Teardown: func() error {
|
||||
return secret.Delete()
|
||||
},
|
||||
Template: testDatasourceBasic,
|
||||
Type: "amazon-secrestmanager",
|
||||
Check: func(buildCommand *exec.Cmd, logfile string) error {
|
||||
if buildCommand.ProcessState != nil {
|
||||
if buildCommand.ProcessState.ExitCode() != 0 {
|
||||
return fmt.Errorf("Bad exit code. Logfile: %s", logfile)
|
||||
}
|
||||
}
|
||||
|
||||
logs, err := os.Open(logfile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable find %s", logfile)
|
||||
}
|
||||
defer logs.Close()
|
||||
|
||||
logsBytes, err := ioutil.ReadAll(logs)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to read %s", logfile)
|
||||
}
|
||||
logsString := string(logsBytes)
|
||||
|
||||
valueLog := fmt.Sprintf("null.basic-example: secret value: %s", secret.Value)
|
||||
secretStringLog := fmt.Sprintf("null.basic-example: secret secret_string: %s", fmt.Sprintf("{%s:%s}", secret.Key, secret.Value))
|
||||
versionIdLog := fmt.Sprintf("null.basic-example: secret version_id: %s", aws.StringValue(secret.Info.VersionId))
|
||||
secretValueLog := fmt.Sprintf("null.basic-example: secret value: %s", secret.Value)
|
||||
|
||||
if matched, _ := regexp.MatchString(valueLog+".*", logsString); !matched {
|
||||
t.Fatalf("logs doesn't contain expected arn %q", logsString)
|
||||
}
|
||||
if matched, _ := regexp.MatchString(secretStringLog+".*", logsString); !matched {
|
||||
t.Fatalf("logs doesn't contain expected secret_string %q", logsString)
|
||||
}
|
||||
if matched, _ := regexp.MatchString(versionIdLog+".*", logsString); !matched {
|
||||
t.Fatalf("logs doesn't contain expected version_id %q", logsString)
|
||||
}
|
||||
if matched, _ := regexp.MatchString(secretValueLog+".*", logsString); !matched {
|
||||
t.Fatalf("logs doesn't contain expected value %q", logsString)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
acctest.TestDatasource(t, testCase)
|
||||
}
|
||||
|
||||
const testDatasourceBasic = `
|
||||
data "amazon-secretsmanager" "test" {
|
||||
name = "packer_datasource_secretsmanager_test_secret"
|
||||
key = "packer_test_key"
|
||||
}
|
||||
|
||||
locals {
|
||||
value = data.amazon-secretsmanager.test.value
|
||||
secret_string = data.amazon-secretsmanager.test.secret_string
|
||||
version_id = data.amazon-secretsmanager.test.version_id
|
||||
secret_value = jsondecode(data.amazon-secretsmanager.test.secret_string)["packer_test_key"]
|
||||
}
|
||||
|
||||
source "null" "basic-example" {
|
||||
communicator = "none"
|
||||
}
|
||||
|
||||
build {
|
||||
sources = [
|
||||
"source.null.basic-example"
|
||||
]
|
||||
|
||||
provisioner "shell-local" {
|
||||
inline = [
|
||||
"echo secret value: ${local.value}",
|
||||
"echo secret secret_string: ${local.secret_string}",
|
||||
"echo secret version_id: ${local.version_id}",
|
||||
"echo secret value: ${local.secret_value}"
|
||||
]
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
type AmazonSecret struct {
|
||||
Name string
|
||||
Key string
|
||||
Value string
|
||||
Description string
|
||||
|
||||
Info *secretsmanager.CreateSecretOutput
|
||||
manager *secretsmanager.SecretsManager
|
||||
}
|
||||
|
||||
func (as *AmazonSecret) Create() error {
|
||||
if as.manager == nil {
|
||||
accessConfig := &awscommon.AccessConfig{}
|
||||
session, err := accessConfig.Session()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to create aws session %s", err.Error())
|
||||
}
|
||||
as.manager = secretsmanager.New(session)
|
||||
}
|
||||
|
||||
newSecret := &secretsmanager.CreateSecretInput{
|
||||
Description: aws.String(as.Description),
|
||||
Name: aws.String(as.Name),
|
||||
SecretString: aws.String(fmt.Sprintf(`{%q:%q}`, as.Key, as.Value)),
|
||||
}
|
||||
|
||||
secret := new(secretsmanager.CreateSecretOutput)
|
||||
var err error
|
||||
err = retry.Config{
|
||||
Tries: 11,
|
||||
ShouldRetry: func(err error) bool {
|
||||
if awserrors.Matches(err, "ResourceExistsException", "") {
|
||||
_ = as.Delete()
|
||||
return true
|
||||
}
|
||||
if awserrors.Matches(err, "InvalidRequestException", "already scheduled for deletion") {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
},
|
||||
RetryDelay: (&retry.Backoff{InitialBackoff: 200 * time.Millisecond, MaxBackoff: 30 * time.Second, Multiplier: 2}).Linear,
|
||||
}.Run(context.TODO(), func(_ context.Context) error {
|
||||
secret, err = as.manager.CreateSecret(newSecret)
|
||||
return err
|
||||
})
|
||||
as.Info = secret
|
||||
return err
|
||||
}
|
||||
|
||||
func (as *AmazonSecret) Delete() error {
|
||||
if as.manager == nil {
|
||||
accessConfig := &awscommon.AccessConfig{}
|
||||
session, err := accessConfig.Session()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to create aws session %s", err.Error())
|
||||
}
|
||||
as.manager = secretsmanager.New(session)
|
||||
}
|
||||
|
||||
secret := &secretsmanager.DeleteSecretInput{
|
||||
ForceDeleteWithoutRecovery: aws.Bool(true),
|
||||
SecretId: aws.String(as.Name),
|
||||
}
|
||||
_, err := as.manager.DeleteSecret(secret)
|
||||
return err
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
package secretsmanager
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDatasourceConfigure_EmptySecretId(t *testing.T) {
|
||||
datasource := Datasource{
|
||||
config: Config{},
|
||||
}
|
||||
if err := datasource.Configure(nil); err == nil {
|
||||
t.Fatalf("Should error if secret id is not specified")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDatasourceConfigure_Dafaults(t *testing.T) {
|
||||
datasource := Datasource{
|
||||
config: Config{
|
||||
Name: "arn:1223",
|
||||
},
|
||||
}
|
||||
if err := datasource.Configure(nil); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
if datasource.config.VersionStage != "AWSCURRENT" {
|
||||
t.Fatalf("VersionStage not set correctly")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDatasourceConfigure(t *testing.T) {
|
||||
datasource := Datasource{
|
||||
config: Config{
|
||||
Name: "arn:1223",
|
||||
},
|
||||
}
|
||||
if err := datasource.Configure(nil); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
}
|
16
go.mod
16
go.mod
|
@ -17,7 +17,7 @@ require (
|
|||
github.com/aliyun/aliyun-oss-go-sdk v0.0.0-20170113022742-e6dbea820a9f
|
||||
github.com/antihax/optional v1.0.0
|
||||
github.com/approvals/go-approval-tests v0.0.0-20160714161514-ad96e53bea43
|
||||
github.com/aws/aws-sdk-go v1.37.15
|
||||
github.com/aws/aws-sdk-go v1.38.0
|
||||
github.com/biogo/hts v0.0.0-20160420073057-50da7d4131a3
|
||||
github.com/c2h5oh/datasize v0.0.0-20200112174442-28bbd4740fee
|
||||
github.com/cheggaaa/pb v1.0.27
|
||||
|
@ -32,24 +32,24 @@ require (
|
|||
github.com/go-resty/resty/v2 v2.3.0
|
||||
github.com/gobwas/glob v0.2.3
|
||||
github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3
|
||||
github.com/google/go-cmp v0.5.2
|
||||
github.com/google/go-cmp v0.5.5
|
||||
github.com/google/go-github/v33 v33.0.1-0.20210113204525-9318e629ec69
|
||||
github.com/google/uuid v1.1.2
|
||||
github.com/gophercloud/gophercloud v0.12.0
|
||||
github.com/gophercloud/utils v0.0.0-20200508015959-b0167b94122c
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.1.0
|
||||
github.com/hako/durafmt v0.0.0-20200710122514-c0fb7b4da026
|
||||
github.com/hashicorp/aws-sdk-go-base v0.6.0
|
||||
github.com/hashicorp/errwrap v1.0.0
|
||||
github.com/hashicorp/go-checkpoint v0.0.0-20171009173528-1545e56e46de
|
||||
github.com/hashicorp/go-cleanhttp v0.5.1
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2
|
||||
github.com/hashicorp/go-cty-funcs v0.0.0-20200930094925-2721b1e36840
|
||||
github.com/hashicorp/go-getter/v2 v2.0.0-20200604122502-a6995fa1edad
|
||||
github.com/hashicorp/go-multierror v1.1.0
|
||||
github.com/hashicorp/go-multierror v1.1.1
|
||||
github.com/hashicorp/go-oracle-terraform v0.0.0-20181016190316-007121241b79
|
||||
github.com/hashicorp/go-uuid v1.0.2
|
||||
github.com/hashicorp/go-version v1.2.0
|
||||
github.com/hashicorp/hcl/v2 v2.8.0
|
||||
github.com/hashicorp/hcl/v2 v2.9.1
|
||||
github.com/hashicorp/packer-plugin-amazon v0.0.1
|
||||
github.com/hashicorp/packer-plugin-docker v0.0.2
|
||||
github.com/hashicorp/packer-plugin-sdk v0.1.1-0.20210323111710-5a7ab7f7a1c0
|
||||
github.com/hashicorp/vault/api v1.0.4
|
||||
|
@ -87,7 +87,7 @@ require (
|
|||
github.com/xanzy/go-cloudstack v0.0.0-20190526095453-42f262b63ed0
|
||||
github.com/yandex-cloud/go-genproto v0.0.0-20200915125933-33de72a328bd
|
||||
github.com/yandex-cloud/go-sdk v0.0.0-20200921111412-ef15ded2014c
|
||||
github.com/zclconf/go-cty v1.7.0
|
||||
github.com/zclconf/go-cty v1.8.1
|
||||
github.com/zclconf/go-cty-yaml v1.0.1
|
||||
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad
|
||||
golang.org/x/mobile v0.0.0-20201208152944-da85bec010a2
|
||||
|
@ -95,7 +95,7 @@ require (
|
|||
golang.org/x/net v0.0.0-20210119194325-5f4716e94777
|
||||
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c
|
||||
golang.org/x/sys v0.0.0-20210319071255-635bc2c9138d
|
||||
golang.org/x/tools v0.0.0-20201111133315-69daaf961d65
|
||||
google.golang.org/api v0.32.0
|
||||
google.golang.org/grpc v1.32.0
|
||||
|
|
37
go.sum
37
go.sum
|
@ -106,8 +106,9 @@ github.com/apparentlymart/go-dump v0.0.0-20180507223929-23540a00eaa3 h1:ZSTrOEhi
|
|||
github.com/apparentlymart/go-dump v0.0.0-20180507223929-23540a00eaa3/go.mod h1:oL81AME2rN47vu18xqj1S1jPIPuN7afo62yKTNn3XMM=
|
||||
github.com/apparentlymart/go-textseg v1.0.0 h1:rRmlIsPEEhUTIKQb7T++Nz/A5Q6C9IuX2wFoYVvnCs0=
|
||||
github.com/apparentlymart/go-textseg v1.0.0/go.mod h1:z96Txxhf3xSFMPmb5X/1W05FF/Nj9VFpLOpjS5yuumk=
|
||||
github.com/apparentlymart/go-textseg/v12 v12.0.0 h1:bNEQyAGak9tojivJNkoqWErVCQbjdL7GzRt3F8NvfJ0=
|
||||
github.com/apparentlymart/go-textseg/v12 v12.0.0/go.mod h1:S/4uRK2UtaQttw1GenVJEynmyUenKwP++x/+DdGV/Ec=
|
||||
github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw=
|
||||
github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo=
|
||||
github.com/approvals/go-approval-tests v0.0.0-20160714161514-ad96e53bea43 h1:ePCAQPf5tUc5IMcUvu6euhSGna7jzs7eiXtJXHig6Zc=
|
||||
github.com/approvals/go-approval-tests v0.0.0-20160714161514-ad96e53bea43/go.mod h1:S6puKjZ9ZeqUPBv2hEBnMZGcM2J6mOsDRQcmxkMAND0=
|
||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||
|
@ -123,8 +124,8 @@ github.com/aws/aws-sdk-go v1.30.8/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU
|
|||
github.com/aws/aws-sdk-go v1.31.9/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
|
||||
github.com/aws/aws-sdk-go v1.36.0/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
|
||||
github.com/aws/aws-sdk-go v1.36.5/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
|
||||
github.com/aws/aws-sdk-go v1.37.15 h1:W7l7gLLMcYRlg6a+uvf3Zz4jYwdqYzhe5ymqwWoOhp4=
|
||||
github.com/aws/aws-sdk-go v1.37.15/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
|
||||
github.com/aws/aws-sdk-go v1.38.0 h1:mqnmtdW8rGIQmp2d0WRFLua0zW0Pel0P6/vd3gJuViY=
|
||||
github.com/aws/aws-sdk-go v1.38.0/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas=
|
||||
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4=
|
||||
|
@ -268,8 +269,9 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
|||
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-github/v33 v33.0.0/go.mod h1:GMdDnVZY/2TsWgp/lkYnpSAh6TrzhANBBwm6k6TTEXg=
|
||||
github.com/google/go-github/v33 v33.0.1-0.20210113204525-9318e629ec69 h1:zL0/Ug5CMhV0XRb3A6vnK1SQ9kJM3VIyRxPQ5t9w8Bg=
|
||||
github.com/google/go-github/v33 v33.0.1-0.20210113204525-9318e629ec69/go.mod h1:GMdDnVZY/2TsWgp/lkYnpSAh6TrzhANBBwm6k6TTEXg=
|
||||
|
@ -310,8 +312,9 @@ github.com/grpc-ecosystem/go-grpc-middleware v1.1.0 h1:THDBEeQ9xZ8JEaCLyLQqXMMdR
|
|||
github.com/grpc-ecosystem/go-grpc-middleware v1.1.0/go.mod h1:f5nM7jw/oeRSadq3xCzHAvxcr8HZnzsqU6ILg/0NiiE=
|
||||
github.com/hako/durafmt v0.0.0-20200710122514-c0fb7b4da026 h1:BpJ2o0OR5FV7vrkDYfXYVJQeMNWa8RhklZOpW2ITAIQ=
|
||||
github.com/hako/durafmt v0.0.0-20200710122514-c0fb7b4da026/go.mod h1:5Scbynm8dF1XAPwIwkGPqzkM/shndPm79Jd1003hTjE=
|
||||
github.com/hashicorp/aws-sdk-go-base v0.6.0 h1:qmUbzM36msbBF59YctwuO5w0M2oNXjlilgKpnEhx1uw=
|
||||
github.com/hashicorp/aws-sdk-go-base v0.6.0/go.mod h1:2fRjWDv3jJBeN6mVWFHV6hFTNeFBx2gpDLQaZNxUVAY=
|
||||
github.com/hashicorp/aws-sdk-go-base v0.7.0 h1:Umcq11kcoARameDgxPiYBbyltTZqO7GgBVSdq4pzX/w=
|
||||
github.com/hashicorp/aws-sdk-go-base v0.7.0/go.mod h1:2fRjWDv3jJBeN6mVWFHV6hFTNeFBx2gpDLQaZNxUVAY=
|
||||
github.com/hashicorp/consul/api v1.4.0 h1:jfESivXnO5uLdH650JU/6AnjRoHrLhULq0FnC3Kp9EY=
|
||||
github.com/hashicorp/consul/api v1.4.0/go.mod h1:xc8u05kyMa3Wjr9eEAsIAo3dg8+LywT5E/Cl7cNS5nU=
|
||||
github.com/hashicorp/consul/sdk v0.4.0 h1:zBtCfKJZcJDBvSCkQJch4ulp59m1rATFLKwNo/LYY30=
|
||||
|
@ -321,8 +324,9 @@ github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brv
|
|||
github.com/hashicorp/go-checkpoint v0.0.0-20171009173528-1545e56e46de h1:XDCSythtg8aWSRSO29uwhgh7b127fWr+m5SemqjSUL8=
|
||||
github.com/hashicorp/go-checkpoint v0.0.0-20171009173528-1545e56e46de/go.mod h1:xIwEieBHERyEvaeKF/TcHh1Hu+lxPM+n2vT1+g9I4m4=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
|
||||
github.com/hashicorp/go-cty-funcs v0.0.0-20200930094925-2721b1e36840 h1:kgvybwEeu0SXktbB2y3uLHX9lklLo+nzUwh59A3jzQc=
|
||||
github.com/hashicorp/go-cty-funcs v0.0.0-20200930094925-2721b1e36840/go.mod h1:Abjk0jbRkDaNCzsRhOv2iDCofYpX1eVsjozoiK63qLA=
|
||||
github.com/hashicorp/go-getter v1.4.1 h1:3A2Mh8smGFcf5M+gmcv898mZdrxpseik45IpcyISLsA=
|
||||
|
@ -345,8 +349,9 @@ github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iP
|
|||
github.com/hashicorp/go-msgpack v0.5.5 h1:i9R9JSrqIz0QVLz3sz+i3YJdT7TTSLcfLLzJi9aZTuI=
|
||||
github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
|
||||
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
|
||||
github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI=
|
||||
github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=
|
||||
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
|
||||
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
|
||||
github.com/hashicorp/go-oracle-terraform v0.0.0-20181016190316-007121241b79 h1:RKu7yAXZTaQsxj1K9GDsh+QVw0+Wu1SWHxtbFN0n+hE=
|
||||
github.com/hashicorp/go-oracle-terraform v0.0.0-20181016190316-007121241b79/go.mod h1:09jT3Y/OIsjTjQ2+3bkVNPDKqWcGIYYvjB2BEKVUdvc=
|
||||
github.com/hashicorp/go-plugin v1.0.1/go.mod h1:++UyYGoz3o5w9ZzAdZxtQKrWWP+iqPBn3cQptSMzBuY=
|
||||
|
@ -378,8 +383,9 @@ github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uG
|
|||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/hashicorp/hcl/v2 v2.6.0/go.mod h1:bQTN5mpo+jewjJgh8jr0JUguIi7qPHUF6yIfAEN3jqY=
|
||||
github.com/hashicorp/hcl/v2 v2.8.0 h1:iHLEAsNDp3N2MtqroP1wf0nF/zB2+McHN5YCzwqIm80=
|
||||
github.com/hashicorp/hcl/v2 v2.8.0/go.mod h1:bQTN5mpo+jewjJgh8jr0JUguIi7qPHUF6yIfAEN3jqY=
|
||||
github.com/hashicorp/hcl/v2 v2.9.1 h1:eOy4gREY0/ZQHNItlfuEZqtcQbXIxzojlP301hDpnac=
|
||||
github.com/hashicorp/hcl/v2 v2.9.1/go.mod h1:FwWsfWEjyV/CMj8s/gqAuiviY72rJ1/oayI9WftqcKg=
|
||||
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
|
||||
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
|
||||
github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY=
|
||||
|
@ -395,6 +401,12 @@ github.com/hashicorp/packer v1.6.7-0.20210126105722-aef4ced967ec/go.mod h1:2+Vo/
|
|||
github.com/hashicorp/packer v1.6.7-0.20210208125835-f616955ebcb6/go.mod h1:7f5ZpTTRG53rQ58BcTADuTnpiBcB3wapuxl4sF2sGMM=
|
||||
github.com/hashicorp/packer v1.6.7-0.20210217093213-201869d627bf/go.mod h1:+EWPPcqee4h8S/y913Dnta1eJkgiqsGXBQgB75A2qV0=
|
||||
github.com/hashicorp/packer v1.7.0/go.mod h1:3KRJcwOctl2JaAGpQMI1bWQRArfWNWqcYjO6AOsVVGQ=
|
||||
github.com/hashicorp/packer-plugin-amazon v0.0.0-20210322103904-ebc9f7a3cb33 h1:c8fxJJE9Ko8FXaTQexP22cHpvOmEZHk30WTWvo/BKFg=
|
||||
github.com/hashicorp/packer-plugin-amazon v0.0.0-20210322103904-ebc9f7a3cb33/go.mod h1:12c9msibyHdId+Mk/pCbdRb1KaLIhaNyxeJ6n8bZt30=
|
||||
github.com/hashicorp/packer-plugin-amazon v0.0.0-20210323151306-ff072d167737 h1:ZA8sQHjGIomiUz4SsccdxHwDk/ZI9CAmimUo7QKhMMs=
|
||||
github.com/hashicorp/packer-plugin-amazon v0.0.0-20210323151306-ff072d167737/go.mod h1:12c9msibyHdId+Mk/pCbdRb1KaLIhaNyxeJ6n8bZt30=
|
||||
github.com/hashicorp/packer-plugin-amazon v0.0.1 h1:EuyjNK9bL7WhQeIJzhBJxOx8nyc61ai5UbOsb1PIVwI=
|
||||
github.com/hashicorp/packer-plugin-amazon v0.0.1/go.mod h1:12c9msibyHdId+Mk/pCbdRb1KaLIhaNyxeJ6n8bZt30=
|
||||
github.com/hashicorp/packer-plugin-docker v0.0.2 h1:j/hQTogaN2pZfZohlZTRu5YvNZg2/qtYYHkxPBxv2Oo=
|
||||
github.com/hashicorp/packer-plugin-docker v0.0.2/go.mod h1:A2p9qztS4n88KsNF+qBM7BWw2HndW636GpFIjNSvbKM=
|
||||
github.com/hashicorp/packer-plugin-sdk v0.0.6/go.mod h1:Nvh28f+Jmpp2rcaN79bULTouNkGNDRfHckhHKTAXtyU=
|
||||
|
@ -405,6 +417,7 @@ github.com/hashicorp/packer-plugin-sdk v0.0.10-0.20210126105622-8e1648006d93/go.
|
|||
github.com/hashicorp/packer-plugin-sdk v0.0.11/go.mod h1:GNb0WNs7zibb8vzUZce1As64z2AW0FEMwhe2J7/NW5I=
|
||||
github.com/hashicorp/packer-plugin-sdk v0.0.12/go.mod h1:hs82OYeufirGG6KRENMpjBWomnIlte99X6wXAPThJ5I=
|
||||
github.com/hashicorp/packer-plugin-sdk v0.0.14/go.mod h1:tNb3XzJPnjMl3QuUdKmF47B5ImerdTakalHzUAvW0aw=
|
||||
github.com/hashicorp/packer-plugin-sdk v0.1.0/go.mod h1:CFsC20uZjtER/EnTn/CSMKD0kEdkqOVev8mtOmfnZiI=
|
||||
github.com/hashicorp/packer-plugin-sdk v0.1.1-0.20210323111710-5a7ab7f7a1c0 h1:nw4RqF7C4jUWGo5PGDG4dSclU+G/vXyVBHIu5j7akd4=
|
||||
github.com/hashicorp/packer-plugin-sdk v0.1.1-0.20210323111710-5a7ab7f7a1c0/go.mod h1:1d3nqB9LUsXMQaNUiL67Q+WYEtjsVcLNTX8ikVlpBrc=
|
||||
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
|
||||
|
@ -665,8 +678,11 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec
|
|||
github.com/zclconf/go-cty v1.0.0/go.mod h1:xnAOWiHeOqg2nWS62VtQ7pbOu17FtxJNW8RLEih+O3s=
|
||||
github.com/zclconf/go-cty v1.2.0/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8=
|
||||
github.com/zclconf/go-cty v1.4.0/go.mod h1:nHzOclRkoj++EU9ZjSrZvRG0BXIWt8c7loYc0qXAFGQ=
|
||||
github.com/zclconf/go-cty v1.7.0 h1:yMqLinUwNCYkmiHjEH+luio1yGl35cjqVzjvdRg2WlY=
|
||||
github.com/zclconf/go-cty v1.7.0/go.mod h1:VDR4+I79ubFBGm1uJac1226K5yANQFHeauxPBoP54+o=
|
||||
github.com/zclconf/go-cty v1.8.0/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk=
|
||||
github.com/zclconf/go-cty v1.8.1 h1:SI0LqNeNxAgv2WWqWJMlG2/Ad/6aYJ7IVYYMigmfkuI=
|
||||
github.com/zclconf/go-cty v1.8.1/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk=
|
||||
github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b/go.mod h1:ZRKQfBXbGkpdV6QMzT3rU1kSTAnfu1dO8dPKjYprgj8=
|
||||
github.com/zclconf/go-cty-yaml v1.0.1 h1:up11wlgAaDvlAGENcFDnZgkn0qUJurso7k6EpURKNF8=
|
||||
github.com/zclconf/go-cty-yaml v1.0.1/go.mod h1:IP3Ylp0wQpYm50IHK8OZWKMu6sPJIUgKa8XhiVHura0=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
|
@ -839,8 +855,9 @@ golang.org/x/sys v0.0.0-20200828194041-157a740278f4/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210319071255-635bc2c9138d h1:jbzgAvDZn8aEnytae+4ou0J0GwFZoHR0hOrTg4qH8GA=
|
||||
golang.org/x/sys v0.0.0-20210319071255-635bc2c9138d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
package version
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/packer-plugin-sdk/version"
|
||||
packerVersion "github.com/hashicorp/packer/version"
|
||||
)
|
||||
|
||||
var AmazonImportPluginVersion *version.PluginVersion
|
||||
|
||||
func init() {
|
||||
AmazonImportPluginVersion = version.InitializePluginVersion(
|
||||
packerVersion.Version, packerVersion.VersionPrerelease)
|
||||
}
|
|
@ -1,290 +0,0 @@
|
|||
# The following Ragel file was autogenerated with unicode2ragel.rb
|
||||
# from: https://www.unicode.org/Public/emoji/12.0/emoji-data.txt
|
||||
#
|
||||
# It defines ["Extended_Pictographic"].
|
||||
#
|
||||
# To use this, make sure that your alphtype is set to byte,
|
||||
# and that your input is in utf8.
|
||||
|
||||
%%{
|
||||
machine Emoji;
|
||||
|
||||
Extended_Pictographic =
|
||||
0xC2 0xA9 #1.1 [1] (©️) copyright
|
||||
| 0xC2 0xAE #1.1 [1] (®️) registered
|
||||
| 0xE2 0x80 0xBC #1.1 [1] (‼️) double exclamation mark
|
||||
| 0xE2 0x81 0x89 #3.0 [1] (⁉️) exclamation question mark
|
||||
| 0xE2 0x84 0xA2 #1.1 [1] (™️) trade mark
|
||||
| 0xE2 0x84 0xB9 #3.0 [1] (ℹ️) information
|
||||
| 0xE2 0x86 0x94..0x99 #1.1 [6] (↔️..↙️) left-right arrow..down...
|
||||
| 0xE2 0x86 0xA9..0xAA #1.1 [2] (↩️..↪️) right arrow curving le...
|
||||
| 0xE2 0x8C 0x9A..0x9B #1.1 [2] (⌚..⌛) watch..hourglass done
|
||||
| 0xE2 0x8C 0xA8 #1.1 [1] (⌨️) keyboard
|
||||
| 0xE2 0x8E 0x88 #3.0 [1] (⎈) HELM SYMBOL
|
||||
| 0xE2 0x8F 0x8F #4.0 [1] (⏏️) eject button
|
||||
| 0xE2 0x8F 0xA9..0xB3 #6.0 [11] (⏩..⏳) fast-forward button..hou...
|
||||
| 0xE2 0x8F 0xB8..0xBA #7.0 [3] (⏸️..⏺️) pause button..record b...
|
||||
| 0xE2 0x93 0x82 #1.1 [1] (Ⓜ️) circled M
|
||||
| 0xE2 0x96 0xAA..0xAB #1.1 [2] (▪️..▫️) black small square..wh...
|
||||
| 0xE2 0x96 0xB6 #1.1 [1] (▶️) play button
|
||||
| 0xE2 0x97 0x80 #1.1 [1] (◀️) reverse button
|
||||
| 0xE2 0x97 0xBB..0xBE #3.2 [4] (◻️..◾) white medium square..bl...
|
||||
| 0xE2 0x98 0x80..0x85 #1.1 [6] (☀️..★) sun..BLACK STAR
|
||||
| 0xE2 0x98 0x87..0x92 #1.1 [12] (☇..☒) LIGHTNING..BALLOT BOX WI...
|
||||
| 0xE2 0x98 0x94..0x95 #4.0 [2] (☔..☕) umbrella with rain drops...
|
||||
| 0xE2 0x98 0x96..0x97 #3.2 [2] (☖..☗) WHITE SHOGI PIECE..BLACK...
|
||||
| 0xE2 0x98 0x98 #4.1 [1] (☘️) shamrock
|
||||
| 0xE2 0x98 0x99 #3.0 [1] (☙) REVERSED ROTATED FLORAL ...
|
||||
| 0xE2 0x98 0x9A..0xFF #1.1 [86] (☚..♯) BLACK LEFT POINTING INDE...
|
||||
| 0xE2 0x99 0x00..0xAF #
|
||||
| 0xE2 0x99 0xB0..0xB1 #3.0 [2] (♰..♱) WEST SYRIAC CROSS..EAST ...
|
||||
| 0xE2 0x99 0xB2..0xBD #3.2 [12] (♲..♽) UNIVERSAL RECYCLING SYMB...
|
||||
| 0xE2 0x99 0xBE..0xBF #4.1 [2] (♾️..♿) infinity..wheelchair sy...
|
||||
| 0xE2 0x9A 0x80..0x85 #3.2 [6] (⚀..⚅) DIE FACE-1..DIE FACE-6
|
||||
| 0xE2 0x9A 0x90..0x91 #4.0 [2] (⚐..⚑) WHITE FLAG..BLACK FLAG
|
||||
| 0xE2 0x9A 0x92..0x9C #4.1 [11] (⚒️..⚜️) hammer and pick..fleur...
|
||||
| 0xE2 0x9A 0x9D #5.1 [1] (⚝) OUTLINED WHITE STAR
|
||||
| 0xE2 0x9A 0x9E..0x9F #5.2 [2] (⚞..⚟) THREE LINES CONVERGING R...
|
||||
| 0xE2 0x9A 0xA0..0xA1 #4.0 [2] (⚠️..⚡) warning..high voltage
|
||||
| 0xE2 0x9A 0xA2..0xB1 #4.1 [16] (⚢..⚱️) DOUBLED FEMALE SIGN..fu...
|
||||
| 0xE2 0x9A 0xB2 #5.0 [1] (⚲) NEUTER
|
||||
| 0xE2 0x9A 0xB3..0xBC #5.1 [10] (⚳..⚼) CERES..SESQUIQUADRATE
|
||||
| 0xE2 0x9A 0xBD..0xBF #5.2 [3] (⚽..⚿) soccer ball..SQUARED KEY
|
||||
| 0xE2 0x9B 0x80..0x83 #5.1 [4] (⛀..⛃) WHITE DRAUGHTS MAN..BLAC...
|
||||
| 0xE2 0x9B 0x84..0x8D #5.2 [10] (⛄..⛍) snowman without snow..DI...
|
||||
| 0xE2 0x9B 0x8E #6.0 [1] (⛎) Ophiuchus
|
||||
| 0xE2 0x9B 0x8F..0xA1 #5.2 [19] (⛏️..⛡) pick..RESTRICTED LEFT E...
|
||||
| 0xE2 0x9B 0xA2 #6.0 [1] (⛢) ASTRONOMICAL SYMBOL FOR ...
|
||||
| 0xE2 0x9B 0xA3 #5.2 [1] (⛣) HEAVY CIRCLE WITH STROKE...
|
||||
| 0xE2 0x9B 0xA4..0xA7 #6.0 [4] (⛤..⛧) PENTAGRAM..INVERTED PENT...
|
||||
| 0xE2 0x9B 0xA8..0xBF #5.2 [24] (⛨..⛿) BLACK CROSS ON SHIELD..W...
|
||||
| 0xE2 0x9C 0x80 #7.0 [1] (✀) BLACK SAFETY SCISSORS
|
||||
| 0xE2 0x9C 0x81..0x84 #1.1 [4] (✁..✄) UPPER BLADE SCISSORS..WH...
|
||||
| 0xE2 0x9C 0x85 #6.0 [1] (✅) check mark button
|
||||
| 0xE2 0x9C 0x88..0x89 #1.1 [2] (✈️..✉️) airplane..envelope
|
||||
| 0xE2 0x9C 0x8A..0x8B #6.0 [2] (✊..✋) raised fist..raised hand
|
||||
| 0xE2 0x9C 0x8C..0x92 #1.1 [7] (✌️..✒️) victory hand..black nib
|
||||
| 0xE2 0x9C 0x94 #1.1 [1] (✔️) check mark
|
||||
| 0xE2 0x9C 0x96 #1.1 [1] (✖️) multiplication sign
|
||||
| 0xE2 0x9C 0x9D #1.1 [1] (✝️) latin cross
|
||||
| 0xE2 0x9C 0xA1 #1.1 [1] (✡️) star of David
|
||||
| 0xE2 0x9C 0xA8 #6.0 [1] (✨) sparkles
|
||||
| 0xE2 0x9C 0xB3..0xB4 #1.1 [2] (✳️..✴️) eight-spoked asterisk....
|
||||
| 0xE2 0x9D 0x84 #1.1 [1] (❄️) snowflake
|
||||
| 0xE2 0x9D 0x87 #1.1 [1] (❇️) sparkle
|
||||
| 0xE2 0x9D 0x8C #6.0 [1] (❌) cross mark
|
||||
| 0xE2 0x9D 0x8E #6.0 [1] (❎) cross mark button
|
||||
| 0xE2 0x9D 0x93..0x95 #6.0 [3] (❓..❕) question mark..white exc...
|
||||
| 0xE2 0x9D 0x97 #5.2 [1] (❗) exclamation mark
|
||||
| 0xE2 0x9D 0xA3..0xA7 #1.1 [5] (❣️..❧) heart exclamation..ROTA...
|
||||
| 0xE2 0x9E 0x95..0x97 #6.0 [3] (➕..➗) plus sign..division sign
|
||||
| 0xE2 0x9E 0xA1 #1.1 [1] (➡️) right arrow
|
||||
| 0xE2 0x9E 0xB0 #6.0 [1] (➰) curly loop
|
||||
| 0xE2 0x9E 0xBF #6.0 [1] (➿) double curly loop
|
||||
| 0xE2 0xA4 0xB4..0xB5 #3.2 [2] (⤴️..⤵️) right arrow curving up...
|
||||
| 0xE2 0xAC 0x85..0x87 #4.0 [3] (⬅️..⬇️) left arrow..down arrow
|
||||
| 0xE2 0xAC 0x9B..0x9C #5.1 [2] (⬛..⬜) black large square..whit...
|
||||
| 0xE2 0xAD 0x90 #5.1 [1] (⭐) star
|
||||
| 0xE2 0xAD 0x95 #5.2 [1] (⭕) hollow red circle
|
||||
| 0xE3 0x80 0xB0 #1.1 [1] (〰️) wavy dash
|
||||
| 0xE3 0x80 0xBD #3.2 [1] (〽️) part alternation mark
|
||||
| 0xE3 0x8A 0x97 #1.1 [1] (㊗️) Japanese “congratulatio...
|
||||
| 0xE3 0x8A 0x99 #1.1 [1] (㊙️) Japanese “secret” button
|
||||
| 0xF0 0x9F 0x80 0x80..0xAB #5.1 [44] (🀀..🀫) MAHJONG TILE EAST WIN...
|
||||
| 0xF0 0x9F 0x80 0xAC..0xAF #NA [4] (..) <reserved-1F02C>..<res...
|
||||
| 0xF0 0x9F 0x80 0xB0..0xFF #5.1[100] (🀰..🂓) DOMINO TILE HOR...
|
||||
| 0xF0 0x9F 0x81..0x81 0x00..0xFF #
|
||||
| 0xF0 0x9F 0x82 0x00..0x93 #
|
||||
| 0xF0 0x9F 0x82 0x94..0x9F #NA [12] (..) <reserved-1F094>..<res...
|
||||
| 0xF0 0x9F 0x82 0xA0..0xAE #6.0 [15] (🂠..🂮) PLAYING CARD BACK..PL...
|
||||
| 0xF0 0x9F 0x82 0xAF..0xB0 #NA [2] (..) <reserved-1F0AF>..<res...
|
||||
| 0xF0 0x9F 0x82 0xB1..0xBE #6.0 [14] (🂱..🂾) PLAYING CARD ACE OF H...
|
||||
| 0xF0 0x9F 0x82 0xBF #7.0 [1] (🂿) PLAYING CARD RED JOKER
|
||||
| 0xF0 0x9F 0x83 0x80 #NA [1] () <reserved-1F0C0>
|
||||
| 0xF0 0x9F 0x83 0x81..0x8F #6.0 [15] (🃁..🃏) PLAYING CARD ACE OF D...
|
||||
| 0xF0 0x9F 0x83 0x90 #NA [1] () <reserved-1F0D0>
|
||||
| 0xF0 0x9F 0x83 0x91..0x9F #6.0 [15] (🃑..🃟) PLAYING CARD ACE OF C...
|
||||
| 0xF0 0x9F 0x83 0xA0..0xB5 #7.0 [22] (🃠..🃵) PLAYING CARD FOOL..PL...
|
||||
| 0xF0 0x9F 0x83 0xB6..0xBF #NA [10] (..) <reserved-1F0F6>..<res...
|
||||
| 0xF0 0x9F 0x84 0x8D..0x8F #NA [3] (🄍..🄏) <reserved-1F10D>..<res...
|
||||
| 0xF0 0x9F 0x84 0xAF #11.0 [1] (🄯) COPYLEFT SYMBOL
|
||||
| 0xF0 0x9F 0x85 0xAC #12.0 [1] (🅬) RAISED MR SIGN
|
||||
| 0xF0 0x9F 0x85 0xAD..0xAF #NA [3] (🅭..🅯) <reserved-1F16D>..<res...
|
||||
| 0xF0 0x9F 0x85 0xB0..0xB1 #6.0 [2] (🅰️..🅱️) A button (blood typ...
|
||||
| 0xF0 0x9F 0x85 0xBE #6.0 [1] (🅾️) O button (blood type)
|
||||
| 0xF0 0x9F 0x85 0xBF #5.2 [1] (🅿️) P button
|
||||
| 0xF0 0x9F 0x86 0x8E #6.0 [1] (🆎) AB button (blood type)
|
||||
| 0xF0 0x9F 0x86 0x91..0x9A #6.0 [10] (🆑..🆚) CL button..VS button
|
||||
| 0xF0 0x9F 0x86 0xAD..0xFF #NA [57] (🆭..) <reserved-1F1AD>..<res...
|
||||
| 0xF0 0x9F 0x87 0x00..0xA5 #
|
||||
| 0xF0 0x9F 0x88 0x81..0x82 #6.0 [2] (🈁..🈂️) Japanese “here” butt...
|
||||
| 0xF0 0x9F 0x88 0x83..0x8F #NA [13] (..) <reserved-1F203>..<res...
|
||||
| 0xF0 0x9F 0x88 0x9A #5.2 [1] (🈚) Japanese “free of charge...
|
||||
| 0xF0 0x9F 0x88 0xAF #5.2 [1] (🈯) Japanese “reserved” button
|
||||
| 0xF0 0x9F 0x88 0xB2..0xBA #6.0 [9] (🈲..🈺) Japanese “prohibited”...
|
||||
| 0xF0 0x9F 0x88 0xBC..0xBF #NA [4] (..) <reserved-1F23C>..<res...
|
||||
| 0xF0 0x9F 0x89 0x89..0x8F #NA [7] (..) <reserved-1F249>..<res...
|
||||
| 0xF0 0x9F 0x89 0x90..0x91 #6.0 [2] (🉐..🉑) Japanese “bargain” bu...
|
||||
| 0xF0 0x9F 0x89 0x92..0x9F #NA [14] (..) <reserved-1F252>..<res...
|
||||
| 0xF0 0x9F 0x89 0xA0..0xA5 #10.0 [6] (🉠..🉥) ROUNDED SYMBOL FOR F...
|
||||
| 0xF0 0x9F 0x89 0xA6..0xFF #NA[154] (..) <reserved-1F266>...
|
||||
| 0xF0 0x9F 0x8A..0x8A 0x00..0xFF #
|
||||
| 0xF0 0x9F 0x8B 0x00..0xBF #
|
||||
| 0xF0 0x9F 0x8C 0x80..0xA0 #6.0 [33] (🌀..🌠) cyclone..shooting star
|
||||
| 0xF0 0x9F 0x8C 0xA1..0xAC #7.0 [12] (🌡️..🌬️) thermometer..wind face
|
||||
| 0xF0 0x9F 0x8C 0xAD..0xAF #8.0 [3] (🌭..🌯) hot dog..burrito
|
||||
| 0xF0 0x9F 0x8C 0xB0..0xB5 #6.0 [6] (🌰..🌵) chestnut..cactus
|
||||
| 0xF0 0x9F 0x8C 0xB6 #7.0 [1] (🌶️) hot pepper
|
||||
| 0xF0 0x9F 0x8C 0xB7..0xFF #6.0 [70] (🌷..🍼) tulip..baby bottle
|
||||
| 0xF0 0x9F 0x8D 0x00..0xBC #
|
||||
| 0xF0 0x9F 0x8D 0xBD #7.0 [1] (🍽️) fork and knife with plate
|
||||
| 0xF0 0x9F 0x8D 0xBE..0xBF #8.0 [2] (🍾..🍿) bottle with popping c...
|
||||
| 0xF0 0x9F 0x8E 0x80..0x93 #6.0 [20] (🎀..🎓) ribbon..graduation cap
|
||||
| 0xF0 0x9F 0x8E 0x94..0x9F #7.0 [12] (🎔..🎟️) HEART WITH TIP ON TH...
|
||||
| 0xF0 0x9F 0x8E 0xA0..0xFF #6.0 [37] (🎠..🏄) carousel horse..perso...
|
||||
| 0xF0 0x9F 0x8F 0x00..0x84 #
|
||||
| 0xF0 0x9F 0x8F 0x85 #7.0 [1] (🏅) sports medal
|
||||
| 0xF0 0x9F 0x8F 0x86..0x8A #6.0 [5] (🏆..🏊) trophy..person swimming
|
||||
| 0xF0 0x9F 0x8F 0x8B..0x8E #7.0 [4] (🏋️..🏎️) person lifting weig...
|
||||
| 0xF0 0x9F 0x8F 0x8F..0x93 #8.0 [5] (🏏..🏓) cricket game..ping pong
|
||||
| 0xF0 0x9F 0x8F 0x94..0x9F #7.0 [12] (🏔️..🏟️) snow-capped mountai...
|
||||
| 0xF0 0x9F 0x8F 0xA0..0xB0 #6.0 [17] (🏠..🏰) house..castle
|
||||
| 0xF0 0x9F 0x8F 0xB1..0xB7 #7.0 [7] (🏱..🏷️) WHITE PENNANT..label
|
||||
| 0xF0 0x9F 0x8F 0xB8..0xBA #8.0 [3] (🏸..🏺) badminton..amphora
|
||||
| 0xF0 0x9F 0x90 0x80..0xBE #6.0 [63] (🐀..🐾) rat..paw prints
|
||||
| 0xF0 0x9F 0x90 0xBF #7.0 [1] (🐿️) chipmunk
|
||||
| 0xF0 0x9F 0x91 0x80 #6.0 [1] (👀) eyes
|
||||
| 0xF0 0x9F 0x91 0x81 #7.0 [1] (👁️) eye
|
||||
| 0xF0 0x9F 0x91 0x82..0xFF #6.0[182] (👂..📷) ear..camera
|
||||
| 0xF0 0x9F 0x92..0x92 0x00..0xFF #
|
||||
| 0xF0 0x9F 0x93 0x00..0xB7 #
|
||||
| 0xF0 0x9F 0x93 0xB8 #7.0 [1] (📸) camera with flash
|
||||
| 0xF0 0x9F 0x93 0xB9..0xBC #6.0 [4] (📹..📼) video camera..videoca...
|
||||
| 0xF0 0x9F 0x93 0xBD..0xBE #7.0 [2] (📽️..📾) film projector..PORT...
|
||||
| 0xF0 0x9F 0x93 0xBF #8.0 [1] (📿) prayer beads
|
||||
| 0xF0 0x9F 0x94 0x80..0xBD #6.0 [62] (🔀..🔽) shuffle tracks button...
|
||||
| 0xF0 0x9F 0x95 0x86..0x8A #7.0 [5] (🕆..🕊️) WHITE LATIN CROSS..dove
|
||||
| 0xF0 0x9F 0x95 0x8B..0x8F #8.0 [5] (🕋..🕏) kaaba..BOWL OF HYGIEIA
|
||||
| 0xF0 0x9F 0x95 0x90..0xA7 #6.0 [24] (🕐..🕧) one o’clock..twelve-t...
|
||||
| 0xF0 0x9F 0x95 0xA8..0xB9 #7.0 [18] (🕨..🕹️) RIGHT SPEAKER..joystick
|
||||
| 0xF0 0x9F 0x95 0xBA #9.0 [1] (🕺) man dancing
|
||||
| 0xF0 0x9F 0x95 0xBB..0xFF #7.0 [41] (🕻..🖣) LEFT HAND TELEPHONE R...
|
||||
| 0xF0 0x9F 0x96 0x00..0xA3 #
|
||||
| 0xF0 0x9F 0x96 0xA4 #9.0 [1] (🖤) black heart
|
||||
| 0xF0 0x9F 0x96 0xA5..0xFF #7.0 [86] (🖥️..🗺️) desktop computer..w...
|
||||
| 0xF0 0x9F 0x97 0x00..0xBA #
|
||||
| 0xF0 0x9F 0x97 0xBB..0xBF #6.0 [5] (🗻..🗿) mount fuji..moai
|
||||
| 0xF0 0x9F 0x98 0x80 #6.1 [1] (😀) grinning face
|
||||
| 0xF0 0x9F 0x98 0x81..0x90 #6.0 [16] (😁..😐) beaming face with smi...
|
||||
| 0xF0 0x9F 0x98 0x91 #6.1 [1] (😑) expressionless face
|
||||
| 0xF0 0x9F 0x98 0x92..0x94 #6.0 [3] (😒..😔) unamused face..pensiv...
|
||||
| 0xF0 0x9F 0x98 0x95 #6.1 [1] (😕) confused face
|
||||
| 0xF0 0x9F 0x98 0x96 #6.0 [1] (😖) confounded face
|
||||
| 0xF0 0x9F 0x98 0x97 #6.1 [1] (😗) kissing face
|
||||
| 0xF0 0x9F 0x98 0x98 #6.0 [1] (😘) face blowing a kiss
|
||||
| 0xF0 0x9F 0x98 0x99 #6.1 [1] (😙) kissing face with smilin...
|
||||
| 0xF0 0x9F 0x98 0x9A #6.0 [1] (😚) kissing face with closed...
|
||||
| 0xF0 0x9F 0x98 0x9B #6.1 [1] (😛) face with tongue
|
||||
| 0xF0 0x9F 0x98 0x9C..0x9E #6.0 [3] (😜..😞) winking face with ton...
|
||||
| 0xF0 0x9F 0x98 0x9F #6.1 [1] (😟) worried face
|
||||
| 0xF0 0x9F 0x98 0xA0..0xA5 #6.0 [6] (😠..😥) angry face..sad but r...
|
||||
| 0xF0 0x9F 0x98 0xA6..0xA7 #6.1 [2] (😦..😧) frowning face with op...
|
||||
| 0xF0 0x9F 0x98 0xA8..0xAB #6.0 [4] (😨..😫) fearful face..tired face
|
||||
| 0xF0 0x9F 0x98 0xAC #6.1 [1] (😬) grimacing face
|
||||
| 0xF0 0x9F 0x98 0xAD #6.0 [1] (😭) loudly crying face
|
||||
| 0xF0 0x9F 0x98 0xAE..0xAF #6.1 [2] (😮..😯) face with open mouth....
|
||||
| 0xF0 0x9F 0x98 0xB0..0xB3 #6.0 [4] (😰..😳) anxious face with swe...
|
||||
| 0xF0 0x9F 0x98 0xB4 #6.1 [1] (😴) sleeping face
|
||||
| 0xF0 0x9F 0x98 0xB5..0xFF #6.0 [12] (😵..🙀) dizzy face..weary cat
|
||||
| 0xF0 0x9F 0x99 0x00..0x80 #
|
||||
| 0xF0 0x9F 0x99 0x81..0x82 #7.0 [2] (🙁..🙂) slightly frowning fac...
|
||||
| 0xF0 0x9F 0x99 0x83..0x84 #8.0 [2] (🙃..🙄) upside-down face..fac...
|
||||
| 0xF0 0x9F 0x99 0x85..0x8F #6.0 [11] (🙅..🙏) person gesturing NO.....
|
||||
| 0xF0 0x9F 0x9A 0x80..0xFF #6.0 [70] (🚀..🛅) rocket..left luggage
|
||||
| 0xF0 0x9F 0x9B 0x00..0x85 #
|
||||
| 0xF0 0x9F 0x9B 0x86..0x8F #7.0 [10] (🛆..🛏️) TRIANGLE WITH ROUNDE...
|
||||
| 0xF0 0x9F 0x9B 0x90 #8.0 [1] (🛐) place of worship
|
||||
| 0xF0 0x9F 0x9B 0x91..0x92 #9.0 [2] (🛑..🛒) stop sign..shopping cart
|
||||
| 0xF0 0x9F 0x9B 0x93..0x94 #10.0 [2] (🛓..🛔) STUPA..PAGODA
|
||||
| 0xF0 0x9F 0x9B 0x95 #12.0 [1] (🛕) hindu temple
|
||||
| 0xF0 0x9F 0x9B 0x96..0x9F #NA [10] (🛖..🛟) <reserved-1F6D6>..<res...
|
||||
| 0xF0 0x9F 0x9B 0xA0..0xAC #7.0 [13] (🛠️..🛬) hammer and wrench..a...
|
||||
| 0xF0 0x9F 0x9B 0xAD..0xAF #NA [3] (..) <reserved-1F6ED>..<res...
|
||||
| 0xF0 0x9F 0x9B 0xB0..0xB3 #7.0 [4] (🛰️..🛳️) satellite..passenge...
|
||||
| 0xF0 0x9F 0x9B 0xB4..0xB6 #9.0 [3] (🛴..🛶) kick scooter..canoe
|
||||
| 0xF0 0x9F 0x9B 0xB7..0xB8 #10.0 [2] (🛷..🛸) sled..flying saucer
|
||||
| 0xF0 0x9F 0x9B 0xB9 #11.0 [1] (🛹) skateboard
|
||||
| 0xF0 0x9F 0x9B 0xBA #12.0 [1] (🛺) auto rickshaw
|
||||
| 0xF0 0x9F 0x9B 0xBB..0xBF #NA [5] (🛻..) <reserved-1F6FB>..<res...
|
||||
| 0xF0 0x9F 0x9D 0xB4..0xBF #NA [12] (🝴..🝿) <reserved-1F774>..<res...
|
||||
| 0xF0 0x9F 0x9F 0x95..0x98 #11.0 [4] (🟕..🟘) CIRCLED TRIANGLE..NE...
|
||||
| 0xF0 0x9F 0x9F 0x99..0x9F #NA [7] (🟙..) <reserved-1F7D9>..<res...
|
||||
| 0xF0 0x9F 0x9F 0xA0..0xAB #12.0 [12] (🟠..🟫) orange circle..brown...
|
||||
| 0xF0 0x9F 0x9F 0xAC..0xBF #NA [20] (..) <reserved-1F7EC>..<res...
|
||||
| 0xF0 0x9F 0xA0 0x8C..0x8F #NA [4] (..) <reserved-1F80C>..<res...
|
||||
| 0xF0 0x9F 0xA1 0x88..0x8F #NA [8] (..) <reserved-1F848>..<res...
|
||||
| 0xF0 0x9F 0xA1 0x9A..0x9F #NA [6] (..) <reserved-1F85A>..<res...
|
||||
| 0xF0 0x9F 0xA2 0x88..0x8F #NA [8] (..) <reserved-1F888>..<res...
|
||||
| 0xF0 0x9F 0xA2 0xAE..0xFF #NA [82] (..) <reserved-1F8AE>..<res...
|
||||
| 0xF0 0x9F 0xA3 0x00..0xBF #
|
||||
| 0xF0 0x9F 0xA4 0x8C #NA [1] (🤌) <reserved-1F90C>
|
||||
| 0xF0 0x9F 0xA4 0x8D..0x8F #12.0 [3] (🤍..🤏) white heart..pinchin...
|
||||
| 0xF0 0x9F 0xA4 0x90..0x98 #8.0 [9] (🤐..🤘) zipper-mouth face..si...
|
||||
| 0xF0 0x9F 0xA4 0x99..0x9E #9.0 [6] (🤙..🤞) call me hand..crossed...
|
||||
| 0xF0 0x9F 0xA4 0x9F #10.0 [1] (🤟) love-you gesture
|
||||
| 0xF0 0x9F 0xA4 0xA0..0xA7 #9.0 [8] (🤠..🤧) cowboy hat face..snee...
|
||||
| 0xF0 0x9F 0xA4 0xA8..0xAF #10.0 [8] (🤨..🤯) face with raised eye...
|
||||
| 0xF0 0x9F 0xA4 0xB0 #9.0 [1] (🤰) pregnant woman
|
||||
| 0xF0 0x9F 0xA4 0xB1..0xB2 #10.0 [2] (🤱..🤲) breast-feeding..palm...
|
||||
| 0xF0 0x9F 0xA4 0xB3..0xBA #9.0 [8] (🤳..🤺) selfie..person fencing
|
||||
| 0xF0 0x9F 0xA4 0xBC..0xBE #9.0 [3] (🤼..🤾) people wrestling..per...
|
||||
| 0xF0 0x9F 0xA4 0xBF #12.0 [1] (🤿) diving mask
|
||||
| 0xF0 0x9F 0xA5 0x80..0x85 #9.0 [6] (🥀..🥅) wilted flower..goal net
|
||||
| 0xF0 0x9F 0xA5 0x87..0x8B #9.0 [5] (🥇..🥋) 1st place medal..mart...
|
||||
| 0xF0 0x9F 0xA5 0x8C #10.0 [1] (🥌) curling stone
|
||||
| 0xF0 0x9F 0xA5 0x8D..0x8F #11.0 [3] (🥍..🥏) lacrosse..flying disc
|
||||
| 0xF0 0x9F 0xA5 0x90..0x9E #9.0 [15] (🥐..🥞) croissant..pancakes
|
||||
| 0xF0 0x9F 0xA5 0x9F..0xAB #10.0 [13] (🥟..🥫) dumpling..canned food
|
||||
| 0xF0 0x9F 0xA5 0xAC..0xB0 #11.0 [5] (🥬..🥰) leafy green..smiling...
|
||||
| 0xF0 0x9F 0xA5 0xB1 #12.0 [1] (🥱) yawning face
|
||||
| 0xF0 0x9F 0xA5 0xB2 #NA [1] (🥲) <reserved-1F972>
|
||||
| 0xF0 0x9F 0xA5 0xB3..0xB6 #11.0 [4] (🥳..🥶) partying face..cold ...
|
||||
| 0xF0 0x9F 0xA5 0xB7..0xB9 #NA [3] (🥷..🥹) <reserved-1F977>..<res...
|
||||
| 0xF0 0x9F 0xA5 0xBA #11.0 [1] (🥺) pleading face
|
||||
| 0xF0 0x9F 0xA5 0xBB #12.0 [1] (🥻) sari
|
||||
| 0xF0 0x9F 0xA5 0xBC..0xBF #11.0 [4] (🥼..🥿) lab coat..flat shoe
|
||||
| 0xF0 0x9F 0xA6 0x80..0x84 #8.0 [5] (🦀..🦄) crab..unicorn
|
||||
| 0xF0 0x9F 0xA6 0x85..0x91 #9.0 [13] (🦅..🦑) eagle..squid
|
||||
| 0xF0 0x9F 0xA6 0x92..0x97 #10.0 [6] (🦒..🦗) giraffe..cricket
|
||||
| 0xF0 0x9F 0xA6 0x98..0xA2 #11.0 [11] (🦘..🦢) kangaroo..swan
|
||||
| 0xF0 0x9F 0xA6 0xA3..0xA4 #NA [2] (🦣..🦤) <reserved-1F9A3>..<res...
|
||||
| 0xF0 0x9F 0xA6 0xA5..0xAA #12.0 [6] (🦥..🦪) sloth..oyster
|
||||
| 0xF0 0x9F 0xA6 0xAB..0xAD #NA [3] (🦫..🦭) <reserved-1F9AB>..<res...
|
||||
| 0xF0 0x9F 0xA6 0xAE..0xAF #12.0 [2] (🦮..🦯) guide dog..probing cane
|
||||
| 0xF0 0x9F 0xA6 0xB0..0xB9 #11.0 [10] (🦰..🦹) red hair..supervillain
|
||||
| 0xF0 0x9F 0xA6 0xBA..0xBF #12.0 [6] (🦺..🦿) safety vest..mechani...
|
||||
| 0xF0 0x9F 0xA7 0x80 #8.0 [1] (🧀) cheese wedge
|
||||
| 0xF0 0x9F 0xA7 0x81..0x82 #11.0 [2] (🧁..🧂) cupcake..salt
|
||||
| 0xF0 0x9F 0xA7 0x83..0x8A #12.0 [8] (🧃..🧊) beverage box..ice cube
|
||||
| 0xF0 0x9F 0xA7 0x8B..0x8C #NA [2] (🧋..🧌) <reserved-1F9CB>..<res...
|
||||
| 0xF0 0x9F 0xA7 0x8D..0x8F #12.0 [3] (🧍..🧏) person standing..dea...
|
||||
| 0xF0 0x9F 0xA7 0x90..0xA6 #10.0 [23] (🧐..🧦) face with monocle..s...
|
||||
| 0xF0 0x9F 0xA7 0xA7..0xBF #11.0 [25] (🧧..🧿) red envelope..nazar ...
|
||||
| 0xF0 0x9F 0xA8 0x80..0xFF #12.0 [84] (🨀..🩓) NEUTRAL CHESS KING.....
|
||||
| 0xF0 0x9F 0xA9 0x00..0x93 #
|
||||
| 0xF0 0x9F 0xA9 0x94..0x9F #NA [12] (..) <reserved-1FA54>..<res...
|
||||
| 0xF0 0x9F 0xA9 0xA0..0xAD #11.0 [14] (🩠..🩭) XIANGQI RED GENERAL....
|
||||
| 0xF0 0x9F 0xA9 0xAE..0xAF #NA [2] (..) <reserved-1FA6E>..<res...
|
||||
| 0xF0 0x9F 0xA9 0xB0..0xB3 #12.0 [4] (🩰..🩳) ballet shoes..shorts
|
||||
| 0xF0 0x9F 0xA9 0xB4..0xB7 #NA [4] (🩴..🩷) <reserved-1FA74>..<res...
|
||||
| 0xF0 0x9F 0xA9 0xB8..0xBA #12.0 [3] (🩸..🩺) drop of blood..steth...
|
||||
| 0xF0 0x9F 0xA9 0xBB..0xBF #NA [5] (🩻..) <reserved-1FA7B>..<res...
|
||||
| 0xF0 0x9F 0xAA 0x80..0x82 #12.0 [3] (🪀..🪂) yo-yo..parachute
|
||||
| 0xF0 0x9F 0xAA 0x83..0x8F #NA [13] (🪃..) <reserved-1FA83>..<res...
|
||||
| 0xF0 0x9F 0xAA 0x90..0x95 #12.0 [6] (🪐..🪕) ringed planet..banjo
|
||||
| 0xF0 0x9F 0xAA 0x96..0xFF #NA[1384] (🪖..) <reserved-1FA96>...
|
||||
| 0xF0 0x9F 0xAB..0xBE 0x00..0xFF #
|
||||
| 0xF0 0x9F 0xBF 0x00..0xBD #
|
||||
;
|
||||
|
||||
}%%
|
4078
vendor/github.com/apparentlymart/go-textseg/v12/textseg/grapheme_clusters.go
generated
vendored
4078
vendor/github.com/apparentlymart/go-textseg/v12/textseg/grapheme_clusters.go
generated
vendored
File diff suppressed because it is too large
Load Diff
525
vendor/github.com/apparentlymart/go-textseg/v13/textseg/emoji_table.rl
generated
vendored
Normal file
525
vendor/github.com/apparentlymart/go-textseg/v13/textseg/emoji_table.rl
generated
vendored
Normal file
|
@ -0,0 +1,525 @@
|
|||
# The following Ragel file was autogenerated with unicode2ragel.rb
|
||||
# from: https://www.unicode.org/Public/13.0.0/ucd/emoji/emoji-data.txt
|
||||
#
|
||||
# It defines ["Extended_Pictographic"].
|
||||
#
|
||||
# To use this, make sure that your alphtype is set to byte,
|
||||
# and that your input is in utf8.
|
||||
|
||||
%%{
|
||||
machine Emoji;
|
||||
|
||||
Extended_Pictographic =
|
||||
0xC2 0xA9 #E0.6 [1] (©️) copyright
|
||||
| 0xC2 0xAE #E0.6 [1] (®️) registered
|
||||
| 0xE2 0x80 0xBC #E0.6 [1] (‼️) double exclamation mark
|
||||
| 0xE2 0x81 0x89 #E0.6 [1] (⁉️) exclamation question ...
|
||||
| 0xE2 0x84 0xA2 #E0.6 [1] (™️) trade mark
|
||||
| 0xE2 0x84 0xB9 #E0.6 [1] (ℹ️) information
|
||||
| 0xE2 0x86 0x94..0x99 #E0.6 [6] (↔️..↙️) left-right arrow..do...
|
||||
| 0xE2 0x86 0xA9..0xAA #E0.6 [2] (↩️..↪️) right arrow curving ...
|
||||
| 0xE2 0x8C 0x9A..0x9B #E0.6 [2] (⌚..⌛) watch..hourglass done
|
||||
| 0xE2 0x8C 0xA8 #E1.0 [1] (⌨️) keyboard
|
||||
| 0xE2 0x8E 0x88 #E0.0 [1] (⎈) HELM SYMBOL
|
||||
| 0xE2 0x8F 0x8F #E1.0 [1] (⏏️) eject button
|
||||
| 0xE2 0x8F 0xA9..0xAC #E0.6 [4] (⏩..⏬) fast-forward button..f...
|
||||
| 0xE2 0x8F 0xAD..0xAE #E0.7 [2] (⏭️..⏮️) next track button..l...
|
||||
| 0xE2 0x8F 0xAF #E1.0 [1] (⏯️) play or pause button
|
||||
| 0xE2 0x8F 0xB0 #E0.6 [1] (⏰) alarm clock
|
||||
| 0xE2 0x8F 0xB1..0xB2 #E1.0 [2] (⏱️..⏲️) stopwatch..timer clock
|
||||
| 0xE2 0x8F 0xB3 #E0.6 [1] (⏳) hourglass not done
|
||||
| 0xE2 0x8F 0xB8..0xBA #E0.7 [3] (⏸️..⏺️) pause button..record...
|
||||
| 0xE2 0x93 0x82 #E0.6 [1] (Ⓜ️) circled M
|
||||
| 0xE2 0x96 0xAA..0xAB #E0.6 [2] (▪️..▫️) black small square.....
|
||||
| 0xE2 0x96 0xB6 #E0.6 [1] (▶️) play button
|
||||
| 0xE2 0x97 0x80 #E0.6 [1] (◀️) reverse button
|
||||
| 0xE2 0x97 0xBB..0xBE #E0.6 [4] (◻️..◾) white medium square.....
|
||||
| 0xE2 0x98 0x80..0x81 #E0.6 [2] (☀️..☁️) sun..cloud
|
||||
| 0xE2 0x98 0x82..0x83 #E0.7 [2] (☂️..☃️) umbrella..snowman
|
||||
| 0xE2 0x98 0x84 #E1.0 [1] (☄️) comet
|
||||
| 0xE2 0x98 0x85 #E0.0 [1] (★) BLACK STAR
|
||||
| 0xE2 0x98 0x87..0x8D #E0.0 [7] (☇..☍) LIGHTNING..OPPOSITION
|
||||
| 0xE2 0x98 0x8E #E0.6 [1] (☎️) telephone
|
||||
| 0xE2 0x98 0x8F..0x90 #E0.0 [2] (☏..☐) WHITE TELEPHONE..BALLO...
|
||||
| 0xE2 0x98 0x91 #E0.6 [1] (☑️) check box with check
|
||||
| 0xE2 0x98 0x92 #E0.0 [1] (☒) BALLOT BOX WITH X
|
||||
| 0xE2 0x98 0x94..0x95 #E0.6 [2] (☔..☕) umbrella with rain dro...
|
||||
| 0xE2 0x98 0x96..0x97 #E0.0 [2] (☖..☗) WHITE SHOGI PIECE..BLA...
|
||||
| 0xE2 0x98 0x98 #E1.0 [1] (☘️) shamrock
|
||||
| 0xE2 0x98 0x99..0x9C #E0.0 [4] (☙..☜) REVERSED ROTATED FLORA...
|
||||
| 0xE2 0x98 0x9D #E0.6 [1] (☝️) index pointing up
|
||||
| 0xE2 0x98 0x9E..0x9F #E0.0 [2] (☞..☟) WHITE RIGHT POINTING I...
|
||||
| 0xE2 0x98 0xA0 #E1.0 [1] (☠️) skull and crossbones
|
||||
| 0xE2 0x98 0xA1 #E0.0 [1] (☡) CAUTION SIGN
|
||||
| 0xE2 0x98 0xA2..0xA3 #E1.0 [2] (☢️..☣️) radioactive..biohazard
|
||||
| 0xE2 0x98 0xA4..0xA5 #E0.0 [2] (☤..☥) CADUCEUS..ANKH
|
||||
| 0xE2 0x98 0xA6 #E1.0 [1] (☦️) orthodox cross
|
||||
| 0xE2 0x98 0xA7..0xA9 #E0.0 [3] (☧..☩) CHI RHO..CROSS OF JERU...
|
||||
| 0xE2 0x98 0xAA #E0.7 [1] (☪️) star and crescent
|
||||
| 0xE2 0x98 0xAB..0xAD #E0.0 [3] (☫..☭) FARSI SYMBOL..HAMMER A...
|
||||
| 0xE2 0x98 0xAE #E1.0 [1] (☮️) peace symbol
|
||||
| 0xE2 0x98 0xAF #E0.7 [1] (☯️) yin yang
|
||||
| 0xE2 0x98 0xB0..0xB7 #E0.0 [8] (☰..☷) TRIGRAM FOR HEAVEN..TR...
|
||||
| 0xE2 0x98 0xB8..0xB9 #E0.7 [2] (☸️..☹️) wheel of dharma..fro...
|
||||
| 0xE2 0x98 0xBA #E0.6 [1] (☺️) smiling face
|
||||
| 0xE2 0x98 0xBB..0xBF #E0.0 [5] (☻..☿) BLACK SMILING FACE..ME...
|
||||
| 0xE2 0x99 0x80 #E4.0 [1] (♀️) female sign
|
||||
| 0xE2 0x99 0x81 #E0.0 [1] (♁) EARTH
|
||||
| 0xE2 0x99 0x82 #E4.0 [1] (♂️) male sign
|
||||
| 0xE2 0x99 0x83..0x87 #E0.0 [5] (♃..♇) JUPITER..PLUTO
|
||||
| 0xE2 0x99 0x88..0x93 #E0.6 [12] (♈..♓) Aries..Pisces
|
||||
| 0xE2 0x99 0x94..0x9E #E0.0 [11] (♔..♞) WHITE CHESS KING..BLAC...
|
||||
| 0xE2 0x99 0x9F #E11.0 [1] (♟️) chess pawn
|
||||
| 0xE2 0x99 0xA0 #E0.6 [1] (♠️) spade suit
|
||||
| 0xE2 0x99 0xA1..0xA2 #E0.0 [2] (♡..♢) WHITE HEART SUIT..WHIT...
|
||||
| 0xE2 0x99 0xA3 #E0.6 [1] (♣️) club suit
|
||||
| 0xE2 0x99 0xA4 #E0.0 [1] (♤) WHITE SPADE SUIT
|
||||
| 0xE2 0x99 0xA5..0xA6 #E0.6 [2] (♥️..♦️) heart suit..diamond ...
|
||||
| 0xE2 0x99 0xA7 #E0.0 [1] (♧) WHITE CLUB SUIT
|
||||
| 0xE2 0x99 0xA8 #E0.6 [1] (♨️) hot springs
|
||||
| 0xE2 0x99 0xA9..0xBA #E0.0 [18] (♩..♺) QUARTER NOTE..RECYCLIN...
|
||||
| 0xE2 0x99 0xBB #E0.6 [1] (♻️) recycling symbol
|
||||
| 0xE2 0x99 0xBC..0xBD #E0.0 [2] (♼..♽) RECYCLED PAPER SYMBOL....
|
||||
| 0xE2 0x99 0xBE #E11.0 [1] (♾️) infinity
|
||||
| 0xE2 0x99 0xBF #E0.6 [1] (♿) wheelchair symbol
|
||||
| 0xE2 0x9A 0x80..0x85 #E0.0 [6] (⚀..⚅) DIE FACE-1..DIE FACE-6
|
||||
| 0xE2 0x9A 0x90..0x91 #E0.0 [2] (⚐..⚑) WHITE FLAG..BLACK FLAG
|
||||
| 0xE2 0x9A 0x92 #E1.0 [1] (⚒️) hammer and pick
|
||||
| 0xE2 0x9A 0x93 #E0.6 [1] (⚓) anchor
|
||||
| 0xE2 0x9A 0x94 #E1.0 [1] (⚔️) crossed swords
|
||||
| 0xE2 0x9A 0x95 #E4.0 [1] (⚕️) medical symbol
|
||||
| 0xE2 0x9A 0x96..0x97 #E1.0 [2] (⚖️..⚗️) balance scale..alembic
|
||||
| 0xE2 0x9A 0x98 #E0.0 [1] (⚘) FLOWER
|
||||
| 0xE2 0x9A 0x99 #E1.0 [1] (⚙️) gear
|
||||
| 0xE2 0x9A 0x9A #E0.0 [1] (⚚) STAFF OF HERMES
|
||||
| 0xE2 0x9A 0x9B..0x9C #E1.0 [2] (⚛️..⚜️) atom symbol..fleur-d...
|
||||
| 0xE2 0x9A 0x9D..0x9F #E0.0 [3] (⚝..⚟) OUTLINED WHITE STAR..T...
|
||||
| 0xE2 0x9A 0xA0..0xA1 #E0.6 [2] (⚠️..⚡) warning..high voltage
|
||||
| 0xE2 0x9A 0xA2..0xA6 #E0.0 [5] (⚢..⚦) DOUBLED FEMALE SIGN..M...
|
||||
| 0xE2 0x9A 0xA7 #E13.0 [1] (⚧️) transgender symbol
|
||||
| 0xE2 0x9A 0xA8..0xA9 #E0.0 [2] (⚨..⚩) VERTICAL MALE WITH STR...
|
||||
| 0xE2 0x9A 0xAA..0xAB #E0.6 [2] (⚪..⚫) white circle..black ci...
|
||||
| 0xE2 0x9A 0xAC..0xAF #E0.0 [4] (⚬..⚯) MEDIUM SMALL WHITE CIR...
|
||||
| 0xE2 0x9A 0xB0..0xB1 #E1.0 [2] (⚰️..⚱️) coffin..funeral urn
|
||||
| 0xE2 0x9A 0xB2..0xBC #E0.0 [11] (⚲..⚼) NEUTER..SESQUIQUADRATE
|
||||
| 0xE2 0x9A 0xBD..0xBE #E0.6 [2] (⚽..⚾) soccer ball..baseball
|
||||
| 0xE2 0x9A 0xBF..0xFF #E0.0 [5] (⚿..⛃) SQUARED KEY..BLACK DRA...
|
||||
| 0xE2 0x9B 0x00..0x83 #
|
||||
| 0xE2 0x9B 0x84..0x85 #E0.6 [2] (⛄..⛅) snowman without snow.....
|
||||
| 0xE2 0x9B 0x86..0x87 #E0.0 [2] (⛆..⛇) RAIN..BLACK SNOWMAN
|
||||
| 0xE2 0x9B 0x88 #E0.7 [1] (⛈️) cloud with lightning ...
|
||||
| 0xE2 0x9B 0x89..0x8D #E0.0 [5] (⛉..⛍) TURNED WHITE SHOGI PIE...
|
||||
| 0xE2 0x9B 0x8E #E0.6 [1] (⛎) Ophiuchus
|
||||
| 0xE2 0x9B 0x8F #E0.7 [1] (⛏️) pick
|
||||
| 0xE2 0x9B 0x90 #E0.0 [1] (⛐) CAR SLIDING
|
||||
| 0xE2 0x9B 0x91 #E0.7 [1] (⛑️) rescue worker’s helmet
|
||||
| 0xE2 0x9B 0x92 #E0.0 [1] (⛒) CIRCLED CROSSING LANES
|
||||
| 0xE2 0x9B 0x93 #E0.7 [1] (⛓️) chains
|
||||
| 0xE2 0x9B 0x94 #E0.6 [1] (⛔) no entry
|
||||
| 0xE2 0x9B 0x95..0xA8 #E0.0 [20] (⛕..⛨) ALTERNATE ONE-WAY LEFT...
|
||||
| 0xE2 0x9B 0xA9 #E0.7 [1] (⛩️) shinto shrine
|
||||
| 0xE2 0x9B 0xAA #E0.6 [1] (⛪) church
|
||||
| 0xE2 0x9B 0xAB..0xAF #E0.0 [5] (⛫..⛯) CASTLE..MAP SYMBOL FOR...
|
||||
| 0xE2 0x9B 0xB0..0xB1 #E0.7 [2] (⛰️..⛱️) mountain..umbrella o...
|
||||
| 0xE2 0x9B 0xB2..0xB3 #E0.6 [2] (⛲..⛳) fountain..flag in hole
|
||||
| 0xE2 0x9B 0xB4 #E0.7 [1] (⛴️) ferry
|
||||
| 0xE2 0x9B 0xB5 #E0.6 [1] (⛵) sailboat
|
||||
| 0xE2 0x9B 0xB6 #E0.0 [1] (⛶) SQUARE FOUR CORNERS
|
||||
| 0xE2 0x9B 0xB7..0xB9 #E0.7 [3] (⛷️..⛹️) skier..person bounci...
|
||||
| 0xE2 0x9B 0xBA #E0.6 [1] (⛺) tent
|
||||
| 0xE2 0x9B 0xBB..0xBC #E0.0 [2] (⛻..⛼) JAPANESE BANK SYMBOL.....
|
||||
| 0xE2 0x9B 0xBD #E0.6 [1] (⛽) fuel pump
|
||||
| 0xE2 0x9B 0xBE..0xFF #E0.0 [4] (⛾..✁) CUP ON BLACK SQUARE..U...
|
||||
| 0xE2 0x9C 0x00..0x81 #
|
||||
| 0xE2 0x9C 0x82 #E0.6 [1] (✂️) scissors
|
||||
| 0xE2 0x9C 0x83..0x84 #E0.0 [2] (✃..✄) LOWER BLADE SCISSORS.....
|
||||
| 0xE2 0x9C 0x85 #E0.6 [1] (✅) check mark button
|
||||
| 0xE2 0x9C 0x88..0x8C #E0.6 [5] (✈️..✌️) airplane..victory hand
|
||||
| 0xE2 0x9C 0x8D #E0.7 [1] (✍️) writing hand
|
||||
| 0xE2 0x9C 0x8E #E0.0 [1] (✎) LOWER RIGHT PENCIL
|
||||
| 0xE2 0x9C 0x8F #E0.6 [1] (✏️) pencil
|
||||
| 0xE2 0x9C 0x90..0x91 #E0.0 [2] (✐..✑) UPPER RIGHT PENCIL..WH...
|
||||
| 0xE2 0x9C 0x92 #E0.6 [1] (✒️) black nib
|
||||
| 0xE2 0x9C 0x94 #E0.6 [1] (✔️) check mark
|
||||
| 0xE2 0x9C 0x96 #E0.6 [1] (✖️) multiply
|
||||
| 0xE2 0x9C 0x9D #E0.7 [1] (✝️) latin cross
|
||||
| 0xE2 0x9C 0xA1 #E0.7 [1] (✡️) star of David
|
||||
| 0xE2 0x9C 0xA8 #E0.6 [1] (✨) sparkles
|
||||
| 0xE2 0x9C 0xB3..0xB4 #E0.6 [2] (✳️..✴️) eight-spoked asteris...
|
||||
| 0xE2 0x9D 0x84 #E0.6 [1] (❄️) snowflake
|
||||
| 0xE2 0x9D 0x87 #E0.6 [1] (❇️) sparkle
|
||||
| 0xE2 0x9D 0x8C #E0.6 [1] (❌) cross mark
|
||||
| 0xE2 0x9D 0x8E #E0.6 [1] (❎) cross mark button
|
||||
| 0xE2 0x9D 0x93..0x95 #E0.6 [3] (❓..❕) question mark..white e...
|
||||
| 0xE2 0x9D 0x97 #E0.6 [1] (❗) exclamation mark
|
||||
| 0xE2 0x9D 0xA3 #E1.0 [1] (❣️) heart exclamation
|
||||
| 0xE2 0x9D 0xA4 #E0.6 [1] (❤️) red heart
|
||||
| 0xE2 0x9D 0xA5..0xA7 #E0.0 [3] (❥..❧) ROTATED HEAVY BLACK HE...
|
||||
| 0xE2 0x9E 0x95..0x97 #E0.6 [3] (➕..➗) plus..divide
|
||||
| 0xE2 0x9E 0xA1 #E0.6 [1] (➡️) right arrow
|
||||
| 0xE2 0x9E 0xB0 #E0.6 [1] (➰) curly loop
|
||||
| 0xE2 0x9E 0xBF #E1.0 [1] (➿) double curly loop
|
||||
| 0xE2 0xA4 0xB4..0xB5 #E0.6 [2] (⤴️..⤵️) right arrow curving ...
|
||||
| 0xE2 0xAC 0x85..0x87 #E0.6 [3] (⬅️..⬇️) left arrow..down arrow
|
||||
| 0xE2 0xAC 0x9B..0x9C #E0.6 [2] (⬛..⬜) black large square..wh...
|
||||
| 0xE2 0xAD 0x90 #E0.6 [1] (⭐) star
|
||||
| 0xE2 0xAD 0x95 #E0.6 [1] (⭕) hollow red circle
|
||||
| 0xE3 0x80 0xB0 #E0.6 [1] (〰️) wavy dash
|
||||
| 0xE3 0x80 0xBD #E0.6 [1] (〽️) part alternation mark
|
||||
| 0xE3 0x8A 0x97 #E0.6 [1] (㊗️) Japanese “congratulat...
|
||||
| 0xE3 0x8A 0x99 #E0.6 [1] (㊙️) Japanese “secret” button
|
||||
| 0xF0 0x9F 0x80 0x80..0x83 #E0.0 [4] (🀀..🀃) MAHJONG TILE EAST W...
|
||||
| 0xF0 0x9F 0x80 0x84 #E0.6 [1] (🀄) mahjong red dragon
|
||||
| 0xF0 0x9F 0x80 0x85..0xFF #E0.0 [202] (🀅..🃎) MAHJONG TILE ...
|
||||
| 0xF0 0x9F 0x81..0x82 0x00..0xFF #
|
||||
| 0xF0 0x9F 0x83 0x00..0x8E #
|
||||
| 0xF0 0x9F 0x83 0x8F #E0.6 [1] (🃏) joker
|
||||
| 0xF0 0x9F 0x83 0x90..0xBF #E0.0 [48] (..) <reserved-1F0D0>..<...
|
||||
| 0xF0 0x9F 0x84 0x8D..0x8F #E0.0 [3] (🄍..🄏) CIRCLED ZERO WITH S...
|
||||
| 0xF0 0x9F 0x84 0xAF #E0.0 [1] (🄯) COPYLEFT SYMBOL
|
||||
| 0xF0 0x9F 0x85 0xAC..0xAF #E0.0 [4] (🅬..🅯) RAISED MR SIGN..CIR...
|
||||
| 0xF0 0x9F 0x85 0xB0..0xB1 #E0.6 [2] (🅰️..🅱️) A button (blood t...
|
||||
| 0xF0 0x9F 0x85 0xBE..0xBF #E0.6 [2] (🅾️..🅿️) O button (blood t...
|
||||
| 0xF0 0x9F 0x86 0x8E #E0.6 [1] (🆎) AB button (blood type)
|
||||
| 0xF0 0x9F 0x86 0x91..0x9A #E0.6 [10] (🆑..🆚) CL button..VS button
|
||||
| 0xF0 0x9F 0x86 0xAD..0xFF #E0.0 [57] (🆭..) MASK WORK SYMBOL..<...
|
||||
| 0xF0 0x9F 0x87 0x00..0xA5 #
|
||||
| 0xF0 0x9F 0x88 0x81..0x82 #E0.6 [2] (🈁..🈂️) Japanese “here” bu...
|
||||
| 0xF0 0x9F 0x88 0x83..0x8F #E0.0 [13] (..) <reserved-1F203>..<...
|
||||
| 0xF0 0x9F 0x88 0x9A #E0.6 [1] (🈚) Japanese “free of char...
|
||||
| 0xF0 0x9F 0x88 0xAF #E0.6 [1] (🈯) Japanese “reserved” bu...
|
||||
| 0xF0 0x9F 0x88 0xB2..0xBA #E0.6 [9] (🈲..🈺) Japanese “prohibite...
|
||||
| 0xF0 0x9F 0x88 0xBC..0xBF #E0.0 [4] (..) <reserved-1F23C>..<...
|
||||
| 0xF0 0x9F 0x89 0x89..0x8F #E0.0 [7] (..) <reserved-1F249>..<...
|
||||
| 0xF0 0x9F 0x89 0x90..0x91 #E0.6 [2] (🉐..🉑) Japanese “bargain” ...
|
||||
| 0xF0 0x9F 0x89 0x92..0xFF #E0.0 [174] (..) <reserved-1F2...
|
||||
| 0xF0 0x9F 0x8A..0x8A 0x00..0xFF #
|
||||
| 0xF0 0x9F 0x8B 0x00..0xBF #
|
||||
| 0xF0 0x9F 0x8C 0x80..0x8C #E0.6 [13] (🌀..🌌) cyclone..milky way
|
||||
| 0xF0 0x9F 0x8C 0x8D..0x8E #E0.7 [2] (🌍..🌎) globe showing Europ...
|
||||
| 0xF0 0x9F 0x8C 0x8F #E0.6 [1] (🌏) globe showing Asia-Aus...
|
||||
| 0xF0 0x9F 0x8C 0x90 #E1.0 [1] (🌐) globe with meridians
|
||||
| 0xF0 0x9F 0x8C 0x91 #E0.6 [1] (🌑) new moon
|
||||
| 0xF0 0x9F 0x8C 0x92 #E1.0 [1] (🌒) waxing crescent moon
|
||||
| 0xF0 0x9F 0x8C 0x93..0x95 #E0.6 [3] (🌓..🌕) first quarter moon....
|
||||
| 0xF0 0x9F 0x8C 0x96..0x98 #E1.0 [3] (🌖..🌘) waning gibbous moon...
|
||||
| 0xF0 0x9F 0x8C 0x99 #E0.6 [1] (🌙) crescent moon
|
||||
| 0xF0 0x9F 0x8C 0x9A #E1.0 [1] (🌚) new moon face
|
||||
| 0xF0 0x9F 0x8C 0x9B #E0.6 [1] (🌛) first quarter moon face
|
||||
| 0xF0 0x9F 0x8C 0x9C #E0.7 [1] (🌜) last quarter moon face
|
||||
| 0xF0 0x9F 0x8C 0x9D..0x9E #E1.0 [2] (🌝..🌞) full moon face..sun...
|
||||
| 0xF0 0x9F 0x8C 0x9F..0xA0 #E0.6 [2] (🌟..🌠) glowing star..shoot...
|
||||
| 0xF0 0x9F 0x8C 0xA1 #E0.7 [1] (🌡️) thermometer
|
||||
| 0xF0 0x9F 0x8C 0xA2..0xA3 #E0.0 [2] (🌢..🌣) BLACK DROPLET..WHIT...
|
||||
| 0xF0 0x9F 0x8C 0xA4..0xAC #E0.7 [9] (🌤️..🌬️) sun behind small ...
|
||||
| 0xF0 0x9F 0x8C 0xAD..0xAF #E1.0 [3] (🌭..🌯) hot dog..burrito
|
||||
| 0xF0 0x9F 0x8C 0xB0..0xB1 #E0.6 [2] (🌰..🌱) chestnut..seedling
|
||||
| 0xF0 0x9F 0x8C 0xB2..0xB3 #E1.0 [2] (🌲..🌳) evergreen tree..dec...
|
||||
| 0xF0 0x9F 0x8C 0xB4..0xB5 #E0.6 [2] (🌴..🌵) palm tree..cactus
|
||||
| 0xF0 0x9F 0x8C 0xB6 #E0.7 [1] (🌶️) hot pepper
|
||||
| 0xF0 0x9F 0x8C 0xB7..0xFF #E0.6 [20] (🌷..🍊) tulip..tangerine
|
||||
| 0xF0 0x9F 0x8D 0x00..0x8A #
|
||||
| 0xF0 0x9F 0x8D 0x8B #E1.0 [1] (🍋) lemon
|
||||
| 0xF0 0x9F 0x8D 0x8C..0x8F #E0.6 [4] (🍌..🍏) banana..green apple
|
||||
| 0xF0 0x9F 0x8D 0x90 #E1.0 [1] (🍐) pear
|
||||
| 0xF0 0x9F 0x8D 0x91..0xBB #E0.6 [43] (🍑..🍻) peach..clinking bee...
|
||||
| 0xF0 0x9F 0x8D 0xBC #E1.0 [1] (🍼) baby bottle
|
||||
| 0xF0 0x9F 0x8D 0xBD #E0.7 [1] (🍽️) fork and knife with p...
|
||||
| 0xF0 0x9F 0x8D 0xBE..0xBF #E1.0 [2] (🍾..🍿) bottle with popping...
|
||||
| 0xF0 0x9F 0x8E 0x80..0x93 #E0.6 [20] (🎀..🎓) ribbon..graduation cap
|
||||
| 0xF0 0x9F 0x8E 0x94..0x95 #E0.0 [2] (🎔..🎕) HEART WITH TIP ON T...
|
||||
| 0xF0 0x9F 0x8E 0x96..0x97 #E0.7 [2] (🎖️..🎗️) military medal..r...
|
||||
| 0xF0 0x9F 0x8E 0x98 #E0.0 [1] (🎘) MUSICAL KEYBOARD WITH ...
|
||||
| 0xF0 0x9F 0x8E 0x99..0x9B #E0.7 [3] (🎙️..🎛️) studio microphone...
|
||||
| 0xF0 0x9F 0x8E 0x9C..0x9D #E0.0 [2] (🎜..🎝) BEAMED ASCENDING MU...
|
||||
| 0xF0 0x9F 0x8E 0x9E..0x9F #E0.7 [2] (🎞️..🎟️) film frames..admi...
|
||||
| 0xF0 0x9F 0x8E 0xA0..0xFF #E0.6 [37] (🎠..🏄) carousel horse..per...
|
||||
| 0xF0 0x9F 0x8F 0x00..0x84 #
|
||||
| 0xF0 0x9F 0x8F 0x85 #E1.0 [1] (🏅) sports medal
|
||||
| 0xF0 0x9F 0x8F 0x86 #E0.6 [1] (🏆) trophy
|
||||
| 0xF0 0x9F 0x8F 0x87 #E1.0 [1] (🏇) horse racing
|
||||
| 0xF0 0x9F 0x8F 0x88 #E0.6 [1] (🏈) american football
|
||||
| 0xF0 0x9F 0x8F 0x89 #E1.0 [1] (🏉) rugby football
|
||||
| 0xF0 0x9F 0x8F 0x8A #E0.6 [1] (🏊) person swimming
|
||||
| 0xF0 0x9F 0x8F 0x8B..0x8E #E0.7 [4] (🏋️..🏎️) person lifting we...
|
||||
| 0xF0 0x9F 0x8F 0x8F..0x93 #E1.0 [5] (🏏..🏓) cricket game..ping ...
|
||||
| 0xF0 0x9F 0x8F 0x94..0x9F #E0.7 [12] (🏔️..🏟️) snow-capped mount...
|
||||
| 0xF0 0x9F 0x8F 0xA0..0xA3 #E0.6 [4] (🏠..🏣) house..Japanese pos...
|
||||
| 0xF0 0x9F 0x8F 0xA4 #E1.0 [1] (🏤) post office
|
||||
| 0xF0 0x9F 0x8F 0xA5..0xB0 #E0.6 [12] (🏥..🏰) hospital..castle
|
||||
| 0xF0 0x9F 0x8F 0xB1..0xB2 #E0.0 [2] (🏱..🏲) WHITE PENNANT..BLAC...
|
||||
| 0xF0 0x9F 0x8F 0xB3 #E0.7 [1] (🏳️) white flag
|
||||
| 0xF0 0x9F 0x8F 0xB4 #E1.0 [1] (🏴) black flag
|
||||
| 0xF0 0x9F 0x8F 0xB5 #E0.7 [1] (🏵️) rosette
|
||||
| 0xF0 0x9F 0x8F 0xB6 #E0.0 [1] (🏶) BLACK ROSETTE
|
||||
| 0xF0 0x9F 0x8F 0xB7 #E0.7 [1] (🏷️) label
|
||||
| 0xF0 0x9F 0x8F 0xB8..0xBA #E1.0 [3] (🏸..🏺) badminton..amphora
|
||||
| 0xF0 0x9F 0x90 0x80..0x87 #E1.0 [8] (🐀..🐇) rat..rabbit
|
||||
| 0xF0 0x9F 0x90 0x88 #E0.7 [1] (🐈) cat
|
||||
| 0xF0 0x9F 0x90 0x89..0x8B #E1.0 [3] (🐉..🐋) dragon..whale
|
||||
| 0xF0 0x9F 0x90 0x8C..0x8E #E0.6 [3] (🐌..🐎) snail..horse
|
||||
| 0xF0 0x9F 0x90 0x8F..0x90 #E1.0 [2] (🐏..🐐) ram..goat
|
||||
| 0xF0 0x9F 0x90 0x91..0x92 #E0.6 [2] (🐑..🐒) ewe..monkey
|
||||
| 0xF0 0x9F 0x90 0x93 #E1.0 [1] (🐓) rooster
|
||||
| 0xF0 0x9F 0x90 0x94 #E0.6 [1] (🐔) chicken
|
||||
| 0xF0 0x9F 0x90 0x95 #E0.7 [1] (🐕) dog
|
||||
| 0xF0 0x9F 0x90 0x96 #E1.0 [1] (🐖) pig
|
||||
| 0xF0 0x9F 0x90 0x97..0xA9 #E0.6 [19] (🐗..🐩) boar..poodle
|
||||
| 0xF0 0x9F 0x90 0xAA #E1.0 [1] (🐪) camel
|
||||
| 0xF0 0x9F 0x90 0xAB..0xBE #E0.6 [20] (🐫..🐾) two-hump camel..paw...
|
||||
| 0xF0 0x9F 0x90 0xBF #E0.7 [1] (🐿️) chipmunk
|
||||
| 0xF0 0x9F 0x91 0x80 #E0.6 [1] (👀) eyes
|
||||
| 0xF0 0x9F 0x91 0x81 #E0.7 [1] (👁️) eye
|
||||
| 0xF0 0x9F 0x91 0x82..0xA4 #E0.6 [35] (👂..👤) ear..bust in silhou...
|
||||
| 0xF0 0x9F 0x91 0xA5 #E1.0 [1] (👥) busts in silhouette
|
||||
| 0xF0 0x9F 0x91 0xA6..0xAB #E0.6 [6] (👦..👫) boy..woman and man ...
|
||||
| 0xF0 0x9F 0x91 0xAC..0xAD #E1.0 [2] (👬..👭) men holding hands.....
|
||||
| 0xF0 0x9F 0x91 0xAE..0xFF #E0.6 [63] (👮..💬) police officer..spe...
|
||||
| 0xF0 0x9F 0x92 0x00..0xAC #
|
||||
| 0xF0 0x9F 0x92 0xAD #E1.0 [1] (💭) thought balloon
|
||||
| 0xF0 0x9F 0x92 0xAE..0xB5 #E0.6 [8] (💮..💵) white flower..dolla...
|
||||
| 0xF0 0x9F 0x92 0xB6..0xB7 #E1.0 [2] (💶..💷) euro banknote..poun...
|
||||
| 0xF0 0x9F 0x92 0xB8..0xFF #E0.6 [52] (💸..📫) money with wings..c...
|
||||
| 0xF0 0x9F 0x93 0x00..0xAB #
|
||||
| 0xF0 0x9F 0x93 0xAC..0xAD #E0.7 [2] (📬..📭) open mailbox with r...
|
||||
| 0xF0 0x9F 0x93 0xAE #E0.6 [1] (📮) postbox
|
||||
| 0xF0 0x9F 0x93 0xAF #E1.0 [1] (📯) postal horn
|
||||
| 0xF0 0x9F 0x93 0xB0..0xB4 #E0.6 [5] (📰..📴) newspaper..mobile p...
|
||||
| 0xF0 0x9F 0x93 0xB5 #E1.0 [1] (📵) no mobile phones
|
||||
| 0xF0 0x9F 0x93 0xB6..0xB7 #E0.6 [2] (📶..📷) antenna bars..camera
|
||||
| 0xF0 0x9F 0x93 0xB8 #E1.0 [1] (📸) camera with flash
|
||||
| 0xF0 0x9F 0x93 0xB9..0xBC #E0.6 [4] (📹..📼) video camera..video...
|
||||
| 0xF0 0x9F 0x93 0xBD #E0.7 [1] (📽️) film projector
|
||||
| 0xF0 0x9F 0x93 0xBE #E0.0 [1] (📾) PORTABLE STEREO
|
||||
| 0xF0 0x9F 0x93 0xBF..0xFF #E1.0 [4] (📿..🔂) prayer beads..repea...
|
||||
| 0xF0 0x9F 0x94 0x00..0x82 #
|
||||
| 0xF0 0x9F 0x94 0x83 #E0.6 [1] (🔃) clockwise vertical arrows
|
||||
| 0xF0 0x9F 0x94 0x84..0x87 #E1.0 [4] (🔄..🔇) counterclockwise ar...
|
||||
| 0xF0 0x9F 0x94 0x88 #E0.7 [1] (🔈) speaker low volume
|
||||
| 0xF0 0x9F 0x94 0x89 #E1.0 [1] (🔉) speaker medium volume
|
||||
| 0xF0 0x9F 0x94 0x8A..0x94 #E0.6 [11] (🔊..🔔) speaker high volume...
|
||||
| 0xF0 0x9F 0x94 0x95 #E1.0 [1] (🔕) bell with slash
|
||||
| 0xF0 0x9F 0x94 0x96..0xAB #E0.6 [22] (🔖..🔫) bookmark..pistol
|
||||
| 0xF0 0x9F 0x94 0xAC..0xAD #E1.0 [2] (🔬..🔭) microscope..telescope
|
||||
| 0xF0 0x9F 0x94 0xAE..0xBD #E0.6 [16] (🔮..🔽) crystal ball..downw...
|
||||
| 0xF0 0x9F 0x95 0x86..0x88 #E0.0 [3] (🕆..🕈) WHITE LATIN CROSS.....
|
||||
| 0xF0 0x9F 0x95 0x89..0x8A #E0.7 [2] (🕉️..🕊️) om..dove
|
||||
| 0xF0 0x9F 0x95 0x8B..0x8E #E1.0 [4] (🕋..🕎) kaaba..menorah
|
||||
| 0xF0 0x9F 0x95 0x8F #E0.0 [1] (🕏) BOWL OF HYGIEIA
|
||||
| 0xF0 0x9F 0x95 0x90..0x9B #E0.6 [12] (🕐..🕛) one o’clock..twelve...
|
||||
| 0xF0 0x9F 0x95 0x9C..0xA7 #E0.7 [12] (🕜..🕧) one-thirty..twelve-...
|
||||
| 0xF0 0x9F 0x95 0xA8..0xAE #E0.0 [7] (🕨..🕮) RIGHT SPEAKER..BOOK
|
||||
| 0xF0 0x9F 0x95 0xAF..0xB0 #E0.7 [2] (🕯️..🕰️) candle..mantelpie...
|
||||
| 0xF0 0x9F 0x95 0xB1..0xB2 #E0.0 [2] (🕱..🕲) BLACK SKULL AND CRO...
|
||||
| 0xF0 0x9F 0x95 0xB3..0xB9 #E0.7 [7] (🕳️..🕹️) hole..joystick
|
||||
| 0xF0 0x9F 0x95 0xBA #E3.0 [1] (🕺) man dancing
|
||||
| 0xF0 0x9F 0x95 0xBB..0xFF #E0.0 [12] (🕻..🖆) LEFT HAND TELEPHONE...
|
||||
| 0xF0 0x9F 0x96 0x00..0x86 #
|
||||
| 0xF0 0x9F 0x96 0x87 #E0.7 [1] (🖇️) linked paperclips
|
||||
| 0xF0 0x9F 0x96 0x88..0x89 #E0.0 [2] (🖈..🖉) BLACK PUSHPIN..LOWE...
|
||||
| 0xF0 0x9F 0x96 0x8A..0x8D #E0.7 [4] (🖊️..🖍️) pen..crayon
|
||||
| 0xF0 0x9F 0x96 0x8E..0x8F #E0.0 [2] (🖎..🖏) LEFT WRITING HAND.....
|
||||
| 0xF0 0x9F 0x96 0x90 #E0.7 [1] (🖐️) hand with fingers spl...
|
||||
| 0xF0 0x9F 0x96 0x91..0x94 #E0.0 [4] (🖑..🖔) REVERSED RAISED HAN...
|
||||
| 0xF0 0x9F 0x96 0x95..0x96 #E1.0 [2] (🖕..🖖) middle finger..vulc...
|
||||
| 0xF0 0x9F 0x96 0x97..0xA3 #E0.0 [13] (🖗..🖣) WHITE DOWN POINTING...
|
||||
| 0xF0 0x9F 0x96 0xA4 #E3.0 [1] (🖤) black heart
|
||||
| 0xF0 0x9F 0x96 0xA5 #E0.7 [1] (🖥️) desktop computer
|
||||
| 0xF0 0x9F 0x96 0xA6..0xA7 #E0.0 [2] (🖦..🖧) KEYBOARD AND MOUSE....
|
||||
| 0xF0 0x9F 0x96 0xA8 #E0.7 [1] (🖨️) printer
|
||||
| 0xF0 0x9F 0x96 0xA9..0xB0 #E0.0 [8] (🖩..🖰) POCKET CALCULATOR.....
|
||||
| 0xF0 0x9F 0x96 0xB1..0xB2 #E0.7 [2] (🖱️..🖲️) computer mouse..t...
|
||||
| 0xF0 0x9F 0x96 0xB3..0xBB #E0.0 [9] (🖳..🖻) OLD PERSONAL COMPUT...
|
||||
| 0xF0 0x9F 0x96 0xBC #E0.7 [1] (🖼️) framed picture
|
||||
| 0xF0 0x9F 0x96 0xBD..0xFF #E0.0 [5] (🖽..🗁) FRAME WITH TILES..O...
|
||||
| 0xF0 0x9F 0x97 0x00..0x81 #
|
||||
| 0xF0 0x9F 0x97 0x82..0x84 #E0.7 [3] (🗂️..🗄️) card index divide...
|
||||
| 0xF0 0x9F 0x97 0x85..0x90 #E0.0 [12] (🗅..🗐) EMPTY NOTE..PAGES
|
||||
| 0xF0 0x9F 0x97 0x91..0x93 #E0.7 [3] (🗑️..🗓️) wastebasket..spir...
|
||||
| 0xF0 0x9F 0x97 0x94..0x9B #E0.0 [8] (🗔..🗛) DESKTOP WINDOW..DEC...
|
||||
| 0xF0 0x9F 0x97 0x9C..0x9E #E0.7 [3] (🗜️..🗞️) clamp..rolled-up ...
|
||||
| 0xF0 0x9F 0x97 0x9F..0xA0 #E0.0 [2] (🗟..🗠) PAGE WITH CIRCLED T...
|
||||
| 0xF0 0x9F 0x97 0xA1 #E0.7 [1] (🗡️) dagger
|
||||
| 0xF0 0x9F 0x97 0xA2 #E0.0 [1] (🗢) LIPS
|
||||
| 0xF0 0x9F 0x97 0xA3 #E0.7 [1] (🗣️) speaking head
|
||||
| 0xF0 0x9F 0x97 0xA4..0xA7 #E0.0 [4] (🗤..🗧) THREE RAYS ABOVE..T...
|
||||
| 0xF0 0x9F 0x97 0xA8 #E2.0 [1] (🗨️) left speech bubble
|
||||
| 0xF0 0x9F 0x97 0xA9..0xAE #E0.0 [6] (🗩..🗮) RIGHT SPEECH BUBBLE...
|
||||
| 0xF0 0x9F 0x97 0xAF #E0.7 [1] (🗯️) right anger bubble
|
||||
| 0xF0 0x9F 0x97 0xB0..0xB2 #E0.0 [3] (🗰..🗲) MOOD BUBBLE..LIGHTN...
|
||||
| 0xF0 0x9F 0x97 0xB3 #E0.7 [1] (🗳️) ballot box with ballot
|
||||
| 0xF0 0x9F 0x97 0xB4..0xB9 #E0.0 [6] (🗴..🗹) BALLOT SCRIPT X..BA...
|
||||
| 0xF0 0x9F 0x97 0xBA #E0.7 [1] (🗺️) world map
|
||||
| 0xF0 0x9F 0x97 0xBB..0xBF #E0.6 [5] (🗻..🗿) mount fuji..moai
|
||||
| 0xF0 0x9F 0x98 0x80 #E1.0 [1] (😀) grinning face
|
||||
| 0xF0 0x9F 0x98 0x81..0x86 #E0.6 [6] (😁..😆) beaming face with s...
|
||||
| 0xF0 0x9F 0x98 0x87..0x88 #E1.0 [2] (😇..😈) smiling face with h...
|
||||
| 0xF0 0x9F 0x98 0x89..0x8D #E0.6 [5] (😉..😍) winking face..smili...
|
||||
| 0xF0 0x9F 0x98 0x8E #E1.0 [1] (😎) smiling face with sung...
|
||||
| 0xF0 0x9F 0x98 0x8F #E0.6 [1] (😏) smirking face
|
||||
| 0xF0 0x9F 0x98 0x90 #E0.7 [1] (😐) neutral face
|
||||
| 0xF0 0x9F 0x98 0x91 #E1.0 [1] (😑) expressionless face
|
||||
| 0xF0 0x9F 0x98 0x92..0x94 #E0.6 [3] (😒..😔) unamused face..pens...
|
||||
| 0xF0 0x9F 0x98 0x95 #E1.0 [1] (😕) confused face
|
||||
| 0xF0 0x9F 0x98 0x96 #E0.6 [1] (😖) confounded face
|
||||
| 0xF0 0x9F 0x98 0x97 #E1.0 [1] (😗) kissing face
|
||||
| 0xF0 0x9F 0x98 0x98 #E0.6 [1] (😘) face blowing a kiss
|
||||
| 0xF0 0x9F 0x98 0x99 #E1.0 [1] (😙) kissing face with smil...
|
||||
| 0xF0 0x9F 0x98 0x9A #E0.6 [1] (😚) kissing face with clos...
|
||||
| 0xF0 0x9F 0x98 0x9B #E1.0 [1] (😛) face with tongue
|
||||
| 0xF0 0x9F 0x98 0x9C..0x9E #E0.6 [3] (😜..😞) winking face with t...
|
||||
| 0xF0 0x9F 0x98 0x9F #E1.0 [1] (😟) worried face
|
||||
| 0xF0 0x9F 0x98 0xA0..0xA5 #E0.6 [6] (😠..😥) angry face..sad but...
|
||||
| 0xF0 0x9F 0x98 0xA6..0xA7 #E1.0 [2] (😦..😧) frowning face with ...
|
||||
| 0xF0 0x9F 0x98 0xA8..0xAB #E0.6 [4] (😨..😫) fearful face..tired...
|
||||
| 0xF0 0x9F 0x98 0xAC #E1.0 [1] (😬) grimacing face
|
||||
| 0xF0 0x9F 0x98 0xAD #E0.6 [1] (😭) loudly crying face
|
||||
| 0xF0 0x9F 0x98 0xAE..0xAF #E1.0 [2] (😮..😯) face with open mout...
|
||||
| 0xF0 0x9F 0x98 0xB0..0xB3 #E0.6 [4] (😰..😳) anxious face with s...
|
||||
| 0xF0 0x9F 0x98 0xB4 #E1.0 [1] (😴) sleeping face
|
||||
| 0xF0 0x9F 0x98 0xB5 #E0.6 [1] (😵) dizzy face
|
||||
| 0xF0 0x9F 0x98 0xB6 #E1.0 [1] (😶) face without mouth
|
||||
| 0xF0 0x9F 0x98 0xB7..0xFF #E0.6 [10] (😷..🙀) face with medical m...
|
||||
| 0xF0 0x9F 0x99 0x00..0x80 #
|
||||
| 0xF0 0x9F 0x99 0x81..0x84 #E1.0 [4] (🙁..🙄) slightly frowning f...
|
||||
| 0xF0 0x9F 0x99 0x85..0x8F #E0.6 [11] (🙅..🙏) person gesturing NO...
|
||||
| 0xF0 0x9F 0x9A 0x80 #E0.6 [1] (🚀) rocket
|
||||
| 0xF0 0x9F 0x9A 0x81..0x82 #E1.0 [2] (🚁..🚂) helicopter..locomotive
|
||||
| 0xF0 0x9F 0x9A 0x83..0x85 #E0.6 [3] (🚃..🚅) railway car..bullet...
|
||||
| 0xF0 0x9F 0x9A 0x86 #E1.0 [1] (🚆) train
|
||||
| 0xF0 0x9F 0x9A 0x87 #E0.6 [1] (🚇) metro
|
||||
| 0xF0 0x9F 0x9A 0x88 #E1.0 [1] (🚈) light rail
|
||||
| 0xF0 0x9F 0x9A 0x89 #E0.6 [1] (🚉) station
|
||||
| 0xF0 0x9F 0x9A 0x8A..0x8B #E1.0 [2] (🚊..🚋) tram..tram car
|
||||
| 0xF0 0x9F 0x9A 0x8C #E0.6 [1] (🚌) bus
|
||||
| 0xF0 0x9F 0x9A 0x8D #E0.7 [1] (🚍) oncoming bus
|
||||
| 0xF0 0x9F 0x9A 0x8E #E1.0 [1] (🚎) trolleybus
|
||||
| 0xF0 0x9F 0x9A 0x8F #E0.6 [1] (🚏) bus stop
|
||||
| 0xF0 0x9F 0x9A 0x90 #E1.0 [1] (🚐) minibus
|
||||
| 0xF0 0x9F 0x9A 0x91..0x93 #E0.6 [3] (🚑..🚓) ambulance..police car
|
||||
| 0xF0 0x9F 0x9A 0x94 #E0.7 [1] (🚔) oncoming police car
|
||||
| 0xF0 0x9F 0x9A 0x95 #E0.6 [1] (🚕) taxi
|
||||
| 0xF0 0x9F 0x9A 0x96 #E1.0 [1] (🚖) oncoming taxi
|
||||
| 0xF0 0x9F 0x9A 0x97 #E0.6 [1] (🚗) automobile
|
||||
| 0xF0 0x9F 0x9A 0x98 #E0.7 [1] (🚘) oncoming automobile
|
||||
| 0xF0 0x9F 0x9A 0x99..0x9A #E0.6 [2] (🚙..🚚) sport utility vehic...
|
||||
| 0xF0 0x9F 0x9A 0x9B..0xA1 #E1.0 [7] (🚛..🚡) articulated lorry.....
|
||||
| 0xF0 0x9F 0x9A 0xA2 #E0.6 [1] (🚢) ship
|
||||
| 0xF0 0x9F 0x9A 0xA3 #E1.0 [1] (🚣) person rowing boat
|
||||
| 0xF0 0x9F 0x9A 0xA4..0xA5 #E0.6 [2] (🚤..🚥) speedboat..horizont...
|
||||
| 0xF0 0x9F 0x9A 0xA6 #E1.0 [1] (🚦) vertical traffic light
|
||||
| 0xF0 0x9F 0x9A 0xA7..0xAD #E0.6 [7] (🚧..🚭) construction..no sm...
|
||||
| 0xF0 0x9F 0x9A 0xAE..0xB1 #E1.0 [4] (🚮..🚱) litter in bin sign....
|
||||
| 0xF0 0x9F 0x9A 0xB2 #E0.6 [1] (🚲) bicycle
|
||||
| 0xF0 0x9F 0x9A 0xB3..0xB5 #E1.0 [3] (🚳..🚵) no bicycles..person...
|
||||
| 0xF0 0x9F 0x9A 0xB6 #E0.6 [1] (🚶) person walking
|
||||
| 0xF0 0x9F 0x9A 0xB7..0xB8 #E1.0 [2] (🚷..🚸) no pedestrians..chi...
|
||||
| 0xF0 0x9F 0x9A 0xB9..0xBE #E0.6 [6] (🚹..🚾) men’s room..water c...
|
||||
| 0xF0 0x9F 0x9A 0xBF #E1.0 [1] (🚿) shower
|
||||
| 0xF0 0x9F 0x9B 0x80 #E0.6 [1] (🛀) person taking bath
|
||||
| 0xF0 0x9F 0x9B 0x81..0x85 #E1.0 [5] (🛁..🛅) bathtub..left luggage
|
||||
| 0xF0 0x9F 0x9B 0x86..0x8A #E0.0 [5] (🛆..🛊) TRIANGLE WITH ROUND...
|
||||
| 0xF0 0x9F 0x9B 0x8B #E0.7 [1] (🛋️) couch and lamp
|
||||
| 0xF0 0x9F 0x9B 0x8C #E1.0 [1] (🛌) person in bed
|
||||
| 0xF0 0x9F 0x9B 0x8D..0x8F #E0.7 [3] (🛍️..🛏️) shopping bags..bed
|
||||
| 0xF0 0x9F 0x9B 0x90 #E1.0 [1] (🛐) place of worship
|
||||
| 0xF0 0x9F 0x9B 0x91..0x92 #E3.0 [2] (🛑..🛒) stop sign..shopping...
|
||||
| 0xF0 0x9F 0x9B 0x93..0x94 #E0.0 [2] (🛓..🛔) STUPA..PAGODA
|
||||
| 0xF0 0x9F 0x9B 0x95 #E12.0 [1] (🛕) hindu temple
|
||||
| 0xF0 0x9F 0x9B 0x96..0x97 #E13.0 [2] (🛖..🛗) hut..elevator
|
||||
| 0xF0 0x9F 0x9B 0x98..0x9F #E0.0 [8] (..🛟) <reserved-1F6D8>..<...
|
||||
| 0xF0 0x9F 0x9B 0xA0..0xA5 #E0.7 [6] (🛠️..🛥️) hammer and wrench...
|
||||
| 0xF0 0x9F 0x9B 0xA6..0xA8 #E0.0 [3] (🛦..🛨) UP-POINTING MILITAR...
|
||||
| 0xF0 0x9F 0x9B 0xA9 #E0.7 [1] (🛩️) small airplane
|
||||
| 0xF0 0x9F 0x9B 0xAA #E0.0 [1] (🛪) NORTHEAST-POINTING AIR...
|
||||
| 0xF0 0x9F 0x9B 0xAB..0xAC #E1.0 [2] (🛫..🛬) airplane departure....
|
||||
| 0xF0 0x9F 0x9B 0xAD..0xAF #E0.0 [3] (..) <reserved-1F6ED>..<...
|
||||
| 0xF0 0x9F 0x9B 0xB0 #E0.7 [1] (🛰️) satellite
|
||||
| 0xF0 0x9F 0x9B 0xB1..0xB2 #E0.0 [2] (🛱..🛲) ONCOMING FIRE ENGIN...
|
||||
| 0xF0 0x9F 0x9B 0xB3 #E0.7 [1] (🛳️) passenger ship
|
||||
| 0xF0 0x9F 0x9B 0xB4..0xB6 #E3.0 [3] (🛴..🛶) kick scooter..canoe
|
||||
| 0xF0 0x9F 0x9B 0xB7..0xB8 #E5.0 [2] (🛷..🛸) sled..flying saucer
|
||||
| 0xF0 0x9F 0x9B 0xB9 #E11.0 [1] (🛹) skateboard
|
||||
| 0xF0 0x9F 0x9B 0xBA #E12.0 [1] (🛺) auto rickshaw
|
||||
| 0xF0 0x9F 0x9B 0xBB..0xBC #E13.0 [2] (🛻..🛼) pickup truck..rolle...
|
||||
| 0xF0 0x9F 0x9B 0xBD..0xBF #E0.0 [3] (..) <reserved-1F6FD>..<...
|
||||
| 0xF0 0x9F 0x9D 0xB4..0xBF #E0.0 [12] (🝴..🝿) <reserved-1F774>..<...
|
||||
| 0xF0 0x9F 0x9F 0x95..0x9F #E0.0 [11] (🟕..) CIRCLED TRIANGLE..<...
|
||||
| 0xF0 0x9F 0x9F 0xA0..0xAB #E12.0 [12] (🟠..🟫) orange circle..brow...
|
||||
| 0xF0 0x9F 0x9F 0xAC..0xBF #E0.0 [20] (..) <reserved-1F7EC>..<...
|
||||
| 0xF0 0x9F 0xA0 0x8C..0x8F #E0.0 [4] (..) <reserved-1F80C>..<...
|
||||
| 0xF0 0x9F 0xA1 0x88..0x8F #E0.0 [8] (..) <reserved-1F848>..<...
|
||||
| 0xF0 0x9F 0xA1 0x9A..0x9F #E0.0 [6] (..) <reserved-1F85A>..<...
|
||||
| 0xF0 0x9F 0xA2 0x88..0x8F #E0.0 [8] (..) <reserved-1F888>..<...
|
||||
| 0xF0 0x9F 0xA2 0xAE..0xFF #E0.0 [82] (..) <reserved-1F8AE>..<...
|
||||
| 0xF0 0x9F 0xA3 0x00..0xBF #
|
||||
| 0xF0 0x9F 0xA4 0x8C #E13.0 [1] (🤌) pinched fingers
|
||||
| 0xF0 0x9F 0xA4 0x8D..0x8F #E12.0 [3] (🤍..🤏) white heart..pinchi...
|
||||
| 0xF0 0x9F 0xA4 0x90..0x98 #E1.0 [9] (🤐..🤘) zipper-mouth face.....
|
||||
| 0xF0 0x9F 0xA4 0x99..0x9E #E3.0 [6] (🤙..🤞) call me hand..cross...
|
||||
| 0xF0 0x9F 0xA4 0x9F #E5.0 [1] (🤟) love-you gesture
|
||||
| 0xF0 0x9F 0xA4 0xA0..0xA7 #E3.0 [8] (🤠..🤧) cowboy hat face..sn...
|
||||
| 0xF0 0x9F 0xA4 0xA8..0xAF #E5.0 [8] (🤨..🤯) face with raised ey...
|
||||
| 0xF0 0x9F 0xA4 0xB0 #E3.0 [1] (🤰) pregnant woman
|
||||
| 0xF0 0x9F 0xA4 0xB1..0xB2 #E5.0 [2] (🤱..🤲) breast-feeding..pal...
|
||||
| 0xF0 0x9F 0xA4 0xB3..0xBA #E3.0 [8] (🤳..🤺) selfie..person fencing
|
||||
| 0xF0 0x9F 0xA4 0xBC..0xBE #E3.0 [3] (🤼..🤾) people wrestling..p...
|
||||
| 0xF0 0x9F 0xA4 0xBF #E12.0 [1] (🤿) diving mask
|
||||
| 0xF0 0x9F 0xA5 0x80..0x85 #E3.0 [6] (🥀..🥅) wilted flower..goal...
|
||||
| 0xF0 0x9F 0xA5 0x87..0x8B #E3.0 [5] (🥇..🥋) 1st place medal..ma...
|
||||
| 0xF0 0x9F 0xA5 0x8C #E5.0 [1] (🥌) curling stone
|
||||
| 0xF0 0x9F 0xA5 0x8D..0x8F #E11.0 [3] (🥍..🥏) lacrosse..flying disc
|
||||
| 0xF0 0x9F 0xA5 0x90..0x9E #E3.0 [15] (🥐..🥞) croissant..pancakes
|
||||
| 0xF0 0x9F 0xA5 0x9F..0xAB #E5.0 [13] (🥟..🥫) dumpling..canned food
|
||||
| 0xF0 0x9F 0xA5 0xAC..0xB0 #E11.0 [5] (🥬..🥰) leafy green..smilin...
|
||||
| 0xF0 0x9F 0xA5 0xB1 #E12.0 [1] (🥱) yawning face
|
||||
| 0xF0 0x9F 0xA5 0xB2 #E13.0 [1] (🥲) smiling face with tear
|
||||
| 0xF0 0x9F 0xA5 0xB3..0xB6 #E11.0 [4] (🥳..🥶) partying face..cold...
|
||||
| 0xF0 0x9F 0xA5 0xB7..0xB8 #E13.0 [2] (🥷..🥸) ninja..disguised face
|
||||
| 0xF0 0x9F 0xA5 0xB9 #E0.0 [1] (🥹) <reserved-1F979>
|
||||
| 0xF0 0x9F 0xA5 0xBA #E11.0 [1] (🥺) pleading face
|
||||
| 0xF0 0x9F 0xA5 0xBB #E12.0 [1] (🥻) sari
|
||||
| 0xF0 0x9F 0xA5 0xBC..0xBF #E11.0 [4] (🥼..🥿) lab coat..flat shoe
|
||||
| 0xF0 0x9F 0xA6 0x80..0x84 #E1.0 [5] (🦀..🦄) crab..unicorn
|
||||
| 0xF0 0x9F 0xA6 0x85..0x91 #E3.0 [13] (🦅..🦑) eagle..squid
|
||||
| 0xF0 0x9F 0xA6 0x92..0x97 #E5.0 [6] (🦒..🦗) giraffe..cricket
|
||||
| 0xF0 0x9F 0xA6 0x98..0xA2 #E11.0 [11] (🦘..🦢) kangaroo..swan
|
||||
| 0xF0 0x9F 0xA6 0xA3..0xA4 #E13.0 [2] (🦣..🦤) mammoth..dodo
|
||||
| 0xF0 0x9F 0xA6 0xA5..0xAA #E12.0 [6] (🦥..🦪) sloth..oyster
|
||||
| 0xF0 0x9F 0xA6 0xAB..0xAD #E13.0 [3] (🦫..🦭) beaver..seal
|
||||
| 0xF0 0x9F 0xA6 0xAE..0xAF #E12.0 [2] (🦮..🦯) guide dog..white cane
|
||||
| 0xF0 0x9F 0xA6 0xB0..0xB9 #E11.0 [10] (🦰..🦹) red hair..supervillain
|
||||
| 0xF0 0x9F 0xA6 0xBA..0xBF #E12.0 [6] (🦺..🦿) safety vest..mechan...
|
||||
| 0xF0 0x9F 0xA7 0x80 #E1.0 [1] (🧀) cheese wedge
|
||||
| 0xF0 0x9F 0xA7 0x81..0x82 #E11.0 [2] (🧁..🧂) cupcake..salt
|
||||
| 0xF0 0x9F 0xA7 0x83..0x8A #E12.0 [8] (🧃..🧊) beverage box..ice
|
||||
| 0xF0 0x9F 0xA7 0x8B #E13.0 [1] (🧋) bubble tea
|
||||
| 0xF0 0x9F 0xA7 0x8C #E0.0 [1] (🧌) <reserved-1F9CC>
|
||||
| 0xF0 0x9F 0xA7 0x8D..0x8F #E12.0 [3] (🧍..🧏) person standing..de...
|
||||
| 0xF0 0x9F 0xA7 0x90..0xA6 #E5.0 [23] (🧐..🧦) face with monocle.....
|
||||
| 0xF0 0x9F 0xA7 0xA7..0xBF #E11.0 [25] (🧧..🧿) red envelope..nazar...
|
||||
| 0xF0 0x9F 0xA8 0x80..0xFF #E0.0 [112] (🨀..) NEUTRAL CHESS KING....
|
||||
| 0xF0 0x9F 0xA9 0x00..0xAF #
|
||||
| 0xF0 0x9F 0xA9 0xB0..0xB3 #E12.0 [4] (🩰..🩳) ballet shoes..shorts
|
||||
| 0xF0 0x9F 0xA9 0xB4 #E13.0 [1] (🩴) thong sandal
|
||||
| 0xF0 0x9F 0xA9 0xB5..0xB7 #E0.0 [3] (🩵..🩷) <reserved-1FA75>..<...
|
||||
| 0xF0 0x9F 0xA9 0xB8..0xBA #E12.0 [3] (🩸..🩺) drop of blood..stet...
|
||||
| 0xF0 0x9F 0xA9 0xBB..0xBF #E0.0 [5] (🩻..) <reserved-1FA7B>..<...
|
||||
| 0xF0 0x9F 0xAA 0x80..0x82 #E12.0 [3] (🪀..🪂) yo-yo..parachute
|
||||
| 0xF0 0x9F 0xAA 0x83..0x86 #E13.0 [4] (🪃..🪆) boomerang..nesting ...
|
||||
| 0xF0 0x9F 0xAA 0x87..0x8F #E0.0 [9] (🪇..) <reserved-1FA87>..<...
|
||||
| 0xF0 0x9F 0xAA 0x90..0x95 #E12.0 [6] (🪐..🪕) ringed planet..banjo
|
||||
| 0xF0 0x9F 0xAA 0x96..0xA8 #E13.0 [19] (🪖..🪨) military helmet..rock
|
||||
| 0xF0 0x9F 0xAA 0xA9..0xAF #E0.0 [7] (🪩..🪯) <reserved-1FAA9>..<...
|
||||
| 0xF0 0x9F 0xAA 0xB0..0xB6 #E13.0 [7] (🪰..🪶) fly..feather
|
||||
| 0xF0 0x9F 0xAA 0xB7..0xBF #E0.0 [9] (🪷..🪿) <reserved-1FAB7>..<...
|
||||
| 0xF0 0x9F 0xAB 0x80..0x82 #E13.0 [3] (🫀..🫂) anatomical heart..p...
|
||||
| 0xF0 0x9F 0xAB 0x83..0x8F #E0.0 [13] (🫃..🫏) <reserved-1FAC3>..<...
|
||||
| 0xF0 0x9F 0xAB 0x90..0x96 #E13.0 [7] (🫐..🫖) blueberries..teapot
|
||||
| 0xF0 0x9F 0xAB 0x97..0xBF #E0.0 [41] (🫗..) <reserved-1FAD7>..<...
|
||||
| 0xF0 0x9F 0xB0 0x80..0xFF #E0.0[1022] (..) <reserved-1FC...
|
||||
| 0xF0 0x9F 0xB1..0xBE 0x00..0xFF #
|
||||
| 0xF0 0x9F 0xBF 0x00..0xBD #
|
||||
;
|
||||
|
||||
}%%
|
|
@ -2,7 +2,7 @@ package textseg
|
|||
|
||||
//go:generate go run make_tables.go -output tables.go
|
||||
//go:generate go run make_test_tables.go -output tables_test.go
|
||||
//go:generate ruby unicode2ragel.rb --url=https://www.unicode.org/Public/12.0.0/ucd/auxiliary/GraphemeBreakProperty.txt -m GraphemeCluster -p "Prepend,CR,LF,Control,Extend,Regional_Indicator,SpacingMark,L,V,T,LV,LVT,ZWJ" -o grapheme_clusters_table.rl
|
||||
//go:generate ruby unicode2ragel.rb --url=https://www.unicode.org/Public/emoji/12.0/emoji-data.txt -m Emoji -p "Extended_Pictographic" -o emoji_table.rl
|
||||
//go:generate ruby unicode2ragel.rb --url=https://www.unicode.org/Public/13.0.0/ucd/auxiliary/GraphemeBreakProperty.txt -m GraphemeCluster -p "Prepend,CR,LF,Control,Extend,Regional_Indicator,SpacingMark,L,V,T,LV,LVT,ZWJ" -o grapheme_clusters_table.rl
|
||||
//go:generate ruby unicode2ragel.rb --url=https://www.unicode.org/Public/13.0.0/ucd/emoji/emoji-data.txt -m Emoji -p "Extended_Pictographic" -o emoji_table.rl
|
||||
//go:generate ragel -Z grapheme_clusters.rl
|
||||
//go:generate gofmt -w grapheme_clusters.go
|
4138
vendor/github.com/apparentlymart/go-textseg/v13/textseg/grapheme_clusters.go
generated
vendored
Normal file
4138
vendor/github.com/apparentlymart/go-textseg/v13/textseg/grapheme_clusters.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
|
@ -1,5 +1,5 @@
|
|||
# The following Ragel file was autogenerated with unicode2ragel.rb
|
||||
# from: https://www.unicode.org/Public/12.0.0/ucd/auxiliary/GraphemeBreakProperty.txt
|
||||
# from: https://www.unicode.org/Public/13.0.0/ucd/auxiliary/GraphemeBreakProperty.txt
|
||||
#
|
||||
# It defines ["Prepend", "CR", "LF", "Control", "Extend", "Regional_Indicator", "SpacingMark", "L", "V", "T", "LV", "LVT", "ZWJ"].
|
||||
#
|
||||
|
@ -18,6 +18,8 @@
|
|||
| 0xF0 0x91 0x82 0xBD #Cf KAITHI NUMBER SIGN
|
||||
| 0xF0 0x91 0x83 0x8D #Cf KAITHI NUMBER SIGN ABOVE
|
||||
| 0xF0 0x91 0x87 0x82..0x83 #Lo [2] SHARADA SIGN JIHVAMULIYA..SHARA...
|
||||
| 0xF0 0x91 0xA4 0xBF #Lo DIVES AKURU PREFIXED NASAL SIGN
|
||||
| 0xF0 0x91 0xA5 0x81 #Lo DIVES AKURU INITIAL RA
|
||||
| 0xF0 0x91 0xA8 0xBA #Lo ZANABAZAR SQUARE CLUSTER-INITIAL L...
|
||||
| 0xF0 0x91 0xAA 0x84..0x89 #Lo [6] SOYOMBO SIGN JIHVAMULIYA..SOYOM...
|
||||
| 0xF0 0x91 0xB5 0x86 #Lo MASARAM GONDI REPHA
|
||||
|
@ -130,7 +132,7 @@
|
|||
| 0xE0 0xAC 0xBF #Mn ORIYA VOWEL SIGN I
|
||||
| 0xE0 0xAD 0x81..0x84 #Mn [4] ORIYA VOWEL SIGN U..ORIYA VOWEL SI...
|
||||
| 0xE0 0xAD 0x8D #Mn ORIYA SIGN VIRAMA
|
||||
| 0xE0 0xAD 0x96 #Mn ORIYA AI LENGTH MARK
|
||||
| 0xE0 0xAD 0x95..0x96 #Mn [2] ORIYA SIGN OVERLINE..ORIYA AI LENG...
|
||||
| 0xE0 0xAD 0x97 #Mc ORIYA AU LENGTH MARK
|
||||
| 0xE0 0xAD 0xA2..0xA3 #Mn [2] ORIYA VOWEL SIGN VOCALIC L..ORIYA ...
|
||||
| 0xE0 0xAE 0x82 #Mn TAMIL SIGN ANUSVARA
|
||||
|
@ -161,6 +163,7 @@
|
|||
| 0xE0 0xB5 0x8D #Mn MALAYALAM SIGN VIRAMA
|
||||
| 0xE0 0xB5 0x97 #Mc MALAYALAM AU LENGTH MARK
|
||||
| 0xE0 0xB5 0xA2..0xA3 #Mn [2] MALAYALAM VOWEL SIGN VOCALIC L..MA...
|
||||
| 0xE0 0xB6 0x81 #Mn SINHALA SIGN CANDRABINDU
|
||||
| 0xE0 0xB7 0x8A #Mn SINHALA SIGN AL-LAKUNA
|
||||
| 0xE0 0xB7 0x8F #Mc SINHALA VOWEL SIGN AELA-PILLA
|
||||
| 0xE0 0xB7 0x92..0x94 #Mn [3] SINHALA VOWEL SIGN KETTI IS-PILLA....
|
||||
|
@ -221,6 +224,8 @@
|
|||
| 0xE1 0xA9 0xBF #Mn TAI THAM COMBINING CRYPTOGRAMMIC DOT
|
||||
| 0xE1 0xAA 0xB0..0xBD #Mn [14] COMBINING DOUBLED CIRCUMFLEX ACCEN...
|
||||
| 0xE1 0xAA 0xBE #Me COMBINING PARENTHESES OVERLAY
|
||||
| 0xE1 0xAA 0xBF..0xFF #Mn [2] COMBINING LATIN SMALL LETTER W BEL...
|
||||
| 0xE1 0xAB 0x00..0x80 #
|
||||
| 0xE1 0xAC 0x80..0x83 #Mn [4] BALINESE SIGN ULU RICEM..BALINESE ...
|
||||
| 0xE1 0xAC 0xB4 #Mn BALINESE SIGN REREKAN
|
||||
| 0xE1 0xAC 0xB5 #Mc BALINESE VOWEL SIGN TEDUNG
|
||||
|
@ -267,6 +272,7 @@
|
|||
| 0xEA 0xA0 0x86 #Mn SYLOTI NAGRI SIGN HASANTA
|
||||
| 0xEA 0xA0 0x8B #Mn SYLOTI NAGRI SIGN ANUSVARA
|
||||
| 0xEA 0xA0 0xA5..0xA6 #Mn [2] SYLOTI NAGRI VOWEL SIGN U..SYLOTI ...
|
||||
| 0xEA 0xA0 0xAC #Mn SYLOTI NAGRI SIGN ALTERNATE HASANTA
|
||||
| 0xEA 0xA3 0x84..0x85 #Mn [2] SAURASHTRA SIGN VIRAMA..SAURASHTRA...
|
||||
| 0xEA 0xA3 0xA0..0xB1 #Mn [18] COMBINING DEVANAGARI DIGIT ZERO..C...
|
||||
| 0xEA 0xA3 0xBF #Mn DEVANAGARI VOWEL SIGN AY
|
||||
|
@ -307,6 +313,7 @@
|
|||
| 0xF0 0x90 0xA8 0xBF #Mn KHAROSHTHI VIRAMA
|
||||
| 0xF0 0x90 0xAB 0xA5..0xA6 #Mn [2] MANICHAEAN ABBREVIATION MARK AB...
|
||||
| 0xF0 0x90 0xB4 0xA4..0xA7 #Mn [4] HANIFI ROHINGYA SIGN HARBAHAY.....
|
||||
| 0xF0 0x90 0xBA 0xAB..0xAC #Mn [2] YEZIDI COMBINING HAMZA MARK..YE...
|
||||
| 0xF0 0x90 0xBD 0x86..0x90 #Mn [11] SOGDIAN COMBINING DOT BELOW..SO...
|
||||
| 0xF0 0x91 0x80 0x81 #Mn BRAHMI SIGN ANUSVARA
|
||||
| 0xF0 0x91 0x80 0xB8..0xFF #Mn [15] BRAHMI VOWEL SIGN AA..BRAHMI VI...
|
||||
|
@ -322,6 +329,7 @@
|
|||
| 0xF0 0x91 0x86 0x80..0x81 #Mn [2] SHARADA SIGN CANDRABINDU..SHARA...
|
||||
| 0xF0 0x91 0x86 0xB6..0xBE #Mn [9] SHARADA VOWEL SIGN U..SHARADA V...
|
||||
| 0xF0 0x91 0x87 0x89..0x8C #Mn [4] SHARADA SANDHI MARK..SHARADA EX...
|
||||
| 0xF0 0x91 0x87 0x8F #Mn SHARADA SIGN INVERTED CANDRABINDU
|
||||
| 0xF0 0x91 0x88 0xAF..0xB1 #Mn [3] KHOJKI VOWEL SIGN U..KHOJKI VOW...
|
||||
| 0xF0 0x91 0x88 0xB4 #Mn KHOJKI SIGN ANUSVARA
|
||||
| 0xF0 0x91 0x88 0xB6..0xB7 #Mn [2] KHOJKI SIGN NUKTA..KHOJKI SIGN ...
|
||||
|
@ -365,6 +373,10 @@
|
|||
| 0xF0 0x91 0x9C 0xA7..0xAB #Mn [5] AHOM VOWEL SIGN AW..AHOM SIGN K...
|
||||
| 0xF0 0x91 0xA0 0xAF..0xB7 #Mn [9] DOGRA VOWEL SIGN U..DOGRA SIGN ...
|
||||
| 0xF0 0x91 0xA0 0xB9..0xBA #Mn [2] DOGRA SIGN VIRAMA..DOGRA SIGN N...
|
||||
| 0xF0 0x91 0xA4 0xB0 #Mc DIVES AKURU VOWEL SIGN AA
|
||||
| 0xF0 0x91 0xA4 0xBB..0xBC #Mn [2] DIVES AKURU SIGN ANUSVARA..DIVE...
|
||||
| 0xF0 0x91 0xA4 0xBE #Mn DIVES AKURU VIRAMA
|
||||
| 0xF0 0x91 0xA5 0x83 #Mn DIVES AKURU SIGN NUKTA
|
||||
| 0xF0 0x91 0xA7 0x94..0x97 #Mn [4] NANDINAGARI VOWEL SIGN U..NANDI...
|
||||
| 0xF0 0x91 0xA7 0x9A..0x9B #Mn [2] NANDINAGARI VOWEL SIGN E..NANDI...
|
||||
| 0xF0 0x91 0xA7 0xA0 #Mn NANDINAGARI SIGN VIRAMA
|
||||
|
@ -397,6 +409,7 @@
|
|||
| 0xF0 0x96 0xAC 0xB0..0xB6 #Mn [7] PAHAWH HMONG MARK CIM TUB..PAHA...
|
||||
| 0xF0 0x96 0xBD 0x8F #Mn MIAO SIGN CONSONANT MODIFIER BAR
|
||||
| 0xF0 0x96 0xBE 0x8F..0x92 #Mn [4] MIAO TONE RIGHT..MIAO TONE BELOW
|
||||
| 0xF0 0x96 0xBF 0xA4 #Mn KHITAN SMALL SCRIPT FILLER
|
||||
| 0xF0 0x9B 0xB2 0x9D..0x9E #Mn [2] DUPLOYAN THICK LETTER SELECTOR....
|
||||
| 0xF0 0x9D 0x85 0xA5 #Mc MUSICAL SYMBOL COMBINING STEM
|
||||
| 0xF0 0x9D 0x85 0xA7..0xA9 #Mn [3] MUSICAL SYMBOL COMBINING TREMOL...
|
||||
|
@ -548,6 +561,7 @@
|
|||
| 0xF0 0x91 0x86 0xB3..0xB5 #Mc [3] SHARADA VOWEL SIGN AA..SHARADA ...
|
||||
| 0xF0 0x91 0x86 0xBF..0xFF #Mc [2] SHARADA VOWEL SIGN AU..SHARADA ...
|
||||
| 0xF0 0x91 0x87 0x00..0x80 #
|
||||
| 0xF0 0x91 0x87 0x8E #Mc SHARADA VOWEL SIGN PRISHTHAMATRA E
|
||||
| 0xF0 0x91 0x88 0xAC..0xAE #Mc [3] KHOJKI VOWEL SIGN AA..KHOJKI VO...
|
||||
| 0xF0 0x91 0x88 0xB2..0xB3 #Mc [2] KHOJKI VOWEL SIGN O..KHOJKI VOW...
|
||||
| 0xF0 0x91 0x88 0xB5 #Mc KHOJKI SIGN VIRAMA
|
||||
|
@ -579,6 +593,11 @@
|
|||
| 0xF0 0x91 0x9C 0xA6 #Mc AHOM VOWEL SIGN E
|
||||
| 0xF0 0x91 0xA0 0xAC..0xAE #Mc [3] DOGRA VOWEL SIGN AA..DOGRA VOWE...
|
||||
| 0xF0 0x91 0xA0 0xB8 #Mc DOGRA SIGN VISARGA
|
||||
| 0xF0 0x91 0xA4 0xB1..0xB5 #Mc [5] DIVES AKURU VOWEL SIGN I..DIVES...
|
||||
| 0xF0 0x91 0xA4 0xB7..0xB8 #Mc [2] DIVES AKURU VOWEL SIGN AI..DIVE...
|
||||
| 0xF0 0x91 0xA4 0xBD #Mc DIVES AKURU SIGN HALANTA
|
||||
| 0xF0 0x91 0xA5 0x80 #Mc DIVES AKURU MEDIAL YA
|
||||
| 0xF0 0x91 0xA5 0x82 #Mc DIVES AKURU MEDIAL RA
|
||||
| 0xF0 0x91 0xA7 0x91..0x93 #Mc [3] NANDINAGARI VOWEL SIGN AA..NAND...
|
||||
| 0xF0 0x91 0xA7 0x9C..0x9F #Mc [4] NANDINAGARI VOWEL SIGN O..NANDI...
|
||||
| 0xF0 0x91 0xA7 0xA4 #Mc NANDINAGARI VOWEL SIGN PRISHTHAMAT...
|
||||
|
@ -596,6 +615,7 @@
|
|||
| 0xF0 0x91 0xBB 0xB5..0xB6 #Mc [2] MAKASAR VOWEL SIGN E..MAKASAR V...
|
||||
| 0xF0 0x96 0xBD 0x91..0xFF #Mc [55] MIAO SIGN ASPIRATION..MIAO VOWE...
|
||||
| 0xF0 0x96 0xBE 0x00..0x87 #
|
||||
| 0xF0 0x96 0xBF 0xB0..0xB1 #Mc [2] VIETNAMESE ALTERNATE READING MA...
|
||||
| 0xF0 0x9D 0x85 0xA6 #Mc MUSICAL SYMBOL COMBINING SPRECHGES...
|
||||
| 0xF0 0x9D 0x85 0xAD #Mc MUSICAL SYMBOL COMBINING AUGMENTAT...
|
||||
;
|
|
@ -79,7 +79,7 @@ end
|
|||
# range and description.
|
||||
|
||||
def each_alpha( url, property )
|
||||
open( url ) do |file|
|
||||
URI.open( url ) do |file|
|
||||
file.each_line do |line|
|
||||
next if line =~ /^#/;
|
||||
next if line !~ /; #{property} *#/;
|
|
@ -21,6 +21,7 @@ const (
|
|||
ApEast1RegionID = "ap-east-1" // Asia Pacific (Hong Kong).
|
||||
ApNortheast1RegionID = "ap-northeast-1" // Asia Pacific (Tokyo).
|
||||
ApNortheast2RegionID = "ap-northeast-2" // Asia Pacific (Seoul).
|
||||
ApNortheast3RegionID = "ap-northeast-3" // Asia Pacific (Osaka).
|
||||
ApSouth1RegionID = "ap-south-1" // Asia Pacific (Mumbai).
|
||||
ApSoutheast1RegionID = "ap-southeast-1" // Asia Pacific (Singapore).
|
||||
ApSoutheast2RegionID = "ap-southeast-2" // Asia Pacific (Sydney).
|
||||
|
@ -121,6 +122,9 @@ var awsPartition = partition{
|
|||
"ap-northeast-2": region{
|
||||
Description: "Asia Pacific (Seoul)",
|
||||
},
|
||||
"ap-northeast-3": region{
|
||||
Description: "Asia Pacific (Osaka)",
|
||||
},
|
||||
"ap-south-1": region{
|
||||
Description: "Asia Pacific (Mumbai)",
|
||||
},
|
||||
|
@ -184,6 +188,7 @@ var awsPartition = partition{
|
|||
"ap-east-1": endpoint{},
|
||||
"ap-northeast-1": endpoint{},
|
||||
"ap-northeast-2": endpoint{},
|
||||
"ap-northeast-3": endpoint{},
|
||||
"ap-south-1": endpoint{},
|
||||
"ap-southeast-1": endpoint{},
|
||||
"ap-southeast-2": endpoint{},
|
||||
|
@ -239,6 +244,7 @@ var awsPartition = partition{
|
|||
"ap-east-1": endpoint{},
|
||||
"ap-northeast-1": endpoint{},
|
||||
"ap-northeast-2": endpoint{},
|
||||
"ap-northeast-3": endpoint{},
|
||||
"ap-south-1": endpoint{},
|
||||
"ap-southeast-1": endpoint{},
|
||||
"ap-southeast-2": endpoint{},
|
||||
|
@ -361,12 +367,13 @@ var awsPartition = partition{
|
|||
"amplifybackend": service{
|
||||
|
||||
Endpoints: endpoints{
|
||||
"ap-northeast-1": endpoint{},
|
||||
"ap-northeast-2": endpoint{},
|
||||
"ap-south-1": endpoint{},
|
||||
"ap-southeast-1": endpoint{},
|
||||
"ap-southeast-2": endpoint{},
|
||||
"ca-central-1": endpoint{},
|
||||
"eu-central-1": endpoint{},
|
||||
"eu-south-1": endpoint{},
|
||||
"eu-west-1": endpoint{},
|
||||
"eu-west-2": endpoint{},
|
||||
"us-east-1": endpoint{},
|
||||
|
@ -452,6 +459,12 @@ var awsPartition = partition{
|
|||
Region: "ap-northeast-2",
|
||||
},
|
||||
},
|
||||
"ap-northeast-3": endpoint{
|
||||
Hostname: "api.ecr.ap-northeast-3.amazonaws.com",
|
||||
CredentialScope: credentialScope{
|
||||
Region: "ap-northeast-3",
|
||||
},
|
||||
},
|
||||
"ap-south-1": endpoint{
|
||||
Hostname: "api.ecr.ap-south-1.amazonaws.com",
|
||||
CredentialScope: credentialScope{
|
||||
|
@ -706,6 +719,7 @@ var awsPartition = partition{
|
|||
"ap-east-1": endpoint{},
|
||||
"ap-northeast-1": endpoint{},
|
||||
"ap-northeast-2": endpoint{},
|
||||
"ap-northeast-3": endpoint{},
|
||||
"ap-south-1": endpoint{},
|
||||
"ap-southeast-1": endpoint{},
|
||||
"ap-southeast-2": endpoint{},
|
||||
|
@ -765,6 +779,7 @@ var awsPartition = partition{
|
|||
"ap-east-1": endpoint{},
|
||||
"ap-northeast-1": endpoint{},
|
||||
"ap-northeast-2": endpoint{},
|
||||
"ap-northeast-3": endpoint{},
|
||||
"ap-south-1": endpoint{},
|
||||
"ap-southeast-1": endpoint{},
|
||||
"ap-southeast-2": endpoint{},
|
||||
|
@ -915,6 +930,7 @@ var awsPartition = partition{
|
|||
"ap-east-1": endpoint{},
|
||||
"ap-northeast-1": endpoint{},
|
||||
"ap-northeast-2": endpoint{},
|
||||
"ap-northeast-3": endpoint{},
|
||||
"ap-south-1": endpoint{},
|
||||
"ap-southeast-1": endpoint{},
|
||||
"ap-southeast-2": endpoint{},
|
||||
|
@ -988,9 +1004,11 @@ var awsPartition = partition{
|
|||
"batch": service{
|
||||
|
||||
Endpoints: endpoints{
|
||||
"af-south-1": endpoint{},
|
||||
"ap-east-1": endpoint{},
|
||||
"ap-northeast-1": endpoint{},
|
||||
"ap-northeast-2": endpoint{},
|
||||
"ap-northeast-3": endpoint{},
|
||||
"ap-south-1": endpoint{},
|
||||
"ap-southeast-1": endpoint{},
|
||||
"ap-southeast-2": endpoint{},
|
||||
|
@ -1120,6 +1138,7 @@ var awsPartition = partition{
|
|||
"ap-east-1": endpoint{},
|
||||
"ap-northeast-1": endpoint{},
|
||||
"ap-northeast-2": endpoint{},
|
||||
"ap-northeast-3": endpoint{},
|
||||
"ap-south-1": endpoint{},
|
||||
"ap-southeast-1": endpoint{},
|
||||
"ap-southeast-2": endpoint{},
|
||||
|
@ -1385,6 +1404,7 @@ var awsPartition = partition{
|
|||
"ap-east-1": endpoint{},
|
||||
"ap-northeast-1": endpoint{},
|
||||
"ap-northeast-2": endpoint{},
|
||||
"ap-northeast-3": endpoint{},
|
||||
"ap-south-1": endpoint{},
|
||||
"ap-southeast-1": endpoint{},
|
||||
"ap-southeast-2": endpoint{},
|
||||
|
@ -1708,6 +1728,7 @@ var awsPartition = partition{
|
|||
"ap-east-1": endpoint{},
|
||||
"ap-northeast-1": endpoint{},
|
||||
"ap-northeast-2": endpoint{},
|
||||
"ap-northeast-3": endpoint{},
|
||||
"ap-south-1": endpoint{},
|
||||
"ap-southeast-1": endpoint{},
|
||||
"ap-southeast-2": endpoint{},
|
||||
|
@ -1765,7 +1786,10 @@ var awsPartition = partition{
|
|||
"contact-lens": service{
|
||||
|
||||
Endpoints: endpoints{
|
||||
"ap-northeast-1": endpoint{},
|
||||
"ap-southeast-2": endpoint{},
|
||||
"eu-central-1": endpoint{},
|
||||
"eu-west-2": endpoint{},
|
||||
"us-east-1": endpoint{},
|
||||
"us-west-2": endpoint{},
|
||||
},
|
||||
|
@ -1902,6 +1926,7 @@ var awsPartition = partition{
|
|||
"ap-east-1": endpoint{},
|
||||
"ap-northeast-1": endpoint{},
|
||||
"ap-northeast-2": endpoint{},
|
||||
"ap-northeast-3": endpoint{},
|
||||
"ap-south-1": endpoint{},
|
||||
"ap-southeast-1": endpoint{},
|
||||
"ap-southeast-2": endpoint{},
|
||||
|
@ -1963,6 +1988,7 @@ var awsPartition = partition{
|
|||
"ap-east-1": endpoint{},
|
||||
"ap-northeast-1": endpoint{},
|
||||
"ap-northeast-2": endpoint{},
|
||||
"ap-northeast-3": endpoint{},
|
||||
"ap-south-1": endpoint{},
|
||||
"ap-southeast-1": endpoint{},
|
||||
"ap-southeast-2": endpoint{},
|
||||
|
@ -2140,6 +2166,7 @@ var awsPartition = partition{
|
|||
"ap-east-1": endpoint{},
|
||||
"ap-northeast-1": endpoint{},
|
||||
"ap-northeast-2": endpoint{},
|
||||
"ap-northeast-3": endpoint{},
|
||||
"ap-south-1": endpoint{},
|
||||
"ap-southeast-1": endpoint{},
|
||||
"ap-southeast-2": endpoint{},
|
||||
|
@ -2202,6 +2229,7 @@ var awsPartition = partition{
|
|||
"ap-east-1": endpoint{},
|
||||
"ap-northeast-1": endpoint{},
|
||||
"ap-northeast-2": endpoint{},
|
||||
"ap-northeast-3": endpoint{},
|
||||
"ap-south-1": endpoint{},
|
||||
"ap-southeast-1": endpoint{},
|
||||
"ap-southeast-2": endpoint{},
|
||||
|
@ -2259,6 +2287,7 @@ var awsPartition = partition{
|
|||
"ap-east-1": endpoint{},
|
||||
"ap-northeast-1": endpoint{},
|
||||
"ap-northeast-2": endpoint{},
|
||||
"ap-northeast-3": endpoint{},
|
||||
"ap-south-1": endpoint{},
|
||||
"ap-southeast-1": endpoint{},
|
||||
"ap-southeast-2": endpoint{},
|
||||
|
@ -2325,6 +2354,7 @@ var awsPartition = partition{
|
|||
"ap-east-1": endpoint{},
|
||||
"ap-northeast-1": endpoint{},
|
||||
"ap-northeast-2": endpoint{},
|
||||
"ap-northeast-3": endpoint{},
|
||||
"ap-south-1": endpoint{},
|
||||
"ap-southeast-1": endpoint{},
|
||||
"ap-southeast-2": endpoint{},
|
||||
|
@ -2376,6 +2406,7 @@ var awsPartition = partition{
|
|||
"ap-east-1": endpoint{},
|
||||
"ap-northeast-1": endpoint{},
|
||||
"ap-northeast-2": endpoint{},
|
||||
"ap-northeast-3": endpoint{},
|
||||
"ap-south-1": endpoint{},
|
||||
"ap-southeast-1": endpoint{},
|
||||
"ap-southeast-2": endpoint{},
|
||||
|
@ -2425,6 +2456,7 @@ var awsPartition = partition{
|
|||
"ap-east-1": endpoint{},
|
||||
"ap-northeast-1": endpoint{},
|
||||
"ap-northeast-2": endpoint{},
|
||||
"ap-northeast-3": endpoint{},
|
||||
"ap-south-1": endpoint{},
|
||||
"ap-southeast-1": endpoint{},
|
||||
"ap-southeast-2": endpoint{},
|
||||
|
@ -2456,6 +2488,7 @@ var awsPartition = partition{
|
|||
"ap-east-1": endpoint{},
|
||||
"ap-northeast-1": endpoint{},
|
||||
"ap-northeast-2": endpoint{},
|
||||
"ap-northeast-3": endpoint{},
|
||||
"ap-south-1": endpoint{},
|
||||
"ap-southeast-1": endpoint{},
|
||||
"ap-southeast-2": endpoint{},
|
||||
|
@ -2505,6 +2538,7 @@ var awsPartition = partition{
|
|||
"ap-east-1": endpoint{},
|
||||
"ap-northeast-1": endpoint{},
|
||||
"ap-northeast-2": endpoint{},
|
||||
"ap-northeast-3": endpoint{},
|
||||
"ap-south-1": endpoint{},
|
||||
"ap-southeast-1": endpoint{},
|
||||
"ap-southeast-2": endpoint{},
|
||||
|
@ -2539,6 +2573,12 @@ var awsPartition = partition{
|
|||
Region: "ap-northeast-2",
|
||||
},
|
||||
},
|
||||
"fips-ap-northeast-3": endpoint{
|
||||
Hostname: "elasticfilesystem-fips.ap-northeast-3.amazonaws.com",
|
||||
CredentialScope: credentialScope{
|
||||
Region: "ap-northeast-3",
|
||||
},
|
||||
},
|
||||
"fips-ap-south-1": endpoint{
|
||||
Hostname: "elasticfilesystem-fips.ap-south-1.amazonaws.com",
|
||||
CredentialScope: credentialScope{
|
||||
|
@ -2652,6 +2692,7 @@ var awsPartition = partition{
|
|||
"ap-east-1": endpoint{},
|
||||
"ap-northeast-1": endpoint{},
|
||||
"ap-northeast-2": endpoint{},
|
||||
"ap-northeast-3": endpoint{},
|
||||
"ap-south-1": endpoint{},
|
||||
"ap-southeast-1": endpoint{},
|
||||
"ap-southeast-2": endpoint{},
|
||||
|
@ -2704,6 +2745,7 @@ var awsPartition = partition{
|
|||
"ap-east-1": endpoint{},
|
||||
"ap-northeast-1": endpoint{},
|
||||
"ap-northeast-2": endpoint{},
|
||||
"ap-northeast-3": endpoint{},
|
||||
"ap-south-1": endpoint{},
|
||||
"ap-southeast-1": endpoint{},
|
||||
"ap-southeast-2": endpoint{},
|
||||
|
@ -2783,9 +2825,19 @@ var awsPartition = partition{
|
|||
"emr-containers": service{
|
||||
|
||||
Endpoints: endpoints{
|
||||
"eu-west-1": endpoint{},
|
||||
"us-east-1": endpoint{},
|
||||
"us-west-2": endpoint{},
|
||||
"ap-northeast-1": endpoint{},
|
||||
"ap-northeast-2": endpoint{},
|
||||
"ap-south-1": endpoint{},
|
||||
"ap-southeast-1": endpoint{},
|
||||
"ap-southeast-2": endpoint{},
|
||||
"ca-central-1": endpoint{},
|
||||
"eu-central-1": endpoint{},
|
||||
"eu-west-1": endpoint{},
|
||||
"eu-west-2": endpoint{},
|
||||
"us-east-1": endpoint{},
|
||||
"us-east-2": endpoint{},
|
||||
"us-west-1": endpoint{},
|
||||
"us-west-2": endpoint{},
|
||||
},
|
||||
},
|
||||
"entitlement.marketplace": service{
|
||||
|
@ -2805,6 +2857,7 @@ var awsPartition = partition{
|
|||
"ap-east-1": endpoint{},
|
||||
"ap-northeast-1": endpoint{},
|
||||
"ap-northeast-2": endpoint{},
|
||||
"ap-northeast-3": endpoint{},
|
||||
"ap-south-1": endpoint{},
|
||||
"ap-southeast-1": endpoint{},
|
||||
"ap-southeast-2": endpoint{},
|
||||
|
@ -2836,6 +2889,7 @@ var awsPartition = partition{
|
|||
"ap-east-1": endpoint{},
|
||||
"ap-northeast-1": endpoint{},
|
||||
"ap-northeast-2": endpoint{},
|
||||
"ap-northeast-3": endpoint{},
|
||||
"ap-south-1": endpoint{},
|
||||
"ap-southeast-1": endpoint{},
|
||||
"ap-southeast-2": endpoint{},
|
||||
|
@ -2885,6 +2939,7 @@ var awsPartition = partition{
|
|||
"ap-east-1": endpoint{},
|
||||
"ap-northeast-1": endpoint{},
|
||||
"ap-northeast-2": endpoint{},
|
||||
"ap-northeast-3": endpoint{},
|
||||
"ap-south-1": endpoint{},
|
||||
"ap-southeast-1": endpoint{},
|
||||
"ap-southeast-2": endpoint{},
|
||||
|
@ -3181,6 +3236,7 @@ var awsPartition = partition{
|
|||
"ap-east-1": endpoint{},
|
||||
"ap-northeast-1": endpoint{},
|
||||
"ap-northeast-2": endpoint{},
|
||||
"ap-northeast-3": endpoint{},
|
||||
"ap-south-1": endpoint{},
|
||||
"ap-southeast-1": endpoint{},
|
||||
"ap-southeast-2": endpoint{},
|
||||
|
@ -3236,6 +3292,7 @@ var awsPartition = partition{
|
|||
"ap-east-1": endpoint{},
|
||||
"ap-northeast-1": endpoint{},
|
||||
"ap-northeast-2": endpoint{},
|
||||
"ap-northeast-3": endpoint{},
|
||||
"ap-south-1": endpoint{},
|
||||
"ap-southeast-1": endpoint{},
|
||||
"ap-southeast-2": endpoint{},
|
||||
|
@ -3696,6 +3753,7 @@ var awsPartition = partition{
|
|||
"ap-east-1": endpoint{},
|
||||
"ap-northeast-1": endpoint{},
|
||||
"ap-northeast-2": endpoint{},
|
||||
"ap-northeast-3": endpoint{},
|
||||
"ap-south-1": endpoint{},
|
||||
"ap-southeast-1": endpoint{},
|
||||
"ap-southeast-2": endpoint{},
|
||||
|
@ -3789,6 +3847,7 @@ var awsPartition = partition{
|
|||
"ap-east-1": endpoint{},
|
||||
"ap-northeast-1": endpoint{},
|
||||
"ap-northeast-2": endpoint{},
|
||||
"ap-northeast-3": endpoint{},
|
||||
"ap-south-1": endpoint{},
|
||||
"ap-southeast-1": endpoint{},
|
||||
"ap-southeast-2": endpoint{},
|
||||
|
@ -3847,11 +3906,12 @@ var awsPartition = partition{
|
|||
Region: "us-west-2",
|
||||
},
|
||||
},
|
||||
"sa-east-1": endpoint{},
|
||||
"us-east-1": endpoint{},
|
||||
"us-east-2": endpoint{},
|
||||
"us-west-1": endpoint{},
|
||||
"us-west-2": endpoint{},
|
||||
"me-south-1": endpoint{},
|
||||
"sa-east-1": endpoint{},
|
||||
"us-east-1": endpoint{},
|
||||
"us-east-2": endpoint{},
|
||||
"us-west-1": endpoint{},
|
||||
"us-west-2": endpoint{},
|
||||
},
|
||||
},
|
||||
"lambda": service{
|
||||
|
@ -3861,6 +3921,7 @@ var awsPartition = partition{
|
|||
"ap-east-1": endpoint{},
|
||||
"ap-northeast-1": endpoint{},
|
||||
"ap-northeast-2": endpoint{},
|
||||
"ap-northeast-3": endpoint{},
|
||||
"ap-south-1": endpoint{},
|
||||
"ap-southeast-1": endpoint{},
|
||||
"ap-southeast-2": endpoint{},
|
||||
|
@ -3977,6 +4038,7 @@ var awsPartition = partition{
|
|||
"ap-east-1": endpoint{},
|
||||
"ap-northeast-1": endpoint{},
|
||||
"ap-northeast-2": endpoint{},
|
||||
"ap-northeast-3": endpoint{},
|
||||
"ap-south-1": endpoint{},
|
||||
"ap-southeast-1": endpoint{},
|
||||
"ap-southeast-2": endpoint{},
|
||||
|
@ -4276,6 +4338,7 @@ var awsPartition = partition{
|
|||
"ap-east-1": endpoint{},
|
||||
"ap-northeast-1": endpoint{},
|
||||
"ap-northeast-2": endpoint{},
|
||||
"ap-northeast-3": endpoint{},
|
||||
"ap-south-1": endpoint{},
|
||||
"ap-southeast-1": endpoint{},
|
||||
"ap-southeast-2": endpoint{},
|
||||
|
@ -4350,6 +4413,7 @@ var awsPartition = partition{
|
|||
"ap-east-1": endpoint{},
|
||||
"ap-northeast-1": endpoint{},
|
||||
"ap-northeast-2": endpoint{},
|
||||
"ap-northeast-3": endpoint{},
|
||||
"ap-south-1": endpoint{},
|
||||
"ap-southeast-1": endpoint{},
|
||||
"ap-southeast-2": endpoint{},
|
||||
|
@ -4957,12 +5021,42 @@ var awsPartition = partition{
|
|||
"eu-west-1": endpoint{},
|
||||
"eu-west-2": endpoint{},
|
||||
"eu-west-3": endpoint{},
|
||||
"me-south-1": endpoint{},
|
||||
"sa-east-1": endpoint{},
|
||||
"us-east-1": endpoint{},
|
||||
"us-east-2": endpoint{},
|
||||
"us-west-1": endpoint{},
|
||||
"us-west-2": endpoint{},
|
||||
"fips-ca-central-1": endpoint{
|
||||
Hostname: "ram-fips.ca-central-1.amazonaws.com",
|
||||
CredentialScope: credentialScope{
|
||||
Region: "ca-central-1",
|
||||
},
|
||||
},
|
||||
"fips-us-east-1": endpoint{
|
||||
Hostname: "ram-fips.us-east-1.amazonaws.com",
|
||||
CredentialScope: credentialScope{
|
||||
Region: "us-east-1",
|
||||
},
|
||||
},
|
||||
"fips-us-east-2": endpoint{
|
||||
Hostname: "ram-fips.us-east-2.amazonaws.com",
|
||||
CredentialScope: credentialScope{
|
||||
Region: "us-east-2",
|
||||
},
|
||||
},
|
||||
"fips-us-west-1": endpoint{
|
||||
Hostname: "ram-fips.us-west-1.amazonaws.com",
|
||||
CredentialScope: credentialScope{
|
||||
Region: "us-west-1",
|
||||
},
|
||||
},
|
||||
"fips-us-west-2": endpoint{
|
||||
Hostname: "ram-fips.us-west-2.amazonaws.com",
|
||||
CredentialScope: credentialScope{
|
||||
Region: "us-west-2",
|
||||
},
|
||||
},
|
||||
"me-south-1": endpoint{},
|
||||
"sa-east-1": endpoint{},
|
||||
"us-east-1": endpoint{},
|
||||
"us-east-2": endpoint{},
|
||||
"us-west-1": endpoint{},
|
||||
"us-west-2": endpoint{},
|
||||
},
|
||||
},
|
||||
"rds": service{
|
||||
|
@ -4972,6 +5066,7 @@ var awsPartition = partition{
|
|||
"ap-east-1": endpoint{},
|
||||
"ap-northeast-1": endpoint{},
|
||||
"ap-northeast-2": endpoint{},
|
||||
"ap-northeast-3": endpoint{},
|
||||
"ap-south-1": endpoint{},
|
||||
"ap-southeast-1": endpoint{},
|
||||
"ap-southeast-2": endpoint{},
|
||||
|
@ -5029,6 +5124,7 @@ var awsPartition = partition{
|
|||
"ap-east-1": endpoint{},
|
||||
"ap-northeast-1": endpoint{},
|
||||
"ap-northeast-2": endpoint{},
|
||||
"ap-northeast-3": endpoint{},
|
||||
"ap-south-1": endpoint{},
|
||||
"ap-southeast-1": endpoint{},
|
||||
"ap-southeast-2": endpoint{},
|
||||
|
@ -5132,6 +5228,7 @@ var awsPartition = partition{
|
|||
"ap-east-1": endpoint{},
|
||||
"ap-northeast-1": endpoint{},
|
||||
"ap-northeast-2": endpoint{},
|
||||
"ap-northeast-3": endpoint{},
|
||||
"ap-south-1": endpoint{},
|
||||
"ap-southeast-1": endpoint{},
|
||||
"ap-southeast-2": endpoint{},
|
||||
|
@ -5334,6 +5431,7 @@ var awsPartition = partition{
|
|||
SignatureVersions: []string{"s3", "s3v4"},
|
||||
},
|
||||
"ap-northeast-2": endpoint{},
|
||||
"ap-northeast-3": endpoint{},
|
||||
"ap-south-1": endpoint{},
|
||||
"ap-southeast-1": endpoint{
|
||||
Hostname: "s3.ap-southeast-1.amazonaws.com",
|
||||
|
@ -5410,6 +5508,13 @@ var awsPartition = partition{
|
|||
Region: "ap-northeast-2",
|
||||
},
|
||||
},
|
||||
"ap-northeast-3": endpoint{
|
||||
Hostname: "s3-control.ap-northeast-3.amazonaws.com",
|
||||
SignatureVersions: []string{"s3v4"},
|
||||
CredentialScope: credentialScope{
|
||||
Region: "ap-northeast-3",
|
||||
},
|
||||
},
|
||||
"ap-south-1": endpoint{
|
||||
Hostname: "s3-control.ap-south-1.amazonaws.com",
|
||||
SignatureVersions: []string{"s3v4"},
|
||||
|
@ -5605,6 +5710,7 @@ var awsPartition = partition{
|
|||
"ap-east-1": endpoint{},
|
||||
"ap-northeast-1": endpoint{},
|
||||
"ap-northeast-2": endpoint{},
|
||||
"ap-northeast-3": endpoint{},
|
||||
"ap-south-1": endpoint{},
|
||||
"ap-southeast-1": endpoint{},
|
||||
"ap-southeast-2": endpoint{},
|
||||
|
@ -5846,6 +5952,7 @@ var awsPartition = partition{
|
|||
"ap-east-1": endpoint{},
|
||||
"ap-northeast-1": endpoint{},
|
||||
"ap-northeast-2": endpoint{},
|
||||
"ap-northeast-3": endpoint{},
|
||||
"ap-south-1": endpoint{},
|
||||
"ap-southeast-1": endpoint{},
|
||||
"ap-southeast-2": endpoint{},
|
||||
|
@ -5956,6 +6063,7 @@ var awsPartition = partition{
|
|||
"ap-east-1": endpoint{},
|
||||
"ap-northeast-1": endpoint{},
|
||||
"ap-northeast-2": endpoint{},
|
||||
"ap-northeast-3": endpoint{},
|
||||
"ap-south-1": endpoint{},
|
||||
"ap-southeast-1": endpoint{},
|
||||
"ap-southeast-2": endpoint{},
|
||||
|
@ -6078,6 +6186,7 @@ var awsPartition = partition{
|
|||
"ap-east-1": endpoint{},
|
||||
"ap-northeast-1": endpoint{},
|
||||
"ap-northeast-2": endpoint{},
|
||||
"ap-northeast-3": endpoint{},
|
||||
"ap-south-1": endpoint{},
|
||||
"ap-southeast-1": endpoint{},
|
||||
"ap-southeast-2": endpoint{},
|
||||
|
@ -6130,6 +6239,7 @@ var awsPartition = partition{
|
|||
"ap-east-1": endpoint{},
|
||||
"ap-northeast-1": endpoint{},
|
||||
"ap-northeast-2": endpoint{},
|
||||
"ap-northeast-3": endpoint{},
|
||||
"ap-south-1": endpoint{},
|
||||
"ap-southeast-1": endpoint{},
|
||||
"ap-southeast-2": endpoint{},
|
||||
|
@ -6181,6 +6291,7 @@ var awsPartition = partition{
|
|||
"ap-east-1": endpoint{},
|
||||
"ap-northeast-1": endpoint{},
|
||||
"ap-northeast-2": endpoint{},
|
||||
"ap-northeast-3": endpoint{},
|
||||
"ap-south-1": endpoint{},
|
||||
"ap-southeast-1": endpoint{},
|
||||
"ap-southeast-2": endpoint{},
|
||||
|
@ -6236,6 +6347,7 @@ var awsPartition = partition{
|
|||
"ap-east-1": endpoint{},
|
||||
"ap-northeast-1": endpoint{},
|
||||
"ap-northeast-2": endpoint{},
|
||||
"ap-northeast-3": endpoint{},
|
||||
"ap-south-1": endpoint{},
|
||||
"ap-southeast-1": endpoint{},
|
||||
"ap-southeast-2": endpoint{},
|
||||
|
@ -6381,6 +6493,7 @@ var awsPartition = partition{
|
|||
"ap-east-1": endpoint{},
|
||||
"ap-northeast-1": endpoint{},
|
||||
"ap-northeast-2": endpoint{},
|
||||
"ap-northeast-3": endpoint{},
|
||||
"ap-south-1": endpoint{},
|
||||
"ap-southeast-1": endpoint{},
|
||||
"ap-southeast-2": endpoint{},
|
||||
|
@ -6448,6 +6561,7 @@ var awsPartition = partition{
|
|||
"ap-east-1": endpoint{},
|
||||
"ap-northeast-1": endpoint{},
|
||||
"ap-northeast-2": endpoint{},
|
||||
"ap-northeast-3": endpoint{},
|
||||
"ap-south-1": endpoint{},
|
||||
"ap-southeast-1": endpoint{},
|
||||
"ap-southeast-2": endpoint{},
|
||||
|
@ -6497,6 +6611,7 @@ var awsPartition = partition{
|
|||
"ap-east-1": endpoint{},
|
||||
"ap-northeast-1": endpoint{},
|
||||
"ap-northeast-2": endpoint{},
|
||||
"ap-northeast-3": endpoint{},
|
||||
"ap-south-1": endpoint{},
|
||||
"ap-southeast-1": endpoint{},
|
||||
"ap-southeast-2": endpoint{},
|
||||
|
@ -6582,6 +6697,7 @@ var awsPartition = partition{
|
|||
"transfer": service{
|
||||
|
||||
Endpoints: endpoints{
|
||||
"af-south-1": endpoint{},
|
||||
"ap-east-1": endpoint{},
|
||||
"ap-northeast-1": endpoint{},
|
||||
"ap-northeast-2": endpoint{},
|
||||
|
@ -6975,6 +7091,7 @@ var awsPartition = partition{
|
|||
Endpoints: endpoints{
|
||||
"ap-northeast-1": endpoint{},
|
||||
"ap-northeast-2": endpoint{},
|
||||
"ap-south-1": endpoint{},
|
||||
"ap-southeast-1": endpoint{},
|
||||
"ap-southeast-2": endpoint{},
|
||||
"ca-central-1": endpoint{},
|
||||
|
@ -7005,6 +7122,7 @@ var awsPartition = partition{
|
|||
"ap-east-1": endpoint{},
|
||||
"ap-northeast-1": endpoint{},
|
||||
"ap-northeast-2": endpoint{},
|
||||
"ap-northeast-3": endpoint{},
|
||||
"ap-south-1": endpoint{},
|
||||
"ap-southeast-1": endpoint{},
|
||||
"ap-southeast-2": endpoint{},
|
||||
|
@ -9128,8 +9246,18 @@ var awsusgovPartition = partition{
|
|||
"ram": service{
|
||||
|
||||
Endpoints: endpoints{
|
||||
"us-gov-east-1": endpoint{},
|
||||
"us-gov-west-1": endpoint{},
|
||||
"us-gov-east-1": endpoint{
|
||||
Hostname: "ram.us-gov-east-1.amazonaws.com",
|
||||
CredentialScope: credentialScope{
|
||||
Region: "us-gov-east-1",
|
||||
},
|
||||
},
|
||||
"us-gov-west-1": endpoint{
|
||||
Hostname: "ram.us-gov-west-1.amazonaws.com",
|
||||
CredentialScope: credentialScope{
|
||||
Region: "us-gov-west-1",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"rds": service{
|
||||
|
@ -10383,6 +10511,19 @@ var awsisobPartition = partition{
|
|||
"us-isob-east-1": endpoint{},
|
||||
},
|
||||
},
|
||||
"route53": service{
|
||||
PartitionEndpoint: "aws-iso-b-global",
|
||||
IsRegionalized: boxedFalse,
|
||||
|
||||
Endpoints: endpoints{
|
||||
"aws-iso-b-global": endpoint{
|
||||
Hostname: "route53.sc2s.sgov.gov",
|
||||
CredentialScope: credentialScope{
|
||||
Region: "us-isob-east-1",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"s3": service{
|
||||
Defaults: endpoint{
|
||||
Protocols: []string{"http", "https"},
|
||||
|
|
|
@ -689,9 +689,12 @@ func (ctx *signingCtx) buildBodyDigest() error {
|
|||
if hash == "" {
|
||||
includeSHA256Header := ctx.unsignedPayload ||
|
||||
ctx.ServiceName == "s3" ||
|
||||
ctx.ServiceName == "s3-object-lambda" ||
|
||||
ctx.ServiceName == "glacier"
|
||||
|
||||
s3Presign := ctx.isPresign && ctx.ServiceName == "s3"
|
||||
s3Presign := ctx.isPresign &&
|
||||
(ctx.ServiceName == "s3" ||
|
||||
ctx.ServiceName == "s3-object-lambda")
|
||||
|
||||
if ctx.unsignedPayload || s3Presign {
|
||||
hash = "UNSIGNED-PAYLOAD"
|
||||
|
|
|
@ -5,4 +5,4 @@ package aws
|
|||
const SDKName = "aws-sdk-go"
|
||||
|
||||
// SDKVersion is the version of this SDK
|
||||
const SDKVersion = "1.37.15"
|
||||
const SDKVersion = "1.38.0"
|
||||
|
|
|
@ -7,6 +7,21 @@ import (
|
|||
"github.com/aws/aws-sdk-go/aws/arn"
|
||||
)
|
||||
|
||||
var supportedServiceARN = []string{
|
||||
"s3",
|
||||
"s3-outposts",
|
||||
"s3-object-lambda",
|
||||
}
|
||||
|
||||
func isSupportedServiceARN(service string) bool {
|
||||
for _, name := range supportedServiceARN {
|
||||
if name == service {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Resource provides the interfaces abstracting ARNs of specific resource
|
||||
// types.
|
||||
type Resource interface {
|
||||
|
@ -29,9 +44,10 @@ func ParseResource(s string, resParser ResourceParser) (resARN Resource, err err
|
|||
return nil, InvalidARNError{ARN: a, Reason: "partition not set"}
|
||||
}
|
||||
|
||||
if a.Service != "s3" && a.Service != "s3-outposts" {
|
||||
if !isSupportedServiceARN(a.Service) {
|
||||
return nil, InvalidARNError{ARN: a, Reason: "service is not supported"}
|
||||
}
|
||||
|
||||
if len(a.Resource) == 0 {
|
||||
return nil, InvalidARNError{ARN: a, Reason: "resource not set"}
|
||||
}
|
||||
|
|
15
vendor/github.com/aws/aws-sdk-go/internal/s3shared/arn/s3_object_lambda_arn.go
generated
vendored
Normal file
15
vendor/github.com/aws/aws-sdk-go/internal/s3shared/arn/s3_object_lambda_arn.go
generated
vendored
Normal file
|
@ -0,0 +1,15 @@
|
|||
package arn
|
||||
|
||||
// S3ObjectLambdaARN represents an ARN for the s3-object-lambda service
|
||||
type S3ObjectLambdaARN interface {
|
||||
Resource
|
||||
|
||||
isS3ObjectLambdasARN()
|
||||
}
|
||||
|
||||
// S3ObjectLambdaAccessPointARN is an S3ObjectLambdaARN for the Access Point resource type
|
||||
type S3ObjectLambdaAccessPointARN struct {
|
||||
AccessPointARN
|
||||
}
|
||||
|
||||
func (s S3ObjectLambdaAccessPointARN) isS3ObjectLambdasARN() {}
|
|
@ -65874,9 +65874,9 @@ type DescribeImageAttributeInput struct {
|
|||
|
||||
// The AMI attribute.
|
||||
//
|
||||
// Note: Depending on your account privileges, the blockDeviceMapping attribute
|
||||
// may return a Client.AuthFailure error. If this happens, use DescribeImages
|
||||
// to get information about the block device mapping for the AMI.
|
||||
// Note: The blockDeviceMapping attribute is deprecated. Using this attribute
|
||||
// returns the Client.AuthFailure error. To get information about the block
|
||||
// device mappings for an AMI, use the DescribeImages action.
|
||||
//
|
||||
// Attribute is a required field
|
||||
Attribute *string `type:"string" required:"true" enum:"ImageAttributeName"`
|
||||
|
@ -82374,12 +82374,21 @@ type FleetLaunchTemplateOverrides struct {
|
|||
// The location where the instance launched, if applicable.
|
||||
Placement *PlacementResponse `locationName:"placement" type:"structure"`
|
||||
|
||||
// The priority for the launch template override. If AllocationStrategy is set
|
||||
// to prioritized, EC2 Fleet uses priority to determine which launch template
|
||||
// override to use first in fulfilling On-Demand capacity. The highest priority
|
||||
// is launched first. Valid values are whole numbers starting at 0. The lower
|
||||
// the number, the higher the priority. If no number is set, the override has
|
||||
// the lowest priority.
|
||||
// The priority for the launch template override. The highest priority is launched
|
||||
// first.
|
||||
//
|
||||
// If the On-Demand AllocationStrategy is set to prioritized, EC2 Fleet uses
|
||||
// priority to determine which launch template override to use first in fulfilling
|
||||
// On-Demand capacity.
|
||||
//
|
||||
// If the Spot AllocationStrategy is set to capacity-optimized-prioritized,
|
||||
// EC2 Fleet uses priority on a best-effort basis to determine which launch
|
||||
// template override to use first in fulfilling Spot capacity, but optimizes
|
||||
// for capacity first.
|
||||
//
|
||||
// Valid values are whole numbers starting at 0. The lower the number, the higher
|
||||
// the priority. If no number is set, the override has the lowest priority.
|
||||
// You can set the same priority for different launch template overrides.
|
||||
Priority *float64 `locationName:"priority" type:"double"`
|
||||
|
||||
// The ID of the subnet in which to launch the instances.
|
||||
|
@ -82457,12 +82466,21 @@ type FleetLaunchTemplateOverridesRequest struct {
|
|||
// The location where the instance launched, if applicable.
|
||||
Placement *Placement `type:"structure"`
|
||||
|
||||
// The priority for the launch template override. If AllocationStrategy is set
|
||||
// to prioritized, EC2 Fleet uses priority to determine which launch template
|
||||
// override to use first in fulfilling On-Demand capacity. The highest priority
|
||||
// is launched first. Valid values are whole numbers starting at 0. The lower
|
||||
// the number, the higher the priority. If no number is set, the launch template
|
||||
// override has the lowest priority.
|
||||
// The priority for the launch template override. The highest priority is launched
|
||||
// first.
|
||||
//
|
||||
// If the On-Demand AllocationStrategy is set to prioritized, EC2 Fleet uses
|
||||
// priority to determine which launch template override to use first in fulfilling
|
||||
// On-Demand capacity.
|
||||
//
|
||||
// If the Spot AllocationStrategy is set to capacity-optimized-prioritized,
|
||||
// EC2 Fleet uses priority on a best-effort basis to determine which launch
|
||||
// template override to use first in fulfilling Spot capacity, but optimizes
|
||||
// for capacity first.
|
||||
//
|
||||
// Valid values are whole numbers starting at 0. The lower the number, the higher
|
||||
// the priority. If no number is set, the launch template override has the lowest
|
||||
// priority. You can set the same priority for different launch template overrides.
|
||||
Priority *float64 `type:"double"`
|
||||
|
||||
// The IDs of the subnets in which to launch the instances. Separate multiple
|
||||
|
@ -92954,12 +92972,21 @@ type LaunchTemplateOverrides struct {
|
|||
// The instance type.
|
||||
InstanceType *string `locationName:"instanceType" type:"string" enum:"InstanceType"`
|
||||
|
||||
// The priority for the launch template override. If OnDemandAllocationStrategy
|
||||
// is set to prioritized, Spot Fleet uses priority to determine which launch
|
||||
// template override to use first in fulfilling On-Demand capacity. The highest
|
||||
// priority is launched first. Valid values are whole numbers starting at 0.
|
||||
// The lower the number, the higher the priority. If no number is set, the launch
|
||||
// template override has the lowest priority.
|
||||
// The priority for the launch template override. The highest priority is launched
|
||||
// first.
|
||||
//
|
||||
// If OnDemandAllocationStrategy is set to prioritized, Spot Fleet uses priority
|
||||
// to determine which launch template override to use first in fulfilling On-Demand
|
||||
// capacity.
|
||||
//
|
||||
// If the Spot AllocationStrategy is set to capacityOptimizedPrioritized, Spot
|
||||
// Fleet uses priority on a best-effort basis to determine which launch template
|
||||
// override to use first in fulfilling Spot capacity, but optimizes for capacity
|
||||
// first.
|
||||
//
|
||||
// Valid values are whole numbers starting at 0. The lower the number, the higher
|
||||
// the priority. If no number is set, the launch template override has the lowest
|
||||
// priority. You can set the same priority for different launch template overrides.
|
||||
Priority *float64 `locationName:"priority" type:"double"`
|
||||
|
||||
// The maximum price per unit hour that you are willing to pay for a Spot Instance.
|
||||
|
@ -113148,9 +113175,16 @@ type SpotFleetRequestConfigData struct {
|
|||
// If the allocation strategy is diversified, Spot Fleet launches instances
|
||||
// from all the Spot Instance pools that you specify.
|
||||
//
|
||||
// If the allocation strategy is capacityOptimized, Spot Fleet launches instances
|
||||
// from Spot Instance pools with optimal capacity for the number of instances
|
||||
// that are launching.
|
||||
// If the allocation strategy is capacityOptimized (recommended), Spot Fleet
|
||||
// launches instances from Spot Instance pools with optimal capacity for the
|
||||
// number of instances that are launching. To give certain instance types a
|
||||
// higher chance of launching first, use capacityOptimizedPrioritized. Set a
|
||||
// priority for each instance type by using the Priority parameter for LaunchTemplateOverrides.
|
||||
// You can assign the same priority to different LaunchTemplateOverrides. EC2
|
||||
// implements the priorities on a best-effort basis, but optimizes for capacity
|
||||
// first. capacityOptimizedPrioritized is supported only if your Spot Fleet
|
||||
// uses a launch template. Note that if the OnDemandAllocationStrategy is set
|
||||
// to prioritized, the same priority is applied when fulfilling On-Demand capacity.
|
||||
AllocationStrategy *string `locationName:"allocationStrategy" type:"string" enum:"AllocationStrategy"`
|
||||
|
||||
// A unique, case-sensitive identifier that you provide to ensure the idempotency
|
||||
|
@ -113926,9 +113960,16 @@ type SpotOptions struct {
|
|||
// If the allocation strategy is diversified, EC2 Fleet launches instances from
|
||||
// all of the Spot Instance pools that you specify.
|
||||
//
|
||||
// If the allocation strategy is capacity-optimized, EC2 Fleet launches instances
|
||||
// from Spot Instance pools with optimal capacity for the number of instances
|
||||
// that are launching.
|
||||
// If the allocation strategy is capacity-optimized (recommended), EC2 Fleet
|
||||
// launches instances from Spot Instance pools with optimal capacity for the
|
||||
// number of instances that are launching. To give certain instance types a
|
||||
// higher chance of launching first, use capacity-optimized-prioritized. Set
|
||||
// a priority for each instance type by using the Priority parameter for LaunchTemplateOverrides.
|
||||
// You can assign the same priority to different LaunchTemplateOverrides. EC2
|
||||
// implements the priorities on a best-effort basis, but optimizes for capacity
|
||||
// first. capacity-optimized-prioritized is supported only if your fleet uses
|
||||
// a launch template. Note that if the On-Demand AllocationStrategy is set to
|
||||
// prioritized, the same priority is applied when fulfilling On-Demand capacity.
|
||||
AllocationStrategy *string `locationName:"allocationStrategy" type:"string" enum:"SpotAllocationStrategy"`
|
||||
|
||||
// The behavior when a Spot Instance is interrupted. The default is terminate.
|
||||
|
@ -114032,9 +114073,16 @@ type SpotOptionsRequest struct {
|
|||
// If the allocation strategy is diversified, EC2 Fleet launches instances from
|
||||
// all of the Spot Instance pools that you specify.
|
||||
//
|
||||
// If the allocation strategy is capacity-optimized, EC2 Fleet launches instances
|
||||
// from Spot Instance pools with optimal capacity for the number of instances
|
||||
// that are launching.
|
||||
// If the allocation strategy is capacity-optimized (recommended), EC2 Fleet
|
||||
// launches instances from Spot Instance pools with optimal capacity for the
|
||||
// number of instances that are launching. To give certain instance types a
|
||||
// higher chance of launching first, use capacity-optimized-prioritized. Set
|
||||
// a priority for each instance type by using the Priority parameter for LaunchTemplateOverrides.
|
||||
// You can assign the same priority to different LaunchTemplateOverrides. EC2
|
||||
// implements the priorities on a best-effort basis, but optimizes for capacity
|
||||
// first. capacity-optimized-prioritized is supported only if your fleet uses
|
||||
// a launch template. Note that if the On-Demand AllocationStrategy is set to
|
||||
// prioritized, the same priority is applied when fulfilling On-Demand capacity.
|
||||
AllocationStrategy *string `type:"string" enum:"SpotAllocationStrategy"`
|
||||
|
||||
// The behavior when a Spot Instance is interrupted. The default is terminate.
|
||||
|
@ -121992,6 +122040,9 @@ const (
|
|||
|
||||
// AllocationStrategyCapacityOptimized is a AllocationStrategy enum value
|
||||
AllocationStrategyCapacityOptimized = "capacityOptimized"
|
||||
|
||||
// AllocationStrategyCapacityOptimizedPrioritized is a AllocationStrategy enum value
|
||||
AllocationStrategyCapacityOptimizedPrioritized = "capacityOptimizedPrioritized"
|
||||
)
|
||||
|
||||
// AllocationStrategy_Values returns all elements of the AllocationStrategy enum
|
||||
|
@ -122000,6 +122051,7 @@ func AllocationStrategy_Values() []string {
|
|||
AllocationStrategyLowestPrice,
|
||||
AllocationStrategyDiversified,
|
||||
AllocationStrategyCapacityOptimized,
|
||||
AllocationStrategyCapacityOptimizedPrioritized,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -126940,6 +126992,9 @@ const (
|
|||
|
||||
// SpotAllocationStrategyCapacityOptimized is a SpotAllocationStrategy enum value
|
||||
SpotAllocationStrategyCapacityOptimized = "capacity-optimized"
|
||||
|
||||
// SpotAllocationStrategyCapacityOptimizedPrioritized is a SpotAllocationStrategy enum value
|
||||
SpotAllocationStrategyCapacityOptimizedPrioritized = "capacity-optimized-prioritized"
|
||||
)
|
||||
|
||||
// SpotAllocationStrategy_Values returns all elements of the SpotAllocationStrategy enum
|
||||
|
@ -126948,6 +127003,7 @@ func SpotAllocationStrategy_Values() []string {
|
|||
SpotAllocationStrategyLowestPrice,
|
||||
SpotAllocationStrategyDiversified,
|
||||
SpotAllocationStrategyCapacityOptimized,
|
||||
SpotAllocationStrategyCapacityOptimizedPrioritized,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -362,6 +362,10 @@ func (c *IAM) AttachGroupPolicyRequest(input *AttachGroupPolicyInput) (req *requ
|
|||
// You use this operation to attach a managed policy to a group. To embed an
|
||||
// inline policy in a group, use PutGroupPolicy.
|
||||
//
|
||||
// As a best practice, you can validate your IAM policies. To learn more, see
|
||||
// Validating IAM policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_policy-validator.html)
|
||||
// in the IAM User Guide.
|
||||
//
|
||||
// For more information about policies, see Managed policies and inline policies
|
||||
// (https://docs.aws.amazon.com/IAM/latest/UserGuide/policies-managed-vs-inline.html)
|
||||
// in the IAM User Guide.
|
||||
|
@ -474,6 +478,10 @@ func (c *IAM) AttachRolePolicyRequest(input *AttachRolePolicyInput) (req *reques
|
|||
// see Managed policies and inline policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/policies-managed-vs-inline.html)
|
||||
// in the IAM User Guide.
|
||||
//
|
||||
// As a best practice, you can validate your IAM policies. To learn more, see
|
||||
// Validating IAM policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_policy-validator.html)
|
||||
// in the IAM User Guide.
|
||||
//
|
||||
// Returns awserr.Error for service API and SDK errors. Use runtime type assertions
|
||||
// with awserr.Error's Code and Message methods to get detailed information about
|
||||
// the error.
|
||||
|
@ -580,6 +588,10 @@ func (c *IAM) AttachUserPolicyRequest(input *AttachUserPolicyInput) (req *reques
|
|||
// You use this operation to attach a managed policy to a user. To embed an
|
||||
// inline policy in a user, use PutUserPolicy.
|
||||
//
|
||||
// As a best practice, you can validate your IAM policies. To learn more, see
|
||||
// Validating IAM policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_policy-validator.html)
|
||||
// in the IAM User Guide.
|
||||
//
|
||||
// For more information about policies, see Managed policies and inline policies
|
||||
// (https://docs.aws.amazon.com/IAM/latest/UserGuide/policies-managed-vs-inline.html)
|
||||
// in the IAM User Guide.
|
||||
|
@ -1414,6 +1426,10 @@ func (c *IAM) CreatePolicyRequest(input *CreatePolicyInput) (req *request.Reques
|
|||
// versions, see Versioning for managed policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/policies-managed-versions.html)
|
||||
// in the IAM User Guide.
|
||||
//
|
||||
// As a best practice, you can validate your IAM policies. To learn more, see
|
||||
// Validating IAM policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_policy-validator.html)
|
||||
// in the IAM User Guide.
|
||||
//
|
||||
// For more information about managed policies in general, see Managed policies
|
||||
// and inline policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/policies-managed-vs-inline.html)
|
||||
// in the IAM User Guide.
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -48,6 +48,8 @@ func defaultInitRequestFn(r *request.Request) {
|
|||
// case opGetObject:
|
||||
// r.Handlers.Build.PushBack(askForTxEncodingAppendMD5)
|
||||
// r.Handlers.Unmarshal.PushBack(useMD5ValidationReader)
|
||||
case opWriteGetObjectResponse:
|
||||
r.Handlers.Build.PushFront(buildWriteGetObjectResponseEndpoint)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package s3
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
|
@ -11,6 +13,13 @@ import (
|
|||
"github.com/aws/aws-sdk-go/internal/s3shared/arn"
|
||||
)
|
||||
|
||||
const (
|
||||
s3Namespace = "s3"
|
||||
s3AccessPointNamespace = "s3-accesspoint"
|
||||
s3ObjectsLambdaNamespace = "s3-object-lambda"
|
||||
s3OutpostsNamespace = "s3-outposts"
|
||||
)
|
||||
|
||||
// Used by shapes with members decorated as endpoint ARN.
|
||||
func parseEndpointARN(v string) (arn.Resource, error) {
|
||||
return arn.ParseResource(v, accessPointResourceParser)
|
||||
|
@ -20,10 +29,14 @@ func accessPointResourceParser(a awsarn.ARN) (arn.Resource, error) {
|
|||
resParts := arn.SplitResource(a.Resource)
|
||||
switch resParts[0] {
|
||||
case "accesspoint":
|
||||
if a.Service != "s3" {
|
||||
return arn.AccessPointARN{}, arn.InvalidARNError{ARN: a, Reason: "service is not s3"}
|
||||
switch a.Service {
|
||||
case s3Namespace:
|
||||
return arn.ParseAccessPointResource(a, resParts[1:])
|
||||
case s3ObjectsLambdaNamespace:
|
||||
return parseS3ObjectLambdaAccessPointResource(a, resParts)
|
||||
default:
|
||||
return arn.AccessPointARN{}, arn.InvalidARNError{ARN: a, Reason: fmt.Sprintf("service is not %s or %s", s3Namespace, s3ObjectsLambdaNamespace)}
|
||||
}
|
||||
return arn.ParseAccessPointResource(a, resParts[1:])
|
||||
case "outpost":
|
||||
if a.Service != "s3-outposts" {
|
||||
return arn.OutpostAccessPointARN{}, arn.InvalidARNError{ARN: a, Reason: "service is not s3-outposts"}
|
||||
|
@ -80,6 +93,25 @@ func parseOutpostAccessPointResource(a awsarn.ARN, resParts []string) (arn.Outpo
|
|||
return outpostAccessPointARN, nil
|
||||
}
|
||||
|
||||
func parseS3ObjectLambdaAccessPointResource(a awsarn.ARN, resParts []string) (arn.S3ObjectLambdaAccessPointARN, error) {
|
||||
if a.Service != s3ObjectsLambdaNamespace {
|
||||
return arn.S3ObjectLambdaAccessPointARN{}, arn.InvalidARNError{ARN: a, Reason: fmt.Sprintf("service is not %s", s3ObjectsLambdaNamespace)}
|
||||
}
|
||||
|
||||
accessPointARN, err := arn.ParseAccessPointResource(a, resParts[1:])
|
||||
if err != nil {
|
||||
return arn.S3ObjectLambdaAccessPointARN{}, err
|
||||
}
|
||||
|
||||
if len(accessPointARN.Region) == 0 {
|
||||
return arn.S3ObjectLambdaAccessPointARN{}, arn.InvalidARNError{ARN: a, Reason: fmt.Sprintf("%s region not set", s3ObjectsLambdaNamespace)}
|
||||
}
|
||||
|
||||
return arn.S3ObjectLambdaAccessPointARN{
|
||||
AccessPointARN: accessPointARN,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func endpointHandler(req *request.Request) {
|
||||
endpoint, ok := req.Params.(endpointARNGetter)
|
||||
if !ok || !endpoint.hasEndpointARN() {
|
||||
|
@ -116,6 +148,11 @@ func endpointHandler(req *request.Request) {
|
|||
if err != nil {
|
||||
req.Error = err
|
||||
}
|
||||
case arn.S3ObjectLambdaAccessPointARN:
|
||||
err = updateRequestS3ObjectLambdaAccessPointEndpoint(req, tv)
|
||||
if err != nil {
|
||||
req.Error = err
|
||||
}
|
||||
case arn.OutpostAccessPointARN:
|
||||
// outposts does not support FIPS regions
|
||||
if resReq.ResourceConfiguredForFIPS() {
|
||||
|
@ -162,6 +199,31 @@ func updateRequestAccessPointEndpoint(req *request.Request, accessPoint arn.Acce
|
|||
return nil
|
||||
}
|
||||
|
||||
func updateRequestS3ObjectLambdaAccessPointEndpoint(req *request.Request, accessPoint arn.S3ObjectLambdaAccessPointARN) error {
|
||||
// DualStack not supported
|
||||
if aws.BoolValue(req.Config.UseDualStack) {
|
||||
return s3shared.NewClientConfiguredForDualStackError(accessPoint,
|
||||
req.ClientInfo.PartitionID, aws.StringValue(req.Config.Region), nil)
|
||||
}
|
||||
|
||||
// Accelerate not supported
|
||||
if aws.BoolValue(req.Config.S3UseAccelerate) {
|
||||
return s3shared.NewClientConfiguredForAccelerateError(accessPoint,
|
||||
req.ClientInfo.PartitionID, aws.StringValue(req.Config.Region), nil)
|
||||
}
|
||||
|
||||
// Ignore the disable host prefix for access points
|
||||
req.Config.DisableEndpointHostPrefix = aws.Bool(false)
|
||||
|
||||
if err := s3ObjectLambdaAccessPointEndpointBuilder(accessPoint).build(req); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
removeBucketFromPath(req.HTTPRequest.URL)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func updateRequestOutpostAccessPointEndpoint(req *request.Request, accessPoint arn.OutpostAccessPointARN) error {
|
||||
// Accelerate not supported
|
||||
if aws.BoolValue(req.Config.S3UseAccelerate) {
|
||||
|
@ -192,3 +254,37 @@ func removeBucketFromPath(u *url.URL) {
|
|||
u.Path = "/"
|
||||
}
|
||||
}
|
||||
|
||||
func buildWriteGetObjectResponseEndpoint(req *request.Request) {
|
||||
// DualStack not supported
|
||||
if aws.BoolValue(req.Config.UseDualStack) {
|
||||
req.Error = awserr.New("ConfigurationError", "client configured for dualstack but not supported for operation", nil)
|
||||
return
|
||||
}
|
||||
|
||||
// Accelerate not supported
|
||||
if aws.BoolValue(req.Config.S3UseAccelerate) {
|
||||
req.Error = awserr.New("ConfigurationError", "client configured for accelerate but not supported for operation", nil)
|
||||
return
|
||||
}
|
||||
|
||||
signingName := s3ObjectsLambdaNamespace
|
||||
signingRegion := req.ClientInfo.SigningRegion
|
||||
|
||||
if !hasCustomEndpoint(req) {
|
||||
endpoint, err := resolveRegionalEndpoint(req, aws.StringValue(req.Config.Region), EndpointsID)
|
||||
if err != nil {
|
||||
req.Error = awserr.New(request.ErrCodeSerialization, "failed to resolve endpoint", err)
|
||||
return
|
||||
}
|
||||
signingRegion = endpoint.SigningRegion
|
||||
|
||||
if err = updateRequestEndpoint(req, endpoint.URL); err != nil {
|
||||
req.Error = err
|
||||
return
|
||||
}
|
||||
updateS3HostPrefixForS3ObjectLambda(req)
|
||||
}
|
||||
|
||||
redirectSigner(req, signingName, signingRegion)
|
||||
}
|
||||
|
|
|
@ -66,13 +66,9 @@ func (a accessPointEndpointBuilder) build(req *request.Request) error {
|
|||
if err = updateRequestEndpoint(req, endpoint.URL); err != nil {
|
||||
return err
|
||||
}
|
||||
const serviceEndpointLabel = "s3-accesspoint"
|
||||
|
||||
// dual stack provided by endpoint resolver
|
||||
cfgHost := req.HTTPRequest.URL.Host
|
||||
if strings.HasPrefix(cfgHost, "s3") {
|
||||
req.HTTPRequest.URL.Host = serviceEndpointLabel + cfgHost[2:]
|
||||
}
|
||||
updateS3HostForS3AccessPoint(req)
|
||||
}
|
||||
|
||||
protocol.HostPrefixBuilder{
|
||||
|
@ -98,6 +94,73 @@ func (a accessPointEndpointBuilder) hostPrefixLabelValues() map[string]string {
|
|||
}
|
||||
}
|
||||
|
||||
// s3ObjectLambdaAccessPointEndpointBuilder represents the endpoint builder for an s3 object lambda access point arn
|
||||
type s3ObjectLambdaAccessPointEndpointBuilder arn.S3ObjectLambdaAccessPointARN
|
||||
|
||||
// build builds the endpoint for corresponding access point arn
|
||||
//
|
||||
// For building an endpoint from access point arn, format used is:
|
||||
// - Access point endpoint format : {accesspointName}-{accountId}.s3-object-lambda.{region}.{dnsSuffix}
|
||||
// - example : myaccesspoint-012345678901.s3-object-lambda.us-west-2.amazonaws.com
|
||||
//
|
||||
// Access Point Endpoint requests are signed using "s3-object-lambda" as signing name.
|
||||
//
|
||||
func (a s3ObjectLambdaAccessPointEndpointBuilder) build(req *request.Request) error {
|
||||
resolveRegion := arn.S3ObjectLambdaAccessPointARN(a).Region
|
||||
cfgRegion := aws.StringValue(req.Config.Region)
|
||||
|
||||
if s3shared.IsFIPS(cfgRegion) {
|
||||
if aws.BoolValue(req.Config.S3UseARNRegion) && s3shared.IsCrossRegion(req, resolveRegion) {
|
||||
// FIPS with cross region is not supported, the SDK must fail
|
||||
// because there is no well defined method for SDK to construct a
|
||||
// correct FIPS endpoint.
|
||||
return s3shared.NewClientConfiguredForCrossRegionFIPSError(arn.S3ObjectLambdaAccessPointARN(a),
|
||||
req.ClientInfo.PartitionID, cfgRegion, nil)
|
||||
}
|
||||
resolveRegion = cfgRegion
|
||||
}
|
||||
|
||||
endpoint, err := resolveRegionalEndpoint(req, resolveRegion, EndpointsID)
|
||||
if err != nil {
|
||||
return s3shared.NewFailedToResolveEndpointError(arn.S3ObjectLambdaAccessPointARN(a),
|
||||
req.ClientInfo.PartitionID, cfgRegion, err)
|
||||
}
|
||||
|
||||
endpoint.URL = endpoints.AddScheme(endpoint.URL, aws.BoolValue(req.Config.DisableSSL))
|
||||
|
||||
endpoint.SigningName = s3ObjectsLambdaNamespace
|
||||
|
||||
if !hasCustomEndpoint(req) {
|
||||
if err = updateRequestEndpoint(req, endpoint.URL); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
updateS3HostPrefixForS3ObjectLambda(req)
|
||||
}
|
||||
|
||||
protocol.HostPrefixBuilder{
|
||||
Prefix: accessPointPrefixTemplate,
|
||||
LabelsFn: a.hostPrefixLabelValues,
|
||||
}.Build(req)
|
||||
|
||||
// signer redirection
|
||||
redirectSigner(req, endpoint.SigningName, endpoint.SigningRegion)
|
||||
|
||||
err = protocol.ValidateEndpointHost(req.Operation.Name, req.HTTPRequest.URL.Host)
|
||||
if err != nil {
|
||||
return s3shared.NewInvalidARNError(arn.S3ObjectLambdaAccessPointARN(a), err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a s3ObjectLambdaAccessPointEndpointBuilder) hostPrefixLabelValues() map[string]string {
|
||||
return map[string]string{
|
||||
accessPointPrefixLabel: arn.S3ObjectLambdaAccessPointARN(a).AccessPointName,
|
||||
accountIDPrefixLabel: arn.S3ObjectLambdaAccessPointARN(a).AccountID,
|
||||
}
|
||||
}
|
||||
|
||||
// outpostAccessPointEndpointBuilder represents the Endpoint builder for outpost access point arn.
|
||||
type outpostAccessPointEndpointBuilder arn.OutpostAccessPointARN
|
||||
|
||||
|
@ -114,7 +177,7 @@ func (o outpostAccessPointEndpointBuilder) build(req *request.Request) error {
|
|||
resolveService := o.Service
|
||||
|
||||
endpointsID := resolveService
|
||||
if resolveService == "s3-outposts" {
|
||||
if resolveService == s3OutpostsNamespace {
|
||||
endpointsID = "s3"
|
||||
}
|
||||
|
||||
|
@ -130,11 +193,7 @@ func (o outpostAccessPointEndpointBuilder) build(req *request.Request) error {
|
|||
if err = updateRequestEndpoint(req, endpoint.URL); err != nil {
|
||||
return err
|
||||
}
|
||||
// add url host as s3-outposts
|
||||
cfgHost := req.HTTPRequest.URL.Host
|
||||
if strings.HasPrefix(cfgHost, endpointsID) {
|
||||
req.HTTPRequest.URL.Host = resolveService + cfgHost[len(endpointsID):]
|
||||
}
|
||||
updateHostPrefix(req, endpointsID, resolveService)
|
||||
}
|
||||
|
||||
protocol.HostPrefixBuilder{
|
||||
|
@ -170,7 +229,6 @@ func resolveRegionalEndpoint(r *request.Request, region string, endpointsID stri
|
|||
}
|
||||
|
||||
func updateRequestEndpoint(r *request.Request, endpoint string) (err error) {
|
||||
|
||||
r.HTTPRequest.URL, err = url.Parse(endpoint + r.Operation.HTTPPath)
|
||||
if err != nil {
|
||||
return awserr.New(request.ErrCodeSerialization,
|
||||
|
@ -185,3 +243,19 @@ func redirectSigner(req *request.Request, signingName string, signingRegion stri
|
|||
req.ClientInfo.SigningName = signingName
|
||||
req.ClientInfo.SigningRegion = signingRegion
|
||||
}
|
||||
|
||||
func updateS3HostForS3AccessPoint(req *request.Request) {
|
||||
updateHostPrefix(req, "s3", s3AccessPointNamespace)
|
||||
}
|
||||
|
||||
func updateS3HostPrefixForS3ObjectLambda(req *request.Request) {
|
||||
updateHostPrefix(req, "s3", s3ObjectsLambdaNamespace)
|
||||
}
|
||||
|
||||
func updateHostPrefix(req *request.Request, oldEndpointPrefix, newEndpointPrefix string) {
|
||||
host := req.HTTPRequest.URL.Host
|
||||
if strings.HasPrefix(host, oldEndpointPrefix) {
|
||||
// replace service hostlabel oldEndpointPrefix to newEndpointPrefix
|
||||
req.HTTPRequest.URL.Host = newEndpointPrefix + host[len(oldEndpointPrefix):]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,13 +48,13 @@ const (
|
|||
// ErrCodeObjectAlreadyInActiveTierError for service response error code
|
||||
// "ObjectAlreadyInActiveTierError".
|
||||
//
|
||||
// This operation is not allowed against this storage tier.
|
||||
// This action is not allowed against this storage tier.
|
||||
ErrCodeObjectAlreadyInActiveTierError = "ObjectAlreadyInActiveTierError"
|
||||
|
||||
// ErrCodeObjectNotInActiveTierError for service response error code
|
||||
// "ObjectNotInActiveTierError".
|
||||
//
|
||||
// The source object of the COPY operation is not in the active tier and is
|
||||
// only stored in Amazon S3 Glacier.
|
||||
// The source object of the COPY action is not in the active tier and is only
|
||||
// stored in Amazon S3 Glacier.
|
||||
ErrCodeObjectNotInActiveTierError = "ObjectNotInActiveTierError"
|
||||
)
|
||||
|
|
|
@ -455,6 +455,10 @@ type S3API interface {
|
|||
UploadPartCopyWithContext(aws.Context, *s3.UploadPartCopyInput, ...request.Option) (*s3.UploadPartCopyOutput, error)
|
||||
UploadPartCopyRequest(*s3.UploadPartCopyInput) (*request.Request, *s3.UploadPartCopyOutput)
|
||||
|
||||
WriteGetObjectResponse(*s3.WriteGetObjectResponseInput) (*s3.WriteGetObjectResponseOutput, error)
|
||||
WriteGetObjectResponseWithContext(aws.Context, *s3.WriteGetObjectResponseInput, ...request.Option) (*s3.WriteGetObjectResponseOutput, error)
|
||||
WriteGetObjectResponseRequest(*s3.WriteGetObjectResponseInput) (*request.Request, *s3.WriteGetObjectResponseOutput)
|
||||
|
||||
WaitUntilBucketExists(*s3.HeadBucketInput) error
|
||||
WaitUntilBucketExistsWithContext(aws.Context, *s3.HeadBucketInput, ...request.WaiterOption) error
|
||||
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
package s3manager
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/aws/aws-sdk-go/aws/arn"
|
||||
)
|
||||
|
||||
func validateSupportedARNType(bucket string) error {
|
||||
if !arn.IsARN(bucket) {
|
||||
return nil
|
||||
}
|
||||
|
||||
parsedARN, err := arn.Parse(bucket)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if parsedARN.Service == "s3-object-lambda" {
|
||||
return fmt.Errorf("manager does not support s3-object-lambda service ARNs")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -192,6 +192,10 @@ func (d Downloader) Download(w io.WriterAt, input *s3.GetObjectInput, options ..
|
|||
// to perform a single GetObjectInput request for that object's range. This will
|
||||
// caused the part size, and concurrency configurations to be ignored.
|
||||
func (d Downloader) DownloadWithContext(ctx aws.Context, w io.WriterAt, input *s3.GetObjectInput, options ...func(*Downloader)) (n int64, err error) {
|
||||
if err := validateSupportedARNType(aws.StringValue(input.Bucket)); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
impl := downloader{w: w, in: input, cfg: d, ctx: ctx}
|
||||
|
||||
for _, option := range options {
|
||||
|
|
|
@ -391,6 +391,10 @@ func (u *uploader) upload() (*UploadOutput, error) {
|
|||
|
||||
// init will initialize all default options.
|
||||
func (u *uploader) init() error {
|
||||
if err := validateSupportedARNType(aws.StringValue(u.in.Bucket)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if u.cfg.Concurrency == 0 {
|
||||
u.cfg.Concurrency = DefaultUploadConcurrency
|
||||
}
|
||||
|
|
|
@ -23,21 +23,21 @@ type UploadInput struct {
|
|||
// The readable body payload to send to S3.
|
||||
Body io.Reader
|
||||
|
||||
// The bucket name to which the PUT operation was initiated.
|
||||
// The bucket name to which the PUT action was initiated.
|
||||
//
|
||||
// When using this API with an access point, you must direct requests to the
|
||||
// access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com.
|
||||
// When using this operation with an access point through the AWS SDKs, you
|
||||
// provide the access point ARN in place of the bucket name. For more information
|
||||
// about access point ARNs, see Using Access Points (https://docs.aws.amazon.com/AmazonS3/latest/dev/using-access-points.html)
|
||||
// When using this action with an access point, you must direct requests to
|
||||
// the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com.
|
||||
// When using this action with an access point through the AWS SDKs, you provide
|
||||
// the access point ARN in place of the bucket name. For more information about
|
||||
// access point ARNs, see Using Access Points (https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html)
|
||||
// in the Amazon Simple Storage Service Developer Guide.
|
||||
//
|
||||
// When using this API with Amazon S3 on Outposts, you must direct requests
|
||||
// When using this action with Amazon S3 on Outposts, you must direct requests
|
||||
// to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form
|
||||
// AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When
|
||||
// using this operation using S3 on Outposts through the AWS SDKs, you provide
|
||||
// using this action using S3 on Outposts through the AWS SDKs, you provide
|
||||
// the Outposts bucket ARN in place of the bucket name. For more information
|
||||
// about S3 on Outposts ARNs, see Using S3 on Outposts (https://docs.aws.amazon.com/AmazonS3/latest/dev/S3onOutposts.html)
|
||||
// about S3 on Outposts ARNs, see Using S3 on Outposts (https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html)
|
||||
// in the Amazon Simple Storage Service Developer Guide.
|
||||
//
|
||||
// Bucket is a required field
|
||||
|
@ -48,8 +48,8 @@ type UploadInput struct {
|
|||
// to true causes Amazon S3 to use an S3 Bucket Key for object encryption with
|
||||
// SSE-KMS.
|
||||
//
|
||||
// Specifying this header with a PUT operation doesn’t affect bucket-level
|
||||
// settings for S3 Bucket Key.
|
||||
// Specifying this header with a PUT action doesn’t affect bucket-level settings
|
||||
// for S3 Bucket Key.
|
||||
BucketKeyEnabled *bool `location:"header" locationName:"x-amz-server-side-encryption-bucket-key-enabled" type:"boolean"`
|
||||
|
||||
// Can be used to specify caching behavior along the request/reply chain. For
|
||||
|
@ -82,7 +82,7 @@ type UploadInput struct {
|
|||
// see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.17 (http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.17).
|
||||
ContentType *string `location:"header" locationName:"Content-Type" type:"string"`
|
||||
|
||||
// The account id of the expected bucket owner. If the bucket is owned by a
|
||||
// The account ID of the expected bucket owner. If the bucket is owned by a
|
||||
// different account, the request will fail with an HTTP 403 (Access Denied)
|
||||
// error.
|
||||
ExpectedBucketOwner *string `location:"header" locationName:"x-amz-expected-bucket-owner" type:"string"`
|
||||
|
@ -111,7 +111,7 @@ type UploadInput struct {
|
|||
// This action is not supported by Amazon S3 on Outposts.
|
||||
GrantWriteACP *string `location:"header" locationName:"x-amz-grant-write-acp" type:"string"`
|
||||
|
||||
// Object key for which the PUT operation was initiated.
|
||||
// Object key for which the PUT action was initiated.
|
||||
//
|
||||
// Key is a required field
|
||||
Key *string `location:"uri" locationName:"Key" min:"1" type:"string" required:"true"`
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -68,7 +68,7 @@ const (
|
|||
// ErrCodeMalformedPolicyDocumentException for service response error code
|
||||
// "MalformedPolicyDocumentException".
|
||||
//
|
||||
// The policy document that you provided isn't valid.
|
||||
// You provided a resource-based policy with syntax errors.
|
||||
ErrCodeMalformedPolicyDocumentException = "MalformedPolicyDocumentException"
|
||||
|
||||
// ErrCodePreconditionNotMetException for service response error code
|
||||
|
@ -80,7 +80,8 @@ const (
|
|||
// ErrCodePublicPolicyException for service response error code
|
||||
// "PublicPolicyException".
|
||||
//
|
||||
// The resource policy did not prevent broad access to the secret.
|
||||
// The BlockPublicPolicy parameter is set to true and the resource policy did
|
||||
// not prevent broad access to the secret.
|
||||
ErrCodePublicPolicyException = "PublicPolicyException"
|
||||
|
||||
// ErrCodeResourceExistsException for service response error code
|
||||
|
|
12
vendor/github.com/aws/aws-sdk-go/service/secretsmanager/secretsmanageriface/interface.go
generated
vendored
12
vendor/github.com/aws/aws-sdk-go/service/secretsmanager/secretsmanageriface/interface.go
generated
vendored
|
@ -114,6 +114,14 @@ type SecretsManagerAPI interface {
|
|||
PutSecretValueWithContext(aws.Context, *secretsmanager.PutSecretValueInput, ...request.Option) (*secretsmanager.PutSecretValueOutput, error)
|
||||
PutSecretValueRequest(*secretsmanager.PutSecretValueInput) (*request.Request, *secretsmanager.PutSecretValueOutput)
|
||||
|
||||
RemoveRegionsFromReplication(*secretsmanager.RemoveRegionsFromReplicationInput) (*secretsmanager.RemoveRegionsFromReplicationOutput, error)
|
||||
RemoveRegionsFromReplicationWithContext(aws.Context, *secretsmanager.RemoveRegionsFromReplicationInput, ...request.Option) (*secretsmanager.RemoveRegionsFromReplicationOutput, error)
|
||||
RemoveRegionsFromReplicationRequest(*secretsmanager.RemoveRegionsFromReplicationInput) (*request.Request, *secretsmanager.RemoveRegionsFromReplicationOutput)
|
||||
|
||||
ReplicateSecretToRegions(*secretsmanager.ReplicateSecretToRegionsInput) (*secretsmanager.ReplicateSecretToRegionsOutput, error)
|
||||
ReplicateSecretToRegionsWithContext(aws.Context, *secretsmanager.ReplicateSecretToRegionsInput, ...request.Option) (*secretsmanager.ReplicateSecretToRegionsOutput, error)
|
||||
ReplicateSecretToRegionsRequest(*secretsmanager.ReplicateSecretToRegionsInput) (*request.Request, *secretsmanager.ReplicateSecretToRegionsOutput)
|
||||
|
||||
RestoreSecret(*secretsmanager.RestoreSecretInput) (*secretsmanager.RestoreSecretOutput, error)
|
||||
RestoreSecretWithContext(aws.Context, *secretsmanager.RestoreSecretInput, ...request.Option) (*secretsmanager.RestoreSecretOutput, error)
|
||||
RestoreSecretRequest(*secretsmanager.RestoreSecretInput) (*request.Request, *secretsmanager.RestoreSecretOutput)
|
||||
|
@ -122,6 +130,10 @@ type SecretsManagerAPI interface {
|
|||
RotateSecretWithContext(aws.Context, *secretsmanager.RotateSecretInput, ...request.Option) (*secretsmanager.RotateSecretOutput, error)
|
||||
RotateSecretRequest(*secretsmanager.RotateSecretInput) (*request.Request, *secretsmanager.RotateSecretOutput)
|
||||
|
||||
StopReplicationToReplica(*secretsmanager.StopReplicationToReplicaInput) (*secretsmanager.StopReplicationToReplicaOutput, error)
|
||||
StopReplicationToReplicaWithContext(aws.Context, *secretsmanager.StopReplicationToReplicaInput, ...request.Option) (*secretsmanager.StopReplicationToReplicaOutput, error)
|
||||
StopReplicationToReplicaRequest(*secretsmanager.StopReplicationToReplicaInput) (*request.Request, *secretsmanager.StopReplicationToReplicaOutput)
|
||||
|
||||
TagResource(*secretsmanager.TagResourceInput) (*secretsmanager.TagResourceOutput, error)
|
||||
TagResourceWithContext(aws.Context, *secretsmanager.TagResourceInput, ...request.Option) (*secretsmanager.TagResourceOutput, error)
|
||||
TagResourceRequest(*secretsmanager.TagResourceInput) (*request.Request, *secretsmanager.TagResourceOutput)
|
||||
|
|
|
@ -15209,6 +15209,12 @@ type AddTagsToResourceInput struct {
|
|||
//
|
||||
// PatchBaseline: pb-012345abcde
|
||||
//
|
||||
// OpsMetadata object: ResourceID for tagging is created from the Amazon Resource
|
||||
// Name (ARN) for the object. Specifically, ResourceID is created from the strings
|
||||
// that come after the word opsmetadata in the ARN. For example, an OpsMetadata
|
||||
// object with an ARN of arn:aws:ssm:us-east-2:1234567890:opsmetadata/aws/ssm/MyGroup/appmanager
|
||||
// has a ResourceID of either aws/ssm/MyGroup/appmanager or /aws/ssm/MyGroup/appmanager.
|
||||
//
|
||||
// For the Document and Parameter values, use the name of the resource.
|
||||
//
|
||||
// The ManagedInstance type for this API action is only for on-premises managed
|
||||
|
@ -17898,6 +17904,149 @@ func (s *AutomationStepNotFoundException) RequestID() string {
|
|||
return s.RespMetadata.RequestID
|
||||
}
|
||||
|
||||
// Defines the basic information about a patch baseline override.
|
||||
type BaselineOverride struct {
|
||||
_ struct{} `type:"structure"`
|
||||
|
||||
// A set of rules defining the approval rules for a patch baseline.
|
||||
ApprovalRules *PatchRuleGroup `type:"structure"`
|
||||
|
||||
// A list of explicitly approved patches for the baseline.
|
||||
//
|
||||
// For information about accepted formats for lists of approved patches and
|
||||
// rejected patches, see About package name formats for approved and rejected
|
||||
// patch lists (https://docs.aws.amazon.com/systems-manager/latest/userguide/patch-manager-approved-rejected-package-name-formats.html)
|
||||
// in the AWS Systems Manager User Guide.
|
||||
ApprovedPatches []*string `type:"list"`
|
||||
|
||||
// Defines the compliance level for approved patches. When an approved patch
|
||||
// is reported as missing, this value describes the severity of the compliance
|
||||
// violation.
|
||||
ApprovedPatchesComplianceLevel *string `type:"string" enum:"PatchComplianceLevel"`
|
||||
|
||||
// Indicates whether the list of approved patches includes non-security updates
|
||||
// that should be applied to the instances. The default value is 'false'. Applies
|
||||
// to Linux instances only.
|
||||
ApprovedPatchesEnableNonSecurity *bool `type:"boolean"`
|
||||
|
||||
// A set of patch filters, typically used for approval rules.
|
||||
GlobalFilters *PatchFilterGroup `type:"structure"`
|
||||
|
||||
// The operating system rule used by the patch baseline override.
|
||||
OperatingSystem *string `type:"string" enum:"OperatingSystem"`
|
||||
|
||||
// A list of explicitly rejected patches for the baseline.
|
||||
//
|
||||
// For information about accepted formats for lists of approved patches and
|
||||
// rejected patches, see About package name formats for approved and rejected
|
||||
// patch lists (https://docs.aws.amazon.com/systems-manager/latest/userguide/patch-manager-approved-rejected-package-name-formats.html)
|
||||
// in the AWS Systems Manager User Guide.
|
||||
RejectedPatches []*string `type:"list"`
|
||||
|
||||
// The action for Patch Manager to take on patches included in the RejectedPackages
|
||||
// list. A patch can be allowed only if it is a dependency of another package,
|
||||
// or blocked entirely along with packages that include it as a dependency.
|
||||
RejectedPatchesAction *string `type:"string" enum:"PatchAction"`
|
||||
|
||||
// Information about the patches to use to update the instances, including target
|
||||
// operating systems and source repositories. Applies to Linux instances only.
|
||||
Sources []*PatchSource `type:"list"`
|
||||
}
|
||||
|
||||
// String returns the string representation
|
||||
func (s BaselineOverride) String() string {
|
||||
return awsutil.Prettify(s)
|
||||
}
|
||||
|
||||
// GoString returns the string representation
|
||||
func (s BaselineOverride) GoString() string {
|
||||
return s.String()
|
||||
}
|
||||
|
||||
// Validate inspects the fields of the type to determine if they are valid.
|
||||
func (s *BaselineOverride) Validate() error {
|
||||
invalidParams := request.ErrInvalidParams{Context: "BaselineOverride"}
|
||||
if s.ApprovalRules != nil {
|
||||
if err := s.ApprovalRules.Validate(); err != nil {
|
||||
invalidParams.AddNested("ApprovalRules", err.(request.ErrInvalidParams))
|
||||
}
|
||||
}
|
||||
if s.GlobalFilters != nil {
|
||||
if err := s.GlobalFilters.Validate(); err != nil {
|
||||
invalidParams.AddNested("GlobalFilters", err.(request.ErrInvalidParams))
|
||||
}
|
||||
}
|
||||
if s.Sources != nil {
|
||||
for i, v := range s.Sources {
|
||||
if v == nil {
|
||||
continue
|
||||
}
|
||||
if err := v.Validate(); err != nil {
|
||||
invalidParams.AddNested(fmt.Sprintf("%s[%v]", "Sources", i), err.(request.ErrInvalidParams))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if invalidParams.Len() > 0 {
|
||||
return invalidParams
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetApprovalRules sets the ApprovalRules field's value.
|
||||
func (s *BaselineOverride) SetApprovalRules(v *PatchRuleGroup) *BaselineOverride {
|
||||
s.ApprovalRules = v
|
||||
return s
|
||||
}
|
||||
|
||||
// SetApprovedPatches sets the ApprovedPatches field's value.
|
||||
func (s *BaselineOverride) SetApprovedPatches(v []*string) *BaselineOverride {
|
||||
s.ApprovedPatches = v
|
||||
return s
|
||||
}
|
||||
|
||||
// SetApprovedPatchesComplianceLevel sets the ApprovedPatchesComplianceLevel field's value.
|
||||
func (s *BaselineOverride) SetApprovedPatchesComplianceLevel(v string) *BaselineOverride {
|
||||
s.ApprovedPatchesComplianceLevel = &v
|
||||
return s
|
||||
}
|
||||
|
||||
// SetApprovedPatchesEnableNonSecurity sets the ApprovedPatchesEnableNonSecurity field's value.
|
||||
func (s *BaselineOverride) SetApprovedPatchesEnableNonSecurity(v bool) *BaselineOverride {
|
||||
s.ApprovedPatchesEnableNonSecurity = &v
|
||||
return s
|
||||
}
|
||||
|
||||
// SetGlobalFilters sets the GlobalFilters field's value.
|
||||
func (s *BaselineOverride) SetGlobalFilters(v *PatchFilterGroup) *BaselineOverride {
|
||||
s.GlobalFilters = v
|
||||
return s
|
||||
}
|
||||
|
||||
// SetOperatingSystem sets the OperatingSystem field's value.
|
||||
func (s *BaselineOverride) SetOperatingSystem(v string) *BaselineOverride {
|
||||
s.OperatingSystem = &v
|
||||
return s
|
||||
}
|
||||
|
||||
// SetRejectedPatches sets the RejectedPatches field's value.
|
||||
func (s *BaselineOverride) SetRejectedPatches(v []*string) *BaselineOverride {
|
||||
s.RejectedPatches = v
|
||||
return s
|
||||
}
|
||||
|
||||
// SetRejectedPatchesAction sets the RejectedPatchesAction field's value.
|
||||
func (s *BaselineOverride) SetRejectedPatchesAction(v string) *BaselineOverride {
|
||||
s.RejectedPatchesAction = &v
|
||||
return s
|
||||
}
|
||||
|
||||
// SetSources sets the Sources field's value.
|
||||
func (s *BaselineOverride) SetSources(v []*PatchSource) *BaselineOverride {
|
||||
s.Sources = v
|
||||
return s
|
||||
}
|
||||
|
||||
type CancelCommandInput struct {
|
||||
_ struct{} `type:"structure"`
|
||||
|
||||
|
@ -20847,6 +20996,18 @@ type CreateOpsMetadataInput struct {
|
|||
//
|
||||
// ResourceId is a required field
|
||||
ResourceId *string `min:"1" type:"string" required:"true"`
|
||||
|
||||
// Optional metadata that you assign to a resource. You can specify a maximum
|
||||
// of five tags for an OpsMetadata object. Tags enable you to categorize a resource
|
||||
// in different ways, such as by purpose, owner, or environment. For example,
|
||||
// you might want to tag an OpsMetadata object to identify an environment or
|
||||
// target AWS Region. In this case, you could specify the following key-value
|
||||
// pairs:
|
||||
//
|
||||
// * Key=Environment,Value=Production
|
||||
//
|
||||
// * Key=Region,Value=us-east-2
|
||||
Tags []*Tag `type:"list"`
|
||||
}
|
||||
|
||||
// String returns the string representation
|
||||
|
@ -20881,6 +21042,16 @@ func (s *CreateOpsMetadataInput) Validate() error {
|
|||
}
|
||||
}
|
||||
}
|
||||
if s.Tags != nil {
|
||||
for i, v := range s.Tags {
|
||||
if v == nil {
|
||||
continue
|
||||
}
|
||||
if err := v.Validate(); err != nil {
|
||||
invalidParams.AddNested(fmt.Sprintf("%s[%v]", "Tags", i), err.(request.ErrInvalidParams))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if invalidParams.Len() > 0 {
|
||||
return invalidParams
|
||||
|
@ -20900,6 +21071,12 @@ func (s *CreateOpsMetadataInput) SetResourceId(v string) *CreateOpsMetadataInput
|
|||
return s
|
||||
}
|
||||
|
||||
// SetTags sets the Tags field's value.
|
||||
func (s *CreateOpsMetadataInput) SetTags(v []*Tag) *CreateOpsMetadataInput {
|
||||
s.Tags = v
|
||||
return s
|
||||
}
|
||||
|
||||
type CreateOpsMetadataOutput struct {
|
||||
_ struct{} `type:"structure"`
|
||||
|
||||
|
@ -20938,8 +21115,8 @@ type CreatePatchBaselineInput struct {
|
|||
// in the AWS Systems Manager User Guide.
|
||||
ApprovedPatches []*string `type:"list"`
|
||||
|
||||
// Defines the compliance level for approved patches. This means that if an
|
||||
// approved patch is reported as missing, this is the severity of the compliance
|
||||
// Defines the compliance level for approved patches. When an approved patch
|
||||
// is reported as missing, this value describes the severity of the compliance
|
||||
// violation. The default value is UNSPECIFIED.
|
||||
ApprovedPatchesComplianceLevel *string `type:"string" enum:"PatchComplianceLevel"`
|
||||
|
||||
|
@ -27871,11 +28048,13 @@ type GetCommandInvocationInput struct {
|
|||
// InstanceId is a required field
|
||||
InstanceId *string `type:"string" required:"true"`
|
||||
|
||||
// (Optional) The name of the plugin for which you want detailed results. If
|
||||
// the document contains only one plugin, the name can be omitted and the details
|
||||
// will be returned.
|
||||
// The name of the plugin for which you want detailed results. If the document
|
||||
// contains only one plugin, you can omit the name and details for that plugin
|
||||
// are returned. If the document contains more than one plugin, you must specify
|
||||
// the name of the plugin for which you want to view details.
|
||||
//
|
||||
// Plugin names are also referred to as step names in Systems Manager documents.
|
||||
// For example, aws:RunShellScript is a plugin.
|
||||
PluginName *string `min:"4" type:"string"`
|
||||
}
|
||||
|
||||
|
@ -27973,8 +28152,8 @@ type GetCommandInvocationOutput struct {
|
|||
// configured for Systems Manager.
|
||||
InstanceId *string `type:"string"`
|
||||
|
||||
// The name of the plugin for which you want detailed results. For example,
|
||||
// aws:RunShellScript is a plugin.
|
||||
// The name of the plugin, or step name, for which details are reported. For
|
||||
// example, aws:RunShellScript is a plugin.
|
||||
PluginName *string `min:"4" type:"string"`
|
||||
|
||||
// The error level response code for the plugin script. If the response code
|
||||
|
@ -28297,6 +28476,9 @@ func (s *GetDefaultPatchBaselineOutput) SetOperatingSystem(v string) *GetDefault
|
|||
type GetDeployablePatchSnapshotForInstanceInput struct {
|
||||
_ struct{} `type:"structure"`
|
||||
|
||||
// Defines the basic information about a patch baseline override.
|
||||
BaselineOverride *BaselineOverride `type:"structure"`
|
||||
|
||||
// The ID of the instance for which the appropriate patch snapshot should be
|
||||
// retrieved.
|
||||
//
|
||||
|
@ -28331,6 +28513,11 @@ func (s *GetDeployablePatchSnapshotForInstanceInput) Validate() error {
|
|||
if s.SnapshotId != nil && len(*s.SnapshotId) < 36 {
|
||||
invalidParams.Add(request.NewErrParamMinLen("SnapshotId", 36))
|
||||
}
|
||||
if s.BaselineOverride != nil {
|
||||
if err := s.BaselineOverride.Validate(); err != nil {
|
||||
invalidParams.AddNested("BaselineOverride", err.(request.ErrInvalidParams))
|
||||
}
|
||||
}
|
||||
|
||||
if invalidParams.Len() > 0 {
|
||||
return invalidParams
|
||||
|
@ -28338,6 +28525,12 @@ func (s *GetDeployablePatchSnapshotForInstanceInput) Validate() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// SetBaselineOverride sets the BaselineOverride field's value.
|
||||
func (s *GetDeployablePatchSnapshotForInstanceInput) SetBaselineOverride(v *BaselineOverride) *GetDeployablePatchSnapshotForInstanceInput {
|
||||
s.BaselineOverride = v
|
||||
return s
|
||||
}
|
||||
|
||||
// SetInstanceId sets the InstanceId field's value.
|
||||
func (s *GetDeployablePatchSnapshotForInstanceInput) SetInstanceId(v string) *GetDeployablePatchSnapshotForInstanceInput {
|
||||
s.InstanceId = &v
|
||||
|
@ -30830,7 +31023,8 @@ func (s *GetPatchBaselineOutput) SetSources(v []*PatchSource) *GetPatchBaselineO
|
|||
type GetServiceSettingInput struct {
|
||||
_ struct{} `type:"structure"`
|
||||
|
||||
// The ID of the service setting to get. The setting ID can be /ssm/parameter-store/default-parameter-tier,
|
||||
// The ID of the service setting to get. The setting ID can be /ssm/automation/customer-script-log-destination,
|
||||
// /ssm/automation/customer-script-log-group-name, /ssm/parameter-store/default-parameter-tier,
|
||||
// /ssm/parameter-store/high-throughput-enabled, or /ssm/managed-instance/activation-tier.
|
||||
//
|
||||
// SettingId is a required field
|
||||
|
@ -31215,6 +31409,10 @@ func (s *InstanceAssociation) SetInstanceId(v string) *InstanceAssociation {
|
|||
}
|
||||
|
||||
// An S3 bucket where you want to store the results of this request.
|
||||
//
|
||||
// For the minimal permissions required to enable Amazon S3 output for an association,
|
||||
// see Creating associations (https://docs.aws.amazon.com/systems-manager/latest/userguide/sysman-state-assoc.html)
|
||||
// in the Systems Manager User Guide.
|
||||
type InstanceAssociationOutputLocation struct {
|
||||
_ struct{} `type:"structure"`
|
||||
|
||||
|
@ -31677,6 +31875,10 @@ type InstanceInformationStringFilter struct {
|
|||
// "InstanceIds"|"AgentVersion"|"PingStatus"|"PlatformTypes"|"ActivationIds"|"IamRole"|"ResourceType"|"AssociationStatus"|"Tag
|
||||
// Key"
|
||||
//
|
||||
// Tag key is not a valid filter. You must specify either tag-key or tag:keyname
|
||||
// and a string. Here are some valid examples: tag-key, tag:123, tag:al!, tag:Windows.
|
||||
// Here are some invalid examples: tag-keys, Tag Key, tag:, tagKey, abc:keyname.
|
||||
//
|
||||
// Key is a required field
|
||||
Key *string `min:"1" type:"string" required:"true"`
|
||||
|
||||
|
@ -42335,12 +42537,12 @@ type PatchRule struct {
|
|||
// The number of days after the release date of each patch matched by the rule
|
||||
// that the patch is marked as approved in the patch baseline. For example,
|
||||
// a value of 7 means that patches are approved seven days after they are released.
|
||||
// Not supported on Ubuntu Server.
|
||||
// Not supported on Debian Server or Ubuntu Server.
|
||||
ApproveAfterDays *int64 `type:"integer"`
|
||||
|
||||
// The cutoff date for auto approval of released patches. Any patches released
|
||||
// on or before this date are installed automatically. Not supported on Ubuntu
|
||||
// Server.
|
||||
// on or before this date are installed automatically. Not supported on Debian
|
||||
// Server or Ubuntu Server.
|
||||
//
|
||||
// Enter dates in the format YYYY-MM-DD. For example, 2020-12-31.
|
||||
ApproveUntilDate *string `min:"1" type:"string"`
|
||||
|
@ -43039,14 +43241,15 @@ type PutParameterInput struct {
|
|||
// * A parameter name can't be prefixed with "aws" or "ssm" (case-insensitive).
|
||||
//
|
||||
// * Parameter names can include only the following symbols and letters:
|
||||
// a-zA-Z0-9_.-/
|
||||
// a-zA-Z0-9_.- In addition, the slash character ( / ) is used to delineate
|
||||
// hierarchies in parameter names. For example: /Dev/Production/East/Project-ABC/MyParameter
|
||||
//
|
||||
// * A parameter name can't include spaces.
|
||||
//
|
||||
// * Parameter hierarchies are limited to a maximum depth of fifteen levels.
|
||||
//
|
||||
// For additional information about valid values for parameter names, see About
|
||||
// requirements and constraints for parameter names (https://docs.aws.amazon.com/systems-manager/latest/userguide/sysman-parameter-name-constraints.html)
|
||||
// For additional information about valid values for parameter names, see Creating
|
||||
// Systems Manager parameters (https://docs.aws.amazon.com/systems-manager/latest/userguide/sysman-paramstore-su-create.html)
|
||||
// in the AWS Systems Manager User Guide.
|
||||
//
|
||||
// The maximum length constraint listed below includes capacity for additional
|
||||
|
@ -43515,6 +43718,11 @@ type RegisterTargetWithMaintenanceWindowInput struct {
|
|||
// The targets to register with the maintenance window. In other words, the
|
||||
// instances to run commands on when the maintenance window runs.
|
||||
//
|
||||
// If a single maintenance window task is registered with multiple targets,
|
||||
// its task invocations occur sequentially and not in parallel. If your task
|
||||
// must run on multiple targets at the same time, register a task for each target
|
||||
// individually and assign each task the same priority level.
|
||||
//
|
||||
// You can specify targets using instance IDs, resource group names, or tags
|
||||
// that have been applied to instances.
|
||||
//
|
||||
|
@ -44005,6 +44213,12 @@ type RemoveTagsFromResourceInput struct {
|
|||
//
|
||||
// PatchBaseline: pb-012345abcde
|
||||
//
|
||||
// OpsMetadata object: ResourceID for tagging is created from the Amazon Resource
|
||||
// Name (ARN) for the object. Specifically, ResourceID is created from the strings
|
||||
// that come after the word opsmetadata in the ARN. For example, an OpsMetadata
|
||||
// object with an ARN of arn:aws:ssm:us-east-2:1234567890:opsmetadata/aws/ssm/MyGroup/appmanager
|
||||
// has a ResourceID of either aws/ssm/MyGroup/appmanager or /aws/ssm/MyGroup/appmanager.
|
||||
//
|
||||
// For the Document and Parameter values, use the name of the resource.
|
||||
//
|
||||
// The ManagedInstance type for this API action is only for on-premises managed
|
||||
|
@ -44095,7 +44309,8 @@ type ResetServiceSettingInput struct {
|
|||
_ struct{} `type:"structure"`
|
||||
|
||||
// The Amazon Resource Name (ARN) of the service setting to reset. The setting
|
||||
// ID can be /ssm/parameter-store/default-parameter-tier, /ssm/parameter-store/high-throughput-enabled,
|
||||
// ID can be /ssm/automation/customer-script-log-destination, /ssm/automation/customer-script-log-group-name,
|
||||
// /ssm/parameter-store/default-parameter-tier, /ssm/parameter-store/high-throughput-enabled,
|
||||
// or /ssm/managed-instance/activation-tier. For example, arn:aws:ssm:us-east-1:111122223333:servicesetting/ssm/parameter-store/high-throughput-enabled.
|
||||
//
|
||||
// SettingId is a required field
|
||||
|
@ -51007,6 +51222,10 @@ type UpdateServiceSettingInput struct {
|
|||
// arn:aws:ssm:us-east-1:111122223333:servicesetting/ssm/parameter-store/high-throughput-enabled.
|
||||
// The setting ID can be one of the following.
|
||||
//
|
||||
// * /ssm/automation/customer-script-log-destination
|
||||
//
|
||||
// * /ssm/automation/customer-script-log-group-name
|
||||
//
|
||||
// * /ssm/parameter-store/default-parameter-tier
|
||||
//
|
||||
// * /ssm/parameter-store/high-throughput-enabled
|
||||
|
@ -51028,6 +51247,12 @@ type UpdateServiceSettingInput struct {
|
|||
// For the /ssm/parameter-store/high-throughput-enabled, and /ssm/managed-instance/activation-tier
|
||||
// setting IDs, the setting value can be true or false.
|
||||
//
|
||||
// For the /ssm/automation/customer-script-log-destination setting ID, the setting
|
||||
// value can be CloudWatch.
|
||||
//
|
||||
// For the /ssm/automation/customer-script-log-group-name setting ID, the setting
|
||||
// value can be the name of a CloudWatch Logs log group.
|
||||
//
|
||||
// SettingValue is a required field
|
||||
SettingValue *string `min:"1" type:"string" required:"true"`
|
||||
}
|
||||
|
@ -53026,6 +53251,9 @@ const (
|
|||
|
||||
// ResourceTypeForTaggingOpsItem is a ResourceTypeForTagging enum value
|
||||
ResourceTypeForTaggingOpsItem = "OpsItem"
|
||||
|
||||
// ResourceTypeForTaggingOpsMetadata is a ResourceTypeForTagging enum value
|
||||
ResourceTypeForTaggingOpsMetadata = "OpsMetadata"
|
||||
)
|
||||
|
||||
// ResourceTypeForTagging_Values returns all elements of the ResourceTypeForTagging enum
|
||||
|
@ -53037,6 +53265,7 @@ func ResourceTypeForTagging_Values() []string {
|
|||
ResourceTypeForTaggingParameter,
|
||||
ResourceTypeForTaggingPatchBaseline,
|
||||
ResourceTypeForTaggingOpsItem,
|
||||
ResourceTypeForTaggingOpsMetadata,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// Copyright 2017, The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE.md file.
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package cmpopts provides common options for the cmp package.
|
||||
package cmpopts
|
||||
|
@ -11,7 +11,6 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
func equateAlways(_, _ interface{}) bool { return true }
|
||||
|
@ -147,10 +146,3 @@ func areConcreteErrors(x, y interface{}) bool {
|
|||
_, ok2 := y.(error)
|
||||
return ok1 && ok2
|
||||
}
|
||||
|
||||
func compareErrors(x, y interface{}) bool {
|
||||
xe := x.(error)
|
||||
ye := y.(error)
|
||||
// TODO(≥go1.13): Use standard definition of errors.Is.
|
||||
return xerrors.Is(xe, ye) || xerrors.Is(ye, xe)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
// Copyright 2021, The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build go1.13
|
||||
|
||||
package cmpopts
|
||||
|
||||
import "errors"
|
||||
|
||||
func compareErrors(x, y interface{}) bool {
|
||||
xe := x.(error)
|
||||
ye := y.(error)
|
||||
return errors.Is(xe, ye) || errors.Is(ye, xe)
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
// Copyright 2021, The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !go1.13
|
||||
|
||||
// TODO(≥go1.13): For support on <go1.13, we use the xerrors package.
|
||||
// Drop this file when we no longer support older Go versions.
|
||||
|
||||
package cmpopts
|
||||
|
||||
import "golang.org/x/xerrors"
|
||||
|
||||
func compareErrors(x, y interface{}) bool {
|
||||
xe := x.(error)
|
||||
ye := y.(error)
|
||||
return xerrors.Is(xe, ye) || xerrors.Is(ye, xe)
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
// Copyright 2017, The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE.md file.
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package cmpopts
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// Copyright 2017, The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE.md file.
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package cmpopts
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// Copyright 2017, The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE.md file.
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package cmpopts
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// Copyright 2018, The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE.md file.
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package cmpopts
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// Copyright 2017, The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE.md file.
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package cmp determines equality of values.
|
||||
//
|
||||
|
@ -100,8 +100,8 @@ func Equal(x, y interface{}, opts ...Option) bool {
|
|||
// same input values and options.
|
||||
//
|
||||
// The output is displayed as a literal in pseudo-Go syntax.
|
||||
// At the start of each line, a "-" prefix indicates an element removed from y,
|
||||
// a "+" prefix to indicates an element added to y, and the lack of a prefix
|
||||
// At the start of each line, a "-" prefix indicates an element removed from x,
|
||||
// a "+" prefix to indicates an element added from y, and the lack of a prefix
|
||||
// indicates an element common to both x and y. If possible, the output
|
||||
// uses fmt.Stringer.String or error.Error methods to produce more humanly
|
||||
// readable outputs. In such cases, the string is prefixed with either an
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// Copyright 2017, The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE.md file.
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build purego
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue