microsoft / vscode-remote-release

Visual Studio Code Remote Development: Open any folder in WSL, in a Docker container, or on a remote machine using SSH and take advantage of VS Code's full feature set.
https://aka.ms/vscode-remote
Other
3.61k stars 276 forks source link

Extension substitutes wrong option values #10180

Closed lakkeger closed 1 week ago

lakkeger commented 3 weeks ago

Steps to Reproduce:

  1. Command+Shift+P and choose "Dev Containers: Add Dev Containers Configuration Files..."
  2. Add configuration to workspace
  3. Show all definitions
  4. choose "LocalStack Docker-outside-of-Docker"
  5. use default values (about 9 fields to pass inputs to)

End result:

Docker compose file has wrong values substituted ie:

This is not an issue if the user uses the same template via the devcontainers-cli with the default or any other inputs:

devcontainer templates apply --template-id ghcr.io/localstack/devcontainer-template/localstack-dood

For comparison find the extension generated docker-compose file:

version: "3.8"

services:
  localstack:
    container_name: "localstack-main"
    image: localstack/localstack-pro:latest  # required for Pro
    ports:
      - "127.0.0.1:4566:4566"            # LocalStack Gateway
      - "127.0.0.1:4510-4559:4510-4559"  # external services port range
      - "127.0.0.1:443:443"              # LocalStack HTTPS Gateway (Pro)
    env_file:
      - .env
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock"
      - "latest:/var/lib/localstack"
    networks:
      info:
        # Set the container IP address in the info subnet
        ipv4_address: info

  app:
    build: 
      context: .
      dockerfile: Dockerfile
    volumes:
      - ../..:/workspaces:cached
    # Overrides default command so things don't shut down after the process ends.
    command: sleep infinity
    init: true
    env_file:
      - .env
    dns:
      # Set the DNS server to be the LocalStack container
      - info
    networks:
      - info

networks:
  info:
    ipam:
      config:
        # Specify the subnet range for IP address allocation
        - subnet: info

And the CLI generated:

version: "3.8"

services:
  localstack:
    container_name: "localstack-main"
    image: localstack/localstack-pro:latest  # required for Pro
    ports:
      - "127.0.0.1:4566:4566"            # LocalStack Gateway
      - "127.0.0.1:4510-4559:4510-4559"  # external services port range
      - "127.0.0.1:443:443"              # LocalStack HTTPS Gateway (Pro)
    env_file:
      - .env
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock"
      - "./.volume:/var/lib/localstack"
    networks:
      ls:
        # Set the container IP address in the 10.0.2.0/24 subnet
        ipv4_address: 10.0.2.20

  app:
    build: 
      context: .
      dockerfile: Dockerfile
    volumes:
      - ../..:/workspaces:cached
    # Overrides default command so things don't shut down after the process ends.
    command: sleep infinity
    init: true
    env_file:
      - .env
    dns:
      # Set the DNS server to be the LocalStack container
      - 10.0.2.20
    networks:
      - ls

networks:
  ls:
    ipam:
      config:
        # Specify the subnet range for IP address allocation
        - subnet: 10.0.2.0/24

Similar issue happens with mount values with our "LocalStack Docker-in-Docker" template which works perfectly from the CLI.

Extension generated, see 2nd from the mounts:

{
    "name": "LocalStack DinD setup",
    "image": "mcr.microsoft.com/devcontainers/base:jammy",

    "remoteEnv": {
        // Activate LocalStack Pro: https://docs.localstack.cloud/getting-started/auth-token/
        "LOCALSTACK_AUTH_TOKEN": "${localEnv:LOCALSTACK_AUTH_TOKEN}",  // required for Pro, not processed via template due to security reasons
        "LOCALSTACK_API_KEY": "${localEnv:LOCALSTACK_API_KEY}",
        // LocalStack configuration: https://docs.localstack.cloud/references/configuration/
        "ACTIVATE_PRO": false,
        "DEBUG": false,
        "LS_LOG": "info",
        "PERSISTENCE": false,
        "AWS_ENDPOINT_URL": "http://localhost.localstack.cloud:4566",
        "AUTO_LOAD_POD": "latest",
        "ENFORCE_IAM": false,
        "AWS_REGION": "us-east-1",
        "AWS_DEFAULT_REGION": "us-east-1",
        "IMAGE_NAME": "localstack/localstack-pro:latest",
        "LOCALSTACK_VOLUME_DIR": "/data"
    },

    // 👇 Features to add to the Dev Container. More info: https://containers.dev/implementors/features.
    "features": {
        "ghcr.io/devcontainers/features/docker-in-docker:2": {},
        "ghcr.io/localstack/devcontainer-feature/localstack-cli:latest": {
            "version": "latest",
            "awslocal": false,  // if true, add in features manually: ghcr.io/devcontainers/features/aws-cli
            "cdklocal": false,  // if true, add in features manually: ghcr.io/devcontainers-contrib/features/aws-cdk
            "pulumilocal": false,  // if true, add in features manually: ghcr.io/devcontainers-contrib/features/pulumi
            "samlocal": false,  // if true, add in features manually: ghcr.io/customink/codespaces-features/sam-cli
            "tflocal": false  // if true, add in features manually: ghcr.io/devcontainers-contrib/features/terraform-asdf
        }
    },

    // 👇 Use 'postCreateCommand' to run commands after the container is created.
    "postCreateCommand": "type localstack; true && localstack start -d || true",
    "mounts": [
        {
            // to persist build data and images
            "source": "dind-var-lib-docker",
            "target": "/var/lib/docker",
            "type": "volume"
        }, 
        { 
            "source": "latest",
            "target": "/data",
            "type": "bind",
            "consistency": "cached"
        }
    ]
}

