launchdarkly / ldcli

The official command line interface for managing LaunchDarkly feature flags.
Other
11 stars 1 forks source link

nodejs server-side client can't connect to dev-server #422

Open browep opened 1 month ago

browep commented 1 month ago

Describe the bug

I am setting up a LD dev-server in my local environment. I have ldcli setup locally via homebrew, access token added, and a project synced locally. I fire up my nodejs server backend, point to the dev-server and the LD client fails to initialize.

setup ldcli:

$ $ ldcli -v
ldcli version 1.5.0
$ ldcli config --set access-token [REDACTED]
Successfully updated
* access-token
$ ldcli dev-server start
2024/09/11 12:27:20 Using database at /Users/[REDACTED]/Library/Application Support/ldcli/dev_server.db
2024/09/11 12:27:20 Server running on 0.0.0.0:8765
2024/09/11 12:27:20 Access the UI for toggling overrides at http://localhost:8765/ui or by running `ldcli dev-server ui`

add a project

$ ldcli dev-server add-project --project toggle-runner-demo --source test
{"_lastSyncedFromSource":1726078548,"context":{"kind":"user","key":"dev-environment"},"flagsState":{"test-flag":{"value":false,"version":3},"enable-toggle-runner":{"value":false,"version":2},"json-settings":{"value":{"propB":"valueB","propA":"valueA"},"version":3},"toggle-runner-mode":{"value":"easy","version":2}},"sourceEnvironmentKey":"test"}

open the ui and see Screen Shot 2024-09-11 at 11 59 40 AM

confirmed that the project exists and was able to sync from the LD servers

start up nodejs server (same machine) with following init code:

  import * as ld from '@launchdarkly/node-server-sdk'
  const options: ld.LDOptions = {
    baseUri: 'http://localhost:8765',
    eventsUri: 'http://localhost:8765',
    streamUri: 'http://localhost:8765',
  }

  ldClient = ld.init("toggle-runner-demo", options)
  await ldClient.waitForInitialization({timeout: 10})

node js logs:

error: [LaunchDarkly] waitForInitialization timed out after 10 seconds.
error: Error initializing LaunchDarkly client
LaunchDarklyTimeoutError: waitForInitialization timed out after 10 seconds.

ldcli logs:

::1 - - [11/Sep/2024:14:17:16 -0600] "GET /all HTTP/1.1" 401 40 "" ""
::1 - - [11/Sep/2024:14:17:16 -0600] "GET /diagnostic HTTP/1.1" 202 0 "" ""

note: i see that the connection is good. the nodejs server can reach the ldcli dev-server, so hosts and ports are correct or at least valid. but the 401 response makes me think some auth is invalid. from https://docs.launchdarkly.com/guides/flags/ldcli-dev-server?q=dev+server#configure-your-sdk-for-testing it says to use the project id for the sdk key, which is toggle-runner-demo as seem from the add-project line.

Expected behavior LD client initializes successfully, someother other than 4xx's in the ldcli logs about connecting.

Logs see above

CLI version

$ ldcli -v
ldcli version 1.5.0

nodejs sdk version: "@launchdarkly/node-server-sdk@npm:^9.5.4":

installed from homebrew

OS/platform macOS 12.7.2 (21G1974)

Additional context

a couple things i have tweaked in an attempt to fix this

mike-zorn commented 1 month ago

Thank you for the detailed bug report! Sorry you're running into this. The 401 in the logs indicate that your application failed to authenticate with the dev server, but it looks like you are correctly setting the SDK key to the project key, so that is surprising behavior.

I can't tell from the screenshot if the flags are listed below where you cropped the image or if they're missing. Are there flags in the UI? Also, can you share the db file located at /Users/[REDACTED]/Library/Application Support/ldcli/dev_server.db? It looks like you're just using the quickstart demo, so I'm assuming there's nothing sensitive in there. If that's wrong, please email me (mike@launchdarkly.com).

browep commented 1 month ago

Screen Shot 2024-09-11 at 7 34 35 PM

