Hi Team, Wonder if you can advise , I am new to g...
# golang
l
Hi Team, Wonder if you can advise , I am new to golang and Pulumi, creating multiple EC2 multiple instances with following Code . I would like to export , publicip, ec2name , hostname for each ec2 machine in a separate record . I am creating a ec2.Instance slice and then exporting their value . What would be the best way to get the output in the following format, desired output:
Copy code
Machine 1
hostname: <http://ec2-15-161-152-141.eu-south-1.compute.amazonaws.com|ec2-15-161-152-141.eu-south-1.compute.amazonaws.com>
Public ip : 15.161.152.141
Machine2
hostname: <http://ec2-15-160-154-234.eu-south-1.compute.amazonaws.com|ec2-15-160-154-234.eu-south-1.compute.amazonaws.com>
Public ip : 15.160.154.234
Current Code :
Copy code
var nodeList []*ec2.Instance

for i := 1; i <= args.NumberOfNodes; i++ {
   vm.Instance, err = ec2.NewInstance(ctx, fmt.Sprintf("machine-%d", i), &ec2.InstanceArgs{
      Tags: pulumi.StringMap{"Name": pulumi.String(fmt.Sprintf("kafka-%d", i))},
      //InstanceType:        pulumi.String("t3.large"),
      InstanceType:        args.InstanceType,
      VpcSecurityGroupIds: pulumi.StringArray{vm.SecurityGroup.ID()},
      Ami:                 pulumi.String("ami-0f8ce9c417115413d"),
      UserData:            userData,
      KeyName:             deployer.KeyName,
   })
   if err != nil {
      panic("error creating ec2 instance")
   }
   nodeList = append(nodeList, vm.Instance)
}

for k, v := range nodeList {
   ctx.Export("publicIp"+strconv.Itoa(k), v.PublicIp)
   ctx.Export("publicHostName"+strconv.Itoa(k), v.PublicDns)


}
Current Outputs:
Copy code
publicHostName0: "<http://ec2-15-161-152-141.eu-south-1.compute.amazonaws.com|ec2-15-161-152-141.eu-south-1.compute.amazonaws.com>"
publicHostName1: "<http://ec2-15-160-154-234.eu-south-1.compute.amazonaws.com|ec2-15-160-154-234.eu-south-1.compute.amazonaws.com>"

    publicIp0      : "15.161.152.141"
    publicIp1      : "15.160.154.234"
b
What's the issue with your current code?
l
Hi @bored-table-20691, Currently there is no issue . However Each ec2 machine information (its Public ip , hostname , public) not coordinating as being on the slice . I am looking to output in the following format as our plan is to store each individual Ec2 information in database
Copy code
Machine 1
hostname: <http://ec2-15-161-152-141.eu-south-1.compute.amazonaws.com|ec2-15-161-152-141.eu-south-1.compute.amazonaws.com>
Public ip : 15.161.152.141


