Intro to the Go programming language (Golang)
Presented by
Jonathan Seth Mainguy
Systems Administrator @ Bandwidth
Go (often referred to as Golang) is a programming language created by Google in 2009 by Robert Griesemer, Rob Pike, and Ken Thompson (Ken wrote Unix, he is kind of a big deal).
Go is a statically typed, compiled language in the tradition of C
The mascot for Go is the Gopher, you can make your own at https://gopherize.me
The best place to start is the Go tour, it is fabulous.
https://tour.golang.org
The community on IRC Freenode is amazing for questions as well.
Freenode: #go-nuts
Say hi to jmainguy if you go on there.
Why should I learn another language? Bash and python do everything I need.
Bash is my first love and has its place. It really sucks at parsing things like json.
Python is great at parsing, but requires additional packages be installed on each server your script will run on. It is hard to keep track of all the additional packages your script needs.
Golang compiles all its dependencies into a single binary, which you can then ship around and run without worry about it failing (Assuming you compiled on same relative OS, it uses some C libraries and such, so if GLIBC is really different it could be a problem)
Golang can import packages like python, except it can also do it straight from a git repo, like
package main
import (
"github.com/Jmainguy/zenoss"
)
func main() {
zenoss.CreateAlarm("https://example.com",
"jmainguy", "password",
"neat", "12345")
}
Golang wont let you import modules, or define variables which you don't end up using. I think that is pretty cool.
[jmainguy@jmainguy-fedora test]$ cat main.go
package main
import (
"fmt" // I don't end up using fmt anywhere so this fails
"github.com/Jmainguy/zenoss"
)
func main() {
Uuid, Success := zenoss.CreateAlarm("https://example.com",
"jmainguy", "password",
"neat", "12345")
}
[jmainguy@jmainguy-fedora test]$ go build
# _/home/jmainguy/go/test
./main.go:4:2: imported and not used: "fmt"
I fixed my code to finally use fmt, but I missed using the Success variable for anything.
[jmainguy@jmainguy-fedora test]$ cat main.go
package main
import (
"fmt"
"github.com/Jmainguy/zenoss"
)
func main() {
Uuid, Success := zenoss.CreateAlarm("https://example.com",
"jmainguy", "password",
"neat", "12345")
fmt.Println(Uuid)
}
[jmainguy@jmainguy-fedora test]$ go build
# _/home/jmainguy/go/test
./main.go:9:8: Success declared and not used
If you dont want a variable, don't define it. You can also use _ if a function returns more variables then you care about.
[jmainguy@jmainguy-fedora test]$ cat main.go
package main
import (
"fmt"
"github.com/Jmainguy/zenoss"
)
func main() {
Uuid, _ := zenoss.CreateAlarm("https://example.com",
"jmainguy", "password",
"neat", "12345")
fmt.Println(Uuid)
}
[jmainguy@jmainguy-fedora test]$ go build
[jmainguy@jmainguy-fedora test]$
[jmainguy@jmainguy-fedora test]$ ls
main.go test
[jmainguy@jmainguy-fedora test]$ file test
test: ELF 64-bit LSB executable, x86-64, version 1 (SYSV),
dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2,
with debug_info, not stripped
Go build finished succesefully and now I have a binary I can run, named after the directory I am in.
You can split your functions out over as many files as you want.
[jmainguy@jmainguy-fedora test]$ cat random.go
package main
import (
"math/rand"
)
func random(min, max int) int {
return rand.Intn(max-min) + min
}
[jmainguy@jmainguy-fedora test]$
[jmainguy@jmainguy-fedora test]$ cat main.go
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
rand.Seed(time.Now().UnixNano())
fmt.Println("Rolling 1d20")
roll := random(1, 20)
fmt.Printf("You rolled a %d\n", roll)
}
[jmainguy@jmainguy-fedora test]$ ./test
Rolling 1d20
You rolled a 8
[jmainguy@jmainguy-fedora test]$ ./test
Rolling 1d20
You rolled a 13
Golang is very specific about types, you must declare them, and use them appropriately. In func random, I am declaring both min, and max inputs will be integers, and the return will be an integer as well.
[jmainguy@jmainguy-fedora test]$ cat random.go
package main
import (
"math/rand"
)
func random(min, max int) int {
return rand.Intn(max-min) + min
}
package main
import (
"bufio"
"fmt"
"math/rand"
"os"
"time"
)
func main() {
welcome()
fmt.Println("What would you like to do?")
reader := bufio.NewReader(os.Stdin)
choice, _ := reader.ReadString('\n')
if choice == "Fight\n" {
rand.Seed(time.Now().UnixNano())
fmt.Println("Rolling 1d20")
roll := random(1, "twenty")
fmt.Printf("You rolled a %d\n", roll)
if roll < 10 {
fmt.Println("You missed")
fmt.Println("The Orc is taken back")
} else {
fmt.Println("You slice the Ork in two")
fmt.Println("You are a murderer")
}
} else {
fmt.Printf("You chose to %s\n", choice)
}
}
[jmainguy@jmainguy-fedora test]$ go build
# _/home/jmainguy/go/test
./main.go:19:21: cannot use "twenty" (type string) as type int in argument to random
I passed a string, to a func expecting an int, so it errored out.
Once I changed "twenty" to 20, it compiled again.
[jmainguy@jmainguy-fedora test]$ ./test
You see a Orc carrying an axe, walking directly toward you
What would you like to do?
Fight
Rolling 1d20
You rolled a 12
You slice the Ork in two
You are a murderer
It creates large binaries, because it contains all its dependencies.
[jmainguy@jmainguy-fedora test]$ ls -ltrh
total 2.1M
-rw-rw-r--. 1 jmainguy jmainguy 106 Sep 19 11:34 random.go
-rw-rw-r--. 1 jmainguy jmainguy 136 Sep 19 11:55 welcome.go
-rw-rw-r--. 1 jmainguy jmainguy 605 Sep 19 12:09 main.go
-rwxrwxr-x. 1 jmainguy jmainguy 2.1M Sep 19 12:10 test
Golang programs make great daemons, as they are quick to create
Here is a daemon that prints a message every 5 seconds until somone kills the process.
for {
fmt.Println("Look, I am a daemon")
// Sleep for 5 seconds, restart loop
time.Sleep(5 *time.Second)
}
Maybe you want to destroy someones cpu in the background. Use a go routine.
package main
import (
"crypto/sha512"
"fmt"
"time"
)
func sha() {
input := "Jon is the cooooolest"
sha_512 := sha512.New()
sha_512.Write([]byte(input))
}
func eat() {
for {
sha()
}
}
func main() {
go eat()
for {
fmt.Println("I am being a good program I swear")
time.Sleep(5 * time.Second)
}
}
[jmainguy@jmainguy-fedora example]$ ./example
I am being a good program I swear
I am being a good program I swear
12684 jmainguy 20 0 32848 29144 1168 S 121.3 0.2 0:38.40 example
You can download go binaries using go, to use as commands on your workstation. Here I am downloading gotty-client, and connecting to a shell on https://soh.re
[jmainguy@jmainguy-fedora example]$ go get github.com/moul/gotty-client/cmd/gotty-client
[jmainguy@jmainguy-fedora example]$ ~/go/bin/gotty-client https://soh.re
[joshua@2ed43af67a04 ~]$ echo "Look, I am in a docker container, via soh.re website"
Look, I am in a docker container, via soh.re website
[joshua@2ed43af67a04 ~]$ ls
blog.txt chat.txt email.txt github.txt projects.MD resume.txt rhca_certified.txt
Interact with API's by creating structs
first, get an idea of what the result looks like
[jmainguy@jmainguy-fedora example]$ curl -k https://es-master-01a.example1:9200
{
"name" : "lab-example-es-master-01a",
"cluster_name" : "lab-example-es-01",
"cluster_uuid" : "randomstring",
"version" : {
"number" : "6.2.2",
"build_hash" : "10b1edd",
"build_date" : "2018-02-16T19:01:30.685723Z",
"build_snapshot" : false,
"lucene_version" : "7.2.1",
"minimum_wire_compatibility_version" : "5.6.0",
"minimum_index_compatibility_version" : "5.0.0"
},
"tagline" : "You Know, for Search"
Use a sweet golang package to convert this into a golang struct.
Now we can use this struct to get the only field we care about
[jmainguy@jmainguy-fedora example]$ ls
example main.go structs.go
[jmainguy@jmainguy-fedora example]$ cat main.go
package main
import (
"net/http"
"io/ioutil"
"encoding/json"
"fmt"
"crypto/tls"
)
func main() {
http.DefaultTransport.(*http.Transport).TLSClientConfig =
&tls.Config{InsecureSkipVerify: true}
// Generated by curl-to-Go: https://mholt.github.io/curl-to-go
resp, _ := http.Get("https://es-master-01a.example:9200/_cluster/health")
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
clusterHealth := ClusterHealth{}
json.Unmarshal(body, &clusterHealth)
fmt.Println(clusterHealth.Status)
}
[jmainguy@jmainguy-fedora example]$ ./example
green
Questions?
Thank you for reading / listening to all this
Here are some good sites you should checkout
https://tour.golang.org
https://gopherize.me/
https://golang.org/pkg/
https://gobyexample.com/
https://soh.re (all code is in golang on this site)