Hi I'm trying to get the clusterIp of the guestboo...
# kubernetes
h
Hi I'm trying to get the clusterIp of the guestbook example https://www.pulumi.com/docs/guides/adopting/from_kubernetes/ but I'm not getting any output of the line export const privateIp = frontend.spec.clusterIP; and if I try console.log(privateIp); I get OutputImpl { __pulumiOutput: true, resources: [Function], allResources: [Function], isKnown: Promise { <pending> }, isSecret: Promise { <pending> }, promise: [Function], toString: [Function], toJSON: [Function] } what could be the reason that I can't get the output of ip address?
f
Hi @hundreds-receptionist-31352, First and foremost, don’t
console.log
pulumi output values, you won’t like the result. You can try to
apply
though, something like
frontend.spec.apply(spec => console.log(spec.clusterIP))
The Pulumi examples are tested and should work as expected. What’s the complete update output ?
h
Thanks richard, my main problem is that I'm installing nginx-ingress-controller with a helm chart and I need the arn of it in order to create a vpc-link but I never can get it I got an empty output
Copy code
const namespaceName = clusterSvcsNamespace.metadata.apply(m => m.name);

const nginx = new k8s.helm.v2.Chart("ingress", {
    repo: "stable",
    chart: "nginx-ingress",
    namespace: namespaceName,
    values : {
      controller: {
        kind: "DaemonSet",
        image: {
            registry: "<http://registry.hub.docker.com|registry.hub.docker.com>",
            repository: "roquesao/nginx",
             tag: "0.21.0",
             runAsUser: "33"
        },
        service: {
          externalTrafficPolicy: "Local",
	        annotations: {
		        "<http://service.beta.kubernetes.io/aws-load-balancer-cross-zone-load-balancing-enabled|service.beta.kubernetes.io/aws-load-balancer-cross-zone-load-balancing-enabled>": "True",
                        "<http://service.beta.kubernetes.io/aws-load-balancer-internal|service.beta.kubernetes.io/aws-load-balancer-internal>": "true",
                        "<http://service.beta.kubernetes.io/aws-load-balancer-type|service.beta.kubernetes.io/aws-load-balancer-type>": "nlb"
		           }
          }
	      
    }
    }
}, { providers: { "kubernetes": eksCluster.provider }});

const name= namespaceName + "/ingress-nginx-ingress-controller"
const frontend = nginx.getResource("v1/Service", name);
const frontendIp = frontend.status.loadBalancer.ingress[0].ip;
I have followed the pulumi example but in my case didn't work , not sure why, the NLB is created but can't get the output
f
Ok, so your issue is not actually with the example but with something totally different, that’s misleading to help you in the first place if you’re not providing your real context.
I previously had issue with this
getResource
method, instead of concatenating the namespace and the service name, you should try :
Copy code
const frontend = nginx.getResource("v1/Service", namespaceName, "ingress-nginx-ingress-controller");
Also ensure the service name you’re inputing here is correct.
h
yes I have tried it , but always get an empty response, I tried in different way to call getResource even waiting that NLB is created and fill the namespaces harcoded, but without luck
f
What are you doing with
frontendIp
? Are you exporting it immediately for stack output ? is it inside a
ComponentResource
? Are you trying to use it elsewhere in your code ?
h
sorry, Just I need to create a NLB with helm (that works now) and then create a vpc link , so I need to take the arn of NLB but I need "to wait" that helm finish to create it, but the variables that is taking the output of helm command is always empty, just the frotendIp is a test from my side to try to get some value from helm command.
f
Ok, so that’s a known issue with Pulumi and Chart deployment. You indeed need to wait for the service (and/or deployment) to be done before being able to read its properties. I don’t know what’s your next component which requires the
frontend
resource, but you need to add in its
CustomResourceOptions
a
dependsOn
like
{ dependsOn: [frontend] }
so you’re ensuring it is provisioned and you can query its properties, you can’t only wait on the
Chart
provisioning atm, a fix is ongoing though.
h
yes I have tried that too but got the same error, so I will wait for the fix, thanks richard!
f
Could you provide the exact code you’re using, you should be able to access the IP one way or another.
h
Copy code
"use strict";
import * as helm from "@pulumi/kubernetes/helm";
import * as eks from "@pulumi/eks";
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
import * as k8s from "@pulumi/kubernetes";

import AWS from 'aws-sdk'; // To set the AWS credentials and AWS Region.


AWS.config.update({
    region: 'us-east-1'
  });