Machine2
hostname: <http://ec2-15-160-154-234.eu-south-1.compute.amazonaws.com|ec2-15-160-154-234.eu-south-1.compute.amazonaws.com>
Public ip : 15.160.154.234
b
I’m not sure I really follow. You can choose how you want to export it, so it can just be:
Copy code
ctx.Export("machine-1-hostname", ...)
ctx.Export("machine-1-public-ip", ...)
ctx.Export("machine-2-hostname", ...)
ctx.Export("machine-2-public-ip", ...)
You can do that in a loop if you want over your values.
l
I am already looping over the slice using following code .Also I want to be more Dynamic way for exporting the value . The code I pasted on my first post uses a loop for create multiple Ec2 machine . User could create 100 of ec2 machines with one request and we want to capture each machine information . I am thinking if I could use map instead of slice to export machine information.
Copy code
for k, v := range nodeList {
   ctx.Export("publicIp"+strconv.Itoa(k), v.PublicIp)
   ctx.Export("publicHostName"+strconv.Itoa(k), v.PublicDns)
So Idea is to export the value in the following format for each machine and store in nosql db
Copy code
{
Machine 1: {
hostname: <http://ec2-15-161-152-141.eu-south-1.compute.amazonaws.com|ec2-15-161-152-141.eu-south-1.compute.amazonaws.com>
Public ip : 15.161.152.141
}
},
{
Machine 2: {
hostname: <http://ec2-15-161-152-142.eu-south-1.compute.amazonaws.com|ec2-15-161-152-142.eu-south-1.compute.amazonaws.com>
Public ip : 15.161.152.142
}
}
b
I see. In which case, your best bet will be to marshal it to a JSON string and export that.
l
agree , any idea how i can export , is there any example I can follow. Sorry still newbie to golang and pulumi
b
This is very much pseudo-code but should give you the idea:
Copy code
var nodeList []*ec2.Instance

...

var ips []pulumi.StringOutput
var dns []pulumi.StringOutput
for _, node := range nodeList {
    ips = append(ips, node.PublicIp)
    dns = append(ips, node.PublicDns)
}

jsonOut := pulumi.All(ips..., dns...).ApplyT(func (args []interface{}) (string, error) {
    length := len(args) / 2

    var output []map[string]string
    for idx, _ := range args {
        ip := args[idx].(string)
        dns := args[idx+length].(string)

        output = append(output, map[string]string{
            "ip": ip,
            "dns": dns,
        }
    }

    outputBytes, err := json.Marshal(output)
    if err != nil {
        return nil, err
    }

    return string(outputBytes), nil
})

ctx.Export("machine-info", jsonOut)
l
Thanks very much @bored-table-20691, Much appreciated 🙏,
Hi @bored-table-20691, I have used the above script and getting following error . it creates machine but when it want execute above code the I get following error + pulumipulumiStack prod-prod-dev creating + virtual_machine ec2-vms creating + awsec2KeyPair deployer creating + awsec2SecurityGroup web-secgrp creating + awsec2KeyPair deployer created + awsec2SecurityGroup web-secgrp created + awsec2Instance machine-1 creating + awsec2Instance machine-2 creating + awsec2Instance machine-3 creating + awsec2Instance machine-1 created + awsec2Instance machine-2 created + awsec2Instance machine-3 created
panic: interface conversion: interface {} is []pulumi.StringOutput, not string
goroutine 160 [running]:
Also code does not accept pulumi.All(ips..., dns...) , I had to add as pulumi.All(ips, dns)
b
What's the specific code you ended up running? Which line is causing the error?
l
Hi @bored-table-20691, So the code is divided in few sections . I am creating the Virtual machine component “NewVirtualMachine” . Then I call this on another function “GetDeployVMFunc” . Then I call “deployfunction” Virtualmachine Component :
Copy code
func NewVirtualMachine(ctx *pulumi.Context, name string, args *virtualmachines.VirtualMachinesArgs, opts ...pulumi.ResourceOption) (*virtualmachines.VirtualMachines, error) {

   vm := &virtualmachines.VirtualMachines{}

   err := ctx.RegisterComponentResource("virtual_machine", name, vm, opts...)
   if err != nil {
      return nil, err
   }

   stackName := ctx.Stack()

   // Create a valid webserver security group
   vm.SecurityGroup, err = ec2.NewSecurityGroup(ctx, "web-secgrp", &ec2.SecurityGroupArgs{
      Ingress: ec2.SecurityGroupIngressArray{
         ec2.SecurityGroupIngressArgs{
            //Protocol:   pulumi.String("tcp"),
            Protocol:   args.Protocol,
            FromPort:   <http://pulumi.Int|pulumi.Int>(80),
            ToPort:     <http://pulumi.Int|pulumi.Int>(80),
            CidrBlocks: pulumi.StringArray{pulumi.String("0.0.0.0/0")},
         },
      },
   })
   if err != nil {
      return nil, err
   }

   userData := pulumi.Sprintf(`#!/bin/bash
      echo "Hello from stack %s" > index.html
      nohup python -m SimpleHTTPServer 80 &`, stackName)

   deployer, err := ec2.NewKeyPair(ctx, "deployer", &ec2.KeyPairArgs{
      PublicKey: pulumi.String("ssh-rsa-key "),
   })
   if err != nil {
      return nil, err
   }

   var nodeList []*ec2.Instance
   var ips []pulumi.StringOutput
   var dns []pulumi.StringOutput

   for i := 1; i <= args.NumberOfNodes; i++ {
      name := fmt.Sprintf("Machine-%d", i)
      vm.Instance, err = ec2.NewInstance(ctx, name, &ec2.InstanceArgs{
         Tags: pulumi.StringMap{"Name": pulumi.String(fmt.Sprintf("Machine-%d", i))},
         //InstanceType:        pulumi.String("t3.large"),
         InstanceType:        args.InstanceType,
         VpcSecurityGroupIds: pulumi.StringArray{vm.SecurityGroup.ID()},
         Ami:                 pulumi.String("ami-0f8ce9c417115413d"),
         UserData:            userData,
         KeyName:             deployer.KeyName,
      })
      if err != nil {
         panic("error creating ec2 instance")
      }

      nodeList = append(nodeList, vm.Instance)

      for _, node := range nodeList {
         ips = append(ips, node.PublicIp)
         dns = append(dns, node.PublicDns)
      }

   }
   jsonOut := pulumi.All(ips, dns).ApplyT(func(args []interface{}) (string, error) {
      length := len(args) / 2

      var output []map[string]string
      for idx, _ := range args {
         ip := args[idx].(string)
         dns := args[idx+length].(string)

         output = append(output, map[string]string{
            "ip":  ip,
            "dns": dns,
         })
      }

      outputBytes, err := json.Marshal(output)
      if err != nil {
         return fmt.Sprintf("Not able to create json"), err
      }
      fmt.Println(string(outputBytes))
      return string(outputBytes), nil
   })

   ctx.Export("machine-info", jsonOut)
   return vm, nil
}
Get Deploy Function :
Copy code
unc (v *virtualMachinesService) GetDeployVMFunc(vm *virtualmachines.CreateVmReq) pulumi.RunFunc {

   return func(ctx *pulumi.Context) error {

      fmt.Println(vm.Protocol)
      _, err := NewVirtualMachine(ctx, "ec2-vms", &virtualmachines.VirtualMachinesArgs{

         Protocol:      pulumi.String(vm.Protocol),
         NumberOfNodes: vm.NumberOfNodes,
         InstanceType:  pulumi.String(vm.InstanceType),
      })

      if err != nil {
         return err
      }
      
      return nil

   }

}
Deploy function :
Copy code
// set out program for the deployment with the resulting network info
w.SetProgram(VirtualMachinesService.GetDeployVMFunc(vm))

fmt.Println("deploying vm webserver...")

// wire up our update to stream progress to stdout
stdoutStreamer := optup.ProgressStreams(os.Stdout)

res, err := s.Up(ctx, stdoutStreamer)
if err != nil {
   fmt.Printf("Failed to deploy vm stack: %v\n", err)
   os.Exit(1)
}
//time.Sleep(60 * time.Second)

for key, element := range res.Outputs {
   fmt.Println("key", key, "=>", element.Value)
}
fmt.Println("Update succeeded!")
And have the Virtual machine Struct setup like this
Copy code
type VirtualMachines struct {
   pulumi.ResourceState
   PublicIP             *ec2.Eip `pulumi:"publicip"`
   NetworkInterface     *ec2.NetworkInterface
   VPC                  *ec2.Vpc
   Instance             *ec2.Instance `pulumi:"instance"`
   Internet_gateway     *ec2.InternetGateway
   Route                *ec2.Route
   GetAvailabilityZones *ec2.AvailabilityZoneGroup
   Subnet               *ec2.Subnet
   SecurityGroup        *ec2.SecurityGroup
}
I suspect panic is due to the following line
Copy code
jsonOut := pulumi.All(ips, dns).ApplyT(func(args []interface{}) (string, error) {
Error:
panic: interface conversion: interface {} is []pulumi.StringOutput, not string
goroutine 160 [running]
b
The goroutine stack will tell you which line specifically is erroring - is that the line it says? What’s the code for the
ApplyT
function?
l
Copy code
+  pulumi:pulumi:Stack prod-prod-dev creating
 +  virtual_machine ec2-vms creating
 +  aws:ec2:KeyPair deployer creating
 +  aws:ec2:SecurityGroup web-secgrp creating
 +  aws:ec2:KeyPair deployer created
 +  aws:ec2:SecurityGroup web-secgrp created
 +  aws:ec2:Instance Machine-1 creating
 +  aws:ec2:Instance Machine-2 creating
 +  aws:ec2:Instance Machine-3 creating
 +  aws:ec2:Instance Machine-2 created
 +  aws:ec2:Instance Machine-3 created
 +  aws:ec2:Instance Machine-1 created
panic: interface conversion: interface {} is []pulumi.StringOutput, not string

goroutine 213 [running]:
<http://github.com/services.NewVirtualMachine.func1(0xc0001acce0|github.com/services.NewVirtualMachine.func1(0xc0001acce0>, 0x2, 0x2, 0x0, 0x0, 0x0, 0x0)
	Documents/github.com/services/virtual_machines.go:208 +0x489
reflect.Value.call(0x2869700, 0x2d3f6a8, 0x13, 0x2cda1e6, 0x4, 0xc000ec4348, 0x1, 0x1, 0x1010f7b, 0xc000081a28, ...)
	/usr/local/go/src/reflect/value.go:476 +0x8e7
reflect.Value.Call(0x2869700, 0x2d3f6a8, 0x13, 0xc000ec4348, 0x1, 0x1, 0x2749b40, 0xc000eba888, 0xc000081b90)
	/usr/local/go/src/reflect/value.go:337 +0xb9
<http://github.com/pulumi/pulumi/sdk/v3/go/pulumi.makeContextful.func1(0xc000ec4330|github.com/pulumi/pulumi/sdk/v3/go/pulumi.makeContextful.func1(0xc000ec4330>, 0x2, 0x2, 0xc000ec4330, 0x2a6ec0, 0x2842ea0)
	/Users/go/pkg/mod/github.com/pulumi/pulumi/sdk/v3@v3.19.0/go/pulumi/types.go:362 +0x7c
reflect.Value.call(0xc000dbc300, 0xc000c63b90, 0x13, 0x2cda1e6, 0x4, 0xc000081f60, 0x2, 0x2, 0x296c2a0, 0x2749b40, ...)
	/usr/local/go/src/reflect/value.go:476 +0x8e7
reflect.Value.Call(0xc000dbc300, 0xc000c63b90, 0x13, 0xc000d31760, 0x2, 0x2, 0xc000ec4300, 0x3, 0x3)
	/usr/local/go/src/reflect/value.go:337 +0xb9
<http://github.com/pulumi/pulumi/sdk/v3/go/pulumi.(*OutputState).ApplyTWithContext.func1(0xc0007fa690|github.com/pulumi/pulumi/sdk/v3/go/pulumi.(*OutputState).ApplyTWithContext.func1(0xc0007fa690>, 0x30297d8, 0xc0001b4050, 0x3043708, 0xc0007fa700, 0xc000dbc300, 0xc000c63b90, 0x13)
	/Users/go/pkg/mod/github.com/pulumi/pulumi/sdk/v3@v3.19.0/go/pulumi/types.go:470 +0x2f1
created by <http://github.com/pulumi/pulumi/sdk/v3/go/pulumi.(*OutputState).ApplyTWithContext|github.com/pulumi/pulumi/sdk/v3/go/pulumi.(*OutputState).ApplyTWithContext>
	/Users/go/pkg/mod/github.com/pulumi/pulumi/sdk/v3@v3.19.0/go/pulumi/types.go:458 +0x1f6
exit status 2
Above is the full output
b
Copy code
Documents/github.com/services/virtual_machines.go:208
This line, which line is it? And can you share the full function for
ApplyT
?
l
so the
virtual_machines.go
file have all the function I mentioned in the above comments
let me add again
b
Ah sorry, I see it now
l
Copy code
func NewVirtualMachine(ctx *pulumi.Context, name string, args *virtualmachines.VirtualMachinesArgs, opts ...pulumi.ResourceOption) (*virtualmachines.VirtualMachines, error) {

   vm := &virtualmachines.VirtualMachines{}

   err := ctx.RegisterComponentResource("virtual_machine", name, vm, opts...)
   if err != nil {
      return nil, err
   }

   stackName := ctx.Stack()

   // Create a valid webserver security group
   vm.SecurityGroup, err = ec2.NewSecurityGroup(ctx, "web-secgrp", &ec2.SecurityGroupArgs{
      Ingress: ec2.SecurityGroupIngressArray{
         ec2.SecurityGroupIngressArgs{
            //Protocol:   pulumi.String("tcp"),
            Protocol:   args.Protocol,
            FromPort:   <http://pulumi.Int|pulumi.Int>(80),
            ToPort:     <http://pulumi.Int|pulumi.Int>(80),
            CidrBlocks: pulumi.StringArray{pulumi.String("0.0.0.0/0")},
         },
      },
   })
   if err != nil {
      return nil, err
   }

   userData := pulumi.Sprintf(`#!/bin/bash
      echo "Hello from stack %s" > index.html
      nohup python -m SimpleHTTPServer 80 &`, stackName)

   deployer, err := ec2.NewKeyPair(ctx, "deployer", &ec2.KeyPairArgs{
      PublicKey: pulumi.String("ssh-rsa-key "),
   })
   if err != nil {
      return nil, err
   }

   var nodeList []*ec2.Instance
   var ips []pulumi.StringOutput
   var dns []pulumi.StringOutput

   for i := 1; i <= args.NumberOfNodes; i++ {
      name := fmt.Sprintf("Machine-%d", i)
      vm.Instance, err = ec2.NewInstance(ctx, name, &ec2.InstanceArgs{
         Tags: pulumi.StringMap{"Name": pulumi.String(fmt.Sprintf("Machine-%d", i))},
         //InstanceType:        pulumi.String("t3.large"),
         InstanceType:        args.InstanceType,
         VpcSecurityGroupIds: pulumi.StringArray{vm.SecurityGroup.ID()},
         Ami:                 pulumi.String("ami-0f8ce9c417115413d"),
         UserData:            userData,
         KeyName:             deployer.KeyName,
      })
      if err != nil {
         panic("error creating ec2 instance")
      }

      nodeList = append(nodeList, vm.Instance)

      for _, node := range nodeList {
         ips = append(ips, node.PublicIp)
         dns = append(dns, node.PublicDns)
      }

   }
jsonOut := pulumi.All(ips, dns).ApplyT(func(args []interface{}) (string, error) {
length := len(args) / 2
Copy code
var output []map[string]string
      for idx, _ := range args {
         ip := args[idx].(string)
         dns := args[idx+length].(string)

         output = append(output, map[string]string{
            "ip":  ip,
            "dns": dns,
         })
      }

      outputBytes, err := json.Marshal(output)
      if err != nil {
         return fmt.Sprintf("Not able to create json"), err
      }
      fmt.Println(string(outputBytes))
      return string(outputBytes), nil
   })

   ctx.Export("machine-info", jsonOut)
   return vm, nil
}
b
which line is 208?
l
Copy code
for idx, _ := range args {
   ip := args[idx].(string)
   dns := args[idx+length].(string)

   output = append(output, map[string]string{
      "ip":  ip,
      "dns": dns,
   })
}
that 208 line
ip := args[idx].(string)
b
Yeah
I’d try something like this instead:
Copy code
outputs := []pulumi.StringOutput
    for _, node := range nodeList {
       outputs = append(outputs, node.PublicIp, node.PublicDns)
    }


   jsonOut := pulumi.All(outputs...).ApplyT(func(args []interface{}) (string, error) {
      length := len(args)
      for idx := 0; idx < length; idx += 2 {
         ip := args[idx].(string)
         dns := args[idx+1].(string)

         output = append(output, map[string]string{
            "ip":  ip,
            "dns": dns,
         })
      }

      outputBytes, err := json.Marshal(output)
      if err != nil {
         return fmt.Sprintf("Not able to create json"), err
      }
      fmt.Println(string(outputBytes))
      return string(outputBytes), nil
   })

   ctx.Export("machine-info", jsonOut)
   return vm, nil
}
l
thanks very Much , Almost came the similar version but was struggling with the getting all the records in slice my version was showing only last record .
Copy code
for _, nodes := range nodeList {

   jsonout := pulumi.All(nodes.PublicIp, nodes.PublicDns).ApplyT(func(args []interface{}) (string, error) {

      var output []map[string]string
      ip := args[0].(string)
      dns := args[1].(string)

      output = append(output, map[string]string{
         "ip":  ip,
         "dns": dns,
      })

      outputBytes, err := json.Marshal(output)
      if err != nil {
         return fmt.Sprintf("Not able to create json"), err
      }
      return string(outputBytes), nil
   })
   // fmt.Println(jsonout)
   ctx.Export("machine-info", jsonout)
}
Let me try now
b
the JSON piece should not be inside the body of the loop
l
Now getting this error , complaining about following line
Copy code
jsonOut := pulumi.All(outputs...).ApplyT(func(args []interface{}) (string, error) {
Cannot use ‘outputs’ (type []pulumi.StringOutput) as the type []interface{}
What is the difference between jsonOut := pulumi.All(outputs).ApplyT(func(args []interface{}) (string, error) { & jsonOut := pulumi.All(outputs…).ApplyT(func(args []interface{}) (string, error) {
b
Copy code
outputs := []interface{}{}
change it to that.
l
sure
b
https://pkg.go.dev/github.com/pulumi/pulumi/sdk/v3@v3.24.1/go/pulumi#All
pulumi.All
accepts a variable argument list, and will wait until they’re all resolved. If you pass in just
outputs
- then it waits for that value to be resolved (which it is, immediately, since it’s not a future).
outputs…
passes each element as an argument, allowing you to wait for each one.
l
🙏👍
I have another question if you dont mind . Since I have return the output to *virtualmachines.VirtualMachines Struct . Why do I need to do ctx.Export(“machine-info”, jsonOut)
Also what is the difference between ctx.Export Vs
Copy code
ctx.RegisterResourceOutputs(vm, pulumi.Map{
"PublicIP": vm.Instance.PublicIp,
Why do we have to use
ctx.Export
, Cant we use
ctx.RegisterResourceOutputs
and use the output some where
b
ctx.Export
exports it as a stack output, so that other stacks can use it as stack references, or if you need some other automation otuside your stack to access it.
Your
RegisterResourceOutputs
call registers it as an output of a component resource.
l
call registers it as an output of a component resource
, so what impact it has on the program as whole
b
None - it just registers it ofr that component resource.
l
hmm isee
would there be a problem if I dont use in my components
b
I’m not sure what you mean. You need to use it in your component resources if you want this to be an output of that resource (so reference-able by your other things).
l
ohoo i see
So to clarify if I use the following code for for virtual machine component , i can only reference to PublicIP of that component
Copy code
ctx.RegisterResourceOutputs(vm, pulumi.Map{
"PublicIP": vm.Instance.PublicIp,
}
b
I believe so, yes
l
Just ran the code Working as expected. 🙏. Next I am going to look how to push this info to DB.
Copy code
+  aws:ec2:Instance Machine-4 creating
 +  aws:ec2:Instance Machine-4 created
 +  aws:ec2:Instance Machine-5 created
[{"dns":"<http://ec2-15-161-190-245.eu-south-1.compute.amazonaws.com|ec2-15-161-190-245.eu-south-1.compute.amazonaws.com>","ip":"15.161.190.245"},{"dns":"<http://ec2-15-161-197-181.eu-south-1.compute.amazonaws.com|ec2-15-161-197-181.eu-south-1.compute.amazonaws.com>","ip":"15.161.197.181"},{"dns":"<http://ec2-15-161-107-21.eu-south-1.compute.amazonaws.com|ec2-15-161-107-21.eu-south-1.compute.amazonaws.com>","ip":"15.161.107.21"},{"dns":"<http://ec2-15-160-211-73.eu-south-1.compute.amazonaws.com|ec2-15-160-211-73.eu-south-1.compute.amazonaws.com>","ip":"15.160.211.73"},{"dns":"<http://ec2-15-161-228-178.eu-south-1.compute.amazonaws.com|ec2-15-161-228-178.eu-south-1.compute.amazonaws.com>","ip":"15.161.228.178"}]
    virtual_machine ec2-vms
    pulumi:pulumi:Stack prod-prod-dev

Outputs:
  + machine-info: "[{\"dns\":\"<http://ec2-15-161-190-245.eu-south-1.compute.amazonaws.com|ec2-15-161-190-245.eu-south-1.compute.amazonaws.com>\",\"ip\":\"15.161.190.245\"},{\"dns\":\"<http://ec2-15-161-197-181.eu-south-1.compute.amazonaws.com|ec2-15-161-197-181.eu-south-1.compute.amazonaws.com>\",\"ip\":\"15.161.197.181\"},{\"dns\":\"<http://ec2-15-161-107-21.eu-south-1.compute.amazonaws.com|ec2-15-161-107-21.eu-south-1.compute.amazonaws.com>\",\"ip\":\"15.161.107.21\"},{\"dns\":\"<http://ec2-15-160-211-73.eu-south-1.compute.amazonaws.com|ec2-15-160-211-73.eu-south-1.compute.amazonaws.com>\",\"ip\":\"15.160.211.73\"},{\"dns\":\"<http://ec2-15-161-228-178.eu-south-1.compute.amazonaws.com|ec2-15-161-228-178.eu-south-1.compute.amazonaws.com>\",\"ip\":\"15.161.228.178\"}]"

Resources:
    + 2 created
    7 unchanged

Duration: 16s

key machine-info => [{"dns":"<http://ec2-15-161-190-245.eu-south-1.compute.amazonaws.com|ec2-15-161-190-245.eu-south-1.compute.amazonaws.com>","ip":"15.161.190.245"},{"dns":"<http://ec2-15-161-197-181.eu-south-1.compute.amazonaws.com|ec2-15-161-197-181.eu-south-1.compute.amazonaws.com>","ip":"15.161.197.181"},{"dns":"<http://ec2-15-161-107-21.eu-south-1.compute.amazonaws.com|ec2-15-161-107-21.eu-south-1.compute.amazonaws.com>","ip":"15.161.107.21"},{"dns":"<http://ec2-15-160-211-73.eu-south-1.compute.amazonaws.com|ec2-15-160-211-73.eu-south-1.compute.amazonaws.com>","ip":"15.160.211.73"},{"dns":"<http://ec2-15-161-228-178.eu-south-1.compute.amazonaws.com|ec2-15-161-228-178.eu-south-1.compute.amazonaws.com>","ip":"15.161.228.178"}]
Update succeeded!
b
👍
l
var
jsonOut
is of pulumi.Output . Can I use it directly to store value to some struct or do I have export it first which we did and can be seen on the output
b
It’s a future value - it won’t be known at runtime what it is.
l
only way I know to print the exported value using range to the res.output. I take that would be the right place to know the future value
Copy code
res, err := s.Up(ctx, stdoutStreamer)
if err != nil {
   fmt.Printf("Failed to deploy vm stack: %v\n", err)
   os.Exit(1)
}
//time.Sleep(60 * time.Second)
for key, element := range res.Outputs {
fmt.Println("key", key, "=>", element.Value)
Copy code
}
b
Yes, you can reference it in the automation API
or via the CLI with
pulumi stack output
l
Thank , I do it normally using Automation api
I am sorry keep asking questions . Can
ApplyT
output to some STRUCT which can then be use in the program like using the struct value to some other programs. pulumi.All(outputs...).ApplyT(func(args []interface{}) (
vm.struct
, error) something like above
b
No - the result of
ApplyT
will always be a future.
l
I see
thanks
Hi @bored-table-20691, I did manage to store the info in the DB, So Thank you so much for the advise 🙏. once I added the info to Db i noticed that i was looking to store Name of each machine . I dont think the name is part of the ec2.InstanceArgs which can be exported using
ctx.export
Copy code
for i := 1; i <= 3; i++ {
name := fmt.Sprintf("Machine-%d", i)
Copy code
vm.Instance, err = ec2.NewInstance(ctx, name, &ec2.InstanceArgs{
   Tags: pulumi.StringMap{"Name": pulumi.String(fmt.Sprintf("Machine-%d", i))},
   //InstanceType:        pulumi.String("t3.large"),
   InstanceType:        args.InstanceType,
   VpcSecurityGroupIds: pulumi.StringArray{vm.SecurityGroup.ID()},
   Ami:                 pulumi.String("ami-0f8ce9c417115413d"),
   UserData:            userData,
   KeyName:             deployer.KeyName,
})
I have updated the code we discussed last week , adding the new slice which picks the name of the node and trying to append it to the output slice interface . But some how not getting the desired result where the name is also added as part of dns, ip . Just wondering where i am missing the trick . really Appreciate for the advise
Copy code
nodeName = append(nodeName, pulumi.Sprintf(name))
      nodeList = append(nodeList, vm.Instance)

   }

   //var outputs []pulumi.StringOutput
   outputs := []interface{}{}

   for _, names := range nodeName {

      for _, node := range nodeList {

         outputs = append(outputs, node.PublicIp, node.PublicDns, names)
      }
   }

   jsonOut := pulumi.All(outputs...).ApplyT(func(args []interface{}) (string, error) {
      length := len(args)
      fmt.Println(length)
      var output []map[string]string
      for idx := 0; idx < length; idx += 3 {
         ip := args[idx].(string)
         dns := args[idx+1].(string)
         name := args[idx+2].(string)

         output = append(output, map[string]string{
            "ip":   ip,
            "dns":  dns,
            "name": name,
         })
      }

      outputBytes, err := json.Marshal(output)
      if err != nil {
         return fmt.Sprintf("Not able to create json"), err
      }
      fmt.Println(string(outputBytes))
      return string(outputBytes), nil
   })

   ctx.Export("machine-info", jsonOut)
   return vm, nil
}
b
You’re loop doesn’t look right, you’re iterating over nodeList for each name, rather than once (so you basically end up with the same list many times over). You want likely something like this (since
nodeName
and
nodeList
are the same length):
Copy code
for idx, node := range nodeList {
    outputs = append(outputs, node.PublicIp, node.PublicDns, nodeName[idx])
}
And then in the
ApplyT
function, it would be similar to what you have in your code above.
l
Thanks, Let me try