3

Using Pulumi I'm attempting to get the primary endpoint from an elasticache cluster so I can pass it as an environment variable to a fargate service on aws. For some reason the same process that works for RDS does not work on ElastiCache.

pulumi version
v3.23.0
"@pulumi/aws": "^4.36.0",
"@pulumi/awsx": "^0.32.0",
"@pulumi/pulumi": "^3.23.0",

The following works perfectly for RDS:

    super("backend:portalInfrastructure:rds", name, {}, opts)

    let securityGroupIds = cluster.securityGroups.map((g:any) => g.id)

    let dbSubnets = new aws.rds.SubnetGroup(`${name}-rds-subnets-${ENV_LOWER}`, {
      subnetIds: vpc.publicSubnetIds,
    })

    //Extra dash on the name here because pulumi doesn't add one for RDS
    let db = new aws.rds.Instance(`${name}-postgres-${ENV_LOWER}-`, {
      engine: 'postgres',
      instanceClass: 'db.t3.micro',
      allocatedStorage: 20,
      dbSubnetGroupName: dbSubnets.id,
      vpcSecurityGroupIds: securityGroupIds,
      // TODO only needs to be publicly accessible
      // to run migrations from external host
      publiclyAccessible: true,
      ...DB_CONN,
      tags: {
        'env':ENV_LOWER
      },

      skipFinalSnapshot: true
    })

    this.DBSetupOutput = {
      dbhost : db.endpoint.apply(e => e.split(":")[0]),
      db: db
    }

    // For dependency tracking, register output properties for this component
    this.registerOutputs({
      DBSetupOutput: this.DBSetupOutput
    })

However when I try this for ElastiCache/Redis:

    super("backend:portalInfrastructure:redis", name, {}, opts)

    let securityGroupIds = cluster.securityGroups.map((g:any) => g.id)
    
    let redisSubnets = new aws.elasticache.SubnetGroup(`${name}-redis-subnets-${ENV_LOWER}`, {
      subnetIds: vpc.publicSubnetIds,
    })

    let redis = new aws.elasticache.Cluster(`${name}-redis-${ENV_LOWER}`, {
      engine: "redis",
      engineVersion: "3.2.10",
      nodeType: "cache.t3.micro",
      numCacheNodes: 1,
      parameterGroupName: "default.redis3.2",
      port: 6379,
      subnetGroupName: redisSubnets.id,
      securityGroupIds: securityGroupIds
    }, {parent: this});

    redis.clusterAddress.apply(address => {
      console.log(address)
    })

    this.RedisSetupOutput = {
      redishost : redis.clusterAddress.apply(a => a),
      redis: redis
    }

    // For dependency tracking, register output properties for this component
    this.registerOutputs({
      RedisSetupOutput: this.RedisSetupOutput
    })

I get the following output for my variable redishost

"Calling [toString] on an [Output<T>] is not supported.\n\nTo get the value of an Output<T> as an Output<string> consider either:\n1: o.apply(v => `prefix${v}suffix`)\n2: pulumi.interpolate `prefix${v}suffix`\n\nSee https://pulumi.io/help/outputs for more details.\nThis function may throw in a future version of @pulumi/pulumi."

I don't understand because I am calling apply to the pulumi output. The same thing happens when trying to get ElastiCache clusterAddress or cacheNodes. If anyone understand how to get the ElastiCache primary endpoint, or can tell me what I'm doing wrong here it would be greatly appreciated.

mkabatek
  • 1,244
  • 12
  • 23
  • I'm having the exact same problem. Were you able to figure out a solution? As far as I can tell this output just seems to be broken... – Throttlehead Aug 15 '22 at 19:14
  • I've even tried using the getter to get the created elastic cache resource later on in the code and the same issue happens. This issue seems to be affecting all the endpoint outputs in the `aws.elasticache` class. – Throttlehead Aug 15 '22 at 19:28
  • I've posted an issue in GitHub. I don't think we're crazy, somethings broken here with this particular package: https://github.com/pulumi/pulumi-aws/issues/2092 – Throttlehead Aug 15 '22 at 19:55

1 Answers1

1

You are creating a redis elasticache cluster. If you read the docs for elasticache, it states the clusterAddress is only populated for a memcache cluster. See here

What you actually need to use is the cacheNodes output, like so:

this.RedisSetupOutput = {
  redishost : redis.cacheNodes
  redis: redis
}

This returns an array of addressed, you can narrow it down by specifying one fo the outputs from the array:

this.RedisSetupOutput = {
  redishost : redis.cacheNodes[0].address
  redis: redis
}
jaxxstorm
  • 12,422
  • 5
  • 57
  • 67
  • Lee is correct (in his answer), but also, you're assuming `apply()` unwraps and returns the wrapped variable. Even if you use `apply()` in the way you have, you'll still end up with a variable of type `Output` (see the last sentence in the docs on Apply(): https://www.pulumi.com/docs/intro/concepts/inputs-outputs/#apply). – Piers Karsenbarg Aug 18 '22 at 11:09