pulumi.Run(func(ctx *pulumi.Context) error { dev, err := metal.NewDevice(ctx, name, &metal.DeviceArgs{ Hostname: pulumi.String(hostname), Metro: pulumi.String(metro), OperatingSystem: pulumi.String(slaveOS), ProjectId: pulumi.String(projectID), Plan: pulumi.String(slavePlan), // Make equinix store our node info for us CustomData: pulumi.String(string(nodeInfoJSON)), BillingCycle: pulumi.String("hourly"), }) if err != nil { log.Errorln("Error creating new Device: ", err) return err } /* To get this UUID manually: Managed to find it in the network logs in browser devtools, under a query to the packet.net api with virtual-networks, it's the first ID field, in case anyone else (or I) need to find that again It's also in the terraform state file, somewhere, apparently. This should be automated later */ vlan0, err := metal.GetVlan(ctx, admVlan, pulumi.ID("1a2ca742-9beb-48ef-831e-b1d362add9dc"), nil) if err != nil { log.Errorln("Error Getting admVlan: ", err) return err } // This is horrible, why does pulumi require their own types // I do not approve of this, don't do this. dev.ID().ToStringOutput().ApplyT(func(devid string) pulumi.Output { portattachment, err := metal.NewPortVlanAttachment(ctx, fmt.Sprintf("%v-%v", name, admVlan), &metal.PortVlanAttachmentArgs{ DeviceId: pulumi.String(devid), PortName: pulumi.String("bond0"), VlanVnid: vlan0.Vxlan, }) pulumi.Printf("Port attachment: %v", portattachment.URN()) // There's no good way to handle this error, so we just log it and continue. // If this happens more than once then there's probably an issue with the code above if err != nil { log.Errorln("Error creating PortVlanAttachment: ", err) } return nil }) // Get the IP address of the new node, eventually put it into DNS as well (or don't store it in the DB at all?) dev.Networks.ToDeviceNetworkArrayOutput().ApplyT(func(ips []metal.DeviceNetwork) pulumi.Output { for _, ip := range ips { parsedip := net.ParseIP(*ip.Address) if adminIPv6SubnetParsed.Contains(parsedip) { nodeInfo.IPAddr = parsedip.String() break } } return nil }) //log.Debugf("%+v", nodeInfo) // log.Debugf("%+v", vlan0) // log.Debugf("%+v", dev) //log.Debugln(pulumi.All(dev.URN().ToStringOutput(), vlan0.URN().ToStringOutput()).ApplyT(func(args []interface{}) string { // return fmt.Sprintf("URNS: %v %v", args...) // })) log.Errorf("%#v", pulumi.Sprintf("%#v", pulumi.Printf("URNs: %#v %#v", dev.URN().ToStringOutput(), vlan0.URN().ToStringOutput()))) dbout := db.Create(&nodeInfo) if dbout.Error != nil { log.Errorln("Error inserting node info into DB: ", err) return err } // While it is slightly redundant to not just merge this return with whatever function came before, // It's good practice so that we can handle errors in future functions without modifications. return nil })