diff --git a/Makefile b/Makefile index 31daec0..7d908f1 100644 --- a/Makefile +++ b/Makefile @@ -31,7 +31,7 @@ EASYTO_ASSETS_RUNTIME = easyto-assets-runtime-$(EASYTO_ASSETS_VERSION) EASYTO_ASSETS_RUNTIME_ARCHIVE = $(EASYTO_ASSETS_RUNTIME).tar.gz EASYTO_ASSETS_RUNTIME_URL = $(EASYTO_ASSETS_RELEASES)/$(EASYTO_ASSETS_VERSION)/$(EASYTO_ASSETS_RUNTIME_ARCHIVE) EASYTO_INIT_RELEASES = https://github.com/cloudboss/easyto-init/releases/download -EASYTO_INIT_VERSION = v0.1.1 +EASYTO_INIT_VERSION = v0.2.0 EASYTO_INIT = easyto-init-$(EASYTO_INIT_VERSION) EASYTO_INIT_ARCHIVE = easyto-init-$(EASYTO_INIT_VERSION).tar.gz EASYTO_INIT_URL = $(EASYTO_INIT_RELEASES)/$(EASYTO_INIT_VERSION)/$(EASYTO_INIT_ARCHIVE) diff --git a/README.md b/README.md index f274a39..ecb80f4 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,8 @@ The `ami` subcommand takes the following options: `--root-device-name`: (Optional, default `/dev/xvda`) - Name of the AMI root device. +`--ssh-interface`: (Optional, default `public_ip`) - The SSH interface to use to connect to the image builder. This must be one of `public_ip` or `private_ip`. + `--debug`: (Optional) - Enable debug output. `--help` or `-h`: (Optional) - Show help output. @@ -77,10 +79,9 @@ env-from: volumes: - ebs: device: /dev/sdb - fs-type: ext4 - make-fs: true mount: destination: /var/lib/postgresql + fs-type: ext4 ``` See the [examples](./examples) folder for more. @@ -222,11 +223,14 @@ The following sources are available for environment variables. Each can be speci #### ebs-volume object -`device`: (Required, type _string_) - Name of the device as defined in the EC2 instance's block device mapping. +`attachment`: (Optional, type _list_ of [_ebs-attachment_](#ebs-attachment-object)) - Configuration of EBS volume attachment, which enables a volume to be attached at runtime based on its tags. + +> [!NOTE] +> The EC2 instance must have an instance profile with permission to call `ec2:AttachVolume` and `ec2:DescribeVolumes`. -`fs-type`: (Required, type _string_) - Filesystem type of the device. Available types are `ext2`, `ext3`, `ext4`, and `btrfs`. The filesystem will be formatted on the first boot. +`device`: (Required, type _string_) - Name of the device as defined in the EC2 instance's block device mapping. -`mount`: (Required, type [_mount_](#mount-object) object) - Configuration of the mount for the EBS volume. +`mount`: (Optional, type [_mount_](#mount-object) object) - Configuration of the mount for the EBS volume. If not defined, no filesystem will be formatted and the volume will not be mounted. #### s3-volume object @@ -275,10 +279,24 @@ A Secrets Manager volume is a pseudo-volume, as the secret from Secrets Manager `secret-id`: (Required, type _string_) - The name or ARN of the secret. If it is in another AWS account, the ARN must be used. +#### ebs-attachment object + +`tags`: (Required, type [_tag-key-value_](#tag-key-value-object)) - A list of tags used to filter the EBS volume when calling `ec2:DescribeVolumes`. + +`timeout`: (Optional, type _int_, default `300`) - How long to wait in seconds for the EBS volume to be available. + +#### tag-key-value object + +`key`: (Required, type _string_) - The name of the tag. + +`value`: (Optional, type _string_) - The value of the tag. If not defined, only the key is used as a filter. + #### mount object `destination`: (Required, type _string_) - The mount destination. This may be a file or a directory depending on the configuration of the volume. +`fs-type`: (Conditional, type _string_) - Filesystem type of the device. Available types are `ext2`, `ext3`, `ext4`, and `btrfs`. The filesystem will be formatted on the first boot. Required for EBS volumes and ignored otherwise. + `group-id`: (Optional, type _int_, default is the value of `security.run-as-group-id`) - The group ID of the destination. `mode`: (Optional, type _string_, default `0755`) - The mode of the destination. diff --git a/cmd/easyto/tree/ami.go b/cmd/easyto/tree/ami.go index 43bd1ca..1523e4a 100644 --- a/cmd/easyto/tree/ami.go +++ b/cmd/easyto/tree/ami.go @@ -3,6 +3,7 @@ package tree import ( "bytes" "encoding/json" + "errors" "fmt" "os" "os/exec" @@ -40,7 +41,9 @@ var ( } amiCfg.packerDir = packerDir - return validateServices(amiCfg.services) + svcErr := validateServices(amiCfg.services) + sshErr := validateSSHInterface(amiCfg.sshInterface) + return errors.Join(svcErr, sshErr) }, RunE: func(cmd *cobra.Command, args []string) error { quotedServices := bytes.NewBufferString("") @@ -61,6 +64,7 @@ var ( "-var", fmt.Sprintf("root_device_name=%s", amiCfg.rootDeviceName), "-var", fmt.Sprintf("root_vol_size=%d", amiCfg.size), "-var", fmt.Sprintf("services=%s", quotedServices.String()), + "-var", fmt.Sprintf("ssh_interface=%s", amiCfg.sshInterface), "-var", fmt.Sprintf("subnet_id=%s", amiCfg.subnetID), "build.pkr.hcl", } @@ -100,6 +104,7 @@ type amiConfig struct { rootDeviceName string services []string size int + sshInterface string subnetID string } @@ -154,13 +159,16 @@ func init() { amiCmd.Flags().StringVar(&amiCfg.rootDeviceName, "root-device-name", "/dev/xvda", "Name of the AMI root device.") + amiCmd.Flags().StringSliceVar(&amiCfg.services, "services", []string{"chrony"}, + "Comma separated list of services to enable [chrony,ssh]. Use an empty string to disable all services.") + + amiCmd.Flags().StringVarP(&amiCfg.sshInterface, "ssh-interface", "i", "public_ip", + "The interface for ssh connection to the builder. Must be one of 'public_ip' or 'private_ip'.") + amiCmd.Flags().StringVarP(&amiCfg.subnetID, "subnet-id", "s", "", "ID of the subnet in which to run the image builder.") amiCmd.MarkFlagRequired("subnet-id") - amiCmd.Flags().StringSliceVar(&amiCfg.services, "services", []string{"chrony"}, - "Comma separated list of services to enable [chrony,ssh]. Use an empty string to disable all services.") - amiCmd.Flags().BoolVar(&amiCfg.debug, "debug", false, "Enable debug output.") } @@ -191,3 +199,12 @@ func validateServices(services []string) error { } return nil } + +func validateSSHInterface(sshInterface string) error { + switch sshInterface { + case "public_ip", "private_ip": + return nil + default: + return fmt.Errorf("invalid ssh interface %s", sshInterface) + } +}