I am trying to create multi instance in GCP with cloud function, use golang programing.
I refer tutorial in https://medium.com/google-cloud/using-cloud-scheduler-and-cloud-functions-to-deploy-a-periodic-compute-engine-vm-worker-2b897ef68dc5 then write some customize in my context. Here is my code
package cloudfunctions
import (
"context"
"fmt"
"log"
"net/http"
"os"
"google.golang.org/api/compute/v1"
)
var ProjectID = ""
var Zone = ""
var Region = ""
var InstanceName = ""
var InstanceType = ""
func DeployInstance(w http.ResponseWriter, r *http.Request) {
ProjectID = os.Getenv("PROJECT_ID")
Zone = os.Getenv("ZONE")
Region = os.Getenv("REGION")
cs, err := InitComputeService()
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
log.Fatal(err)
}
var listInstance = []string{"e2-standard-2", "e2-standard-8", "n2-standard-2", "n2-standard-8", "n1-custom-2-8192", "n1-custom-8-32768", "c2-standard-8" }
for i:=0; i < 7; i++ {
InstanceType = listInstance[i]
InstanceName = "benchmark-"+InstanceType
instance, err := GetInstance(cs)
if err != nil {
w.WriteHeader(http.StatusTemporaryRedirect)
w.Write([]byte(err.Error() + " instance may not exist yet"))
log.Print(err)
_, err = CreateInstance(cs)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte("creating instance " + InstanceName + "in zone: " + Zone))
startInstance(cs, w)
}
} else {
msg := "instance is in intermediate state: " + instance.Status
w.WriteHeader(http.StatusAccepted)
w.Write([]byte(msg))
log.Println(msg)
}
}
}
func InitComputeService() (*compute.Service, error) {
ctx := context.Background()
return compute.NewService(ctx)
}
func GetInstance(computeService *compute.Service) (*compute.Instance, error) {
return computeService.Instances.Get(ProjectID, Zone, InstanceName).Do()
}
func StartInstance(computeService *compute.Service) (*compute.Operation, error) {
return computeService.Instances.Start(ProjectID, Zone, InstanceName).Do()
}
// CreateInstance creates a given instance with metadata that logs its information.
func CreateInstance(computeService *compute.Service) (*compute.Operation, error) {
instance := &compute.Instance{
Name: InstanceName,
MachineType: fmt.Sprintf("zones/%s/machineTypes/%s", Zone, InstanceType),
NetworkInterfaces: []*compute.NetworkInterface{
{
Name: "default",
Subnetwork: fmt.Sprintf("projects/%s/regions/%s/subnetworks/default", ProjectID, Region),
AccessConfigs: []*compute.AccessConfig{
{
Name: "External NAT",
Type: "ONE_TO_ONE_NAT",
NetworkTier: "PREMIUM",
},
},
},
},
Scheduling: &compute.Scheduling{
Preemptible: true,
},
Disks: []*compute.AttachedDisk{
{
Boot: true, // The first disk must be a boot disk.
AutoDelete: true, //Optional
Mode: "READ_WRITE", //Mode should be READ_WRITE or READ_ONLY
Interface: "SCSI", //SCSI or NVME - NVME only for SSDs
InitializeParams: &compute.AttachedDiskInitializeParams{
DiskName: "worker-instance-boot-disk",
SourceImage: "projects/centos-cloud/global/images/family/centos-7",
DiskType: fmt.Sprintf("projects/%s/zones/%s/diskTypes/pd-ssd", ProjectID, Zone),
DiskSizeGb: 200,
},
},
},
}
return computeService.Instances.Insert(ProjectID, Zone, instance).Do()
}
// startInstance is a wrapper function for the switch statement
func startInstance(cs *compute.Service, w http.ResponseWriter) {
operation, err := StartInstance(cs)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
log.Fatal(err)
}
w.WriteHeader(http.StatusOK)
data, _ := operation.MarshalJSON()
w.Write(data)
}
In above code, I want to create 7 instance with 7 difference setting, specific is instance type and instance name. I test this code in cloud function with DeployInstance is start function. But there is only one instance was created, with name is benchmark-e2-standard-2 and type is e2-standard-2. It output an error with message Error: Infrastructure cannot communicate with function. There was likely a crash or deadlock in the user-provided code. Additional troubleshooting documentation can be found at https://cloud.google.com/functions/docs/troubleshooting#logging
I visited website but I not find a solution to fix my code. Who can help me why my code not true, how can I fix it. Step by step if possible.
Thanks in advance.
I was found my answer. Root cause is each instance must have a disk partition, with different name.
So, I change my code with some change, you can see it bellow.
package cloudfunctions
import (
"context"
"fmt"
"log"
"net/http"
"os"
"google.golang.org/api/compute/v1"
"time"
)
var ProjectID = ""
var Zone = ""
var Region = ""
var InstanceName = ""
var InstanceType = ""
var IDiskName = ""
func DeployInstance(w http.ResponseWriter, r *http.Request) {
ProjectID = os.Getenv("PROJECT_ID")
Zone = os.Getenv("ZONE")
Region = os.Getenv("REGION")
var listInstance = []string{"e2-standard-8","e2-standard-2", "n2-standard-2", "n2-standard-8", "n1-custom-2-8192", "n1-custom-8-32768", "c2-standard-8"}
for i:=0; i < len(listInstance); i++ {
cs, err := compute.NewService(context.Background())
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
log.Fatal(err)
}
InstanceType = listInstance[i]
InstanceName = "benchmark-"+InstanceType
IDiskName = InstanceName+"-boot-disk"
instance, err := GetInstance(cs)
if err != nil {
w.WriteHeader(http.StatusTemporaryRedirect)
w.Write([]byte(err.Error() + " instance may not exist yet"))
_, err = CreateInstance(cs)
if err != nil {
for {
disk, derr := cs.Disks.Get(ProjectID, Zone, IDiskName).Context(context.Background()).Do()
log.Print(IDiskName + " is " + disk.Status)
time.Sleep(1 * time.Second)
if derr != nil {
startInstance(cs, w)
break
}
}
}
} else {
msg := "instance "+ InstanceName +" is in intermediate state: " + instance.Status
w.WriteHeader(http.StatusAccepted)
w.Write([]byte(msg))
log.Println(msg)
}
}
}
func GetInstance(computeService *compute.Service) (*compute.Instance, error) {
return computeService.Instances.Get(ProjectID, Zone, InstanceName).Do()
}
func StartInstance(computeService *compute.Service) (*compute.Operation, error) {
return computeService.Instances.Start(ProjectID, Zone, InstanceName).Do()
}
// CreateInstance creates a given instance with metadata that logs its information.
func CreateInstance(computeService *compute.Service) (*compute.Operation, error) {
instance := &compute.Instance{
Name: InstanceName,
MachineType: fmt.Sprintf("zones/%s/machineTypes/%s", Zone, InstanceType),
NetworkInterfaces: []*compute.NetworkInterface{
{
Name: "default",
Subnetwork: fmt.Sprintf("projects/%s/regions/%s/subnetworks/default", ProjectID, Region),
AccessConfigs: []*compute.AccessConfig{
{
Name: "External NAT",
Type: "ONE_TO_ONE_NAT",
NetworkTier: "PREMIUM",
},
},
},
},
Scheduling: &compute.Scheduling{
Preemptible: true,
},
Disks: []*compute.AttachedDisk{
{
Boot: true, // The first disk must be a boot disk.
AutoDelete: true, //Optional
Mode: "READ_WRITE", //Mode should be READ_WRITE or READ_ONLY
Interface: "SCSI", //SCSI or NVME - NVME only for SSDs
InitializeParams: &compute.AttachedDiskInitializeParams{
DiskName: IDiskName,
SourceImage: "projects/centos-cloud/global/images/family/centos-7",
DiskType: fmt.Sprintf("projects/%s/zones/%s/diskTypes/pd-ssd", ProjectID, Zone),
DiskSizeGb: 100,
},
},
},
}
return computeService.Instances.Insert(ProjectID, Zone, instance).Do()
}
// startInstance is a wrapper function for the switch statement
func startInstance(cs *compute.Service, w http.ResponseWriter) {
operation, err := StartInstance(cs)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
log.Fatal(err)
}
w.WriteHeader(http.StatusOK)
data, _ := operation.MarshalJSON()
w.Write(data)
}
If you have any question about this problem, drop your comment. I hope I can support for you.
Thanks all.
Related
In DynamoDB I Have a table that contains:
- email (primary key)
- password (attribute)
- rname (attribute)
I'm using V1 of the AWS Go SDK, to implement to perform a query using just the primary key to my database:
My struct to unMarshal to is:
type Item struct {
Email string `json:"email"`
Password string `json:"password"`
Rname string `json:"rname"`
}
and the code:
result, err := client.Query(&dynamodb.QueryInput{
TableName: aws.String("accountsTable"),
KeyConditions: map[string]*dynamodb.Condition{
"email": {
ComparisonOperator: aws.String("EQ"),
AttributeValueList: []*dynamodb.AttributeValue{
{
S: aws.String(email),
},
},
},
},
})
if err != nil {
return false, err
}
item := []Item{}
err = dynamodbattribute.UnmarshalListOfMaps(result.Items, &item)
if err != nil {
return false, err
}
However, I get the issue that the key is invalid. I check the key in the database and it matches the one i print out to the console too.
Not sure how to get round this issue as example's i've seen seem to work for their's and look the same.
Any help in fixing this issue would be appreciated thanks :)
You need to set the values of password and rname to omitempty so that it's not set to empty values as they are not keys they should not be included on a Query as it throws an invalid key exception:
type Item struct {
Email string `json:"email" dynamodbav:"email,omitempty"`
Password string `json:"password" dynamodbav:"password,omitempty"`
Rname string `json:"rname" dynamodbav:"rname,omitempty"`
}
Update
I believe the issue is due to the fact you try to marshall the entire response in a single command, however, iterating works for me. (I do not use Go).
package main
import (
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/dynamodb"
"github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute"
"fmt"
)
func main() {
// Create Session
sess := session.Must(session.NewSessionWithOptions(session.Options{
SharedConfigState: session.SharedConfigEnable,
}))
// Create DynamoDB Client with Logging
client := dynamodb.New(sess, aws.NewConfig())
type Item struct {
Email string `dynamodbav: "email"`
Password string `dynamodbav: "password,omitempty"`
Rname string `dynamodbav: "rname,omitempty"`
}
result, err := client.Query(&dynamodb.QueryInput{
TableName: aws.String("accountsTable"),
KeyConditions: map[string]*dynamodb.Condition{
"email": {
ComparisonOperator: aws.String("EQ"),
AttributeValueList: []*dynamodb.AttributeValue{
{
S: aws.String("lhnng#amazon.com"),
},
},
},
},
})
if err != nil {
fmt.Println("Query API call failed:")
fmt.Println((err.Error()))
}
for _, i := range result.Items {
item := Item{}
err = dynamodbattribute.UnmarshalMap(i, &item)
if err != nil {
fmt.Println("Got error unmarshalling: %s", err)
}
fmt.Println("Email: ", item.Email)
fmt.Println()
}
}
Moreover, as you use a single key of email, it means there is at most 1 item with the same email address, meaning you should use GetItem rather than Query:
package main
import (
"fmt"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/dynamodb"
"github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute"
)
func main() {
// Item to Get
type Item struct {
Email string `dynamodbav: "email"`
Password string `dynamodbav: "password,omitempty"`
Rname string `dynamodbav: "rname,omitempty"`
}
// Create Session
sess := session.Must(session.NewSessionWithOptions(session.Options{
SharedConfigState: session.SharedConfigEnable,
}))
// Create DynamoDB Client
client := dynamodb.New(sess, aws.NewConfig())
// Get Item
result, err := client.GetItem(&dynamodb.GetItemInput{
TableName: aws.String("accountsTable"),
Key: map[string]*dynamodb.AttributeValue{
"email": {
S: aws.String("lhnng#amazon.com"),
},
},
})
// Catch Error
if err != nil {
fmt.Println("GetItem API call failed:")
fmt.Println((err.Error()))
}
item := Item{}
// Unmarhsall
err = dynamodbattribute.UnmarshalMap(result.Item, &item)
if err != nil {
panic(fmt.Sprintf("Failed to unmarshal Record, %v", err))
}
// If Item Returns Empty
if item.Email == "" {
fmt.Println("Could not find Item")
return
}
// Print Result
fmt.Println("Found item:")
fmt.Println("Email: ", item.Email)
}
go version: 1.19
gin version (or commit ref): 1.8.1
operating system: Ubuntu
I have a saas project which is based upon Rest APIs. All apis are developed in GO using gin package. When the user logs in then I set current user details in the request context so that I can access these details furthere to display some data. However I had a case in which 2 requests hits in parallel & the context values for the 1st request are override with the context values in the 2nd request. Due to this, my data is displaying wrong.
package main
import (
"fmt"
"strings"
"github.com/gin-gonic/gin"
"github.com/golang-jwt/jwt"
)
func main() {
g := gin.Default()
g.Use(ParseJWTToken)
g.GET("/hello/:name", hello)
g.Run(":9000")
}
func hello(c *gin.Context) {
c.Keys = make(map[string]interface{})
c.Keys["current_user_id"] = 10
c.Keys["current_user_name"] = c.Param("name")
fmt.Println(c.Keys)
c.String(200, "Hello %s", c.Param("name"))
}
var role, userName string
var userId float64
func ParseJWTToken(c *gin.Context) {
merchantDatabase := make(map[string]interface{})
if values, _ := c.Request.Header["Authorization"]; len(values) > 0 {
bearer := strings.Split(c.Request.Header["Authorization"][0], "Bearer")
bearerToken := strings.TrimSpace(bearer[1])
var userAgent string
var userAgentCheck bool
if values, _ := c.Request.Header["User-Agent"]; len(values) > 0 {
userAgent = values[0]
}
_ = config.InitKeys()
token, err := jwt.Parse(bearerToken, func(token *jwt.Token) (interface{}, error) {
return config.SignKey, nil
})
if err != nil {
c.Abort()
return
}
if !token.Valid {
c.Abort()
return
}
if len(token.Claims.(jwt.MapClaims)) > 0 {
for key, claim := range token.Claims.(jwt.MapClaims) {
if key == "user_agent" {
if claim == userAgent {
userAgentCheck = true
}
}
if key == "role" {
role = claim.(string)
}
if key == "id" {
userId = claim.(float64)
}
if key == "name" {
userName = claim.(string)
}
}
}
merchantDatabase["userid"] = userId
merchantDatabase["role"] = role
merchantDatabase["username"] = userName
c.Keys = merchantDatabase
if userAgentCheck {
c.Next()
} else {
c.Abort()
return
}
} else {
c.Abort()
return
}
}
This issue is not produced every time for parallel requests.
How can I fix that ?
I have used global variables for the details that were overridden. Declaring these inside the middleware fixed the issue. Find complete thread here: https://github.com/gin-gonic/gin/issues/3437
I'd like to write a method that will populate a Go Language array with the common timezones that are accepted by the time.Format() call, for use in an HTML template (Form select to allow them to read and choose their timezone). Is there a common way to do this?
To get a list of time zones, you can use something like:
package main
import (
"fmt"
"io/ioutil"
"strings"
)
var zoneDirs = []string{
// Update path according to your OS
"/usr/share/zoneinfo/",
"/usr/share/lib/zoneinfo/",
"/usr/lib/locale/TZ/",
}
var zoneDir string
func main() {
for _, zoneDir = range zoneDirs {
ReadFile("")
}
}
func ReadFile(path string) {
files, _ := ioutil.ReadDir(zoneDir + path)
for _, f := range files {
if f.Name() != strings.ToUpper(f.Name()[:1]) + f.Name()[1:] {
continue
}
if f.IsDir() {
ReadFile(path + "/" + f.Name())
} else {
fmt.Println((path + "/" + f.Name())[1:])
}
}
}
output:
Africa/Abidjan
Africa/Accra
Africa/Addis_Ababa
Africa/Algiers
Africa/Asmara
Africa/Asmera
Africa/Bamako
Africa/Bangui
...
Go's time pkg uses a timezone database.
You can load a timezone location like this:
loc, err := time.LoadLocation("America/Chicago")
if err != nil {
// handle error
}
t := time.Now().In(loc)
The Format function is not related to setting the time zone, this function takes a fixed reference time that allows you to format the date how you would like. Take a look at the time pkg docs.
For instance:
fmt.Println(t.Format("MST")) // outputs CST
Here is a running example
Here is an example: https://play.golang.org/p/KFGQiW5A1P-
package main
import (
"fmt"
"io/ioutil"
"strings"
"unicode"
)
func main() {
fmt.Println(GetOsTimeZones())
}
func GetOsTimeZones() []string {
var zones []string
var zoneDirs = []string{
// Update path according to your OS
"/usr/share/zoneinfo/",
"/usr/share/lib/zoneinfo/",
"/usr/lib/locale/TZ/",
}
for _, zd := range zoneDirs {
zones = walkTzDir(zd, zones)
for idx, zone := range zones {
zones[idx] = strings.ReplaceAll(zone, zd+"/", "")
}
}
return zones
}
func walkTzDir(path string, zones []string) []string {
fileInfos, err := ioutil.ReadDir(path)
if err != nil {
return zones
}
isAlpha := func(s string) bool {
for _, r := range s {
if !unicode.IsLetter(r) {
return false
}
}
return true
}
for _, info := range fileInfos {
if info.Name() != strings.ToUpper(info.Name()[:1])+info.Name()[1:] {
continue
}
if !isAlpha(info.Name()[:1]) {
continue
}
newPath := path + "/" + info.Name()
if info.IsDir() {
zones = walkTzDir(newPath, zones)
} else {
zones = append(zones, newPath)
}
}
return zones
}
i'm really new to Go, su just bear with me here. I'm trying to write a code for loading mysql data to redis cluster using following :redis-go-cluster,
load2redis
This is the code. Its a little bit long, just bear with me here.
package main
import (
"bytes"
"database/sql"
"flag"
// "github.com/garyburd/redigo/redis"
_ "github.com/go-sql-driver/mysql"
//"gopkg.in/redis.v4"
"github.com/chasex/redis-go-cluster"
"log"
"runtime"
// "strings"
"sync"
"time"
)
var client *redis.Cluster
type Task interface {
Execute()
}
type Pool struct {
mu sync.Mutex
size int
tasks chan Task
kill chan struct{}
wg sync.WaitGroup
}
func NewPool(size int) *Pool {
pool := &Pool{
tasks: make(chan Task, 128),
kill: make(chan struct{}),
}
pool.Resize(size)
return pool
}
func (p *Pool) worker() {
defer p.wg.Done()
for {
select {
case task, ok := <-p.tasks:
if !ok {
return
}
task.Execute()
case <-p.kill:
return
}
}
}
func (p *Pool) Resize(n int) {
p.mu.Lock()
defer p.mu.Unlock()
for p.size < n {
p.size++
p.wg.Add(1)
go p.worker()
}
for p.size > n {
p.size--
p.kill <- struct{}{}
}
}
func (p *Pool) Close() {
close(p.tasks)
}
func (p *Pool) Wait() {
p.wg.Wait()
}
func (p *Pool) Exec(task Task) {
p.tasks <- task
}
type RedisTask struct {
Index int
Command string
Key string
Value string
MapData map[string]string
}
func (e RedisTask) Execute() {
log.Println("executing:", e.Key, ",", e.Index)
if e.Command == "SET" {
_,err := redis.String(client.Do("SET", e.Key, e.Value))
checkErr(err, "set error:")
} else if e.Command == "SADD" {
_,err := redis.Strings(client.Do("SADD", e.Key, e.Value))
checkErr(err, "sadd error:")
} else if e.Command == "HMSET" {
_,err := redis.StringMap(client.Do("HMSET", e.Key, e.MapData))
checkErr(err, "hmset error:")
}
// TODO: clean data
}
func main() {
runtime.GOMAXPROCS(runtime.NumCPU())
startTime := time.Now().UnixNano() / int64(time.Millisecond)
host := flag.String("s", "localhost:3306", "mysql server host and port ,eg localhost:3306")
username := flag.String("u", "test", "username to login mysql")
password := flag.String("p", "test", "password for mysql")
database := flag.String("d", "test", "database you want to execute query")
query := flag.String("q", "select 1;", "your query sql")
ds := flag.String("ds", "key", "redis structure")
PK := flag.String("pk", "Rkey", "the redis Key in the fields of mysql query result")
//redisHost := flag.String("rs", "localhost:6379", "redis host and port ,eg localhost:6379")
//redisPassword := flag.String("rp", "test", "redis password")
poolSize := flag.Int("size", 10000, "redis pool size")
flag.Parse()
var buf bytes.Buffer = bytes.Buffer{}
buf.WriteString(*username)
buf.WriteString(":")
buf.WriteString(*password)
buf.WriteString("#tcp(")
buf.WriteString(*host)
buf.WriteString(")/")
buf.WriteString(*database)
db, err := sql.Open("mysql", buf.String())
checkErr(err, "connect to mysql error !")
defer db.Close()
poolWorker := NewPool(*poolSize)
// Execute the query
rows, err := db.Query(*query)
checkErr(err, "execute sql error!")
// pool = newPool(*redisHost, *redisPassword, *poolSize)
//client = redis.NewClient(&redis.Options{
// Addr: *redisHost,
// Password: *redisPassword, // no password set
// DB: 0, // use default DB
//})
client,_ = redis.NewCluster(&redis.Options{
StartNodes: []string{"10.x.x.x:6000", "10.x.x.x:6001", "10.x.x.x:6002"},
ConnTimeout: 50 * time.Millisecond,
ReadTimeout: 50 * time.Millisecond,
WriteTimeout: 50 * time.Millisecond,
KeepAlive: 16,
AliveTime: 60 * time.Second,
})
//checkErr(err, "client error:")
//pong, err := client.Ping().Result()
//checkErr(err, "redis client error:")
//log.Println(pong)
columns, err := rows.Columns()
checkErr(err, "get columns error!")
length := len(columns)
values := make([]sql.RawBytes, length)
scanArgs := make([]interface{}, len(values))
for i := range values {
scanArgs[i] = &values[i]
}
count := 0
for rows.Next() {
count += 1
err = rows.Scan(scanArgs...)
checkErr(err, "scan error")
var value string
var key string
var task RedisTask
if *ds == "key" {
key = getStringData(values[0])
value = getStringData(values[1])
if value != "" {
task = RedisTask{
Index: count,
Command: "SET",
Key: key,
Value: value,
}
}
} else if *ds == "set" {
key = getStringData(values[0])
value = getStringData(values[1])
if value != "" {
task = RedisTask{
Index: count,
Command: "SADD",
Key: key,
Value: value,
}
}
} else if *ds == "hash" {
key = getStringData(values[0])
// args := redis.Args{}.Add(key)
m := make(map[string]string)
for i, col := range values {
if col != nil && columns[i] != *PK {
value = getStringData(col)
m[columns[i]] = value
}
}
task = RedisTask{
Index: count,
Command: "HMSET",
Key: key,
MapData: m,
}
}
poolWorker.Exec(task)
}
if err = rows.Err(); err != nil {
panic(err.Error()) // proper error handling instead of panic in your app
}
poolWorker.Close()
poolWorker.Wait()
EndTime := time.Now().UnixNano() / int64(time.Millisecond)
log.Println("======================================== executing time:", EndTime-startTime, " ms, total:", count)
}
func getStringData(data sql.RawBytes) string {
if data == nil {
return ""
}
value := string(data)
return clearBad(value)
}
func clearBad(str string) string {
// str = strings.Trim(str, "`")
// str = strings.Trim(str, "ï½€")
// str = strings.Trim(str, "-")
// str = strings.Trim(str, ".")
// str = strings.Trim(str, " ")
// str = strings.Trim(str, ";")
// str = strings.Trim(str, ",")
// str = strings.Trim(str, ":")
// str = strings.Trim(str, ";")
// str = strings.Trim(str, "'")
// str = strings.Trim(str, "!")
return str
}
func checkErr(err error, msg string) {
if err != nil {
log.Fatalln(msg, err)
}
}
When i'm executing it, i'm getting following exception:
./rak -u user -p user -s 10.X.X.X:8080 -d test -q "SELECT CONCAT( 'student:', c.sid ) Rkey, c.sname SNAME, c.saddress SADDRESS, c.sage SAGE FROM STUDENT c WHERE c.sid > 0;" -ds hash -size 1200
2017/07/21 10:29:09 rak.go:93: executing: student:2 , 2
2017/07/21 10:29:09 rak.go:93: executing: student:1 , 1
2017/07/21 10:29:09 rak.go:93: executing: student:3 , 3
2017/07/21 10:29:09 rak.go:268: hmset error: Do: unknown type map[string]string
$
Can somebody explain to me what i'm doing wrong here? I'd be very grateful.
As pointed out, Do does not work with maps. This is one way you could fix it.
} else if e.Command == "HMSET" {
// Build up a string slice to hold the key value pairs
args := make([]string, 0, len(e.MapData) * 2)
for k, v := range e.MapData {
args = append(args, k, v)
}
_,err := redis.StringMap(client.Do("HMSET", e.Key, args...))
checkErr(err, "hmset error:")
}
The Do method maps to the Redis command set and arguments are expected in the same way. For example.
127.0.0.1:6379> HMSET myKey foo bar baz boff
OK
127.0.0.1:6379> HGETALL myKey
1) "foo"
2) "bar"
3) "baz"
4) "boff"
127.0.0.1:6379>
The same map-set operation using the redis client in your code would be
client.Do("HMSET", "myKey", "foo", "bar", "baz", "boff")
When the arguments for keys and values of the map are dynamic, the most straight forward way is
client.Do("HMSET", "myKey", []string{"foo", "bar", "baz", "boff"}...)
which is exactly what the first code block above does.
Accepted values for Do function arguements are int64, float64, string or []byte .Since you passed a map it failed with error unknown type %T
Here is a reference to the respective code that does it
redis-go-cluster/node.go
I'd like to write a method that will populate a Go Language array with the common timezones that are accepted by the time.Format() call, for use in an HTML template (Form select to allow them to read and choose their timezone). Is there a common way to do this?
To get a list of time zones, you can use something like:
package main
import (
"fmt"
"io/ioutil"
"strings"
)
var zoneDirs = []string{
// Update path according to your OS
"/usr/share/zoneinfo/",
"/usr/share/lib/zoneinfo/",
"/usr/lib/locale/TZ/",
}
var zoneDir string
func main() {
for _, zoneDir = range zoneDirs {
ReadFile("")
}
}
func ReadFile(path string) {
files, _ := ioutil.ReadDir(zoneDir + path)
for _, f := range files {
if f.Name() != strings.ToUpper(f.Name()[:1]) + f.Name()[1:] {
continue
}
if f.IsDir() {
ReadFile(path + "/" + f.Name())
} else {
fmt.Println((path + "/" + f.Name())[1:])
}
}
}
output:
Africa/Abidjan
Africa/Accra
Africa/Addis_Ababa
Africa/Algiers
Africa/Asmara
Africa/Asmera
Africa/Bamako
Africa/Bangui
...
Go's time pkg uses a timezone database.
You can load a timezone location like this:
loc, err := time.LoadLocation("America/Chicago")
if err != nil {
// handle error
}
t := time.Now().In(loc)
The Format function is not related to setting the time zone, this function takes a fixed reference time that allows you to format the date how you would like. Take a look at the time pkg docs.
For instance:
fmt.Println(t.Format("MST")) // outputs CST
Here is a running example
Here is an example: https://play.golang.org/p/KFGQiW5A1P-
package main
import (
"fmt"
"io/ioutil"
"strings"
"unicode"
)
func main() {
fmt.Println(GetOsTimeZones())
}
func GetOsTimeZones() []string {
var zones []string
var zoneDirs = []string{
// Update path according to your OS
"/usr/share/zoneinfo/",
"/usr/share/lib/zoneinfo/",
"/usr/lib/locale/TZ/",
}
for _, zd := range zoneDirs {
zones = walkTzDir(zd, zones)
for idx, zone := range zones {
zones[idx] = strings.ReplaceAll(zone, zd+"/", "")
}
}
return zones
}
func walkTzDir(path string, zones []string) []string {
fileInfos, err := ioutil.ReadDir(path)
if err != nil {
return zones
}
isAlpha := func(s string) bool {
for _, r := range s {
if !unicode.IsLetter(r) {
return false
}
}
return true
}
for _, info := range fileInfos {
if info.Name() != strings.ToUpper(info.Name()[:1])+info.Name()[1:] {
continue
}
if !isAlpha(info.Name()[:1]) {
continue
}
newPath := path + "/" + info.Name()
if info.IsDir() {
zones = walkTzDir(newPath, zones)
} else {
zones = append(zones, newPath)
}
}
return zones
}