internal/pkg/cli/flag.go (403 lines of code) (raw):
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package cli
import (
"errors"
"fmt"
"strconv"
"strings"
"github.com/aws/copilot-cli/internal/pkg/manifest"
"github.com/aws/copilot-cli/internal/pkg/manifest/manifestinfo"
"github.com/dustin/go-humanize/english"
)
// Long flag names.
const (
// Common flags.
nameFlag = "name"
appFlag = "app"
envFlag = "env"
workloadFlag = "workload"
svcTypeFlag = "svc-type"
jobTypeFlag = "job-type"
typeFlag = "type"
profileFlag = "profile"
yesFlag = "yes"
jsonFlag = "json"
allFlag = "all"
forceFlag = "force"
allowDowngradeFlag = "allow-downgrade"
noRollbackFlag = "no-rollback"
manifestFlag = "manifest"
resourceTagsFlag = "resource-tags"
detachFlag = "detach"
// Deploy flags.
yesInitWorkloadFlag = "init-wkld"
// Build flags.
dockerFileFlag = "dockerfile"
dockerFileContextFlag = "build-context"
dockerFileBuildArgsFlag = "build-args"
imageTagFlag = "tag"
stackOutputDirFlag = "output-dir"
uploadAssetsFlag = "upload-assets"
deployFlag = "deploy"
diffFlag = "diff"
diffAutoApproveFlag = "diff-yes"
sourcesFlag = "sources"
// Flags for operational commands.
limitFlag = "limit"
lastFlag = "last"
followFlag = "follow"
previousFlag = "previous"
sinceFlag = "since"
startTimeFlag = "start-time"
endTimeFlag = "end-time"
tasksFlag = "tasks"
logGroupFlag = "log-group"
containerLogFlag = "container"
includeStateMachineLogsFlag = "include-state-machine"
resourcesFlag = "resources"
taskIDFlag = "task-id"
containerFlag = "container"
// Run local flags
portOverrideFlag = "port-override"
envVarOverrideFlag = "env-var-override"
proxyFlag = "proxy"
proxyNetworkFlag = "proxy-network"
watchFlag = "watch"
useTaskRoleFlag = "use-task-role"
// Flags for CI/CD.
githubURLFlag = "github-url"
repoURLFlag = "url"
githubAccessTokenFlag = "github-access-token"
gitBranchFlag = "git-branch"
envsFlag = "environments"
pipelineTypeFlag = "pipeline-type"
// Flags for ls.
localFlag = "local"
// Flags for storage.
storageTypeFlag = "storage-type"
storageLifecycleFlag = "lifecycle"
storageAddIngressFromFlag = "add-ingress-from"
storagePartitionKeyFlag = "partition-key"
storageSortKeyFlag = "sort-key"
storageNoSortFlag = "no-sort"
storageLSIConfigFlag = "lsi"
storageNoLSIFlag = "no-lsi"
storageAuroraServerlessVersionFlag = "serverless-version"
storageRDSEngineFlag = "engine"
storageRDSInitialDBFlag = "initial-db"
storageRDSParameterGroupFlag = "parameter-group"
// Flags for one-off tasks.
taskGroupNameFlag = "task-group-name"
countFlag = "count"
cpuFlag = "cpu"
memoryFlag = "memory"
imageFlag = "image"
taskRoleFlag = "task-role"
executionRoleFlag = "execution-role"
clusterFlag = "cluster"
acknowledgeSecretsAccessFlag = "acknowledge-secrets-access"
subnetsFlag = "subnets"
securityGroupsFlag = "security-groups"
envVarsFlag = "env-vars"
envFileFlag = "env-file"
secretsFlag = "secrets"
commandFlag = "command"
entrypointFlag = "entrypoint"
taskDefaultFlag = "default"
generateCommandFlag = "generate-cmd"
osFlag = "platform-os"
archFlag = "platform-arch"
// Flags for environment configurations.
vpcIDFlag = "import-vpc-id"
publicSubnetsFlag = "import-public-subnets"
privateSubnetsFlag = "import-private-subnets"
certsFlag = "import-cert-arns"
internalALBSubnetsFlag = "internal-alb-subnets"
allowVPCIngressFlag = "internal-alb-allow-vpc-ingress"
overrideVPCCIDRFlag = "override-vpc-cidr"
overrideAZsFlag = "override-az-names"
overridePublicSubnetCIDRsFlag = "override-public-cidrs"
overridePrivateSubnetCIDRsFlag = "override-private-cidrs"
enableContainerInsightsFlag = "container-insights"
defaultConfigFlag = "default-config"
accessKeyIDFlag = "aws-access-key-id"
secretAccessKeyFlag = "aws-secret-access-key"
sessionTokenFlag = "aws-session-token"
regionFlag = "region"
// Flags for creating secrets.
valuesFlag = "values"
overwriteFlag = "overwrite"
inputFilePathFlag = "cli-input-yaml"
// Flags for overriding templates.
iacToolFlag = "tool"
cdkLanguageFlag = "cdk-language"
skipResourcesFlag = "skip-resources"
// Other.
svcPortFlag = "port"
noSubscriptionFlag = "no-subscribe"
subscribeTopicsFlag = "subscribe-topics"
ingressTypeFlag = "ingress-type"
retriesFlag = "retries"
timeoutFlag = "timeout"
scheduleFlag = "schedule"
domainNameFlag = "domain"
permissionsBoundaryFlag = "permissions-boundary"
prodEnvFlag = "prod"
deleteSecretFlag = "delete-secret"
deployEnvFlag = "deploy-env"
yesInitEnvFlag = "init-env"
)
// Short flag names.
// A short flag only exists if the flag or flag set is mandatory by the command.
const (
nameFlagShort = "n"
appFlagShort = "a"
envFlagShort = "e"
typeFlagShort = "t"
workloadFlagShort = "w"
previousFlagShort = "p"
dockerFileFlagShort = "d"
commandFlagShort = "c"
imageFlagShort = "i"
repoURLFlagShort = "u"
githubAccessTokenFlagShort = "t"
gitBranchFlagShort = "b"
envsFlagShort = "e"
pipelineTypeShort = "p"
storageLifecycleShort = "l"
scheduleFlagShort = "s"
)
// Descriptions for flags.
var (
svcTypeFlagDescription = fmt.Sprintf(`Type of service to create. Must be one of:
%s.`, strings.Join(applyAll(manifestinfo.ServiceTypes(), strconv.Quote), ", "))
imageFlagDescription = fmt.Sprintf(`The location of an existing Docker image.
Cannot be specified with --%s or --%s.`, dockerFileFlag, dockerFileContextFlag)
dockerFileFlagDescription = fmt.Sprintf(`Path to the Dockerfile.
Cannot be specified with --%s.`, imageFlag)
dockerFileBuildArgsFlagDescription = fmt.Sprintf(`Key-value pairs converted to --build-args.
Cannot be specified with --%s.`, imageFlag)
dockerFileContextFlagDescription = fmt.Sprintf(`Path to the Docker build context.
Cannot be specified with --%s.`, imageFlag)
sourcesFlagDescription = fmt.Sprintf(`List of relative paths to source directories or files.
Must be specified with '--%s "Static Site"'.`, svcTypeFlag)
storageTypeFlagDescription = fmt.Sprintf(`Type of storage to add. Must be one of:
%s.`, strings.Join(applyAll(storageTypes, strconv.Quote), ", "))
storageLifecycleFlagDescription = fmt.Sprintf(`Whether the storage should be created and deleted
at the same time as a workload or an environment.
Must be one of: %s.`, english.OxfordWordSeries(applyAll(validLifecycleOptions, strconv.Quote), "or"))
storageAddIngressFromFlagDescription = fmt.Sprintf(`The workload that needs access to an
environment storage resource. Must be
specified with %q and %q.
Can be specified with %q.`,
fmt.Sprintf("--%s", nameFlag),
fmt.Sprintf("--%s", storageTypeFlag),
fmt.Sprintf("--%s", storageRDSEngineFlag))
jobTypeFlagDescription = fmt.Sprintf(`Type of job to create. Must be one of:
%s.`, strings.Join(applyAll(manifestinfo.JobTypes(), strconv.Quote), ", "))
wkldTypeFlagDescription = fmt.Sprintf(`Type of job or svc to create. Must be one of:
%s.`, strings.Join(applyAll(manifestinfo.WorkloadTypes(), strconv.Quote), ", "))
clusterFlagDescription = fmt.Sprintf(`Optional. The short name or full ARN of the cluster to run the task in.
Cannot be specified with --%s, --%s or --%s.`, appFlag, envFlag, taskDefaultFlag)
acknowledgeSecretsAccessDescription = fmt.Sprintf(`Optional. Skip the confirmation question and grant access to the secrets specified by --secrets flag.
This flag is useful only when '%s' flag is specified`, secretsFlag)
subnetsFlagDescription = fmt.Sprintf(`Optional. The subnet IDs for the task to use. Can be specified multiple times.
Cannot be specified with --%s, --%s or --%s.`, appFlag, envFlag, taskDefaultFlag)
securityGroupsFlagDescription = "Optional. Additional security group IDs for the task to use. Can be specified multiple times."
taskRunDefaultFlagDescription = fmt.Sprintf(`Optional. Run tasks in default cluster and default subnets.
Cannot be specified with --%s, --%s or --%s.`, appFlag, envFlag, subnetsFlag)
taskExecDefaultFlagDescription = fmt.Sprintf(`Optional. Execute commands in running tasks in default cluster and default subnets.
Cannot be specified with --%s or --%s.`, appFlag, envFlag)
taskDeleteDefaultFlagDescription = fmt.Sprintf(`Optional. Delete a task which was launched in the default cluster and subnets.
Cannot be specified with --%s or --%s.`, appFlag, envFlag)
taskEnvFlagDescription = fmt.Sprintf(`Optional. Name of the environment.
Cannot be specified with --%s, --%s or --%s.`, taskDefaultFlag, subnetsFlag, securityGroupsFlag)
taskAppFlagDescription = fmt.Sprintf(`Optional. Name of the application.
Cannot be specified with --%s, --%s or --%s.`, taskDefaultFlag, subnetsFlag, securityGroupsFlag)
osFlagDescription = fmt.Sprintf(`Optional. Operating system of the task. Must be specified along with '%s'.`, archFlag)
archFlagDescription = fmt.Sprintf(`Optional. Architecture of the task. Must be specified along with '%s'.`, osFlag)
secretNameFlagDescription = fmt.Sprintf(`The name of the secret.
Mutually exclusive with the --%s flag.`, inputFilePathFlag)
secretValuesFlagDescription = fmt.Sprintf(`Values of the secret in each environment. Specified as <environment>=<value> separated by commas.
Mutually exclusive with the --%s flag.`, inputFilePathFlag)
secretInputFilePathFlagDescription = fmt.Sprintf(`Optional. A YAML file in which the secret values are specified.
Mutually exclusive with the -%s ,--%s and --%s flags.`, nameFlagShort, nameFlag, valuesFlag)
iacToolFlagDescription = fmt.Sprintf(`Infrastructure as Code tool to override a template.
Must be one of: %s.`, strings.Join(applyAll(validIaCTools, strconv.Quote), ", "))
cdkLanguageFlagDescription = `Optional. The Cloud Development Kit language.`
overrideEnvFlagDescription = `Optional. Name of the environment to use when retrieving resources in a template.
Defaults to a random environment.`
skipResourcesFlagDescription = `Optional. Skip asking for which resources to override and generate empty IaC extension files.`
repoURLFlagDescription = fmt.Sprintf(`The repository URL to trigger your pipeline.
Supported providers are: %s.`, strings.Join(manifest.PipelineProviders, ", "))
ingressTypeFlagDescription = fmt.Sprintf(`Required for a Request-Driven Web Service. Allowed source of traffic to your service.
Must be one of %s.`, english.OxfordWordSeries(rdwsIngressOptions, "or"))
)
const (
// Common flags
appFlagDescription = "Name of the application."
envFlagDescription = "Name of the environment."
svcFlagDescription = "Name of the service."
jobFlagDescription = "Name of the job."
workloadFlagDescription = "Name of the service or job."
workloadsFlagDescription = "Names of the service or jobs to deploy, with an optional priority tag (e.g. fe/1, be/2, my-job/1)."
nameFlagDescription = "Name of the service, job, or task group."
yesFlagDescription = "Skips confirmation prompt."
resourceTagsFlagDescription = `Optional. Labels with a key and value separated by commas.
Allows you to categorize resources.`
diffFlagDescription = "Compares the generated CloudFormation template to the deployed stack."
diffAutoApproveFlagDescription = "Skip interactive approval of diff before deploying."
// Deployment.
deployFlagDescription = `Deploy your service or job to a new or existing environment.`
allowDowngradeFlagDescription = `Optional. Allow using an older version of Copilot to update Copilot components
updated by a newer version of Copilot.`
forceFlagDescription = `Optional. Force a new service deployment using the existing image.
Not available with the "Static Site" service type.`
noRollbackFlagDescription = `Optional. Disable automatic stack
rollback in case of deployment failure.
We do not recommend using this flag for a
production environment.`
forceEnvDeployFlagDescription = "Optional. Force update the environment stack template."
yesInitWorkloadFlagDescription = "Optional. When specified with --all, initialize all local workloads before deployment."
allWorkloadsFlagDescription = "Optional. Deploy all workloads with manifests in the current Copilot workspace."
detachFlagDescription = "Optional. Skip displaying CloudFormation deployment progress."
// Operational.
jsonFlagDescription = "Optional. Output in JSON format."
limitFlagDescription = `Optional. The maximum number of log events returned. Default is 10
unless any time filtering flags are set.`
lastFlagDescription = `Optional. The number of executions of the scheduled job for which
logs should be shown.`
followFlagDescription = "Optional. Specifies if the logs should be streamed."
previousFlagDescription = "Optional. Print logs for the last stopped task if exists."
sinceFlagDescription = `Optional. Only return logs newer than a relative duration like 5s, 2m, or 3h.
Defaults to all logs. Only one of start-time / since may be used.`
startTimeFlagDescription = `Optional. Only return logs after a specific date (RFC3339).
Defaults to all logs. Only one of start-time / since may be used.`
endTimeFlagDescription = `Optional. Only return logs before a specific date (RFC3339).
Defaults to all logs. Only one of end-time / follow may be used.`
tasksLogsFlagDescription = "Optional. Only return logs from specific task IDs."
includeStateMachineLogsFlagDescription = "Optional. Include logs from the state machine executions."
logGroupFlagDescription = "Optional. Only return logs from specific log group."
containerLogFlagDescription = "Optional. Return only logs from a specific container."
envResourcesFlagDescription = "Optional. Show the resources in your environment."
svcResourcesFlagDescription = "Optional. Show the resources in your service."
pipelineResourcesFlagDescription = "Optional. Show the resources in your pipeline."
localSvcFlagDescription = "Only show services in the workspace."
localJobFlagDescription = "Only show jobs in the workspace."
localPipelineFlagDescription = "Only show pipelines in the workspace."
// Run local
envVarOverrideFlagDescription = `Optional. Override environment variables passed to containers.
Format: [container]:KEY=VALUE. Omit container name to apply to all containers.`
portOverridesFlagDescription = `Optional. Override ports exposed by service. Format: <host port>:<service port>.
Example: --port-override 5000:80 binds localhost:5000 to the service's port 80.`
proxyFlagDescription = `Optional. Proxy outbound requests to your environment's VPC.`
proxyNetworkFlagDescription = `Optional. Set the IP Network used by --proxy.`
watchFlagDescription = `Optional. Watch changes to local files and restart containers when updated. Directories and files in the main .dockerignore file are ignored.`
useTaskRoleFlagDescription = "Optional. Run containers with TaskRole credentials instead of session credentials."
svcManifestFlagDescription = `Optional. Name of the environment in which the service was deployed;
output the manifest file used for that deployment.`
manifestFlagDescription = "Optional. Output the manifest file used for the deployment."
execYesFlagDescription = "Optional. Whether to update the Session Manager Plugin."
taskIDFlagDescription = "Optional. ID of the task you want to exec in."
execCommandFlagDescription = `Optional. The command that is passed to a running container.`
containerFlagDescription = "Optional. The specific container you want to exec in. By default the first essential container will be used."
// Build.
imageTagFlagDescription = `Optional. The tag for the container images Copilot builds from Dockerfiles.`
uploadAssetsFlagDescription = `Optional. Whether to upload assets (container images, Lambda functions, etc.).
Uploaded asset locations are filled in the template configuration.`
stackOutputDirFlagDescription = "Optional. Writes the stack template and template configuration to a directory."
// CI/CD.
pipelineFlagDescription = "Name of the pipeline."
githubURLFlagDescription = "(Deprecated.) Use '--url' instead. Repository URL to trigger your pipeline."
githubAccessTokenFlagDescription = "GitHub personal access token for your repository."
gitBranchFlagDescription = "Branch used to trigger your pipeline."
pipelineEnvsFlagDescription = "Environments to add to the pipeline."
pipelineTypeFlagDescription = `The type of pipeline. Must be either "Workloads" or "Environments".`
// Storage.
storageFlagDescription = "Name of the storage resource to create."
storageWorkloadFlagDescription = "Name of the service/job that accesses the storage."
storagePartitionKeyFlagDescription = `Partition key for the DDB table.
Must be of the format '<keyName>:<dataType>'.`
storageSortKeyFlagDescription = `Optional. Sort key for the DDB table.
Must be of the format '<keyName>:<dataType>'.`
storageNoSortFlagDescription = "Optional. Skip configuring sort keys."
storageNoLSIFlagDescription = `Optional. Don't ask about configuring alternate sort keys.`
storageLSIConfigFlagDescription = `Optional. Attribute to use as an alternate sort key. May be specified up to 5 times.
Must be of the format '<keyName>:<dataType>'.`
storageAuroraServerlessVersionFlagDescription = `Optional. Aurora Serverless version.
With "environment" lifecycle, use "v2".
With "workload" lifecycle, use "v1" or "v2".
`
storageRDSEngineFlagDescription = `The database engine used in the cluster.
Must be either "MySQL" or "PostgreSQL".`
storageRDSInitialDBFlagDescription = "The initial database to create in the cluster."
storageRDSParameterGroupFlagDescription = "Optional. The name of the parameter group to associate with the cluster."
// One-off tasks.
countFlagDescription = "Optional. The number of tasks to set up."
cpuFlagDescription = "Optional. The number of CPU units to reserve for each task."
memoryFlagDescription = "Optional. The amount of memory to reserve in MiB for each task."
taskRoleFlagDescription = "Optional. The ARN of the role for the task to use."
executionRoleFlagDescription = "Optional. The ARN of the role that grants the container agent permission to make AWS API calls."
envVarsFlagDescription = "Optional. Environment variables specified by key=value separated by commas."
envFileFlagDescription = `Optional. A path to an environment variable (.env) file.
Each line should be of the form of VARIABLE=VALUE.
Values specified with --env-vars take precedence over --env-file.`
secretsFlagDescription = "Optional. Secrets to inject into the container. Specified by key=value separated by commas."
runCommandFlagDescription = `Optional. The command that is passed to "docker run" to override the default command.`
entrypointFlagDescription = `Optional. The entrypoint that is passed to "docker run" to override the default entrypoint.`
taskGroupFlagDescription = `Optional. The group name of the task.
Tasks with the same group name share the same set of resources.
(default directory name)`
taskImageTagFlagDescription = `Optional. The container image tag in addition to "latest".`
generateCommandFlagDescription = `Optional. Generate a command with a pre-filled value for each flag.
To use it for an ECS service, specify --generate-cmd <cluster name>/<service name>.
Alternatively, if the service or job is created with Copilot, specify --generate-cmd <application>/<environment>/<service or job name>.
Cannot be specified with any other flags.`
// Environment configurations.
vpcIDFlagDescription = "Optional. Use an existing VPC ID."
publicSubnetsFlagDescription = "Optional. Use existing public subnet IDs."
privateSubnetsFlagDescription = "Optional. Use existing private subnet IDs."
certsFlagDescription = "Optional. Apply existing ACM certificates to the internet-facing load balancer."
internalALBSubnetsFlagDescription = `Optional. Specify subnet IDs for an internal load balancer.
By default, the load balancer will be placed in your private subnets.
Cannot be specified with --default-config or any of the --override flags.`
allowVPCIngressFlagDescription = `Optional. Allow internal ALB ingress from port 80 and/or port 443.`
overrideVPCCIDRFlagDescription = `Optional. Global CIDR to use for VPC.
(default 10.0.0.0/16)`
overrideAZsFlagDescription = `Optional. Availability Zone names.
(default 2 random AZs)`
overridePublicSubnetCIDRsFlagDescription = `Optional. CIDR to use for public subnets.
(default 10.0.0.0/24,10.0.1.0/24)`
overridePrivateSubnetCIDRsFlagDescription = `Optional. CIDR to use for private subnets.
(default 10.0.2.0/24,10.0.3.0/24)`
enableContainerInsightsFlagDescription = "Optional. Enable CloudWatch Container Insights."
defaultConfigFlagDescription = "Optional. Skip prompting and use default environment configuration."
profileFlagDescription = "Name of the profile for the environment account."
accessKeyIDFlagDescription = "Optional. An AWS access key for the environment account."
secretAccessKeyFlagDescription = "Optional. An AWS secret access key for the environment account."
sessionTokenFlagDescription = "Optional. An AWS session token for temporary credentials."
envRegionTokenFlagDescription = "Optional. An AWS region where the environment will be created."
// Other.
domainNameFlagDescription = "Optional. Your existing custom domain name."
deleteSecretFlagDescription = "Deletes AWS Secrets Manager secret associated with a pipeline source repository."
svcPortFlagDescription = "The port on which your service listens."
noSubscriptionFlagDescription = "Optional. Turn off selection for adding subscriptions for worker services."
subscribeTopicsFlagDescription = `Optional. SNS topics to subscribe to from other services in your application.
Must be of format '<svcName>:<topicName>'.`
retriesFlagDescription = "Optional. The number of times to try restarting the job on a failure."
timeoutFlagDescription = `Optional. The total execution time for the task, including retries.
Accepts valid Go duration strings. For example: "2h", "1h30m", "900s".`
scheduleFlagDescription = `The schedule on which to run this job.
Accepts cron expressions of the format (M H DoM M DoW) and schedule definition strings.
For example: "0 * * * *", "@daily", "@weekly", "@every 1h30m".
AWS Schedule Expressions of the form "rate(10 minutes)" or "cron(0 12 L * ? 2021)"
are also accepted.`
upgradeAllEnvsDescription = "Optional. Upgrade all environments."
secretOverwriteFlagDescription = "Optional. Whether to overwrite an existing secret."
permissionsBoundaryFlagDescription = `Optional. The name or ARN of an existing IAM policy with which to set a
permissions boundary for all roles generated within the application.`
prodEnvFlagDescription = "If the environment contains production services."
deployEnvFlagDescription = "Deploy the target environment before deploying the workload."
yesInitEnvFlagDescription = "Confirm initializing the target environment if it does not exist."
)
type portOverride struct {
host string
container string
}
type portOverrides []portOverride
func (p *portOverrides) Set(val string) error {
err := errors.New("should be in format 8080:80")
split := strings.Split(val, ":")
if len(split) != 2 {
return err
}
if _, ok := strconv.Atoi(split[0]); ok != nil {
return err
}
if _, ok := strconv.Atoi(split[1]); ok != nil {
return err
}
*p = append(*p, portOverride{
host: split[0],
container: split[1],
})
return nil
}
func (p *portOverrides) Type() string {
return "list"
}
func (p *portOverrides) String() string {
return fmt.Sprintf("%+v", *p)
}