-
Notifications
You must be signed in to change notification settings - Fork 116
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
SNOW-724764: Silent failure for PUT operation #701
Comments
hi and thank you for submitting this issue with us! special thanks for providing a detailed error description 👍
should suffice from the reproduction perspective. Also modified the cfg := &sf.Config{
Account: account,
User: user,
..
Tracing: "debug",
} (few more words about this connection parameter)
so if you could please provide further details on how to get to this issue, that would be very helpful to troubleshoot this issue further. Finally, thank you for the suggestion on the extra linting, will draw the team's attention. |
Hey @sfc-gh-dszmolka, here's how I was able to reproduce it just now: > mkdir gosnowflake_test && cd gosnowflake_test
> go mod init gosnowflake-test
> touch main.go I added this code in package main
import (
"bytes"
"context"
"crypto/rsa"
"database/sql"
"encoding/pem"
"errors"
"fmt"
"log"
"os"
"github.com/snowflakedb/gosnowflake"
"github.com/youmark/pkcs8"
"golang.org/x/crypto/ssh"
)
func getPrivateKey(path, passphrase string) (*rsa.PrivateKey, error) {
privateKeyBytes, err := os.ReadFile(path)
if err != nil {
return nil, fmt.Errorf("failed to read private key %s: %s", path, err)
}
if len(privateKeyBytes) == 0 {
return nil, errors.New("private key is empty")
}
privateKeyBlock, _ := pem.Decode(privateKeyBytes)
if privateKeyBlock == nil {
return nil, fmt.Errorf("could not parse private key, key is not in PEM format")
}
if privateKeyBlock.Type == "ENCRYPTED PRIVATE KEY" {
if passphrase == "" {
return nil, fmt.Errorf("private key requires a passphrase, but private_key_passphrase was not supplied")
}
// Only keys encrypted with pbes2 http://oid-info.com/get/1.2.840.113549.1.5.13 are supported.
// pbeWithMD5AndDES-CBC http://oid-info.com/get/1.2.840.113549.1.5.3 is not supported.
privateKey, err := pkcs8.ParsePKCS8PrivateKeyRSA(privateKeyBlock.Bytes, []byte(passphrase))
if err != nil {
return nil, fmt.Errorf("failed to decrypt encrypted private key (only ciphers aes-128-cbc, aes-128-gcm, aes-192-cbc, aes-192-gcm, aes-256-cbc, aes-256-gcm, and des-ede3-cbc are supported): %s", err)
}
return privateKey, nil
}
privateKey, err := ssh.ParseRawPrivateKey(privateKeyBytes)
if err != nil {
return nil, fmt.Errorf("could not parse private key: %s", err)
}
rsaPrivateKey, ok := privateKey.(*rsa.PrivateKey)
if !ok {
return nil, fmt.Errorf("private key must be of type RSA but got %T instead: ", privateKey)
}
return rsaPrivateKey, nil
}
func main() {
privateKey, err := getPrivateKey("/home/.ssh/snowflake_rsa_key.pem", "test")
if err != nil {
log.Fatalf("failed to read private key: %s", err)
}
if err := gosnowflake.GetLogger().SetLogLevel("trace"); err != nil {
log.Fatalf("failed to set log level: %s", err)
}
dsn, err := gosnowflake.DSN(&gosnowflake.Config{
Account: "TODO",
Authenticator: gosnowflake.AuthTypeJwt,
User: "TODO",
Role: "TODO",
Database: "TODO",
Warehouse: "TODO",
Schema: "TODO",
PrivateKey: privateKey,
Tracing: "debug",
})
if err != nil {
log.Fatalf("failed to create DSN: %s", err)
}
db, err := sql.Open("snowflake", dsn)
if err != nil {
log.Fatalf("failed to connect to snowflake: %s", err)
}
_, err = db.ExecContext(gosnowflake.WithFileStream(context.Background(), bytes.NewReader([]byte("foobar"))), "PUT file:///./foo.txt @~ OVERWRITE=true")
if err != nil {
log.Fatalf("failed to write to snowflake: %s", err)
}
} NOTES:
> docker run --rm -it -v $(pwd):/workspace -v ${HOME}/.ssh:/home/.ssh --name=golang golang:1.20-alpine sh
/go # cd /workspace/
/workspace # go mod tidy
/workspace # CGO_ENABLED=0 go build . Leave this terminal window open and launch a new one: > docker exec -it --user=1000 golang sh
/go $ cd /workspace/
/workspace $ ./gosnowflake-test Note that you won't get Now go to the terminal in which you ran Here is the log from when it fails: And here is the log from when it succeeds: |
hi @mihaitodor this is awesome 🤩 thank you for these details; could easily reproduce the issue. i could not yet figure out where in addition as other folks hinted on the internet for similar issues with different libraries:
the issue can be worked around by adding the envvar and setting |
Awesome, thanks for the quick test and glad you were able to reproduce it! It's probably fine to require the |
absolutely agree, and that's why one of the asks to the driver team is to provide a better/more intuitive error message if possible ;) will keep this Issue updated with the progress. |
as it turns out, the offending The behaviour is not changed, but the error handling is better and more intuitive, and is coming with #770 which is already merged and awaiting the next release which is expected towards end of April. |
@sfc-gh-dszmolka Thank you very much! This also revealed that, in my use case inside Benthos, I should probably add Somehow, I didn't notice this before. Might be worth mentioning it in the docs here. Otherwise, happy to close this issue. |
fix released with 1.6.20 |
Issue description
This driver fails to upload files silently when compiled with
CGO_ENABLED=0
and theUSER
environment variable isn't set. This can happen, for example, when running the app in a simple Go container with--user 1000:1000
(trydocker run --rm -it --user 1000:1000 golang:1.18-alpine sh
). I tried addinggosnowflake.GetLogger().SetLogLevel("trace")
, but there's no hint in the output that a failure has occurred.One cause for the issue is here, where the error is swallowed for some reason... I modified the code and logged the error returned by it and it contains "user: Current requires cgo or $USER set in environment", which helped me find the root cause. Even so, returning non-nil errors there doesn't seem to be enough to trigger a failure log, so more changes might be needed.
Not sure if you considered adding extra linting to this repo, but I believe
golangci-lint
should be able to detect missing error checks, among other potential issues and it can be run with ease using GitHub Actions: https://github.com/marketplace/actions/run-golangci-lintExample code
The sample code from the docs here should suffice.
Error log
N/A
Configuration
Driver version (or git SHA):
v1.6.16
Go version: run
go version
in your consolego version go1.19.4 darwin/amd64
Server version: E.g. 1.90.1
You may get the server version by running a query:
7.0.0
Client OS: E.g. Debian 8.1 (Jessie), Windows 10
golang:1.18-alpine
Docker container.The text was updated successfully, but these errors were encountered: