Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cannot use mainNetwork.CustomResourceState.ID() (type pulumi.IDOutput) as type pulumi.IntInput #52

Open
sebandgo opened this issue Mar 15, 2021 · 12 comments
Labels
kind/bug Some behavior is incorrect or out of spec

Comments

@sebandgo
Copy link

sebandgo commented Mar 15, 2021

Hello,
I have followed the example from Pulumi Documentation (https://www.pulumi.com/docs/reference/pkg/hcloud/networksubnet/) but it looks like that the hcloud.NewNetworkSubnet doesn't gets the .ID() output from hcloud.NewNetwork.

Expected behavior

Subnet to be created under the right Network CIDR.

Current behaviour

mainNetwork.ID() output cannot be used as Input for Subnets.

./main.go:104:7: cannot use mainNetwork.CustomResourceState.ID() (type pulumi.IDOutput) as type pulumi.IntInput in field value:
pulumi.IDOutput does not implement pulumi.IntInput (missing ToIntOutput method)

As you can see below if I provide the ID manually using pulumi.Int(1061706) it works.

Steps to reproduce

package main

import (
	"fmt"

	"github.com/pulumi/pulumi-hcloud/sdk/go/hcloud"
	"github.com/pulumi/pulumi/sdk/v2/go/pulumi"
)

func main() {

	pulumi.Run(func(ctx *pulumi.Context) error {

		//
		// Network
		//

		selectedNetwork := map[string]string{}

		productionNetwork := map[string]string{
			"production": "10.1.0.0/16",
		}

		stagingNetwork := map[string]string{
			"staging": "10.2.0.0/16",
		}

		developmentNetwork := map[string]string{
			"development": "10.3.0.0/16",
		}

		switch ctx.Stack() {

		case "production":
			selectedNetwork = productionNetwork
		case "staging":
			selectedNetwork = stagingNetwork
		case "development":
			selectedNetwork = developmentNetwork

		}

		for networkName, networkCIDR := range selectedNetwork {

			mainNetwork, err := hcloud.NewNetwork(
				ctx,
				networkName,
				&hcloud.NetworkArgs{
					IpRange: pulumi.String(networkCIDR),
				},
			)

			if err != nil {
				return err
			}

			fmt.Println(mainNetwork.ID())

			ctx.Export("network/"+networkName+"/id", mainNetwork.ID())
			ctx.Export("network/"+networkName+"/name", mainNetwork.Name)

			//
			// Subnets
			//

			selectedSubnet := map[string]string{}

			productionSubnets := map[string]string{
				"kubernetes": "10.1.1.0/24",
				"databases":  "10.1.2.0/24",
			}

			stagingSubnets := map[string]string{
				"kubernetes": "10.2.1.0/24",
				"databases":  "10.2.2.0/24",
			}

			developmentSubnets := map[string]string{
				"kubernetes": "10.3.1.0/24",
				"databases":  "10.3.2.0/24",
			}

			switch ctx.Stack() {

			case "production":
				selectedSubnet = productionSubnets
			case "staging":
				selectedSubnet = stagingSubnets
			case "development":
				selectedSubnet = developmentSubnets

			}

			for subnetName, subnetCIDR := range selectedSubnet {

				_, err := hcloud.NewNetworkSubnet(
					ctx,
					subnetName,
					&hcloud.NetworkSubnetArgs{
						NetworkId:   mainNetwork.ID(), //pulumi.Int(1061706),
						Type:        pulumi.String("cloud"),
						NetworkZone: pulumi.String("eu-central"),
						IpRange:     pulumi.String(subnetCIDR),
					},
				)

				if err != nil {
					return err
				}

			}
		}

		return nil

	})
}

Context (Environment)

go version go1.16.2 darwin/amd64
github.com/pulumi/pulumi-hcloud/sdk v0.6.2
github.com/pulumi/pulumi/sdk/v2 v2.20.0 [v2.22.0]

Affected feature

@sebandgo sebandgo added the kind/bug Some behavior is incorrect or out of spec label Mar 15, 2021
@viveklak viveklak added bug kind/bug Some behavior is incorrect or out of spec and removed kind/bug Some behavior is incorrect or out of spec labels Mar 16, 2021
@sebandgo
Copy link
Author

sebandgo commented Mar 18, 2021

Same issue with cloud.NewVolume and hcloud.NewVolumeAttachment, the [resource].ID() isn't passed. Works with pulumi.Int([Resource ID]):

...
			mdbNode, err := hcloud.NewServer(
				ctx,
				"just-a-node",
				...)

			if err != nil {
				return err
			}

			//
			// Volume
			//

			dataVolume, err = hcloud.NewVolume(ctx, nodeName+"-data", &hcloud.VolumeArgs{
				// _, err = hcloud.NewVolume(ctx, nodeName+"-data", &hcloud.VolumeArgs{
				Location: pulumi.String("ngb1"),
				Size:     pulumi.Int(50),
				// ServerId:  pulumi.Int(10733537), //mdbNode.ID(), <- Commented so we can use hcloud.NewVolumeAttachment
				Format:    pulumi.String("xfs"),
				Automount: pulumi.Bool(true),
			})

			if err != nil {
				return err
			}

			//
			// Volume Attachment
			//

			_, err = hcloud.NewVolumeAttachment(ctx, "main", &hcloud.VolumeAttachmentArgs{
				VolumeId:  pulumi.Int(10733537), // dataVolume.ID()
				ServerId:  pulumi.Int(10103105), // mdbNode.ID()
				Automount: pulumi.Bool(true),
			})

			if err != nil {
				return err
			}
...

SDK Version:

github.com/pulumi/pulumi-hcloud/sdk v0.7.0
github.com/pulumi/pulumi/sdk/v2 v2.23.1

@brpaz
Copy link

brpaz commented Apr 20, 2021

Same issue with v1.0 and Pulumi v3 sdk.

Any workaround or way to fix this?

@TobiasAhnert
Copy link

Same problem here. I myself are no go-guru, but the following ugly trick seemed to work for now and created some resources successfully. However, it is not elegant this way, so can anyone fix this for good?

		mynet, err := hcloud.NewNetwork(ctx, "demo-network", &hcloud.NetworkArgs{
			IpRange: pulumi.String("10.0.1.0/24"),
		})
		if err != nil {
			return err
		}

		convertedNetId := mynet.ID().ToStringOutput().ApplyT(func(id string) (int, error) {
			return strconv.Atoi(strings.Split(id, "-")[0])
		}).(pulumi.IntOutput)

		mysubnet, err := hcloud.NewNetworkSubnet(ctx, "foonet", &hcloud.NetworkSubnetArgs{
			NetworkId:   convertedNetId,
			Type:        pulumi.String("cloud"),
			NetworkZone: pulumi.String("eu-central"),
			IpRange:     pulumi.String("10.0.1.0/24"),
		})
		if err != nil {
			return err
		}

@RobbieMcKinstry
Copy link

Hm, I came across this issue today on my first day as a Pulumi employee. Am I correct in saying the reason pulumi.IDOutput does not have a conversion function to pulumi.IntInput is because the IDOutput is provider-specific, and not necessarily an integer? I was working with the DigitalOcean provider, there are a couple of locations where I hit this same situation. The DO LoadBalancer type expects a list of Droplet IDs as an array of integers, but the *Droplet.ID() method provides a pulumi.IDOutput.

Here's my (overly verbose) workaround:

var conversionCallback = func(val string) (int, error) {
    return strconv.Atoi(val)
}
// "droplet" is is struct of type "*digitalocean.Droplet"
// after this line, dropletId is a "pulumi.Int"
var dropletId = droplet.ID().ToStringOutput().ApplyT(conversionCallback).(pulumi.IntOutput)

I wonder, should providers offer a package-level conversion function between pulumi.IDOutput and pulumi.Int if their concrete implementation is an Int under the hood?

@daenney
Copy link

daenney commented Dec 29, 2022

I think I'm running into the same issue with hcloud.PrimaryIp and passing them into hcloud.ServerArgs.

ip, _ := hcloud.NewPrimaryIp(....)

s, _ := hcloud.NewServer(ctx, "server", &hcloud.ServerArgs{
	PublicNets: hcloud.ServerPublicNetArray{
			&hcloud.ServerPublicNetArgs{
				Ipv4Enabled: pulumi.Bool(true),
				Ipv4: ip.ID(),
			},
		},
}

cannot use ip.ID() (value of type pulumi.IDOutput) as pulumi.IntPtrInput value in struct literal: pulumi.IDOutput does not implement pulumi.IntPtrInput (missing method ToIntPtrOutput)compiler InvalidIfaceAssign

This makes it really difficult to use any of the resources created by the provider as inputs for a later resource.

@marco-m
Copy link

marco-m commented May 2, 2023

The absolute minimum Go code to convert the ID from string to int is (in May 2023):

network, err := hcloud.NewNetwork(ctx, "foo", &hcloud.NetworkArgs{
....
_, err = hcloud.NewNetworkSubnet(ctx, "bar", &hcloud.NetworkSubnetArgs{
	NetworkId: network.ID().ApplyT(strconv.Atoi).(pulumi.IntOutput),
...

Although with the current pulumi + hcloud versions, one needs --skip-preview to be able to perform a pulumi up, see #175.
UPDATE: As of 2023-06-07,
github.com/pulumi/pulumi-hcloud/sdk v1.12.1
github.com/pulumi/pulumi/sdk/v3 v3.69.0

pulumi up shows correctly the preview!

@bo0ts
Copy link

bo0ts commented Sep 15, 2023

This issue is really surprising to new users and even the documented examples are just wrong and don't work out of the box. See the go code in https://www.pulumi.com/registry/packages/hcloud/api-docs/networksubnet/

@MindTooth
Copy link

MindTooth commented Sep 26, 2023

I've for a long time been looking into using Pulumi instead of Terraform, but even before I'm starting, the examples and the provider does not work out of the box. I'm not sure what to make out of this? 🤷🏻‍♂️

I'm using a banal example from the docs, and that already throws an error:

firewall, err := hcloud.NewFirewall(ctx, "myfirewall", &hcloud.FirewallArgs{
	Rules: hcloud.FirewallRuleArray{
		&hcloud.FirewallRuleArgs{
			Direction: pulumi.String("in"),
			Protocol:  pulumi.String("icmp"),
			SourceIps: pulumi.StringArray{
				pulumi.String("0.0.0.0/0"),
				pulumi.String("::/0"),
			},
		},
		&hcloud.FirewallRuleArgs{
			Direction: pulumi.String("in"),
			Protocol:  pulumi.String("tcp"),
			Port:      pulumi.String("22"),
			SourceIps: pulumi.StringArray{
				pulumi.String("0.0.0.0/0"),
				pulumi.String("::/0"),
			},
		},
	},
})

...	
_, err = hcloud.NewServer(ctx, "node1", &hcloud.ServerArgs{
	Image:      pulumi.String("debian-12"),
	ServerType: pulumi.String("cx11"),
	Location:   pulumi.String("hel1"),
	FirewallIds: pulumi.IntArray{
		firewall.ID(),
	},
})
./main.go:47:5: cannot use firewall.ID() (value of type pulumi.IDOutput) as pulumi.IntInput value in array or slice literal: pulumi.IDOutput does not implement pulumi.IntInput (missing method ToIntOutput)

My current take is that I need hacks to make it work, or continue using Terraform to have proper code?

@daenney
Copy link

daenney commented Sep 26, 2023

You can do what the previous poster suggested, firewall.ID().ApplyT(strconv.Atoi).(pulumi.IntOutput)

@bo0ts
Copy link

bo0ts commented Sep 26, 2023

You can do what the previous poster suggested, firewall.ID().ApplyT(strconv.Atoi).(pulumi.IntOutput)

Broken examples for simple use-cases still do not inspire much confidence which is a pity considering how good pulumi is.

@srhb
Copy link

srhb commented Oct 20, 2023

Is there a way to workaround this issue for the yaml provider? (technically in json. I don't see anything relevant in the builtin fn::s)

@rylabs-billy
Copy link

In case it's helpful, just adding another, slightly different use-cased workaround since this is still open.

func GetResourceId(i pulumi.IDOutput) (int, error) {
	_i := i.ApplyT(strconv.Atoi).(pulumi.IntOutput)
	id, err := strconv.Atoi(_i.ElementType().String())
	if err != nil {
		return 0, err
	}
	return id, nil
}

Then I just call it from main (or anywhere else) with something like: id, _ := internal.GetResourceId(resource.ID()).

In my case resource.ID().ApplyT(strconv.Atoi).(pulumi.IntOutput) wasn't enough because my downstream function param is expecting an int. I would otherwise need to rewrite it to take a pulumi.IntOutput type, and then bloat that function with the conversion responsibility.

This isn't necessarily my favorite approach, but gets it done for the time being. I'll happily scrap it for something leaner. :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind/bug Some behavior is incorrect or out of spec
Projects
None yet
Development

No branches or pull requests