Search code examples
pythonpulumi

Multiples Output Applies | Object of type Output is not JSON serializable


I'm trying to get the value of two Outputs (Load Balancers) and inject them into a Container Definition resource (aws.ecs.TaskDefinition). Both Load Balancers and Task Definition are being created in the same stack, the dependency is managed with the depends_on flag).

I followed the explanation described here and was able to reproduce it, but in my specific case I need to pass two variables to the attribute container_definitions of the class aws.ecs.TaskDefinition.

So I tried:

First defining the Load Balancers it self:
load_balancer_1 = aws.lb.LoadBalancer("LoadBalancer1",
// stuff here
    )  
load_balancer_2 = aws.lb.LoadBalancer("LoadBalancer2",
    // stuff here
        )  
Then creating the auxiliary json method objects with the correct values so later I can interpolate them:
 def get_lb1_dnsName(lb1_dnsname):
        return json.dumps(
            {
                "name": "var1",
                "value": lb1_dnsname
            }         
        )
    
    def get_lb2_dnsName(lb2_dnsname):
        return json.dumps(
            {
                "name": "var2",
                "value": lb2_dnsname
            }         
        )
And then interpolating the auxiliary json objects to the main json object which defines the task definition:
 container_task_definition = aws.ecs.TaskDefinition("TaskDefinition",    
        // stuff here
        container_definitions=json.dumps([
                {   "name":"foo",
                    "essential":True,
                    "image":"image-url:latest",
                    "logConfiguration": {
                        "logDriver": "awslogs",      
                        "options": {
                            "awslogs-group": "/ecs/foo",
                            "awslogs-region": "us-east-1",
                            "awslogs-create-group": "true",
                            "awslogs-stream-prefix": "ecs"
                        }
                    },
                    "environment": [
                        load_balancer_1.dns_name.apply(get_lb1_dnsName),
                        load_balancer_2.dns_name.apply(get_lb2_dnsName)
                     
                    ]
                }
            ]
        ),
        opts=pulumi.ResourceOptions(depends_on=[load_balancer_1, load_balancer_2])
    )

Even though I keep receiving the error:

TypeError: Object of type Output is not JSON serializable

So I wonder how to properly set the Load Balancers dns_name to the enviroment variables of the Task Definition. e.g:

 "environment": [
                        "env1": dns_of_load_balancer_1
                        "env2": dns_of_load_balancer_2                      
                ]

Solution

  • Creating the individual functions is fine, but if you're working with multiple outputs, you need to use all

    It's personal preference, but I prefer to wrap the entire string with the apply, it ends up looking a little like this:

    task_definition = aws.ecs.TaskDefinition(
        "app-task",
        family="fargate-task-definition",
        cpu="256",
        memory="512",
        network_mode="awsvpc",
        requires_compatibilities=["FARGATE"],
        execution_role_arn=role.arn,
        container_definitions=pulumi.Output.all(lb_one=alb.dns_name, lb_two=alb2.dns_name).apply(
            lambda args: json.dumps(
                [
                    {
                        "name": "my-app",
                        "image": "nginx",
                        "portMappings": [
                            {"containerPort": 80, "hostPort": 80, "protocol": "tcp"}
                        ],
                        "environment": [
                            {"name": "LOADBALANCER_ONE", "value": args["lb_one"]},
                            {"name": "LOADBALANCER_TWO", "value": args["lb_two"]},
                        ],
                    }
                ]
            ),
        ),
    )
    

    In addition to this, you don't actually need the explicit depends_on in your resource options. By using the outputs from the original resources as inputs (via apply/all) to your task definition, Pulumi can figure out the order (although it doesn't hurt to have them)