From 4b259f57d9460fcf04a7175abbaec4d4a553836c Mon Sep 17 00:00:00 2001 From: Jocelyn Giroux Date: Wed, 10 Jan 2018 14:58:22 -0500 Subject: [PATCH] Fix breaking change with new Docker version (symbolic links no longer supported on mapping) Add --no-temp option to allow disabling mapping of temporary folder. Refactoring of the options management Print environment variables on --debug --- .gitignore | 1 + README.md | 51 +++++++++++++++++++--------------------- docker.go | 30 +++++++++++++++--------- main.go | 69 +++++++++++++++++++++++------------------------------- 4 files changed, 73 insertions(+), 78 deletions(-) diff --git a/.gitignore b/.gitignore index 4482e91b..6a0d468c 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ .pkg dist vendor +tasks.json diff --git a/README.md b/README.md index 5f10f854..fccc88a5 100644 --- a/README.md +++ b/README.md @@ -38,19 +38,19 @@ or install it through command line: On `OSX`: ```bash -curl -sL https://github.com/coveo/tgf/releases/download/v1.15.3/tgf_1.15.3_macOS_64-bits.zip | bsdtar -xf- -C /usr/local/bin && chmod +x /usr/local/bin/tgf +curl -sL https://github.com/coveo/tgf/releases/download/v1.15.4/tgf_1.15.4_macOS_64-bits.zip | bsdtar -xf- -C /usr/local/bin && chmod +x /usr/local/bin/tgf ``` On `Linux`: ```bash -curl -sL https://github.com/coveo/tgf/releases/download/v1.15.3/tgf_1.15.3_linux_64-bits.zip | gzip -d > /usr/local/bin/tgf && chmod +x /usr/local/bin/tgf +curl -sL https://github.com/coveo/tgf/releases/download/v1.15.4/tgf_1.15.4_linux_64-bits.zip | gzip -d > /usr/local/bin/tgf && chmod +x /usr/local/bin/tgf ``` On `Windows` with Powershell: ```powershell -Invoke-WebRequest https://github.com/coveo/tgf/releases/download/v1.15.3/tgf_1.15.3_windows_64-bits.zip -OutFile tgf.zip +Invoke-WebRequest https://github.com/coveo/tgf/releases/download/v1.15.4/tgf_1.15.4_windows_64-bits.zip -OutFile tgf.zip ``` ## Configuration @@ -105,61 +105,58 @@ Note: *The key names are not case sensitive* > tgf usage: tgf [] -DESCRIPTION: -TGF (terragrunt frontend) is a Docker frontend for terragrunt/terraform. It automatically maps your current -folder, your HOME folder, your TEMP folder as well of most environment variables to the docker process. You -can add -D to your command to get the exact docker command that is generated. +DESCRIPTION: TGF (terragrunt frontend) is a Docker frontend for terragrunt/terraform. It automatically maps your current folder, your HOME folder, your TEMP folder as well of most +environment variables to the docker process. You can add -D to your command to get the exact docker command that is generated. -It then looks in your current folder and all its parents to find a file named '.tgf.config' to retrieve the -default configuration. If not all configurable values are satisfied and you have an AWS configuration, it -will then try to retrieve the missing elements from the AWS Parameter Store under the key '/default/tgf'. +It then looks in your current folder and all its parents to find a file named '.tgf.config' to retrieve the default configuration. If not all configurable values are satisfied and you have an AWS configuration, +it will then try to retrieve the missing elements from the AWS Parameter Store under the key '/default/tgf'. -Configurable values are: docker-image, docker-image-version, docker-image-tag, docker-refresh, docker-options, recommended-image-version, required-image-version, logging-level, entry-point, tgf-recommended-version. +Configurable values are: docker-image, docker-image-version, docker-image-tag, docker-image-build, docker-refresh, docker-options, recommended-image-version, required-image-version, logging-level, +entry-point, tgf-recommended-version. -You can get the full documentation at https://github.com/coveo/tgf/blob/master/README.md and check for new -version at https://github.com/coveo/tgf/releases/latest. +You can get the full documentation at https://github.com/coveo/tgf/blob/master/README.md and check for new version at https://github.com/coveo/tgf/releases/latest. Any docker image could be used, but TGF specialized images could be found at: https://hub.docker.com/r/coveo/tgf/tags. -Terragrunt documentation could be found at https://github.com/coveo/terragrunt/blob/master/README.md (Coveo fork) or https://github.com/gruntwork-io/terragrunt/blob/master/README.md (Gruntwork.io original) +Terragrunt documentation could be found at https://github.com/coveo/terragrunt/blob/master/README.md (Coveo fork) or https://github.com/gruntwork-io/terragrunt/blob/master/README.md +(Gruntwork.io original) Terraform documentation could be found at https://www.terraform.io/docs/index.html. -IMPORTANT: Most of the tgf command line arguments are in uppercase to avoid potential conflict with the -underlying command. If any of the tgf arguments conflicts with an argument of the desired entry point, you -must place that argument after -- to ensure that they are not interpreted by tgf and are passed to the entry point. -Any non conflicting argument will be passed to the entry point wherever it is located on the invocation arguments. +IMPORTANT: Most of the tgf command line arguments are in uppercase to avoid potential conflict with the underlying command. If any of the tgf arguments conflicts with an argument of the desired entry point, you +must place that argument after -- to ensure that they are not interpreted by tgf and are passed to the entry point. Any non conflicting argument will be passed to the entry point wherever it is located on the +invocation arguments. tgf ls -- -D # Avoid -D to be interpretated by tgf as --debug-docker -VERSION: 1.15.3 +VERSION: 1.15.4 AUTHOR: Coveo Flags: -H, --tgf-help Show context-sensitive help (also try --help-man). + -D, --debug-docker Print the docker command issued + -F, --flush-cache Invoke terragrunt with --terragrunt-update-source to flush the cache + --refresh-image Force a refresh of the docker image (alias --ri) + --docker-arg= ... Supply extra argument to Docker (alias --da) + --get-image-name Just return the resulting image name (alias --gi) + --no-home Disable the mapping of the home directory (alias --nh) + --no-temp Disable the mapping of the temp directory (alias --nt) -E, --entrypoint=terragrunt Override the entry point for docker --image=coveo/tgf Use the specified image instead of the default one --image-version=version Use a different version of docker image instead of the default one (alias --iv) -T, --tag=latest Use a different tag of docker image instead of the default one -P, --profile="" Set the AWS profile configuration to use - -D, --debug-docker Print the docker command issued - --refresh-image Force a refresh of the docker image (alias --ri) -L, --logging-level= Set the logging level (critical=0, error=1, warning=2, notice=3, info=4, debug=5, full=6) - -F, --flush-cache Invoke terragrunt with --terragrunt-update-source to flush the cache - --no-home Disable the mapping of the home directory (alias --nh) - --get-image-name Just return the resulting image name (alias --gi) - --docker-arg= ... Supply extra argument to Docker (alias --da) --all-versions Get versions of TGF & all others underlying utilities (alias --av) --current-version Get current version infomation (alias --cv) - ``` Example: ```bash > tgf --current-version -tgf v1.15.3 +tgf v1.15.4 ``` Returns the current version of the tgf tool diff --git a/docker.go b/docker.go index b2687f57..b5d6f619 100644 --- a/docker.go +++ b/docker.go @@ -54,21 +54,17 @@ func callDocker(args ...string) int { homeWithoutVolume := strings.TrimPrefix(home, filepath.VolumeName(home)) cwd := filepath.ToSlash(Must(os.Getwd()).(string)) + cwd = Must(filepath.EvalSymlinks(cwd)).(string) currentDrive := fmt.Sprintf("%s/", filepath.VolumeName(cwd)) rootFolder := strings.Split(strings.TrimPrefix(cwd, currentDrive), "/")[0] - temp := filepath.ToSlash(filepath.Join(os.TempDir(), "tgf-cache")) - tempDrive := fmt.Sprintf("%s/", filepath.VolumeName(temp)) - tempFolder := strings.TrimPrefix(temp, tempDrive) - dockerArgs := []string{ "run", "-it", "-v", fmt.Sprintf("%s%s:/%[2]s", convertDrive(currentDrive), rootFolder), - "-v", fmt.Sprintf("%s%s:/var/tgf", convertDrive(tempDrive), tempFolder), "-w", strings.TrimPrefix(cwd, filepath.VolumeName(cwd)), "--rm", } - if mapHome { + if !noHome { dockerArgs = append(dockerArgs, []string{ "-v", fmt.Sprintf("%v:%v", convertDrive(home), homeWithoutVolume), "-e", fmt.Sprintf("HOME=%v", homeWithoutVolume), @@ -77,7 +73,14 @@ func callDocker(args ...string) int { dockerArgs = append(dockerArgs, config.DockerOptions...) } - os.Setenv("TERRAGRUNT_CACHE", "/var/tgf") + if !noTemp { + temp := filepath.ToSlash(filepath.Join(Must(filepath.EvalSymlinks(os.TempDir())).(string), "tgf-cache")) + tempDrive := fmt.Sprintf("%s/", filepath.VolumeName(temp)) + tempFolder := strings.TrimPrefix(temp, tempDrive) + dockerArgs = append(dockerArgs, "-v", fmt.Sprintf("%s%s:/var/tgf", convertDrive(tempDrive), tempFolder)) + os.Setenv("TERRAGRUNT_CACHE", "/var/tgf") + } + os.Setenv("TGF_COMMAND", config.EntryPoint) os.Setenv("TGF_VERSION", version) os.Setenv("TGF_IMAGE", config.Image) @@ -97,7 +100,7 @@ func callDocker(args ...string) int { for _, do := range dockerOptions { dockerArgs = append(dockerArgs, strings.Split(do, " ")...) } - dockerArgs = append(dockerArgs, getEnviron(mapHome)...) + dockerArgs = append(dockerArgs, getEnviron(!noHome)...) dockerArgs = append(dockerArgs, imageName) dockerArgs = append(dockerArgs, command...) dockerCmd := exec.Command("docker", dockerArgs...) @@ -106,7 +109,12 @@ func callDocker(args ...string) int { dockerCmd.Stderr = &stderr if debug { - printfDebug(os.Stderr, "%s\n\n", strings.Join(dockerCmd.Args, " ")) + for _, s := range os.Environ() { + if strings.HasPrefix(s, "TGF_") || strings.HasPrefix(s, "TERRAGRUNT_") || strings.HasPrefix(s, "AWS_") { + printfDebug(os.Stderr, "export %s\n", s) + } + } + printfDebug(os.Stderr, "\n%s\n\n", strings.Join(dockerCmd.Args, " ")) } if err := dockerCmd.Run(); err != nil { @@ -172,7 +180,7 @@ func refreshImage(image string) { fmt.Fprintln(os.Stderr) } -func getEnviron(mapHome bool) (result []string) { +func getEnviron(noHome bool) (result []string) { for _, env := range os.Environ() { split := strings.Split(env, "=") varName := strings.TrimSpace(split[0]) @@ -193,7 +201,7 @@ func getEnviron(mapHome bool) (result []string) { "PROMPT", "SHELL", "SH", "ZSH", "HOME", "LANG", "LC_CTYPE", "DISPLAY", "TERM": case "LOGNAME", "USER": - if !mapHome { + if noHome { continue } fallthrough diff --git a/main.go b/main.go index a3afa758..27daa1e4 100644 --- a/main.go +++ b/main.go @@ -54,7 +54,8 @@ var ( debug bool flushCache bool getImageName bool - mapHome bool + noHome bool + noTemp bool refresh bool ) @@ -97,50 +98,38 @@ func main() { app.HelpFlag.Bool() kingpin.CommandLine = app.Application + app.Switch("debug-docker", "Print the docker command issued", 'D').BoolVar(&debug) + app.Switch("flush-cache", "Invoke terragrunt with --terragrunt-update-source to flush the cache", 'F').BoolVar(&flushCache) + app.Switch("refresh-image", "Force a refresh of the docker image (alias --ri)").BoolVar(&refresh) + app.Argument("docker-arg", "Supply extra argument to Docker (alias --da)").PlaceHolder("").StringsVar(&dockerOptions) + app.Switch("get-image-name", "Just return the resulting image name (alias --gi)").BoolVar(&getImageName) + app.Switch("no-home", "Disable the mapping of the home directory (alias --nh)").BoolVar(&noHome) + app.Switch("no-temp", "Disable the mapping of the temp directory (alias --nt)").BoolVar(&noTemp) + var ( - defaultEntryPoint = app.Argument("entrypoint", "Override the entry point for docker", 'E').PlaceHolder("terragrunt").String() - image = app.Argument("image", "Use the specified image instead of the default one").PlaceHolder("coveo/tgf").String() - imageVersion = app.Argument("image-version", "Use a different version of docker image instead of the default one (alias --iv)").PlaceHolder("version").Default("-").String() - imageTag = app.Argument("tag", "Use a different tag of docker image instead of the default one", 'T').PlaceHolder("latest").Default("-").String() - awsProfile = app.Argument("profile", "Set the AWS profile configuration to use", 'P').Default("").String() - debug1 = app.Switch("debug-docker", "Print the docker command issued", 'D').Bool() - refresh1 = app.Switch("refresh-image", "Force a refresh of the docker image (alias --ri)").Bool() - loggingLevel = app.Argument("logging-level", "Set the logging level (critical=0, error=1, warning=2, notice=3, info=4, debug=5, full=6)", 'L').PlaceHolder("").String() - flushCache1 = app.Switch("flush-cache", "Invoke terragrunt with --terragrunt-update-source to flush the cache", 'F').Bool() - noHome1 = app.Switch("no-home", "Disable the mapping of the home directory (alias --nh)").Bool() - getImageName1 = app.Switch("get-image-name", "Just return the resulting image name (alias --gi)").Bool() - dockerOptions1 = app.Argument("docker-arg", "Supply extra argument to Docker (alias --da)").PlaceHolder("").Strings() - getAllVersions1 = app.Switch("all-versions", "Get versions of TGF & all others underlying utilities (alias --av)").Bool() - getCurrentVersion1 = app.Switch("current-version", "Get current version infomation (alias --cv)").Bool() - - // Shorten version of the tags - refresh2 = app.Switch("ri", "alias for refresh-image)").Hidden().Bool() - getImageName2 = app.Switch("gi", "alias for get-image-name").Hidden().Bool() - noHome2 = app.Switch("nh", "alias for no-home-mapping").Hidden().Bool() - getCurrentVersion2 = app.Switch("cv", "alias for current-version").Hidden().Bool() - getAllVersions2 = app.Switch("av", "alias for all-versions").Hidden().Bool() - dockerOptions2 = app.Argument("da", "alias for docker-arg").Hidden().Strings() - imageVersion2 = app.Argument("iv", "alias for image-version").Default("-").Hidden().String() + defaultEntryPoint = app.Argument("entrypoint", "Override the entry point for docker", 'E').PlaceHolder("terragrunt").String() + image = app.Argument("image", "Use the specified image instead of the default one").PlaceHolder("coveo/tgf").String() + imageVersion = app.Argument("image-version", "Use a different version of docker image instead of the default one (alias --iv)").PlaceHolder("version").Default("-").String() + imageTag = app.Argument("tag", "Use a different tag of docker image instead of the default one", 'T').PlaceHolder("latest").Default("-").String() + awsProfile = app.Argument("profile", "Set the AWS profile configuration to use", 'P').Default("").String() + loggingLevel = app.Argument("logging-level", "Set the logging level (critical=0, error=1, warning=2, notice=3, info=4, debug=5, full=6)", 'L').PlaceHolder("").String() + getAllVersions = app.Switch("all-versions", "Get versions of TGF & all others underlying utilities (alias --av)").Bool() + getCurrentVersion = app.Switch("current-version", "Get current version infomation (alias --cv)").Bool() ) + app.Switch("ri", "alias for refresh-image)").Hidden().BoolVar(&refresh) + app.Switch("gi", "alias for get-image-name").Hidden().BoolVar(&getImageName) + app.Switch("nh", "alias for no-home").Hidden().BoolVar(&noHome) + app.Switch("nt", "alias for no-temp").Hidden().BoolVar(&noTemp) + app.Switch("cv", "alias for current-version").Hidden().BoolVar(getCurrentVersion) + app.Switch("av", "alias for all-versions").Hidden().BoolVar(getAllVersions) + app.Argument("da", "alias for docker-arg").Hidden().StringsVar(&dockerOptions) + app.Argument("iv", "alias for image-version").Default("-").Hidden().StringVar(imageVersion) + // Split up the managed parameters from the unmanaged ones managed, unmanaged := app.SplitManaged() Must(app.Parse(managed)) - // We combine the tags that have multiple definitions - debug = *debug1 - flushCache = *flushCache1 - getImageName = *getImageName1 || *getImageName2 - mapHome = !(*noHome1 || *noHome2) - refresh = *refresh1 || *refresh2 - dockerOptions = append(*dockerOptions1, *dockerOptions2...) - getCurrentVersion := *getCurrentVersion1 || *getCurrentVersion2 - getAllVersions := *getAllVersions1 || *getAllVersions2 - dockerOptions = append(*dockerOptions1, *dockerOptions2...) - if *imageVersion2 != "-" { - imageVersion = imageVersion2 - } - // If AWS profile is supplied, we freeze the current session if *awsProfile != "" { Must(aws_helper.InitAwsSession(*awsProfile)) @@ -180,12 +169,12 @@ func main() { os.Exit(1) } - if getCurrentVersion { + if *getCurrentVersion { fmt.Printf("tgf v%s\n", version) os.Exit(0) } - if getAllVersions { + if *getAllVersions { if config.EntryPoint != "terragrunt" { fmt.Fprintln(os.Stderr, errorString("--all-version works only with terragrunt as the entrypoint")) os.Exit(1)