function getLoadBalancer():any {
    var elb1 = new AWS.ELBv2();
    const params={}
     return new Promise(function(resolve, reject) {
       elb1.describeLoadBalancers(params, function(err: any, data: unknown) {
         if (err) {
           reject(err); // an error occurred
         }
         else {
           resolve(data);
         }
       });
     });
   }
 


  export  async function getLB() {
          
            let result = await getLoadBalancer();
            return result.LoadBalancers[0].LoadBalancerArn;
    
    } 
    
 async function installNginxIngressController(eksCluster:  eks.Cluster ) {

  

const clusterSvcsNamespace = new k8s.core.v1.Namespace("nginx-ingress-namespace", undefined, { provider: eksCluster.provider});

const namespaceName = clusterSvcsNamespace.metadata.apply(m => m.name);

const nginx = new k8s.helm.v2.Chart("ingress", {
    repo: "stable",
    chart: "nginx-ingress",
    namespace: namespaceName,
    values : {
      controller: {
        kind: "DaemonSet",
        image: {
            registry: "<http://registry.hub.docker.com|registry.hub.docker.com>",
            repository: "roquesao/nginx",
             tag: "0.21.0",
             runAsUser: "33"
        },
        service: {
          externalTrafficPolicy: "Local",
          annotations: {
            "<http://service.beta.kubernetes.io/aws-load-balancer-cross-zone-load-balancing-enabled|service.beta.kubernetes.io/aws-load-balancer-cross-zone-load-balancing-enabled>": "True",
                        "<http://service.beta.kubernetes.io/aws-load-balancer-internal|service.beta.kubernetes.io/aws-load-balancer-internal>": "true",
                        "<http://service.beta.kubernetes.io/aws-load-balancer-type|service.beta.kubernetes.io/aws-load-balancer-type>": "nlb",
                        "<http://service.beta.kubernetes.io/aws-load-balancer-additional-resource-tags|service.beta.kubernetes.io/aws-load-balancer-additional-resource-tags>": "apigateway-vpc-link=True"
               }
          },
          podAnnotations: {
                   "<http://ad.datadoghq.com/nginx-ingress-controller.init_configs|ad.datadoghq.com/nginx-ingress-controller.init_configs>": "[{},{}]",
                  "<http://ad.datadoghq.com/nginx-ingress-controller.check_names|ad.datadoghq.com/nginx-ingress-controller.check_names>": '["nginx","nginx_ingress_controller"]',
                  "<http://ad.datadoghq.com/nginx-ingress-controller.instances|ad.datadoghq.com/nginx-ingress-controller.instances>": '[{"nginx_status_url":"<http://%%host%>%/nginx_status"},{"prometheus_url":"<http://%%host%>%:10254/metrics"}]',
                  "<http://ad.datadoghq.com/nginx-ingress-controller.logs|ad.datadoghq.com/nginx-ingress-controller.logs>" : '[{"service": "controller","source":"nginx-ingress-controller"}]',
                   "<http://prometheus.io/port|prometheus.io/port>": "10254",
                   "<http://prometheus.io/scrape|prometheus.io/scrape>": "true"              
              
          }
        
    }
    }
}, { providers: { "kubernetes": eksCluster.provider }});
 
 return nginx;
}

export async function VpcLink(eksCluster:  eks.Cluster) {
  const nginx= await installNginxIngressController(eksCluster);
   
  
  const VpcLink = new aws.apigateway.VpcLink("vpc-eks", {
  description: "vpc-eks",
  targetArn: getLB(),
},{dependsOn:nginx });

}
when you call to the VpcLink function it call to installNginxIngressController and that is where helm is executed
and the error
pulumi:pulumi:Stack (eks-aws-eks):
TypeError: Cannot read property 'LoadBalancerArn' of undefined
f
Ok, there’re a lot of problems in your code (and you should use a linter, it’s very dirty), that explains the problem. • don’t use
aws-sdk
for credentials and config, Pulumi has a provider to configure this • You should use a
ComponentResource
to group what you’re trying to achieve here • avoid
export
if you are not actually using the function elsewhere • You are mixing `async`/`await`,
Promise
and pulumi Components, that can’t end well • You are mixing Pulumi with
aws-sdk
to manage your resources (used in
getLoadBalancer
), that won’t work, rely only on Pulumi if you want to use it. I don’t have the time to rewrite your code to show you, but that’s basically what you should do here (starting in a
ComponentResource
object and dropping the
aws-sdk
stuff)
h
yes is a little dirty due to I'm trying to put it working and trying a mix of possible solutions, I will take a look at ComponentResource, thanks richard for your help
f
One other thing, if you want to use AWS ApiGateway, you should use it directly as your ingress controller, not sure what you’re doing is doable/the right way (but I never used ApiGateway, so)
Here a basic component to help you (code not tested though) :
Copy code
// import * as aws from "@pulumi/aws"
import * as k8s from "@pulumi/kubernetes"
import * as pulumi from "@pulumi/pulumi"

