-
Notifications
You must be signed in to change notification settings - Fork 4.3k
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
Multiple Go client instances cannot be created if a custom HTTP client is passed #3435
Comments
The best practice communicated to us from the Go team is to use the x/net/http2 package when you want to use HTTP/2. This necessarily requires calling ConfigureTransport, and that in turn is surfacing this error from inside the Go net library (net/http/transport.go). On the one hand, I could try intercepting the error and ignoring it, but on the other hand, having that error is in theory useful in case you really didn't mean to register the same protocol twice to different handlers. This is easy to work around though; simply pass two different transports. It's often a bad idea to use DefaultTransport with more than one client anyways. I recommend https://github.com/hashicorp/go-cleanhttp which can give you clean transports. |
Thanks for the explanation. I've also discovered it on today's debugging journey. However I believe this could be fixed by adding this as to
Not many know that they shouldn't use http.Default Client and Transport. Saying that it's bad unfortunately doesn't fix the issue. I suggest to rethink about including the three line fix with the test case. Thanks. |
Or better after the fix 42953d6, just adding the case will fix this issue:
|
I don't really want to do that as there are still legitimate reasons people may want to use DefaultTransport, if they already have it set up via other means (and aren't trying to create multiple Vault API clients). We already default -- if no HTTP client is passed in, or now, if you pass in a client with no transport -- to using our own transport anyways, and most users simply pass no custom HTTP client and get cleanhttp automatically. BTW, thanks again for vim-go :-D |
Fair enough. You're welcome and thanks for the fix Jeff :) |
I ran into this issue while using Client.Clone(), which doesn't give me an option to pass in a different Transport instance. Is the |
The clone method is perfectly useful, just not if you need a custom transport. But I don't follow why you can't use SetToken after the clone. The header is added to the request by the client, the underlying transport has nothing to do with it. |
I've been getting the vault/api/api_integration_test.go Line 24 in 672feed
I'm most likely completely missing something here, but how can you use |
Doesn't seem to be limited to the func TestClone(t *testing.T) {
client1, err1 := vaultapi.NewClient(nil)
if err1 != nil {
t.Fatalf("NewClient failed: %v", err1)
}
client2, err2 := client1.Clone()
if err2 != nil {
t.Fatalf("Clone failed: %v", err2)
}
_ = client2
} fails with |
It does seem like attempting to do so is broken, but using clone is never a prerequisite. I didn't follow what your meant about Vault's integration tests, but they don't use clone. |
I'm still curious how |
It's possible it doesn't; it's also possible it used to work and that the error coming from the http2 library is due to changed behavior.
Not currently, you'd have to create a new client. |
Thanks for confirming. My current workaround is to serialize all requests so I can safely set the token for each request using |
@jefferai thanks for the rapid fix! After pulling it in, unfortunately I'm now getting an error even earlier, when trying to spin up my in-memory test server (this is code copied verbatim from Vault's api_integration_test.go): func TestVaultServer(t *testing.T) {
testVaultServerBackends(t, testVaultServerDefaultBackends)
}
var testVaultServerDefaultBackends = map[string]logical.Factory{
"transit": transit.Factory,
"pki": pki.Factory,
}
func testVaultServerBackends(t testing.TB, backends map[string]logical.Factory) (*api.Client, func()) {
coreConfig := &vault.CoreConfig{
DisableMlock: true,
DisableCache: true,
Logger: logxi.NullLog,
LogicalBackends: backends,
}
cluster := vault.NewTestCluster(t, coreConfig, &vault.TestClusterOptions{
HandlerFunc: vaulthttp.Handler,
})
cluster.Start()
// make it easy to get access to the active
core := cluster.Cores[0].Core
vault.TestWaitActive(t, core)
client := cluster.Cores[0].Client
client.SetToken(cluster.RootToken)
// Sanity check
secret, err := client.Auth().Token().LookupSelf()
if err != nil {
t.Fatal(err)
}
if secret == nil || secret.Data["id"].(string) != cluster.RootToken {
t.Fatalf("token mismatch: %#v vs %q", secret, cluster.RootToken)
}
return client, func() { defer cluster.Cleanup() }
} Running this test errors with:
Reverting the fix (2afbbb3) makes this pass again. |
Are you current against master? We use NewTestCluster in a ton of tests and CI is passing. |
I ran This alternative fix seems to work (for my use case at least): if _, found := tp.TLSNextProto["h2"]; !found {
if err := http2.ConfigureTransport(tp); err != nil {
return nil, err
}
} |
I'm going to do something entirely different, but it may not be until Monday. |
@johannespetzold The error you were seeing appears to be a compatibility break between the built-in Go http2 support in Go 1.9 and the current version of the http2 libraries vendored in Vault. Note that currently you'll need to either keep the transport configured from DefaultConfig or you'll need to call http2.ConfigureTransport on your transport via the x/net/http2 package. I've significantly updated the API code; see the |
Ref: golang/go#22481 |
@jefferai thanks for the new fix, I can confirm that the |
Expected Behavior:
I should be able to construct multiple Client instances in a Go source code with a custom HTTP client.
Actual Behavior:
After creating the first client, no more clients can be created
Steps to Reproduce:
Add the following to
api/client_test.go
and rungo test
you should see the following
Important Factoids:
This because of the following code in
NewClient()
that tries to registerhttps
multiple times:Because of the code above, the second call to
NewClient()
returns an error (viahttp2.ConfigureTransport(tp)
.The text was updated successfully, but these errors were encountered: