pulumi / pulumi-command

Apache License 2.0
64 stars 26 forks source link

error: EOF: running "cd /home/ubuntu && sudo docker compose -p project_name down": #553

Open gavindsouza opened 3 days ago

gavindsouza commented 3 days ago

What happened?

I did pulumi up -s dev -y, everything looked ok. I ran pulumi destroy -s dev -y hoping everything gets dropped. However, there's a EOF failure while executing delete for a remote.Command.

I couldn't seem to get past it now. Although it seems like the command itself has successfully run on remote. Modifying the file and trying up/delete/destroy didn't work - and it might've been concerning if it did too.

I passed --continue-on-error additionally to fully execute destroy (and drop the created resources). Followed up with a pulumi stack rm dev.

^ This seems to have worked for me as a workaround.

Example

% pulumi destroy -s dev -y                                                                                                                                                                       24-11-12 - 17:37:56
Previewing destroy (dev)

View in Browser (Ctrl+O): https://app.pulumi.com/***/***/dev/previews/a551c903-e165-495d-80dc-d1c1982a3fc8

     Type                            Name                           Plan       Info
 -   pulumi:pulumi:Stack             ***-dev        delete     3 warnings
 -   ├─ command:remote:Command       install-docker                 delete
 -   ├─ aws:route53:Record           update-dns                     delete
 -   ├─ aws:ec2:Instance             ***                  delete
 -   ├─ docker-build:index:Image     ***-image            delete
 -   ├─ command:remote:Command       start-or-update-application-1  delete
 -   └─ command:remote:CopyToRemote  update-compose-file            delete

Diagnostics:
  pulumi:pulumi:Stack (***-dev):
    warning: using pulumi-resource-aws from $PATH at /nix/store/zb0xqqshlfaqi07c5mdrdv4gpjrv2qqm-pulumi-3.137.0/bin/pulumi-resource-aws
    warning: using pulumi-resource-aws from $PATH at /nix/store/zb0xqqshlfaqi07c5mdrdv4gpjrv2qqm-pulumi-3.137.0/bin/pulumi-resource-aws
    warning: resource plugin aws is expected to have version >=6.58.0, but has 6.56.1; the wrong version may be on your path, or this may be a bug in the plugin

Outputs:
  - image_name   : "ghcr.io/***/***/***:1731428754"
  - public_dns   : "***"
  - public_domain: "***.***.***"
  - public_ip    : "***"

Resources:
    - 7 to delete

Destroying (dev)

View in Browser (Ctrl+O): https://app.pulumi.com/***/***/dev/updates/97

     Type                       Name                           Status                  Info
     pulumi:pulumi:Stack        ***-dev        **failed**              1 error; 3 warnings
 -   └─ command:remote:Command  start-or-update-application-1  **deleting failed**     1 error; 2 warnings

Diagnostics:
  pulumi:pulumi:Stack (***-dev):
    warning: using pulumi-resource-aws from $PATH at /nix/store/zb0xqqshlfaqi07c5mdrdv4gpjrv2qqm-pulumi-3.137.0/bin/pulumi-resource-aws
    warning: using pulumi-resource-aws from $PATH at /nix/store/zb0xqqshlfaqi07c5mdrdv4gpjrv2qqm-pulumi-3.137.0/bin/pulumi-resource-aws
    warning: resource plugin aws is expected to have version >=6.58.0, but has 6.56.1; the wrong version may be on your path, or this may be a bug in the plugin
    error: update failed

  command:remote:Command (start-or-update-application-1):
    warning: Unable to set 'PULUMI_COMMAND_STDOUT'. This only works if your SSH server is configured to accept
        these variables via AcceptEnv. Alternatively, if a Bash-like shell runs the command on the remote host, you could
        prefix the command itself with the variables in the form 'VAR=value command'
    warning: Unable to set 'PULUMI_COMMAND_STDERR'. This only works if your SSH server is configured to accept
        these variables via AcceptEnv. Alternatively, if a Bash-like shell runs the command on the remote host, you could
        prefix the command itself with the variables in the form 'VAR=value command'
    error: EOF: running "cd /home/ubuntu && sudo docker compose -p project_name down":

Resources:

Duration: 6s

Output of pulumi about

% pulumi about                                                      24-11-12 - 18:11:05
CLI
Version      3.137.0
Go Version   go1.23.2
Go Compiler  gc

Plugins
KIND      NAME          VERSION
resource  aws           6.58.0
resource  command       1.0.1
resource  docker-build  0.0.7
language  python        unknown

Host
OS       nixos
Version  24.05 (Uakari)
Arch     x86_64

This project is written in python: executable='/***/v2/***/venv/bin/python' version='3.12.7'

Backend
Name           pulumi.com
URL            https://app.pulumi.com/***
User           ***
Organizations  ***, ***
Token type     personal

Dependencies:
NAME                 VERSION
pip                  24.3.1
pre_commit           4.0.1
pulumi_aws           6.58.0
pulumi_command       1.0.1
pulumi_docker_build  0.0.7

Pulumi locates its logs in /tmp by default
warning: Failed to get information about the current stack: No current stack

Additional context

No response

Contributing

