nodejs-datastore icon indicating copy to clipboard operation
nodejs-datastore copied to clipboard

IPv6 Emulator Addresses not functioning

Open stephenplusplus opened this issue 6 years ago • 6 comments

The Datastore emulator supports-- and automatically use sometimes-- IPv6 addresses (https://cloud.google.com/sdk/gcloud/reference/beta/emulators/datastore/start). Our code has only been parsing input such as "localhost:8081", which is still the default emulator address format. However, if you start a second emulator, or just define the address yourself, it can be IPv6.

image

So, this is a two part issue.

  1. Our code needs to figure out how to handle these addresses. This will definitely involve changes to our code, and possibly to the generated client code or gax as well. That code automatically concatenates servicePath and port, but IPv6 is a bit different. We might be able to get creative with parsing the IPv6 to work around that, e.g. options.servicePath = '[::1:8244]' and options.port = ??.

  2. I can't seem to get gRPC to send requests to the IPv6 address. Here are the settings our client passes and then the response.

{ libName: 'gccl',
  libVersion: '4.3.0',
  scopes:
   [ 'https://www.googleapis.com/auth/cloud-platform',
     'https://www.googleapis.com/auth/datastore' ],
  servicePath: '[::1:8244]',
  port: 443,
  projectId: undefined }
{ Error: Deadline exceeded
    at Http2CallStream.call.on (/Users/stephen/dev/nodejs-datastore/node_modules/@grpc/grpc-js/build/src/client.js:96:45)
    at Http2CallStream.emit (events.js:194:15)
    at process.nextTick (/Users/stephen/dev/nodejs-datastore/node_modules/@grpc/grpc-js/build/src/call-stream.js:71:22)
    at process._tickCallback (internal/process/next_tick.js:61:11)
  code: 4,
  details: 'Deadline exceeded',
  metadata: Metadata { options: undefined, internalRepr: Map {} } }

The emulator readout doesn't change, so it's not being hit.

  • Is there a default emulator port for these addresses?
  • Can gRPC handle directly pinging IPv6 addresses?
  • Is there a strict format we should be following?
    • Do we use http://?
    • Does the IP have to be wrapped within brackets?
    • Is a specific port required?

I've tried all of the combinations I can think of, and it's either "Invalid URL: http://::1:8244" or a Deadline Exceeded error.

stephenplusplus avatar Sep 23 '19 19:09 stephenplusplus

@bcoe @JustinBeckwith any ideas where to turn for halp?

stephenplusplus avatar Oct 14 '19 20:10 stephenplusplus

The grpc libraries can handle IPv6 addresses. I think the IP address you passed there is not the one you intended. The localhost address is ::1, also written as [::1]. The address [::1:8244] is an entirely different address, and I'm not even sure it's valid. If you want localhost with port 8244, the format is [::1]:8244. But if you're doing that, you probably shouldn't also pass port: 443, which appears to be conflicting

However, all of this should be unnecessary. localhost should resolve to both the IPv4 and IPv6 addresses, and grpc should automatically connect to whichever one has a running service.

In both cases, an important caveat is that grpc-js cannot handle IPv6 addresses at all on Node versions below 12.6 as a result of nodejs/node#28216.

http(s):// should be omitted from addresses passed to grpc. If you want to specify that it is a dns address, prefix it with dns://.

murgatroid99 avatar Oct 14 '19 22:10 murgatroid99

This seems both complicated and simple at the same time. See the image in my original post, which shows to set DATASTORE_EMULATOR_HOST=::1:8244. I assumed 8244 was not a port, since it isn't in the correct format, [::1]:8244.

If I swap out the ::1 for localhost when setting the env var, our code does fine, and we are working again. So task 1 is having this library parse the env var for IPv6, so that in this case, we pass {servicePath: '::1', port: 8244}.

But that's where I'm stuck-- we have a bunch of code in the way that thwarts my easy testing of this, so to just ask outright, is that the right format to give to gRPC? I assume we also want support for ipV6 addresses that aren't localhost and don't have a port. Is that as simple as just passing the address as the servicePath and omitting the port?

stephenplusplus avatar Oct 15 '19 14:10 stephenplusplus

This servicePath and port setup is not gRPC's interface. The gRPC library accepts a single string that describes both the host and port. Some intermediate library is merging those two pieces of information to pass to gRPC, and that intermediate library is probably not sufficiently aware of IPv6 to enclose the servicePath in square brackets when that servicePath is an IPv6 address (but not otherwise).

murgatroid99 avatar Oct 15 '19 15:10 murgatroid99

We should add support to use IPv6 emulator, but I am not sure this is a bug. Relabeling.

crwilcox avatar Sep 21 '20 19:09 crwilcox

For me the emulator generates this kind of address: [::1]:8052 . If I understood correctly, this should be in correct format. And yet it doesn't work either.

If I set a non-IPv6 address with --host-port option, I can connect to emulator just fine.

I use Node 20 btw

wlinna avatar Oct 25 '23 14:10 wlinna