Unable to find .env file in Go file executed via serverless function - go

I have a React web app calling a Go 'backend' (i.e. serverless functions) - but for whatever reason it can't access my .env file.
My overall project structure is roughly as follows:
- root
-- .env
-- src
-- api (where my functions are stored)
As a result, I figured I'd just be able to utilise a dotenv package. However, my file is returning the first err, indicating it can't find the variable.
package handler
import (
"fmt"
"log"
"net/http"
"os"
"github.com/joho/godotenv"
)
func Main(w http.ResponseWriter, r *http.Request) {
if err := godotenv.Load(); err != nil {
fmt.Println("No .env file found")
log.Panicln("No .env file found")
}
uri := os.Getenv("MONGO_URI")
fmt.Println(uri)
}
Does anyone have any suggestions as to why my app can't find my .env file, despite it existing?

Related

How to prevent Kubernetes go-client-discovery pkg sending error to stderr

I am using the go discovery client pkg (k8s.io/client-go/discovery, v0.22.2) to list all supported resources in a cluster ->
discoveryClient, err := discovery.NewDiscoveryClientForConfig(GetK8sConfig())
if err != nil {
// do something
}
resourceList, err := discoveryClient.ServerPreferredResources()
When I run this code I get the following error ->
I1213 09:19:15.932915 38142 request.go:665] Waited for 1.008601388s due to client-side throttling, not priority and fairness, request: GET:https://35.225.61.23/apis/scheduling.k8s.io/v1beta1?timeout=32s
Now, I don't mind the error, what bothers me is that I can't prevent this error from being printed.
Any idea how to stop the discovery client from sending errors to the stderr?
The client use the klog library that implement the default logging conventions. You could read more in the readme.
You should initialize the library with different values in your main. As example :
import (
"bytes"
"flag"
"fmt"
"k8s.io/klog/v2"
)
func main() {
klog.InitFlags(nil)
flag.Set("logtostderr", "false")
flag.Set("alsologtostderr", "false")
flag.Parse()
Another approach, if you want to sue Zap logger with json payload as output, you can do something like:
import (
...
"github.com/go-logr/zapr"
"go.uber.org/zap"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/klog/v2"
...
)
func main() {
flag.Parse()
if logger, err := zap.NewProduction(); err == nil {
klog.SetLogger(zapr.NewLogger(logger))
}
From:
W0630 12:59:05.205701 1 client_config.go:614] Neither --kubeconfig nor --master was specified. Using the inClusterConfig. This might not work.
to
{"level":"info","ts":1625058100.1339207,"caller":"v2/klog.go:921","msg":"Neither --kubeconfig nor --master was specified. Using the inClusterConfig. This might not work.\n"}

Creating temp file with extension in Go within TravisCI

I am working on testing an application of mine, for which I need to create temporary files with specific extensions. My goal is to create files in a temp directory that look similar to this example123.ac.json.
In order to do this I am using ioutil.TempDir and ioutil.TempFile.
Here is a small contrived example of what I am doing.
main.go:
package main
func main() {
}
main_test.go:
package main
import (
"fmt"
"io/ioutil"
"os"
"testing"
)
func TestMain(t *testing.T) {
dir, err := ioutil.TempDir("", "testing")
if err != nil {
t.Fatalf("unable to create temp directory for testing")
}
defer os.RemoveAll(dir)
file, err := ioutil.TempFile(dir, "*.ac.json") // Create a temporary file with '.ac.json' extension
if err != nil {
t.Fatalf("unable to create temporary file for testing")
}
fmt.Printf("created the following file: %v\n", file.Name())
}
When I run the tests locally on my Mac with go test the following is outputted from the fmt.Printf is
$ go test
created the following file: /var/folders/tj/1_mxwn350_d2c5r9b_2zgy7m0000gn/T/testing566832606/900756901.ac.json
PASS
ok github.com/JonathonGore/travisci-bug 0.004s
So it works as expected but when I run it in TravisCI the following is outputted from the Printf statement:
created the following file: /tmp/testing768620677/*.ac.json193187872
For some reason it is using the literal asterisk inside TravisCI but not when running on my own computer.
Here is a link to the TravisCI logs if interested.
For completeness here is my .travis.yml:
language: go
go:
- "1.10"
Anyone have any idea what is going on here? Or am I missing something obvious?
The feature of replacing the first asterisk with the random value was added in Go 1.11. It looks like you are using go 1.10 for your Travis CI runs so the asterisk won't be replaced.

Can not run tests from non-root folder

I have a tests which looks like:
package tst
import (
"testing"
"github.com/demas/cowl-go/pkg/postgres"
"log"
"os"
"fmt"
"github.com/jmoiron/sqlx"
"github.com/demas/cowl-go/pkg/quzx-crawler"
"github.com/SlyMarbo/rss"
"time"
_ "github.com/lib/pq"
)
func TestMain(m *testing.M) {
prepare()
retCode := m.Run()
os.Exit(retCode)
}
func prepare() {
connectionString := fmt.Sprintf("user=%s password=%s host=%s port=%s dbname=%s sslmode=disable",
os.Getenv("DBUSER"),
os.Getenv("DBPASS"),
os.Getenv("DBHOST"),
os.Getenv("DBPORT"),
os.Getenv("DBNAME"))
db, err := sqlx.Open("postgres", connectionString)
if err != nil {
log.Fatal(err)
}
db.Exec(`DELETE FROM Settings`)
db.Exec(`DELETE FROM HackerNews`)
// ....
}
Tests works fine if I keep in the root project folder, but if I move them to tst folder I get error message:
D:\development\gopath\src\github.com\demas\cowl-go\tst>go test -v
2017/03/31 16:30:06 sql: unknown driver "postgres" (forgotten import?)
exit status 1
FAIL github.com/demas/cowl-go/tst 0.085s
Why ?
As already mentioned by #JimB in the comments, the error means that you're trying to open a db connection, using sqlx.Open, without first importing a db driver. This can be fixed by, in your case, adding this _ "github.com/lib/pq" import spec.
If, even after adding that import, you're still seeing the same error, then that means that one of your dependencies is also trying to open a db connection without first importing the necessary driver.
Please note that while log.Fatal is a nice and clean way to stop your program it can sometimes be lacking, as you already know. You might want to consider using panic instead, its output is much more chaotic but, on the other hand, you'll get the line number and file name that caused the panic and eventually you'll learn to parse it quickly.

Beego - Endpoint Testing

I am testing http custom endpoint for beego
package test
import (
"github.com/astaxie/beego"
. "github.com/smartystreets/goconvey/convey"
_ "golife-api-cons/routers"
"net/http"
"net/http/httptest"
"path/filepath"
"runtime"
"testing"
)
func init() {
_, file, _, _ := runtime.Caller(1)
apppath, _ := filepath.Abs(filepath.Dir(filepath.Join(file, ".."+string(filepath.Separator))))
beego.TestBeegoInit(apppath)
}
// TestGet is a sample to run an endpoint test
func TestGet(t *testing.T) {
r, _ := http.NewRequest("GET", "/my/endpoint/fetches/data", nil)
w := httptest.NewRecorder()
beego.BeeApp.Handlers.ServeHTTP(w, r)
beego.Trace("testing", "TestGet", "Code[%d]\n%s", w.Code, w.Body.String())
Convey("Subject: Test Station Endpoint\n", t, func() {
Convey("Status Code Should Be 200", func() {
So(w.Code, ShouldEqual, 200)
})
Convey("The Result Should Not Be Empty", func() {
So(w.Body.Len(), ShouldBeGreaterThan, 0)
})
})
}
When i run using go test -v ,
I get in response dial tcp :0: getsockopt: connection refused
I am using MariaDB running on my local,
I have verified using netstat -tulpn that my database is running perfectly fine (I get a valid response if i use postman and my server is running)
One weird observation , after inclusion of line _ "golife-api-cons/routers" i get this error even before test's are ran
My test passes with response 200 OK , but without any data as i get in response the above mentioned error
EDIT
The default path by used by TestBeegoInit function used is /path/to/my/project/test
which is not the desired path , so i tried giving the absolute path too , still i am not able to connect DB.
After much trying I came to know that beego initializes its variable called as AppPath in beego/conf.go like -
AppPath, _ = filepath.Abs(filepath.Dir(os.Args[0]))
when you run your tests you run them with go test -v
but as a result the os.Args[0] is the text executable which will be /tmp/path/to/test and not path/to/app/exe
hence as a result it does not find config/app.conf which is in your app path which has db connection details.
Responsible line in beego/conf.go -
appConfigPath = filepath.Join(AppPath, "conf", "app.conf")
This all happens in beego's init function when you say
import (
"github.com/astaxie/beego"
_ "path/to/routers"
)
Hack for this is -
create a new package / file with init function which looks has -
package common
import (
"os"
"strings"
)
func init() {
cwd := os.Getenv("PWD")
rootDir := strings.Split(cwd, "tests/")
os.Args[0] = rootDir[0] // path to you dir
}
here you are changing os.Args[0] and assigning your directory path
make sure you import it before beego so now import will look like
import (
_ "path/to/common"
"github.com/astaxie/beego"
_ "path/to/routers"
)
And finally you connect to DB !
You are initializing your app as
apppath, _ := filepath.Abs(filepath.Dir(filepath.Join(file, ".."+string(filepath.Separator))))
beego.TestBeegoInit(apppath)
}
Where file is the caller file.
TestBeegoInit is:
func TestBeegoInit(ap string) {
os.Setenv("BEEGO_RUNMODE", "test")
appConfigPath = filepath.Join(ap, "conf", "app.conf")
os.Chdir(ap)
initBeforeHTTPRun()
}
hence the location where your tests are looking for configuration is
<this_file>/../conf/app.conf
which basically is the default config file.
Basically you are not able to connect to the database. Perhaps because you are unknowingly connecting to your default database for the tests too. I suspect this is not what you are trying to do.

Go: embed static files in binary

This might be a very amateur question. I'm trying to embed static files into binary, ie. html. How do I do that with https://github.com/jteeuwen/go-bindata?
So I can access an asset with this https://github.com/jteeuwen/go-bindata#accessing-an-asset, but what do I do with "data", and how to do I parse files, execute template, and serve them in the directory?
I couldn't find any examples online, and will appreciate some help!
5/6 years later, this should be easier with Go 1.16 (Q1 2021), which adds support for embedded files (issue/proposal 41191 )
It will be permitted to use //go:embed naming a single file to initialize a plain string or []byte variable:
//go:embed gopher.png
var gopherPNG []byte
The import is required to flag the file as containing //go:embed lines and needing processing.
Goimports (and gopls etc) can be taught this rule and automatically add the import in any file with a //go:embed as needed.
That sparked a debate on issue 42328 about how to avoid surprising inclusion of "hidden" files when using //go:embed
This as resolved in CL 275092 and commit 37588ff
Decision to exclude files matching .* and _* from embedded directory results when embedding an entire directory tree.
See src/embed/internal/embedtest/embed_test.go
//go:embed testdata/k*.txt
var local embed.FS
testFiles(t, local, "testdata/ken.txt", "If a program is too slow, it must have a loop.\n")
//go:embed testdata/k*.txt
var s string
testString(t, s, "local variable s", "If a program is too slow, it must have a loop.\n")
//go:embed testdata/h*.txt
var b []byte
testString(t, string(b), "local variable b", "hello, world\n")
Note: with CL 281492, cmd/go passes embedcfg to gccgo if supported.
See also (Jan. 2021) issue 43854 "opt-in for //go:embed to not ignore files and empty dirs".
Given a directory structure like so:
example/
main.go
data/hi.html
example/main.go
package main
import (
"html/template"
"log"
"net/http"
"os"
)
var tmpl *template.Template
func init() {
data, err := Asset("data/hi.html")
if err != nil {
log.Fatal(err)
}
tmpl = template.Must(template.New("tmpl").Parse(string(data)))
}
func main() {
// print to stdout
tmpl.Execute(os.Stdout, map[string]string{"Name": "James"})
http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
tmpl.Execute(w, map[string]string{"Name": "James"})
})
log.Fatal(http.ListenAndServe(":8000", nil))
}
example/data/hi.html
<h1>Hi, {{.Name}}</h1>
run like so:
go-bindata data && go build && ./example
Console Output:
<h1>Hi, James</h1>
HTTP output:
Hi, James

Resources