How to connect to AWS RDS using Golang? - mysql

I am trying to connect to the AWS RDS using the following code. I got help from this website but when I executed this code, it gave me the following error.
Error
panic: failed to create authentication token: failed to refresh cached credentials, no EC2 IMDS role found, operation error ec2imds: GetMetadata, request canceled, context deadline exceeded
Code
func Connect() (db *sql.DB) {
db_user := middleware.LoadEnvVariable("DB_USER")
// db_password := middleware.LoadEnvVariable("DB_PASSWORD")
db_host := "database endpoint string"
db_db := middleware.LoadEnvVariable("DB_DB")
dbEndpoint := fmt.Sprintf("%s:%d", db_address, 3306)
region := "ap-south-1a"
cfg, err := config.LoadDefaultConfig(context.TODO())
if err != nil {
panic("configuration error: " + err.Error())
}
authenticationToken, err := auth.BuildAuthToken(context.TODO(), dbEndpoint, region, db_user, cfg.Credentials)
if err != nil {
panic("failed to create authentication token: " + err.Error())
}
s := fmt.Sprintf("%s:%s#tcp(%s)/%s?tls=true&allowCleartextPasswords=true", db_user, authenticationToken, dbEndpoint, db_db)
dbbase, err := sql.Open("mysql", s)
if err != nil {
log.Fatal(err)
}
return dbbase
}

Related

How to connect MySQL with AWS?

I am trying to connect the MySQL database with AWS RDS but don't have any idea what should be included.
I created the RDS database, got the DB HOST value, and got the region but I don't know how to apply it and make it work.
func Connect() (db *sql.DB) {
db_user := middleware.LoadEnvVariable("DB_USER")
db_password := middleware.LoadEnvVariable("DB_PASSWORD")
db_address := middleware.LoadEnvVariable("DB_ADDRESS")
db_db := middleware.LoadEnvVariable("DB_DB")
s := fmt.Sprintf("%s:%s#tcp(%s:3306)/%s", db_user, db_password, db_address, db_db)
db, err := sql.Open("mysql", s)
if err != nil {
log.Fatal(err)
}
return db
}

How to set up loop in database until it connects to mysqlDB

