tree

package
v0.8.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 19, 2026 License: MIT Imports: 14 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	AMICmd = &cobra.Command{
		Use:   "ami",
		Short: "Convert a container image to an EC2 AMI",
		PreRunE: func(cmd *cobra.Command, args []string) error {
			cmd.SilenceUsage = true

			assetDir, err := expandPath(amiCfg.assetDir)
			if err != nil {
				return fmt.Errorf("failed to expand asset directory path: %w", err)
			}
			if _, err = os.Stat(assetDir); os.IsNotExist(err) {
				return fmt.Errorf("asset directory does not exist: %s", assetDir)
			}
			amiCfg.assetDir = assetDir

			packerDir, err := expandPath(amiCfg.packerDir)
			if err != nil {
				return fmt.Errorf("failed to expand packer directory path: %w", err)
			}
			if _, err = os.Stat(packerDir); os.IsNotExist(err) {
				return fmt.Errorf("packer directory does not exist: %s", packerDir)
			}
			amiCfg.packerDir = packerDir

			svcErr := validateServices(amiCfg.services)
			sshErr := validateSSHInterface(amiCfg.sshInterface)
			modeErr := validateBuilderImageMode(amiCfg.builderImageMode, amiCfg.builderImage)
			return errors.Join(svcErr, sshErr, modeErr)
		},
		RunE: func(cmd *cobra.Command, args []string) error {
			ctx := context.Background()

			resp, err := sourceami.Resolve(ctx, amiCfg.builderImage, constants.ETVersion)
			if err != nil {
				return fmt.Errorf("failed to resolve builder AMI: %w", err)
			}

			if amiCfg.builderImage != "" && amiCfg.builderImageMode == "" {
				fmt.Println("No --builder-image-mode specified, defaulting to slow mode")
			}

			if amiCfg.builderImageMode != "" {
				switch amiCfg.builderImageMode {
				case "fast":
					resp.Mode = sourceami.ModeFast
				case "slow":
					resp.Mode = sourceami.ModeSlow
				}
			}

			var packerSubdir, sshUsername string
			switch resp.Mode {
			case sourceami.ModeFast:
				packerSubdir = "fast"
				sshUsername = "cloudboss"
			case sourceami.ModeSlow:
				packerSubdir = "slow"
				sshUsername = "admin"
				if amiCfg.builderImage == "" {
					fmt.Printf("Builder AMI %s%s not found, falling back to slow mode\n",
						constants.AMIPatternCloudboss, constants.ETVersion)
				}
			}

			if amiCfg.builderImage != "" {
				sshUsername = amiCfg.builderImageLoginUser
			}

			if amiCfg.debug {
				fmt.Printf("Using %s path with AMI %s\n", packerSubdir, resp.AMI)
			}

			quotedServices := bytes.NewBufferString("")
			err = json.NewEncoder(quotedServices).Encode(amiCfg.services)
			if err != nil {
				return fmt.Errorf("unexpected value for services: %w", err)
			}

			packerArgs := []string{
				"build",
				"-var", fmt.Sprintf("ami_name=%s", amiCfg.amiName),
				"-var", fmt.Sprintf("container_image=%s", amiCfg.containerImage),
				"-var", fmt.Sprintf("debug=%t", amiCfg.debug),
				"-var", fmt.Sprintf("is_public=%t", amiCfg.public),
				"-var", fmt.Sprintf("login_user=%s", amiCfg.loginUser),
				"-var", fmt.Sprintf("login_shell=%s", amiCfg.loginShell),
				"-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("source_ami=%s", resp.AMI),
				"-var", fmt.Sprintf("ssh_interface=%s", amiCfg.sshInterface),
				"-var", fmt.Sprintf("ssh_username=%s", sshUsername),
				"-var", fmt.Sprintf("subnet_id=%s", amiCfg.subnetID),
			}

			if resp.Mode == sourceami.ModeSlow {
				packerArgs = append(packerArgs, "-var", fmt.Sprintf("asset_dir=%s", amiCfg.assetDir))
			}

			packerArgs = append(packerArgs, "build.pkr.hcl")

			packerWorkDir := filepath.Join(amiCfg.packerDir, packerSubdir)
			packer := exec.Command(filepath.Join(amiCfg.packerDir, "packer"), packerArgs...)

			packer.Stdin = os.Stdin
			packer.Stdout = os.Stdout
			packer.Stderr = os.Stderr

			packer.Dir = packerWorkDir

			packer.Env = append(os.Environ(), []string{
				"CHECKPOINT_DISABLE=1",
				fmt.Sprintf("PACKER_PLUGIN_PATH=%s/plugins", amiCfg.packerDir),
			}...)

			if amiCfg.debug {
				fmt.Printf("%+v\n", packer)
			}

			cmd.SilenceUsage = true

			return packer.Run()
		},
	}
)
View Source
var (
	CopyBuilderCmd = &cobra.Command{
		Use:   "copy-builder",
		Short: "Copy the official easyto builder AMI to your account/region",
		RunE: func(cmd *cobra.Command, args []string) error {
			cmd.SilenceUsage = true

			ctx := context.Background()

			cfg := copybuilder.Config{
				SourceRegion: copyBuilderCfg.sourceRegion,
				DestRegion:   copyBuilderCfg.destRegion,
				Version:      copyBuilderCfg.version,
				Name:         copyBuilderCfg.name,
				CopyTags:     copyBuilderCfg.copyTags,
				Wait:         copyBuilderCfg.wait,
				Public:       copyBuilderCfg.public,
				Output:       os.Stdout,
			}

			result, err := copybuilder.Copy(ctx, cfg)
			if err != nil {
				return err
			}

			cmd.Printf("Copied %s (%s) to %s (%s)\n",
				result.SourceName, result.SourceAMI,
				result.DestName, result.DestAMI)
			return nil
		},
	}
)
View Source
var (
	RootCmd = &cobra.Command{
		Use:   "easyto",
		Short: "A container image conversion tool",
	}
)
View Source
var (
	VersionCmd = &cobra.Command{
		Use:   "version",
		Short: "Show the version of easyto",
		Run: func(cmd *cobra.Command, args []string) {
			cmd.Println(constants.ETVersion)
		},
	}
)

Functions

This section is empty.

Types

This section is empty.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL