Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Crosswalk for AWS Guides needs refresh for AWSX 2.x #10230

Closed
scottslowe opened this issue Nov 7, 2023 · 5 comments · Fixed by pulumi/pulumi-hugo#3693
Closed

Crosswalk for AWS Guides needs refresh for AWSX 2.x #10230

scottslowe opened this issue Nov 7, 2023 · 5 comments · Fixed by pulumi/pulumi-hugo#3693
Assignees
Labels
area/docs Improvements or additions to documentation emergent An issue that was added to the current milestone after planning impact/usability Something that impacts users' ability to use the product easily and intuitively kind/bug Some behavior is incorrect or out of spec resolution/fixed This issue was fixed size/M Estimated effort to complete (up to 5 days).
Milestone

Comments

@scottslowe
Copy link
Contributor

Problem description

A community user brought up a product documentation issue on the following URL: https://www.pulumi.com/docs/clouds/aws/guides/

Specifically, the user was tripped up by the ECR example, which references parameters that are no longer supported in AWSX 2.x (like the path parameter, which is replaced by context).

This carries over into the more detailed ECR guide found at https://www.pulumi.com/docs/clouds/aws/guides/ecr/ as well.

Pretty much every awsx.ecr.Image example is wrong; I checked the ECR page, the EKS page, and the ECS page and found incorrect examples.

Affected product version(s)

The docs reflect AWSX 1.x, but AWSX 2.x is the default/major version now in use.

Suggestions for a fix

Update all code examples that use awsx.ecr.Image to reflect correct usage with AWSX 2.x.

@scottslowe scottslowe added the needs-triage Needs attention from the triage team label Nov 7, 2023
@github-project-automation github-project-automation bot moved this to 🤔 Triage in Docs 📚 Nov 7, 2023
@toriancrane toriancrane added area/docs Improvements or additions to documentation kind/bug Some behavior is incorrect or out of spec impact/usability Something that impacts users' ability to use the product easily and intuitively and removed needs-triage Needs attention from the triage team labels Nov 7, 2023
@toriancrane toriancrane moved this from 🤔 Triage to 🎬 Ready in Docs 📚 Nov 7, 2023
@cnunciato
Copy link
Contributor

cnunciato commented Nov 14, 2023

Some preliminary investigation. For this, I did a few things:

  • Created a new TypeScript project
  • Upgraded AWS to ^6 and AWSx to ^2
  • Replaced the code in index.ts with the code from https://www.pulumi.com/docs/clouds/aws/guides/
  • Noticed two squiggles in VS Code -- one for path (as mentioned) and one for the container property of awsx.ecs.FargateService (not mentioned).

Then I searched this repo for references to awsx.ecr.Image and awsx.ecs.FargateService. Here's what I found:

For aws.ecs.Image

12 files contain references to the no-longer-existent path parameter of aws.ecs.Image:

  • themes/default/content/blog/aws-lambda-container-support/index.md
  • themes/default/content/blog/building-and-publishing-docker-images-to-a-private-amazon-ecr-repository/index.md
  • themes/default/content/blog/crosswalk-for-aws-1-0/index.md
  • themes/default/content/blog/crosswalk-for-aws-all-languages/index.md
  • themes/default/content/blog/managing-containers-on-aws-with-pulumi/index.md
  • themes/default/content/blog/nov-2022-launches/index.md
  • themes/default/content/docs/clouds/aws/guides/_index.md
  • themes/default/content/docs/clouds/aws/guides/ecr.md
  • themes/default/content/docs/clouds/aws/guides/ecs.md
  • themes/default/content/docs/clouds/aws/guides/eks.md
  • themes/default/content/docs/clouds/kubernetes/guides/apps.md

For awsx.ecs.FargateService:

21 files contain references to container blocks without a name property:

  • themes/default/content/blog/aws-lambda-efs/index.md
  • themes/default/content/blog/building-and-publishing-docker-images-to-a-private-amazon-ecr-repository/index.md
  • themes/default/content/blog/crosswalk-for-aws-1-0/index.md
  • themes/default/content/blog/crosswalk-for-aws-all-languages/index.md
  • themes/default/content/blog/deploying-a-pern-stack-application-to-aws/index.md
  • themes/default/content/blog/deploying-the-infrastructure-of-oauth-server-for-cms-app/index.md
  • themes/default/content/blog/get-started-with-docker-on-aws-fargate-using-pulumi/index.md
  • themes/default/content/blog/introducing-pulumi-crosswalk-for-aws-the-easiest-way-to-aws/index.md
  • themes/default/content/blog/managing-containers-on-aws-with-pulumi/index.md
  • themes/default/content/blog/nov-2022-launches/index.md
  • themes/default/content/blog/pulumi-universal-iac/index.md
  • themes/default/content/blog/run-your-own-rss-server/index.md
  • themes/default/content/blog/running-containers-in-aws-the-lowdown-ecs-fargate-and-eks/index.md
  • themes/default/content/docs/clouds/aws/guides/_index.md
  • themes/default/content/docs/clouds/aws/guides/ecr.md
  • themes/default/content/docs/clouds/aws/guides/ecs.md
  • themes/default/content/docs/clouds/aws/guides/elb.md
  • themes/default/content/crosswalk/aws.md
  • themes/default/content/topics/containers.md

It's likely there are other AWSx resources that are similarly affected (as I only noticed FargateService because I stumbled upon it), but this should give us plenty of work to address within the scope of this particular issue. We can (and should) investigate other AWSx resources as follow-ups.

@cnunciato cnunciato added the size/M Estimated effort to complete (up to 5 days). label Nov 14, 2023
@desteves
Copy link
Contributor

Related: #10162

@cnunciato cnunciato self-assigned this Nov 16, 2023
@cnunciato cnunciato moved this from 🎬 Ready to 🔧 In Progress in Docs 📚 Nov 16, 2023
@cnunciato cnunciato added this to the 0.96 milestone Nov 16, 2023
@cnunciato cnunciato added the emergent An issue that was added to the current milestone after planning label Nov 16, 2023
@cnunciato
Copy link
Contributor

cnunciato commented Nov 16, 2023

All right, I think I have a good sense now of what's needed to fix up the issues here. It boils down to this:

  • Change path to context
  • Give container blocks a name
  • Make sure there's a platform: "linux/amd64" property passed to all awsx.ecr.Images, pretty much everywhere (this is important because as of Docker v4, this is no longer the default, so will not work when run on most users' machines)
  • Make sure it's clear which ports are involved in the example (also important, as by default, this stuff generally only works when both the load balancer and the service are intended to listen on port 80)

Related updates will need to be made in pulumi/templates and pulumi/examples as well.

The full examples I'm using to make these updates is:

# ./app/Dockerfile
FROM nginx
"use strict";
const pulumi = require("@pulumi/pulumi");
const aws = require("@pulumi/aws");
const awsx = require("@pulumi/awsx");

const repo = new awsx.ecr.Repository("repo", {
    forceDelete: true,
});

const image = new awsx.ecr.Image("image", {
    repositoryUrl: repo.url,
    context: "./app",
    platform: "linux/amd64",
});

const cluster = new aws.ecs.Cluster("cluster");

const lb = new awsx.lb.ApplicationLoadBalancer("lb");

const service = new awsx.ecs.FargateService("service", {
    cluster: cluster.arn,
    assignPublicIp: true,
    taskDefinitionArgs: {
        container: {
            name: "my-service",
            image: image.imageUri,
            cpu: 128,
            memory: 512,
            essential: true,
            portMappings: [{
                containerPort: 80,
                targetGroup: lb.defaultTargetGroup,
            }],
        },
    },
});

exports.url = pulumi.interpolate`http://${lb.loadBalancer.dnsName}`;
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
import * as awsx from "@pulumi/awsx";

const repo = new awsx.ecr.Repository("repo", {
    forceDelete: true,
});

const image = new awsx.ecr.Image("image", {
    repositoryUrl: repo.url,
    context: "./app",
    platform: "linux/amd64",
});

const cluster = new aws.ecs.Cluster("cluster");

const lb = new awsx.lb.ApplicationLoadBalancer("lb");

const service = new awsx.ecs.FargateService("service", {
    cluster: cluster.arn,
    assignPublicIp: true,
    taskDefinitionArgs: {
        container: {
            name: "my-service",
            image: image.imageUri,
            cpu: 128,
            memory: 512,
            essential: true,
            portMappings: [{
                containerPort: 80,
                targetGroup: lb.defaultTargetGroup,
            }],
        },
    },
});

export const url = pulumi.interpolate`http://${lb.loadBalancer.dnsName}`;
import pulumi
import pulumi_aws as aws
import pulumi_awsx as awsx

repository = awsx.ecr.Repository(
    "repository",
    awsx.ecr.RepositoryArgs(
        force_delete=True
    ),
)

image = awsx.ecr.Image(
    "image",
    awsx.ecr.ImageArgs(
        repository_url=repository.url, context="./app", platform="linux/amd64"
    ),
)

cluster = aws.ecs.Cluster("cluster")
lb = awsx.lb.ApplicationLoadBalancer("lb")

service = awsx.ecs.FargateService(
    "service",
    awsx.ecs.FargateServiceArgs(
        cluster=cluster.arn,
        assign_public_ip=True,
        task_definition_args=awsx.ecs.FargateServiceTaskDefinitionArgs(
            container=awsx.ecs.TaskDefinitionContainerDefinitionArgs(
                name="my-service",
                image=image.image_uri,
                cpu=128,
                memory=512,
                essential=True,
                port_mappings=[
                    awsx.ecs.TaskDefinitionPortMappingArgs(
                        container_port=80,
                        target_group=lb.default_target_group,
                    )
                ],
            ),
        ),
    ),
)

pulumi.export("url", pulumi.Output.concat("http://", lb.load_balancer.dns_name))
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v6/go/aws/ecs"
	"github.com/pulumi/pulumi-awsx/sdk/v2/go/awsx/ecr"
	ecsx "github.com/pulumi/pulumi-awsx/sdk/v2/go/awsx/ecs"
	"github.com/pulumi/pulumi-awsx/sdk/v2/go/awsx/lb"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		repository, err := ecr.NewRepository(ctx, "repository", &ecr.RepositoryArgs{
			ForceDelete: pulumi.Bool(true),
		})
		if err != nil {
			return err
		}

		image, err := ecr.NewImage(ctx, "image", &ecr.ImageArgs{
			RepositoryUrl: repository.Url,
			Context:       pulumi.String("./app"),
			Platform:      pulumi.StringPtr("linux/amd64"),
		})
		if err != nil {
			return err
		}

		cluster, err := ecs.NewCluster(ctx, "cluster", nil)
		if err != nil {
			return err
		}

		lb, err := lb.NewApplicationLoadBalancer(ctx, "lb", nil)
		if err != nil {
			return err
		}

		_, err = ecsx.NewFargateService(ctx, "service", &ecsx.FargateServiceArgs{
			Cluster:        cluster.Arn,
			AssignPublicIp: pulumi.Bool(true),
			TaskDefinitionArgs: &ecsx.FargateServiceTaskDefinitionArgs{
				Container: &ecsx.TaskDefinitionContainerDefinitionArgs{
					Name:      pulumi.String("app"),
					Image:     image.ImageUri,
					Cpu:       pulumi.Int(128),
					Memory:    pulumi.Int(512),
					Essential: pulumi.Bool(true),
					PortMappings: ecsx.TaskDefinitionPortMappingArray{
						&ecsx.TaskDefinitionPortMappingArgs{
							ContainerPort: pulumi.Int(80),
							TargetGroup:   lb.DefaultTargetGroup,
						},
					},
				},
			},
		})
		if err != nil {
			return err
		}

		ctx.Export("url", pulumi.Sprintf("http://%s", lb.LoadBalancer.DnsName()))
		return nil
	})
}
using System.Collections.Generic;
using Pulumi;
using Aws = Pulumi.Aws;
using Awsx = Pulumi.Awsx;