^ flags show in the UI

dev_server.db.tgz

^ dev db, just has the sample

from https://github.com/launchdarkly/ldcli/blob/main/internal/dev_server/sdk/project_key_middleware.go#L37 , it looks like 401 is thrown if the key is empty, could it be that the header is not being set? is there a good way to get deeper into what the node SDK is sending? is there a curl command i could run locally that should work?

more context: running node v20 for the server app

browep commented 1 month ago

looks like the ldcli server is responding as appropriate with a valid auth header:

$ curl -v -H "authorization: toggle-runner-demo" "http://localhost:8765/all"
*   Trying 127.0.0.1:8765...
* Connected to localhost (127.0.0.1) port 8765 (#0)
> GET /all HTTP/1.1
> Host: localhost:8765
> User-Agent: curl/8.1.2
> Accept: */*
> authorization: toggle-runner-demo
>
< HTTP/1.1 200 OK
< Content-Type: text/event-stream
< Date: Thu, 12 Sep 2024 15:00:01 GMT
< Transfer-Encoding: chunked
<
event:put
data:{"path":"","data":{"flags":{"enable-toggle-runner":{"key":"enable-toggle-runner","on":true,"prerequisites":[],"targets":[],"rules":[],"fallthrough":{"variation":0},"offVariation":0,"variations":[false],"clientSideAvailability":{"usingMobileKey":true,"usingEnvironmentId":true},"clientSide":true,"salt":"","trackEvents":false,"trackEventsFallthrough":false,"debugEventsUntilDate":0,"version":2,"deleted":false},"json-settings":{"key":"json-settings","on":true,"prerequisites":[],"targets":[],"rules":[],"fallthrough":{"variation":0},"offVariation":0,"variations":[{"propA":"valueA","propB":"valueB"}],"clientSideAvailability":{"usingMobileKey":true,"usingEnvironmentId":true},"clientSide":true,"salt":"","trackEvents":false,"trackEventsFallthrough":false,"debugEventsUntilDate":0,"version":3,"deleted":false},"toggle-runner-mode":{"key":"toggle-runner-mode","on":true,"prerequisites":[],"targets":[],"rules":[],"fallthrough":{"variation":0},"offVariation":0,"variations":["easy"],"clientSideAvailability":{"usingMobileKey":true,"usingEnvironmentId":true},"clientSide":true,"salt":"","trackEvents":false,"trackEventsFallthrough":false,"debugEventsUntilDate":0,"version":2,"deleted":false}}}}

so it seems its not being sent by the nodejs server, unclear why. i have datadog installed, and that adds headers, but i dont think takes any away. ngrep shows no authorization header being sent:

T ::1:62935 -> ::1:8765 [AP] #27478
  GET /all HTTP/1.1..x-datadog-trace-id: 1334710925540581334..x-datadog-parent-id: 1349953054004235511..x-datadog-sampling-priority: 1..x-datadog-tags: _dd.p.tid=66e310ee00000000,_dd.p.dm=-0..traceparent: 00-66
  e310ee000000001285d883e2addfd6-12bbff2677604cf7-01..tracestate: dd=t.dm:-0;t.tid:66e310ee00000000;s:1;p:12bbff2677604cf7..Host: localhost:8765..Connection: keep-alive....
###
T ::1:8765 -> ::1:62935 [AP] #27481
  HTTP/1.1 401 Unauthorized..Content-Type: text/plain; charset=utf-8..X-Content-Type-Options: nosniff..Date: Thu, 12 Sep 2024 16:08:58 GMT..Content-Length: 40....project key not on Authorization header.

i might try creating a fresh nodejs project and see if i can dupe the error with a clean slate

mike-zorn commented 1 month ago

OK. That's good that we were able to isolate the issue to the SDK via the curl request.

Very strange that the SDK isn't setting the header. I confirmed that the authorization header gets set appropriately in our sample app when you set the SDK key to toggle-runner-demo. Do you have any kind of custom http client or proxy configuration?