export interface NginxIngressArgs {
  namespaceName?: string
}

export class NginxIngress extends pulumi.ComponentResource {
  public readonly frontendIp: pulumi.Output<string>

  public readonly service: pulumi.Output<k8s.core.v1.Service>

  constructor (
    name: string,
    args: NginxIngressArgs,
    opts?: pulumi.ComponentResourceOptions,
  ) {
    super(`${pulumi.getProject()}:NginxIngress`, name, {}, opts)

    const { namespaceName = "default" } = args

    if (namespaceName !== "default") {
      const namespace = new k8s.core.v1.Namespace("nginx-ingress-namespace", {
        metadata: {
          name: namespaceName,
        },
      }, { parent: this })
    }

    const nginx = new k8s.helm.v2.Chart("ingress", {
      repo: "stable",
      chart: "nginx-ingress",
      namespace: namespaceName,
      values : {
        controller: {
          kind: "DaemonSet",
          image: {
            registry: "<http://registry.hub.docker.com|registry.hub.docker.com>",
            repository: "roquesao/nginx",
            tag: "0.21.0",
            runAsUser: "33",
          },
          service: {
            externalTrafficPolicy: "Local",
            annotations: {
              "<http://service.beta.kubernetes.io/aws-load-balancer-cross-zone-load-balancing-enabled|service.beta.kubernetes.io/aws-load-balancer-cross-zone-load-balancing-enabled>": "True",
              "<http://service.beta.kubernetes.io/aws-load-balancer-internal|service.beta.kubernetes.io/aws-load-balancer-internal>": "true",
              "<http://service.beta.kubernetes.io/aws-load-balancer-type|service.beta.kubernetes.io/aws-load-balancer-type>": "nlb",
              "<http://service.beta.kubernetes.io/aws-load-balancer-additional-resource-tags|service.beta.kubernetes.io/aws-load-balancer-additional-resource-tags>": "apigateway-vpc-link=True",
            },
          },
          podAnnotations: {
            "<http://ad.datadoghq.com/nginx-ingress-controller.init_configs|ad.datadoghq.com/nginx-ingress-controller.init_configs>": "[{},{}]",
            "<http://ad.datadoghq.com/nginx-ingress-controller.check_names|ad.datadoghq.com/nginx-ingress-controller.check_names>": '["nginx","nginx_ingress_controller"]',
            "<http://ad.datadoghq.com/nginx-ingress-controller.instances|ad.datadoghq.com/nginx-ingress-controller.instances>": '[{"nginx_status_url":"<http://%%host%>%/nginx_status"},{"prometheus_url":"<http://%%host%>%:10254/metrics"}]',
            "<http://ad.datadoghq.com/nginx-ingress-controller.logs|ad.datadoghq.com/nginx-ingress-controller.logs>" : '[{"service": "controller","source":"nginx-ingress-controller"}]',
            "<http://prometheus.io/port|prometheus.io/port>": "10254",
            "<http://prometheus.io/scrape|prometheus.io/scrape>": "true",
          },
        },
      },
    }, { parent: this })

    this.service = nginx.getResource(
      "v1/Service",
      namespaceName,
      "ingress-nginx-ingress-controller",
    )

    // const vpcLink = new aws.apigateway.VpcLink("vpc-eks", {
    //   description: "vpc-eks",
    //   targetArn: ???, // No idea how to get this one
    // },{ dependsOn: [this.service] })

    this.frontendIp = this.service.status.loadBalancer.ingress[0].ip

    this.registerOutputs({
      service: this.service,
    })
  }
}
you can use it like
Copy code
const cluster = eks.Cluster(...)

const providers = {
  kubernetes: cluster.provider,
}

const ingressController = new NginxIngress("ingress-controller", {
  namespaceName: "nginx",
}, { providers })

// do something with `ingressController.frontendIp`
// that's an output and you need to `dependsOn: [ingressController.service]` wherever you use it