return await Deployment.RunAsync(() =>
{
    var cluster = new Aws.Ecs.Cluster("cluster");

    var repo = new Awsx.Ecr.Repository("repo", new()
    {
        ForceDelete = true,
    });

    var image = new Awsx.Ecr.Image("image", new()
    {
        RepositoryUrl = repo.Url,
        Context = "./app",
        Platform = "linux/amd64",
    });

    var lb = new Awsx.Lb.ApplicationLoadBalancer("lb");

    var service = new Awsx.Ecs.FargateService("service", new Awsx.Ecs.FargateServiceArgs
    {
        Cluster = cluster.Arn,
        AssignPublicIp = true,
        TaskDefinitionArgs = new Awsx.Ecs.Inputs.FargateServiceTaskDefinitionArgs
        {
            Container = new Awsx.Ecs.Inputs.TaskDefinitionContainerDefinitionArgs
            {
                Name = "my-service",
                Image = image.ImageUri,
                Cpu = 128,
                Memory = 512,
                Essential = true,
                PortMappings = new[]
                {
                    new Awsx.Ecs.Inputs.TaskDefinitionPortMappingArgs
                    {
                        ContainerPort = 80,
                        TargetGroup = lb.DefaultTargetGroup,
                    },
                },
            },
        },
    });

    return new Dictionary<string, object?>
    {
        ["url"] = lb.LoadBalancer.Apply(loadBalancer => Output.Format($"http://{loadBalancer.DnsName}")),
    };
});
package myproject;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.awsx.ecr.Repository;
import com.pulumi.awsx.ecr.RepositoryArgs;
import com.pulumi.awsx.ecr.Image;
import com.pulumi.awsx.ecr.ImageArgs;
import com.pulumi.aws.ecs.Cluster;
import com.pulumi.awsx.lb.ApplicationLoadBalancer;
import com.pulumi.awsx.ecs.FargateService;
import com.pulumi.awsx.ecs.FargateServiceArgs;
import com.pulumi.awsx.ecs.inputs.FargateServiceTaskDefinitionArgs;
import com.pulumi.awsx.ecs.inputs.TaskDefinitionContainerDefinitionArgs;
import com.pulumi.awsx.ecs.inputs.TaskDefinitionPortMappingArgs;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var repository = new Repository("repository", RepositoryArgs.builder()
            .forceDelete(true)
            .build());

        var image = new Image("image", ImageArgs.builder()
            .repositoryUrl(repository.url())
            .context("./app")
            .platform("linux/amd64")
            .build());

        var cluster = new Cluster("cluster");

        var lb = new ApplicationLoadBalancer("lb");

        var service = new FargateService("service", FargateServiceArgs.builder()
            .cluster(cluster.arn())
            .assignPublicIp(true)
            .taskDefinitionArgs(FargateServiceTaskDefinitionArgs.builder()
                .container(TaskDefinitionContainerDefinitionArgs.builder()
                    .name("my-service")
                    .image(image.imageUri())
                    .cpu(128)
                    .memory(512)
                    .essential(true)
                    .portMappings(TaskDefinitionPortMappingArgs.builder()
                        .containerPort(80)
                        .targetGroup(lb.defaultTargetGroup())
                        .build())
                    .build())
                .build())
            .build());

        ctx.export("url", Output.format("http://%s", lb.loadBalancer().applyValue(loadBalancer -> loadBalancer.dnsName())));
    }
}

☝️ This example, however, will fail until pulumi/pulumi-awsx#820 is fixed.

name: my-project
runtime: yaml

resources:
  repo:
    type: awsx:ecr:Repository
    properties:
      forceDelete: true

  lb:
    type: awsx:lb:ApplicationLoadBalancer

  image:
    type: awsx:ecr:Image
    properties:
      repositoryUrl: ${repo.url}
      context: ./app
      platform: linux/amd64

  cluster:
    type: aws:ecs:Cluster

  service:
    type: awsx:ecs:FargateService
    properties:
      cluster: ${cluster.arn}
      assignPublicIp: true
      taskDefinitionArgs:
        container:
          name: my-service
          image: ${image.imageUri}
          cpu: 128
          memory: 512
          essential: true
          portMappings:
          - containerPort: 80
            targetGroup: ${lb.defaultTargetGroup}

outputs:
  url: http://${lb.loadBalancer.dnsName}

This provisions a load balancer that listens on port 80 and forwards to a container service that also listens on port 80. If the example forwards to a port other than 80, the containerPort property can be changed accordingly.

@interurban
Copy link
Collaborator

Related to #11566

@cnunciato
Copy link
Contributor

This is now complete, with the exception of the Kubernetes "apps" page, which has deeper issues. I'll file a follow-up for that one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/docs Improvements or additions to documentation emergent An issue that was added to the current milestone after planning impact/usability Something that impacts users' ability to use the product easily and intuitively kind/bug Some behavior is incorrect or out of spec resolution/fixed This issue was fixed size/M Estimated effort to complete (up to 5 days).
Projects
Archived in project
Development

Successfully merging a pull request may close this issue.

6 participants