I have init funcion in my golang program. I need to make it so the connection loops until it connects to database if it cant connect it idles then try's again and again for 60 seconds if it cant connect at end then it exist out. Also, have environment variable that overrides the default 60 seconds and user can put their own time for until it connects. I have my code below im looking and theres no solid solution in web .
var override string = os.Getenv("OVERRIDE")
func dsn() string {
return fmt.Sprintf("%s:%s#tcp(%s:%s)/%s", username, password, ipdb, portdb, dbName)
func init() {
var db, err = sql.Open("mysql", dsn())
if err != nil {
fmt.Println(err.Error())
} else {
fmt.Printf("Connection established to MYSQL server\n%s\n", dsn())
}
// Checking if table exists in database
rows, table_check := db.Query("select * from " + "Url" + ";")
if table_check == nil {
fmt.Println("\nTable exists in the Database")
count := 0
for rows.Next() {
count++
}
fmt.Printf("Number of records are %d \n", count)
} else {
fmt.Printf("\nTable does not exist in Database %s", table_check)
_, status := db.Exec("CREATE TABLE Url (LongUrl varchar(255),ShortUrl varchar(32));")
if status == nil {
fmt.Println("\n New table created in the Database")
} else {
fmt.Printf("\n The table was not created %s", status)
}
}
defer db.Close()
}
func main(){
......
}
You could use a switch with a timer channel.
For every 500 ms the connection is attempted, and if in 60 seconds the switch has not been resolved then the timeout channel exits the loop.
For example:
func main() {
doneCh := make(chan bool)
db, err := sql.Open("mysql", dsn())
if err != nil {
fmt.Errorf("Could not open connection: %w", err)
os.Exit(1)
}
// Start polling for connection
go func() {
ticker := time.NewTicker(500 * time.Millisecond)
timeoutTimer := time.After(time.Second * 60)
for {
select {
case <-timeoutTimer:
err = errors.New("connection to db timed out")
doneCh <- true
return
case <-ticker.C:
// Simulate some strange wait ... :)
if rand.Intn(10) == 2 {
err = db.Ping()
if err == nil {
doneCh <- true
return
}
}
fmt.Println("Retrying connection ... ")
}
}
}()
// Start waiting for timeout or success
fmt.Println("Waiting for DB connection ...")
<-doneCh
if err != nil {
fmt.Printf("Could not connect to DB: %v \n", err)
os.Exit(1)
}
defer db.Close()
// Do some work
fmt.Printf("Done! Do work now. %+v", db.Stats())
}
Note
Handle your errors as necessary. The sql.Ping() may return you some specific error which will indicate to you that you should retry.
Some errors may not be worth retrying with.
For timers and channels see:
Timers
Channels
Edit: Supposedly simpler way without channels and using a while loop
func main() {
db, err := sql.Open("mysql", dsn())
if err != nil {
fmt.Errorf("Could not open connection: %w", err)
os.Exit(1)
}
defer db.Close()
timeOut := time.Second * 60
idleDuration := time.Millisecond * 500
start := time.Now()
for time.Since(start) < timeOut {
if err = db.Ping(); err == nil {
break
}
time.Sleep(idleDuration)
fmt.Println("Retrying to connect ...")
}
if time.Since(start) > timeOut {
fmt.Printf("Could not connect to DB, timeout after %s", timeOut)
os.Exit(1)
}
// Do some work
fmt.Printf("Done! \nDo work now. %+v", db.Stats())
}

Error while creating connection with phpmyadmin using golang "commands out of sync. Did you run multiple statements at once?"

I'm facing some issue while fetching the data from the MySQL database using golang below is my code and the error that I'm facing
package main
import (
"database/sql"
"fmt"
_ "github.com/go-sql-driver/mysql"
)
func ConnectMsqlDb() (db *sql.DB, err error) {
db, err = sql.Open("mysql", fmt.Sprintf("%s:%s#tcp(%s:"+sqlDbPort+")/"+sqlDB, sqlUserName, sqlPassword, dbServerIP))
if err != nil {
return nil, err
}
//defer db.Close()
err = db.Ping()
if err != nil {
return nil, err
}
return db, nil
}
func GetSqlData() (err error, data interface{}) {
db, err := ConnectMsqlDb()
if err != nil {
// here it will returning me the error
return err, nil
}
rows, err := db.Query("SELECT * FROM users")
if err != nil {
return err, nil
}
for rows.Next() {
}
defer db.Close()
fmt.Println(rows)
return err, rows
}
func main() {
err, data := GetSqlData()
fmt.Println("data", data, "err", err)
}
error
data commands out of sync. Did you run multiple statements at once?
Can anyone tell me why I'm facing this issue
If the error is comming while opening a connection to mysqld , it could be possible that MySQL server (mysqld) is blocking the host from connecting to it. It means that mysqld has received many connection requests from the given host that were interrupted in the middle.
Read why? To confirm you could see the DB's logs as well. So, a way to unblock it is to flush the cached hosts using the MySQL CLI:
mysql> FLUSH HOSTS;
And then try again to connect.
Plus, give this answer a read as well. Might help.
You can check the state of the socket used by mysqld using (For Linux):
netstat -nt
Check if there's any previously hanging connection from the host to mysqld. If yes, then kill it and try again.

AWS SDK How to increase ECS cluster ec2 instance without auto scaling

I'm using Demon service in ECS Cluster. Demon service cannot use auto-scaling.
I want to increase cluster ec2 instance count via aws ecs sdk.
But I can't find the function doing this.
Is there someone who knows this?
I found solution in aws cli sdk. by changing AsgMaxSize
import "github.com/aws/amazon-ecs-cli/ecs-cli/modules/clients/aws/cloudformation"
...
sess, err := session.NewSession(&aws.Config{
Region: aws.String("us-west-2"),
Credentials: credentials.NewStaticCredentials("AKID", "Secret", ""),
})
cloudClient := cloudformation.NewCloudformationClient(&config.CommandConfig{
Session:sess,
})
stackName := "EC2ContainerService-name"
params, err := cloudClient.GetStackParameters(stackName)
if err != nil {
log.Println(err)
return nil
}
log.Println(params)
newParams, err := cloudformation.NewCfnStackParamsForUpdate([]string{"AsgMaxSize"}, params)
if err != nil {
return nil
}
newParams.Add("AsgMaxSize", "3")
out, err := cloudClient.UpdateStack(stackName, newParams)
if err != nil {
log.Println(err)
return nil
}

How to create a new MySQL database with go-sql-driver

I'm working on Golang script that automatically clone a database.
I'm using go-sql-driver but i can't find in the documentation a way to create a new database.
Connection to MySQL require an URL scheme like:
user:password#tcp(localhost:3306)/database_name
But the database not exists yet, I just want to connect to the server and then create a new one.
How can I do that? I have to use another driver?
You can perfectly use the go-sql-driver. However, you need to use a mysql user which has the proper access rights to create new databases.
Here is an example:
func create(name string) {
db, err := sql.Open("mysql", "admin:admin#tcp(127.0.0.1:3306)/")
if err != nil {
panic(err)
}
defer db.Close()
_,err = db.Exec("CREATE DATABASE "+name)
if err != nil {
panic(err)
}
_,err = db.Exec("USE "+name)
if err != nil {
panic(err)
}
_,err = db.Exec("CREATE TABLE example ( id integer, data varchar(32) )")
if err != nil {
panic(err)
}
}
Note that the database name is not provided in the connection string. We just create the database after the connection (CREATE DATABASE command), and switch the connection to use it (USE command).
Note: the VividCortex guys maintain a nice database/sql tutorial and documentation at http://go-database-sql.org/index.html
If you want to create a new database if it does not exist, and use it directly in your program, be aware that database/sql maintains a connection pool.
Therefore the opened database connection, should preferably contain the database name. I've seen "Error 1046: No database selected" when database/sql opens a new connection after using db.Exec("USE "+name) manually.
func createAndOpen(name string) *sql.DB {
db, err := sql.Open("mysql", "admin:admin#tcp(127.0.0.1:3306)/")
if err != nil {
panic(err)
}
defer db.Close()
_,err = db.Exec("CREATE DATABASE IF NOT EXISTS "+name)
if err != nil {
panic(err)
}
db.Close()
db, err = sql.Open("mysql", "admin:admin#tcp(127.0.0.1:3306)/" + name)
if err != nil {
panic(err)
}
defer db.Close()
return db
}
My db_config.go file looks like for GO ORM 2.0:
package infrastructure
import (
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm2.0/utils"
)
//Setup Models: initializaing the mysql database
func GetDatabaseInstance() *gorm.DB {
get := utils.GetEnvWithKey
USER := get("DB_USER")
PASS := get("DB_PASS")
HOST := get("DB_HOST")
PORT := get("DB_PORT")
DBNAME := get("DB_NAME")
dsn := fmt.Sprintf("%s:%s#tcp(%s:%s)/%s?charset=utf8&parseTime=True&loc=Local", USER, PASS, HOST, PORT, DBNAME)
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
_ = db.Exec("CREATE DATABASE IF NOT EXISTS " + DBNAME + ";")
if err != nil {
panic(err.Error())
}
return db
}