This message was deleted.
s
This message was deleted.
b
l
šŸ‘Thanks
Hi @billowy-army-68599 Thanks for sharing that worked perfectly as expected . Now I would like to clarify one more qustion . After provisioning these Instances we would like to deploy Elasticsearch cluster or mongo db . What would be best way to deploy any apps using pulumi, any pointers will be appreciated .
b
do you mean inside the ec2 instance? if so, then use the new pulumi-command provider: https://www.pulumi.com/registry/packages/command/api-docs/
l
yes Inside ec2 machines when they ready
Thanks i will have look
One more thing to clarify please
Lets say If wanted to decommission one of the 5 web servers I added instead of destrying the whole stack . what would be the best way to remove individual ec2 machine from the stack. I am looking to do it using automation api.
b
you'd need to remove the instance from your code or do
pulumi destroy --target <urn>
l
Thanks, Just wondering how I can get the urn of the specific resource using code ?
b
pulumi stack -u
l
Thanks very much for sharing . How we can access this feature using autmation api , is there any example which I can look please
b
l
Hi @billowy-army-68599, I would really appreciate your advise .So I have Implemented the Ec2 instances . We are now looking to get the Public Ip address every Instance and other properties when they are fully provisioned . Following the auzre example I mentioned above . I am trying to implement similar function to the IP address . In my version I am trying to achieve the similar function using ec2.GetInstance function which does not except the pulumi.StringOutput and give me errros . • First I would to confirm if I am using the write approach to GetInstance properties for Ec2 machine. More importantly when they are fully provisioned . • I am using this example as it uses ApplyT(func(args []interface{}) (string, error) function which I think waits for the resource to be ready and gives use resource properties . • Can i achieve the following some other way Azure Version
Copy code
func (ws *Webserver) GetIPAddress(ctx *pulumi.Context) pulumi.StringOutput {
   // The public IP address is not allocated until the VM is running, so wait for that resource to create, and then
   // lookup the IP address again to report its public IP.
   ready := pulumi.All(ws.VM.ID(), ws.PublicIP.Name, ws.PublicIP.ResourceGroupName)
   return ready.ApplyT(func(args []interface{}) (string, error) {
      name := args[1].(string)
      resourceGroupName := args[2].(string)
      ip, err := network.GetPublicIP(ctx, &network.GetPublicIPArgs{
         Name:              name,
         ResourceGroupName: resourceGroupName,
      })
      if err != nil {
         return "", err
      }
      return ip.IpAddress, nil
   }).(pulumi.StringOutput)
}
My Version for EC2
Copy code
func (v *virtualMachinesService) GetIPAddress(ctx *pulumi.Context) pulumi.StringOutput {
   vm := new(virtualmachines.VirtualMachines)
   // The public IP address is not allocated until the VM is running, so wait for that resource to create, and then
   // lookup the IP address again to report its public IP.
   ready := pulumi.All(vm.Instance.ID(), vm.Instance.PublicIp)
   return ready.ApplyT(func(args []interface{}) (string, error) {
      pubip := args[1].(string)

      ip, err := ec2.GetInstance(ctx, "web-server-www-",vm.Instance.ID(), &ec2.InstanceState{
         PublicIp: pubip,
      }

      })
      if err != nil {
         return "", err
      }
      return ip.p, nil
   }).(pulumi.StringOutput)
}
Copy code
type VirtualMachines struct {
   pulumi.ResourceState
   PublicIP         *ec2.Eip
   NetworkInterface *ec2.NetworkInterface
   VPC               *ec2.Vpc
   Instance  *ec2.Instance
   Internet_gateway *ec2.InternetGateway
   Route *ec2.Route
   GetAvailabilityZones *ec2.AvailabilityZoneGroup
   Subnet *ec2.Subnet
   SecurityGroup *ec2.SecurityGroup


}
b
You shouldn't need to use
GetInstance
for AWS EC2 instances, you should have an output with the IP address already which you can store in a slice
how did you provision your EC2 instances?
l
One way I tried
Copy code
// ctx.Export("ipAddress", srv.PublicIp)
// Export the resulting server's IP address and DNS name.
ctx.Export("publicIp", vm.Instance.PublicIp)
ctx.Export("publicHostName", vm.Instance.PublicDns)
Is that the output you think I can store in the slice ?
Here is code of the VM
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)
fmt.Println(args.InstanceType)
   fmt.Println(args.NumberOfNodes)
   for i := 1; i <= args.NumberOfNodes; i++ {
      vm.Instance, err = ec2.NewInstance(ctx, fmt.Sprintf("web-server-www-%d", i), &ec2.InstanceArgs{
         Tags:                pulumi.StringMap{"Name": pulumi.String(fmt.Sprintf("web-server-www-%d", i))},
         //InstanceType:        pulumi.String("t3.large"),
         InstanceType:        args.InstanceType,
         VpcSecurityGroupIds: pulumi.StringArray{vm.SecurityGroup.ID()},
         Ami:                 pulumi.String("ami-0a24e25f7f758ff73"),
         UserData:            userData,
      })
      if err != nil {
         panic("error creating ec2 instance")
      }
   }

   // ctx.Export("ipAddress", srv.PublicIp)
   // Export the resulting server's IP address and DNS name.
   ctx.Export("publicIp", vm.Instance.PublicIp)
   ctx.Export("publicHostName", vm.Instance.PublicDns)
   return nil, nil
}
Then I read this in
Copy code
func(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
      }
      fmt.Println(vm.NumberOfNodes)
   // ctx.Export("URN", vm.URN())
      return nil

}

}
then use the deploy function which deploys the machines
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!")

   for key, element := range res.Outputs {
      fmt.Println("Key:", key, "=>", "Element:", element.Value)
   }
   fmt.Println("Update succeeded!")

      //fmt.Printf("deployed server running at public IP %s\n", res.Outputs["ip"].Value.(string))



   return nil
}
So I do see the Ip address on the console , but we want to make sure we get the Instance Information (publicip, PublicDNS, EIP and other info ) Just after EC2 machine is fully ready as we would like to store that info in DB for further usage
Thats why i am trying to implement GetIPaddress function as a starting point to safely get the required information and use the
return ready.ApplyT(func(args []interface{}) (pulumi.StringOutput, error)
which i think waits for the resource to be ready .
Below the Structs I am using
Copy code
type VirtualMachines struct {
   pulumi.ResourceState
   PublicIP         *ec2.Eip
   NetworkInterface *ec2.NetworkInterface
   VPC               *ec2.Vpc
   Instance  *ec2.Instance
   Internet_gateway *ec2.InternetGateway
   Route *ec2.Route
   GetAvailabilityZones *ec2.AvailabilityZoneGroup
   Subnet *ec2.Subnet
   SecurityGroup *ec2.SecurityGroup


}

type VirtualMachinesArgs struct {
   // A required username for the VM login.
   Username pulumi.StringInput

   // A required encrypted password for the VM password.
   Password pulumi.StringInput

   // An optional boot script that the VM will use.
   BootScript pulumi.StringInput

   // An optional VM size; if unspecified, Standard_A0 (micro) will be used.
   VMSize pulumi.StringInput

   // A required Resource Group in which to create the VM
   ResourceGroupName pulumi.StringInput

   // A required Subnet in which to deploy the VM
   SubnetID pulumi.StringInput

   // A required Subnet in which to deploy the VM
   CidrBlock pulumi.StringInput

   // This value for VPC to enable DNS
   EnableDnsHostnames pulumi.Bool

   // A map of tags to assign to the resource. If configured with a provider `defaultTags` configuration block present, tags with matching keys will overwrite those defined at the provider-level.
   Tags pulumi.StringMapInput
//
   DestinationCidrBlock pulumi.StringInput

   // Specify true to indicate
   // that instances launched into the subnet should be assigned
   // a public IP address. Default is `false`.
   MapPublicIpOnLaunch pulumi.Bool

   Protocol pulumi.StringInput

   // The instance type to use for the instance. Updates to this field will trigger a stop/start of the EC2 instance.
   InstanceType pulumi.StringInput
   // Number of Nodes
   NumberOfNodes int

   Workdir auto.LocalWorkspace
}
b
You don't need to use
GetInstance
unless there's something in that call that you need. You already get the IPs, so just push them into a slice
if you want to push them into a database, you'll need to iterate over the slice and use an
ApplyT
to get the string value
l
Thanks very much @billowy-army-68599, I will have look šŸ™
Hi @billowy-army-68599, Following the example you mention earlier . Noticed that example built on v2 pulumi. So not able to find the AppyIDArray method , Just wondering that other method can I use to send out the pulumi.IDArrayOutput in v4 aws pulumi.
Copy code
func idOutputArrayToIDArrayOutput(as []pulumi.IDOutput) pulumi.IDArrayOutput {
   var outputs []interface{}
   for _, a := range as {
      outputs = append(outputs, a)
   }
   return pulumi.All(outputs...).ApplyIDArray(func(vs []interface{}) []pulumi.ID {
      var results []pulumi.ID
      for _, v := range vs {
         results = append(results, v.(pulumi.ID))
      }
      return results
   })
}
I have rewrriten like this , is that the right implementation of idOutputArrayToIDArrayOutput
Copy code
func idOutputArrayToIDArrayOutput(as []pulumi.IDOutput) pulumi.IDArrayOutput {
   var outputs []interface{}
   for _, a := range as {
      outputs = append(outputs, a)
   }
   return pulumi.IDArrayOutput(pulumi.All(outputs...).ApplyT(func(vs []interface{}) []pulumi.ID {
      var results []pulumi.ID
      for _, v := range vs {
         results = append(results, v.(pulumi.ID))
      }
      return results
   }).(pulumi.AnyOutput))
}
Hi @billowy-army-68599, I get below error when i implement above changed code, When I comment the code its works fine . Any suggestion how I can write the idOutputArrayToIDArrayOutput function please . really appreciate you advise .
pulumi:pulumi:Stack vpc-vpc-pulumi  error: an unhandled error occurred: go inline source runtime error, an unhandled error occurred:: interface conversion: pulumi.Output is pulumi.IDArrayOutput, not pulumi.IDArrayArrayOutput
pulumi:pulumi:Stack vpc-vpc-pulumi **failed** 1 error
Diagnostics:
pulumi:pulumi:Stack (vpc-vpc-pulumi):
error: an unhandled error occurred: go inline source runtime error, an unhandled error occurred:: interface conversion: pulumi.Output is pulumi.IDArrayOutput, not pulumi.IDArrayArrayOutput
b
i cant help here I'm afraid
l
Sure Thanks