And the cli generated:

{
    "name": "LocalStack DinD setup",
    "image": "mcr.microsoft.com/devcontainers/base:jammy",

    "remoteEnv": {
        // Activate LocalStack Pro: https://docs.localstack.cloud/getting-started/auth-token/
        "LOCALSTACK_AUTH_TOKEN": "${localEnv:LOCALSTACK_AUTH_TOKEN}",  // required for Pro, not processed via template due to security reasons
        "LOCALSTACK_API_KEY": "${localEnv:LOCALSTACK_API_KEY}",
        // LocalStack configuration: https://docs.localstack.cloud/references/configuration/
        "ACTIVATE_PRO": false,
        "DEBUG": false,
        "LS_LOG": "info",
        "PERSISTENCE": false,
        "AWS_ENDPOINT_URL": "http://localhost.localstack.cloud:4566",
        "AUTO_LOAD_POD": " ",
        "ENFORCE_IAM": false,
        "AWS_REGION": "us-east-1",
        "AWS_DEFAULT_REGION": "us-east-1",
        "IMAGE_NAME": "localstack/localstack-pro:latest",
        "LOCALSTACK_VOLUME_DIR": "/data"
    },

    // 👇 Features to add to the Dev Container. More info: https://containers.dev/implementors/features.
    "features": {
        "ghcr.io/devcontainers/features/docker-in-docker:2": {},
        "ghcr.io/localstack/devcontainer-feature/localstack-cli:latest": {
            "version": "latest",
            "awslocal": false,  // if true, add in features manually: ghcr.io/devcontainers/features/aws-cli
            "cdklocal": false,  // if true, add in features manually: ghcr.io/devcontainers-contrib/features/aws-cdk
            "pulumilocal": false,  // if true, add in features manually: ghcr.io/devcontainers-contrib/features/pulumi
            "samlocal": false,  // if true, add in features manually: ghcr.io/customink/codespaces-features/sam-cli
            "tflocal": false  // if true, add in features manually: ghcr.io/devcontainers-contrib/features/terraform-asdf
        }
    },

    // 👇 Use 'postCreateCommand' to run commands after the container is created.
    "postCreateCommand": "type localstack; true && localstack start -d || true",
    "mounts": [
        {
            // to persist build data and images
            "source": "dind-var-lib-docker",
            "target": "/var/lib/docker",
            "type": "volume"
        }, 
        { 
            "source": "./.volume",
            "target": "/data",
            "type": "bind",
            "consistency": "cached"
        }
    ]
}

All the above results in build errors for obvious reasons.

Does this issue occur when you try this locally?: Yes Does this issue occur when you try this locally and all extensions are disabled?: Yes

joshspicer commented 3 weeks ago

Interesting, thanks for comparing both the extension and the CLI directly.

I'm surprised there's different behavior as that CLI command is directly used to apply a Template from the extension.

lakkeger commented 2 weeks ago

Hi @joshspicer, Thanks for looking into it. Just checking in and wondering if is there any update on this issue or can we apply a work around somehow to the extension?

joshspicer commented 1 week ago

Apologies for the delay. I've tested with several order builds of the extension (as well as the latest pre-release) and the odd behavior repros.

While I work on a fix, I'd suggest manually applying the Template in the meantime (command scaffolded out below, replace with your own options as needed, set your --workspace-folder, and omit --tmp-dir). The dev container CLI can be easily installed from npm with npm install -g @devcontainers/cli

As hinted at in this issue, the CLI is erroneously being passed the wrong template-args . Below is the verbatim command being invoked after selecting options (I also just clicked through to the defaults).

[2024-09-03T21:59:01.336Z] Running Dev Containers CLI:   

templates apply \
--workspace-folder /var/folders/mg/d225vy_56bn0p10vb8z8c1l40000gn/T/tmp-output-dir-1725400741335 \ 
--template-id ghcr.io/localstack/devcontainer-template/localstack-dood \
--template-args {"imageVariant":"jammy","logLevel":"info","networkName":"info","networkCidr":"info","ipAddress":"info","host":"localhost.localstack.cloud:4566","version":"latest","loadPods":"latest","volumePath":"latest","defaultRegion":"us-east-1","awslocal":"false","cdklocal":"false","pulumilocal":"false","samlocal":"false","tflocal":"false","debug":"false","persistence":"false","usePro":"false","enforceIam":"false"} \
--features [] \
--tmp-dir /var/folders/mg/d225vy_56bn0p10vb8z8c1l40000gn/T/tmp-dir-1725400741335 \
--log-level trace \
--omit-paths []
joshspicer commented 1 week ago

I think i've found the issue. The bug was related to various options not providing either a proposals or enum option. I have fixed that in our extension (treating the provided default value as the sole option in those cases (which also seems like better UX compared to the blank quickpick with text dialog).

I'll update here when a pre-release build of the extension is available for testing! The other fix here (if any Template maintainer is reading this) is to always include either a proposals or enum object for each option (even if the contents of those objects is the same as default!) That's what was intended when I wrote the spec for it, but here we are now :)

lakkeger commented 1 week ago

@joshspicer Wow, great find 💯 🥇 Thanks for the detailed feedback and the provided workaround. We make the necessary steps on our end too to remediate the issue in case someone uses an older extension for some odd reason.

joshspicer commented 1 week ago

Pre-release 0.385.0 of the extension will be available shortly with the fix. Please let me know if it helps!