Table 'test_db.colors' doesn't exist - mysql

I am building an app using Docker, docker-compose, MySQL and Go.
When I attempt to test one endpoint I get the error Table 'test_db.colors' doesn't exist.
It seems that the sql dump does not imported properly.
But I can connect to the database, at least there is no error, which is created in the same .sql file.
When I start the app the terminal shows:
golang_app | 2020/06/20 21:48:04 docker:docker#tcp(db_mysql:3306)/test_db
golang_app | 2020/06/20 21:48:04 DB Connected
After I make a request to the endpoint I get:
2020/06/20 22:05:00 File: handlers.go Function: main.testDBHandler Line: 26 Error 1146: Table 'test_db.colors' doesn't exist
The file structure is:
./
|_app/
|_docker-compose.yml
|_Go/
|_*.go
|_Dockerfile
|_MySQL/
|_Dockerfile
|_.env
|_sql-scripts/
|_test.sql
The contents of the files are listed below:
docker-compose.yml
version: '3'
services:
fullstack-mysql:
container_name: db_mysql
build:
context: ./MySQL
ports:
- 3306:3306
volumes:
- database_mysql:/var/lib/mysql
- mysql-log:/var/log/mysql
- mysql-conf:/etc/mysql/conf.d
- ./MySQL/sql-scripts:/docker-entrypoint-initdb.d
networks:
- fullstack
app:
container_name: golang_app
env_file:
- ./Go/.env
build:
context: ./Go
ports:
- 9000:9000
restart: unless-stopped
volumes:
- api:/usr/src/app/
depends_on:
- fullstack-mysql
networks:
- fullstack
phpmyadmin:
image: phpmyadmin/phpmyadmin
container_name: phpmyadmin_container
depends_on:
- fullstack-mysql
environment:
- PMA_HOST=fullstack-mysql #Note the "mysql". Must be the name of the what you used as the mysql service.
- PMA_USER=root
- PMA_PORT=3306
- PMA_PASSWORD=root
- PMA_ARBITRARY=1
ports:
- 9095:80
restart: always
networks:
- fullstack
links:
- fullstack-mysql
volumes:
api:
database_mysql:
mysql-log:
driver: local
mysql-conf:
driver: local
networks:
fullstack:
driver: bridge
app/MySQL/Dockerfile
FROM mysql:8.0
ENV MYSQL_ROOT_PASSWORD=$(MYSQL_ROOT_PASSWORD)
ENV MYSQL_PASSWORD=$(MYSQL_PASSWORD)
ENV MYSQL_USER=$(MYSQL_USER)
ENV MYSQL_DATABASE=$(MYSQL_DATABASE)
ENV MYSQL_PORT=$(MYSQL_PORT)
ENV MYSQL_DRIVER=$(MYSQL_DRIVER)
COPY ./sql-scripts/test.sql /docker-entrypoint-initdb.d/
EXPOSE 3306
app/MySQL/.env
MYSQL_ROOT_PASSWORD=root
MYSQL_PASSWORD=docker
MYSQL_USER=docker
MYSQL_DATABASE=test_db
MYSQL_HOST=127.0.0.1
MYSQL_PORT=3306
MYSQL_DRIVER=mysql
app/MySQL/sql-scripts/test.sql
CREATE DATABASE IF NOT EXISTS test_db;
CREATE USER IF NOT EXISTS 'root'#'%' IDENTIFIED BY 'root';
GRANT ALL PRIVILEGES ON *.* TO 'root'#'%' WITH GRANT OPTION;
CREATE USER IF NOT EXISTS 'docker'#'%' IDENTIFIED BY 'docker';
GRANT SELECT, INSERT, UPDATE, DELETE ON *.* TO 'docker'#'%' WITH GRANT OPTION;
FLUSH PRIVILEGES;
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
SET time_zone = "+00:00";
CREATE TABLE IF NOT EXISTS `colors` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(20) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1;
INSERT INTO `colors` (`id`, `name`) VALUES
(2, 'black'),
(4, 'blue'),
(5, 'green'),
(3, 'red'),
(1, 'white'),
(6, 'yellow');
main.go
package main
import (
"database/sql"
"log"
"net"
"net/http"
"os"
"os/exec"
"strconv"
"strings"
_ "github.com/go-sql-driver/mysql"
"github.com/jimlawless/whereami"
)
func setConfig() {
config = Configs{}
config.cookieName = os.Getenv("COOKIE_NAME")
config.cookieValue = os.Getenv("COOKIE_VALUE")
age, err := strconv.Atoi(os.Getenv("COOKIE_MAX_AGE"))
if err != nil {
log.Println(whereami.WhereAmI(), err.Error())
}
config.cookieMaxAge = age
config.cookieHTTPOnly, err = strconv.ParseBool(os.Getenv("COOKIE_HTTP_ONLY"))
if err != nil {
log.Println(whereami.WhereAmI(), err.Error())
}
config.cookiePath = os.Getenv("COOKIE_PATH")
config.domain = os.Getenv("DOMAIN")
config.port = os.Getenv("PORT")
config.apiKey = os.Getenv("APP_KEY")
config.apiVersion = os.Getenv("API_VERSION")
config.apiPath = os.Getenv("API_PATH")
config.protocol = os.Getenv("PROTOCOL")
config.mysqlDB = os.Getenv("MYSQL_DATABASE")
config.mysqlHost = os.Getenv("MYSQL_HOST")
config.mysqlPassword = os.Getenv("MYSQL_PASSWORD")
config.mysqlPort = os.Getenv("MYSQL_PORT")
config.mysqlUser = os.Getenv("MYSQL_USER")
config.mysqlDriver = os.Getenv("MYSQL_DRIVER")
}
func main() {
defer recoverPanic()
setConfig()
err := db()
if err != nil {
log.Fatal(whereami.WhereAmI(), err.Error())
}
routes()
}
func (fs FileSystem) Open(path string) (http.File, error) {
f, err := fs.fs.Open(path)
if err != nil {
return nil, err
}
s, err := f.Stat()
if s.IsDir() {
index := strings.TrimSuffix(path, "/") + "/index.html"
if _, err := fs.fs.Open(index); err != nil {
return nil, err
}
}
return f, nil
}
func db() error {
connStr:=config.mysqlUser+":"+config.mysqlPassword+"#tcp("+config.mysqlHost+":"+config.mysqlPort+")/"+config.mysqlDB
log.Println(connStr)
db, err := sql.Open(config.mysqlDriver, connStr)
if err != nil {
log.Fatal(whereami.WhereAmI(), err.Error())
}
err = db.Ping()
if err != nil {
log.Println("Ping Error: " + err.Error())
} else {
dbx.conn = db
log.Println("DB Connected")
}
//log.Println(fmt.Sprintf("%s", dbx.conn), whereami.WhereAmI())
return err
}
func recoverPanic() {
if rec := recover(); rec != nil {
err := rec.(error)
log.Println(whereami.WhereAmI(), err.Error())
var l *net.TCPListener
file, err := l.File()
if err != nil {
log.Println(whereami.WhereAmI(), err.Error())
}
path := os.Args
args := []string{"-graceful"}
cmd := exec.Command(path[0], args...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.ExtraFiles = []*os.File{file}
err2 := cmd.Start()
if err2 != nil {
log.Println(whereami.WhereAmI(), err2.Error())
} else {
log.Println(whereami.WhereAmI(), "Restarted...")
}
}
}
handlers.go
package main
import (
"fmt"
"log"
"net/http"
"github.com/jimlawless/whereami"
)
func testDBHandler(w http.ResponseWriter, req *http.Request) {
id := 1
var name string
if err := dbx.conn.QueryRow("SELECT name FROM colors WHERE id = ? LIMIT 1", id).Scan(&name); err != nil {
log.Println(whereami.WhereAmI(), err.Error())
}
fmt.Fprintf(w, name)
}

A few things to check:
Does the mysql container indicate that it started up correctly?
Is your mysql setup too complicated (see below)?
Have you tried connecting to your mysql instance with another application (e.g. datagrip, or some other mysql client?)
Have you ensured that mysql is actually done with it's startup process before you connect to it? depends_on may not really work properly here -- other application won't start up until after mysql starts, but mysql won't necessarily be configured yet -- i.e. your test.sql may not have actually run.
Your mysql setup seems somewhat complicated. Does it need to be? I've used a similar set of technologies and my docker compose for the database looked like this:
fullstack-mysql:
image: mysql:8.0
ports:
- 3306:3306
volumes:
- database_mysql:/var/lib/mysql
- mysql-log:/var/log/mysql
- mysql-conf:/etc/mysql/conf.d
- ./MySQL/sql-scripts:/docker-entrypoint-initdb.d
environment:
- MYSQL_ROOT_PASSWORD=root
- MYSQL_PASSWORD=docker
- MYSQL_USER=docker
- MYSQL_DATABASE=test_db
- MYSQL_HOST=127.0.0.1
- MYSQL_PORT=3306
- MYSQL_DRIVER=mysql
networks:
- fullstack
Assuming you don't need to do anything complicated, this should remove most of the mysql db setup.
The only other thing I did differently is map individual startup scripts, rather than the whole directory -- i.e.
volumes:
./MySQL/sql-scripts/test.sql:/docker-entrypoint-initdb.d/test.sql
Though I think the folder mapping you have specified should work. One more bit I just noticed: in your mysql dockerfile, you do: COPY ./sql-scripts/test.sql /docker-entrypoint-initdb.d/ but this seems redundant with the docker-compose file, which places a volume in the same location.

The initialization scripts on the entry point are only run the first time the DB is created ( I.e. when the folder /var/lib/mysql is empty)
Delete the database_mysql folder in your host machine and have docker-compose recreate it automatically. That will cause the scripts to run.
Note that all data stored in the DB will be lost when you delete the folder.

Related

connection refused with go&mysql&docker

I'm trying to connect mysqlDB which is created on Docker from my local go file.
main.go
package main
import (
"database/sql"
"fmt"
_ "github.com/go-sql-driver/mysql"
)
func main() {
fmt.Println("Hello")
// All following 4 codes won't connect to the database.
// "db01" is docker container name. "test" is db name.
// db, err := sql.Open("mysql", "root:password#tcp(localhost:3306)/test")
// db, err := sql.Open("mysql", "root:password#tcp(localhost)/test")
// db, err := sql.Open("mysql", "root:password#tcp(db01)/test")
db, err := sql.Open("mysql", "root:password#tcp(db01:3306)/test")
if err != nil {
fmt.Println(err)
}
defer db.Close()
fmt.Println(db)
err = db.Ping()
if err != nil {
fmt.Println(err)
}
}
docker command
docker run --name db01 -dit -e MYSQL_ROOT_PASSWORD=password mysql:latest
error message
when trying with localhost:3306
dial tcp [::1]:3306: connect: connection refused
when trying with db01
dial tcp: lookup db01: no such host
mysql db is created on docker container without any issue, so I think connection between go file and docker container is not going well.
Do I have to create docker-compose.yml file?
I want to connect without it at now.
Thank you.
You created a docker container and ran MySQL in it. That container will have its own network address. You can publish a port of that container on your localhost by running:
docker run --name db01 -p 3306:3306 -dit -e MYSQL_ROOT_PASSWORD=password mysql:latest
This will publish the port 3306 of the container on localhost:3306. Then you can connect to it.
Alternatively, you can get the IP address of the container running using docker inspect <containerId>, and connect to that address:3306.

Unable to ping mysql db docker in golang

I am new to golang, docker and mysql. I am trying to connect to mysql running in docker locally on my macos using golang.
Here is the code:
`package main
import (
"context"
"database/sql"
_ "github.com/go-sql-driver/mysql"
"log"
"time"
)
func dbConn() *sql.DB {
db, err := sql.Open("mysql", "root:Abc123$##tcp(172.17.0.2:3306)/test")
if err != nil {
log.Printf("Error %s when opening DB connection\n", err)
return nil
}
db.SetMaxOpenConns(10)
db.SetMaxIdleConns(10)
db.SetConnMaxLifetime(time.Minute * 2)
ctx, cancelfunc := context.WithTimeout(context.Background(), time.Second)
defer cancelfunc()
err = db.PingContext(ctx)
if err != nil {
log.Printf("Error %s pinging DB", err)
return db
}
log.Print("Connected to the DB successfully\n")
defer func() {
err := db.Close()
if err != nil {
log.Print(err)
}
}()
return db
}
func main() {
db := dbConn()
defer db.Close()
}`
I am running docker with the following command:
docker run --name mysql -e MYSQL_ROOT_PASSWORD=abcd1234 -p 3306:3306 -d mysql:8.0.30
I get the following error:
Error dial tcp 172.17.0.2:3306: i/o timeout pinging DB
docker is running locally. I created a test-db with command-line:
`mysql> create database test_db;`
and then did a
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
| test_db |
+--------------------+
6 rows in set (0.00 sec)
Please help me understand my mistake here? Or what am I missing?
I used host.docker.internal in this docker-compose.yml file to create the mysql sever in docker.
version: '3'
services:
mysql-development:
image: mysql:8.0.30
environment:
MYSQL_ROOT_PASSWORD: xyz1234
MYSQL_DATABASE: test
ports:
- "3306:3306"
extra_hosts:
- "host.docker.internal:host-gateway"
Used this to run the docker image:
docker-compose -f docker-compose.yml up
Then connected to docker mysql instance using:
docker exec -it 24f058c73227 mysql -P 3306 --protocol=tcp -u root -p
Then created a separate user and granted all privileges to the new user.
mysql> CREATE user ‘user2’#‘172.19.0.1' IDENTIFIED BY ‘xyz1234’;
mysql> GRANT ALL PRIVILEGES ON *.* TO 'user2'#'172.19.0.1' WITH GRANT
OPTION;
This helped me connect to mysql server running on the docker locally on macos.

How do I connect to a MySQL instance without using the password?

I trying to connect db I have set no password for the db I am leaving blank in the password field. But it's not connecting and showing error connector.go:95: could not use requested auth plugin 'mysql_native_password': this user requires mysql native password authentication.. Also I am using phpmyadmin as db so how to connect here is my code
package main
import (
"database/sql"
"fmt"
"log"
"github.com/go-sql-driver/mysql"
)
var db *sql.DB
func main() {
// Capture connection properties.
cfg := mysql.Config{
User: "root",
Passwd: "",
Net: "tcp",
Addr: "127.0.0.1:3306",
DBName: "recordings",
}
// Get a database handle.
var err error
db, err = sql.Open("mysql", cfg.FormatDSN())
if err != nil {
log.Fatal(err)
}
pingErr := db.Ping()
if pingErr != nil {
log.Fatal(pingErr)
}
fmt.Println("Connected!")
}
That looks a lot like the code from the Tutorial: Accessing a relational database which unfortunately does not work. You need to specify AllowNativePasswords: true for it to work. That value is true by default, but the defaults are only applied if you use NewConfig() and not create the Config struct yourself. But this will work as well:
cfg := mysql.Config{
User: "root",
Passwd: "",
Net: "tcp",
Addr: "127.0.0.1:3306",
DBName: "recordings",
AllowNativePasswords: true,
}
Try to change authentication plugin of root user to mysql_native_password in your database. More information about here
UPDATE mysql.user SET plugin = 'mysql_native_password' WHERE user = 'root' AND plugin = 'unix_socket';

$GOPATH/go.mod exists but should not on Docker

I'm trying to build a Docker container that contains both MySQL and a Go server.
Just importing the MySQL libraries cause the error.
Any pointers to what I'm doing wrong?
This is the terminal after build:
Successfully built 5d5356e2ca72
Successfully tagged test3:latest
$GOPATH/go.mod exists but should not
But there is no go.mod in the $GOPATH
$ ls -a $GOPATH
. .. bin pkg
This is the go server:
package main
import (
"database/sql"
"flag"
"fmt"
"log"
"net/http"
"strings"
_ "github.com/go-sql-driver/mysql"
)
type FileSystem struct {
fs http.FileSystem
}
var listen = flag.String("listen", ":8989", "listen address")
var dir = flag.String("dir", ".", "directory to serve")
func main() {
db()
flag.Parse()
directory := "./"
fileServer := http.FileServer(FileSystem{http.Dir(directory)})
http.Handle("/", fileServer)
fmt.Printf("Web server running. Listening on %q", *listen)
err := http.ListenAndServe(*listen, http.FileServer(http.Dir(*dir)))
fmt.Printf("%v\n", err)
}
func (fs FileSystem) Open(path string) (http.File, error) {
f, err := fs.fs.Open(path)
if err != nil {
return nil, err
}
s, err := f.Stat()
if s.IsDir() {
index := strings.TrimSuffix(path, "/") + "/index.html"
if _, err := fs.fs.Open(index); err != nil {
return nil, err
}
}
return f, nil
}
func db() {
db, err := sql.Open("mysql", "root:root#tcp(192.168.0.33:4200)/mysql")
if err != nil {
log.Print(err.Error())
} else {
log.Print("DB connected successfully")
}
defer db.Close()
}
This is my go.mod
module test3
go 1.14
require github.com/go-sql-driver/mysql v1.5.0
This is the Dockerfile
FROM golang:alpine AS builder
ENV GO111MODULE=auto \
CGO_ENABLED=0 \
GOOS=linux \
GOARCH=amd64
COPY . .
COPY ./server.go .
COPY ./favicon.ico .
COPY ./assets /assets
EXPOSE 8989
CMD ["go", "run", "./server.go"]
And this is how I build the container:
docker rmi test3 -f
docker build --no-cache -t test3 .
docker run -p 8989:8989 test3
$GOPATH/go.mod exists but should not
By default the goland:alpine image starts the working directory in the GOPATH (i.e. /go) folder where globally installed packages are created with the go install command.
The folder structure looks like:
go/
bin/
src/
pkg/
By directly copying go.mod into the working directory (i.e. GOPATH, i.e. /go), the golang toolkit throws an error, because go.mod is supposed to be in a package folder.
Before the release of Go modules in version 1.11, the convention was to create your packages in the /go/src folder. However, with the release of Go modules you can create golang packages anywhere as long as they include a go.mod file.
So to fix the error, you could copy the golang files (go.mod, etc) into a folder under /home/app or /go/src/app.
Copy into /home/app
RUN mkdir ../home/app
WORKDIR /../home/app
COPY . .
Copy into /go/src/app
RUN mkdir src/app
WORKDIR /src/app
COPY . .

Can't connect to remote MySql in Go

I need to connect to a remote MySql server using Go. I'm using following code to connect to MySql via gorm.
type DBController struct {
DB gorm.DB
}
func (dc *DBController) InitDB() {
var err error
host := v.GetString("db.mysql.host")
port := v.GetString("db.mysql.port")
user := v.GetString("db.mysql.user")
pass := v.GetString("db.mysql.pass")
db := v.GetString("db.mysql.db")
//user:password#tcp(localhost:5555)/dbname
conn := fmt.Sprintf("%s:%s#tcp(%s:%s)/%s", user, pass, host, port, db)
//conn := v.GetString($user+":"$pass+"#tcp("+$host+":"+$port+")/"+$db)
log.Debug(conn)
dc.DB, err = gorm.Open("mysql", conn)
if err != nil {
log.Fatalf("Error when connect database, the error is '%v'", err)
}
dc.DB.LogMode(true)
}
func (dc *DBController) GetDB() gorm.DB {
return dc.DB
}
When I run the Go server I'm getting following errors
No configuration file loaded - using defaults
:#tcp(:)/
Error when connect database, the error is 'dial tcp: unknown port tcp/'
exit status 1
How can fix this error?
I'm guessing "v" is your config variable… Which contains no data, this is not a problem with Gorm, it's because dc.Open() is not receiving the config values.
If you try to run it with static data, it should work.