Vote on this issue by adding a 👍 reaction. To contribute a fix for this issue, leave a comment (and link to your pull request, if you've opened one already).

mjeffryes commented 2 days ago

Thanks for reporting this @gavindsouza. Could you share the program you used (or at least the remote.Command resource ) so we can attempt to repro?

gavindsouza commented 1 day ago

The commented delete action in the run_docker_compose is where the failure occurs. Appreciate the help.

"""Script that builds a fresh image and deploys it to an AWS EC2 instance."""

import os
import json
import time
import pulumi
from pulumi import FileAsset
from pulumi_aws import ec2, route53
from pathlib import Path
import pulumi_command as command
from pulumi_docker_build import (
    Image,
    RegistryArgs,
    BuildContextArgs,
    DockerfileArgs,
    Platform,
)

SERVER_NAME = "application.service"
SERVER_USER = "ubuntu"
NODE_VERSION = "20.18.0"
PYTHON_VERSION = "3.11.9"
RELEASE_VERSION = int(time.time())

# AWS Environment Variables
AWS_KEY_NAME = os.environ["AWS_KEY_NAME"]
AWS_PEM_KEY = os.environ["AWS_PEM_KEY"]
AWS_SUBNET = os.environ["AWS_SUBNET"]
AWS_SECURITY_GROUPS = eval(os.environ["AWS_SECURITY_GROUPS"])
AWS_INSTANCE_TYPE = ec2.InstanceType.T2_X_LARGE

# Load application configuration
apps_data = Path("apps.json").read_text()
apps_data_json = json.loads(apps_data)

main_app_info = apps_data_json.pop(0)
assert main_app_info["name"] == "main_app", "Main app must be the first in the list."
MAIN_APP_COMMIT_SHA = main_app_info["version"]

# Docker image settings
IMAGE_NAME = f"ghcr.io/organization/{SERVER_NAME}:{RELEASE_VERSION}"

for app in apps_data_json:
    app["url"] = app["url"].format(PAT=os.environ["GITHUB_PAT"])
Path("_apps.json").write_text(json.dumps(apps_data_json))

# Generate Docker Compose configuration
Path("_compose.yml").write_text(
    Path("docker-compose.yml")
    .read_text()
    .format(
        IMAGE_NAME=IMAGE_NAME,
        INSTALL_APPS=", ".join(f"--install-app {x['name']}" for x in apps_data_json),
    )
)

# Build and push the Docker image
generate_image = Image(
    "application-service-image",
    tags=[IMAGE_NAME],
    context=BuildContextArgs(location="."),
    dockerfile=DockerfileArgs(location="Containerfile"),
    platforms=[Platform.LINUX_AMD64],
    build_args={
        "MAIN_APP_VERSION": MAIN_APP_COMMIT_SHA,
        "PYTHON_VERSION": PYTHON_VERSION,
        "NODE_VERSION": NODE_VERSION,
    },
    push=True,
    registries=[
        RegistryArgs(
            address="ghcr.io",
            username=os.environ["GITHUB_USER"],
            password=os.environ["GITHUB_PKG_TOKEN"],
        ),
        RegistryArgs(
            address="docker.io",
        ),
    ],
)

# EC2 instance configuration
server = ec2.Instance(
    SERVER_NAME,
    instance_type=AWS_INSTANCE_TYPE,
    ami=ec2.get_ami(
        most_recent=True,
        owners=["amazon"],
        filters=[{"name": "name", "values": ["*ubuntu-latest-*"]}],
    ).id,
    key_name=ec2.get_key_pair(key_name=AWS_KEY_NAME).key_name,
    vpc_security_group_ids=AWS_SECURITY_GROUPS,
    subnet_id=AWS_SUBNET,
    opts=pulumi.ResourceOptions(depends_on=[generate_image]),
)

# Set up remote connection for commands
ssh_connection = command.remote.ConnectionArgs(
    host=server.public_ip,
    user=SERVER_USER,
    private_key=AWS_PEM_KEY,
)

# Install Docker on the remote EC2 instance
setup_docker = command.remote.Command(
    "install-docker",
    connection=ssh_connection,
    create="curl -fsSL https://get.docker.com | sh",
    opts=pulumi.ResourceOptions(depends_on=[server]),
)

# Upload Docker Compose configuration file to the EC2 instance
upload_compose_file = command.remote.CopyToRemote(
    "update-compose-file",
    connection=ssh_connection,
    source=FileAsset("_compose.yml"),
    remote_path=f"/home/{SERVER_USER}/docker-compose.yml",
    opts=pulumi.ResourceOptions(depends_on=[server]),
)

# Run Docker Compose on the remote instance to start the application
run_docker_compose = command.remote.Command(
    "start-or-update-application",
    connection=ssh_connection,
    create=(
        f"sudo docker login 'ghcr.io' -u '{os.environ['GITHUB_USER']}' -p '{os.environ['GITHUB_PKG_TOKEN']}' && "
        "sudo docker compose -p application_service up -d"
    ),
    # delete=(f"sudo docker compose -p application_service down"),
    opts=pulumi.ResourceOptions(depends_on=[setup_docker, upload_compose_file]),
)

# Configure DNS record for the application
update_dns = route53.Record(
    "update-dns",
    name="application",
    zone_id=route53.get_zone(name=os.environ["AWS_ROUTE53_ZONE_NAME"]).id,
    type="A",
    ttl=300,
    records=[server.public_ip],
    opts=pulumi.ResourceOptions(depends_on=[server]),
)

# Export outputs
pulumi.export("public_ip", server.public_ip)
pulumi.export("public_dns", server.public_dns)
pulumi.export("image_name", IMAGE_NAME)
pulumi.export("public_domain", update_dns.fqdn)