Go to check EC2 environment? Or DNS domain name? - amazon-ec2

I want to see if the program is being run in EC2 or not.
One way is to run hostname -d in EC2 to get the DNS domain name.
How do I get this DNS domain name in Go.
I looked at the net package using http://golang.org/pkg/net/#LookupNS
But I need to pass an argument.
How do I check if it's in EC2 or not?
Thanks

You can see if there is an interface with a specific name with this function:
package main
import (
"log"
"net"
"strings"
)
func trace(fmt string, args ...interface{}) {
log.Printf(fmt, args...)
}
func HasAddrWithName(name string) (bool, error) {
ifaces, err := net.Interfaces()
if err != nil {
return false, err
}
for _, iface := range ifaces {
addrs, err := iface.Addrs()
if err != nil {
trace("%s", err)
continue
}
for _, addr := range addrs {
ipaddr, _, err := net.ParseCIDR(addr.String())
if err != nil {
trace("%s", err)
continue
}
hosts, err := net.LookupAddr(ipaddr.String())
if err != nil {
trace("%s", err)
continue
}
for idx, h := range hosts {
trace("%d: %s\n", idx, h)
if strings.Contains(h, name) {
return true, nil
}
}
}
}
return false, nil
}
func main() {
hasAddr, err := HasAddrWithName(".ec2.internal")
if err != nil {
log.Fatal(err)
}
if hasAddr {
log.Println("inside ec2")
return
}
log.Println("Not inside ec2")
}
The function will try to find all the interface an resolve the ip to a dns name. if the name contains the specific string returns true.

The right way, IMO, is to try and hit the metadata API at http://169.254.169.254/latest/meta-data from the machine itself. The worrisome part is that you feel the need to know this in code. I am not quite sure what the use case for this is but it seems to me that there ought to be a way for you to know this outside of your code.
Nevertheless:
package main
import (
"fmt"
"io/ioutil"
"net/http"
"os"
"time"
)
func main() {
/* if you just need the hostname */
name, _ := os.Hostname()
fmt.Println(name)
/* if you must hit the EC2 metadata API */
client := http.Client{
Timeout: time.Duration(2 * time.Second),
}
resp, err := client.Get("http://169.254.169.254/latest/meta-data/public-hostname")
if err != nil {
fmt.Println("Probably not on EC2")
fmt.Println(err)
return
}
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
fmt.Println(string(body))
}

Related

GCP - get project NAT GW's

We have account on GCP which contain valid cloud Nat, now we want to get those values via
GCP sdk, I've tried the following and get empty response (maybe I use the wrong API and it not ListExternalVpnGatewaysRequest)
package main
import (
"context"
"fmt"
compute "cloud.google.com/go/compute/apiv1"
"google.golang.org/api/iterator"
computepb "google.golang.org/genproto/googleapis/cloud/compute/v1"
)
func main() {
ctx := context.Background()
c, err := compute.NewExternalVpnGatewaysRESTClient(ctx)
if err != nil {
fmt.Println(err)
}
defer c.Close()
proj := "dev-proj"
req := &computepb.ListExternalVpnGatewaysRequest{
//Filter: new(string),
//MaxResults: new(uint32),
//OrderBy: new(string),
//PageToken: new(string),
Project: proj,
//ReturnPartialSuccess: new(bool),
}
it := c.List(ctx, req)
for {
resp, err := it.Next()
if err == iterator.Done {
break
}
if err != nil {
fmt.Println(err)
}
// TODO: Use resp.
_ = resp
fmt.Println(resp)
}
}
I need to get the following values using GCP GO SDK
update
I tried the following as-is and I got error
package main
import (
"context"
"fmt"
"google.golang.org/api/compute/v1"
"log"
)
func main() {
project := "my-proj"
region := "my-region"
ctx := context.Background()
computeService, err := compute.New(ctx)
if err != nil {
log.Fatal(err)
}
req := computeService.Routers.List(project, region)
if err := req.Pages(ctx, func(page *compute.RouterList) error {
for _, router := range page.Items {
// process each `router` resource:
fmt.Printf("%#v\n", router)
// NAT Gateways are found in router.nats
}
return nil
}); err != nil {
log.Fatal(err)
}
}
Error is: ./main.go:16:36: cannot use ctx (type context.Context) as type *http.Client in argument to compute.New
A VPN Gateway is not the same as a NAT Gateway.
Use this code to list routers. Within the list of routers, is the NAT Gateways
import "google.golang.org/api/compute/v1"
// Replace with valid values for your project
project := "my-project"
region := "my-region"
ctx := context.Background()
c, err := google.DefaultClient(ctx, compute.CloudPlatformScope)
if err != nil {
log.Fatal(err)
}
computeService, err := compute.New(c)
if err != nil {
log.Fatal(err)
}
req := computeService.Routers.List(project, region)
if err := req.Pages(ctx, func(page *compute.RouterList) error {
for _, router := range page.Items {
// process each `router` resource:
fmt.Printf("%#v\n", router)
// NAT Gateways are found in router.nats
}
return nil
}); err != nil {
log.Fatal(err)
}
SDK Documentation

How to pass variadic functions into another function

i am working with aws-sdk-v2 and I want to make a minimum working example using "secretsmanager" service.
I am trying to follow the steps in this similiar example which is using "kms" service.
here is my script:
package main
import (
"context"
"fmt"
"log"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/feature/ec2/imds"
"github.com/aws/aws-sdk-go-v2/service/secretsmanager"
)
func main() {
cfg, err := config.LoadDefaultConfig(context.TODO())
if err != nil {
log.Printf("error: %v", err)
return
}
client := imds.NewFromConfig(cfg)
region, err := client.GetRegion(context.TODO(), &imds.GetRegionInput{})
if err != nil {
log.Printf("Unable to retrieve the region from the EC2 instance %v\n", err)
}
fmt.Printf(region.Region)
svc := secretsmanager.NewFromConfig(cfg)
input := &secretsmanager.CreateSecretInput{Name: aws.String("test")}
opts := &secretsmanager.Options{Region: region.Region}
result, err := svc.CreateSecret(context.TODO(), input, opts)
if err != nil {
fmt.Println(err)
}
fmt.Println(result)
}
error:
./main.go:38:46: cannot use opts (type *secretsmanager.Options) as type func(*secretsmanager.Options) in argument to svc.CreateSecret
so the error is obviously in those line:
opts := &secretsmanager.Options{Region: region.Region}
result, err := svc.CreateSecret(context.TODO(), input, opts)
from the documentation, the function CreateSecret takes these input types:
func (c *Client) CreateSecret(ctx context.Context, params *CreateSecretInput, optFns ...func(*Options)) (*CreateSecretOutput, error)
I can't find out how can I create this ...func(*Options) part in my context. Can someone please help me with this part?
I figured it out:
opts := func(o *secretsmanager.Options) {
o.Region = region.Region
}
result, err := svc.CreateSecret(context.TODO(), input, opts)

How to list running instances on Google Cloud Platform with Go

I'm trying to learn Go by managing Google Cloud Platform. I didn't understand how to use related functions about Compute. The goal is listing instances with some go code.
This is https://godoc.org/google.golang.org/api/compute/v1#InstancesService.List the related function.
func (r *InstancesService) List(project string, zone string) *InstancesListCall
There are two structs, InstancesService and InstancesListCall
As far as i understand i should define these structs but it's not clear the things should be defined in the structs. I've searched for examples but many of them using rest calls instead of golang api. Have any idea how to list instances with go?
i had to write something like this today and googling for examples turned up surprisingly little. i've written up what i learned below, however, i'm quite new to golang so maybe smarter people can suggest improvements.
my work in progress is at: https://github.com/grenade/rubberneck
if you want to run your go program from a development pc that is not on the google compute platform:
set up the gcloud cli to run on your pc (instructions: https://cloud.google.com/sdk/gcloud)
create a service account for your go application to run under (instructions: https://cloud.google.com/docs/authentication/production#creating_a_service_account)
grant permissions to the service account (use the same instructions link above)
create a local key file containing your new service account credentials (use the same instructions link above)
set the GOOGLE_APPLICATION_CREDENTIALS environment variable to the path of your local key file
write your go application. something like this:
package main
import (
"golang.org/x/net/context"
"google.golang.org/api/compute/v1"
"golang.org/x/oauth2/google"
"fmt"
"strings"
)
func main() {
projects := [...]string{
"my-project-one",
"my-project-two",
}
filters := [...]string{
"status = RUNNING",
"name != my-uninteresting-instance-one",
"name != my-uninteresting-instance-two",
}
ctx := context.Background()
client, err := google.DefaultClient(ctx,compute.ComputeScope)
if err != nil {
fmt.Println(err)
}
computeService, err := compute.New(client)
for _, project := range projects {
zoneListCall := computeService.Zones.List(project)
zoneList, err := zoneListCall.Do()
if err != nil {
fmt.Println("Error", err)
} else {
for _, zone := range zoneList.Items {
instanceListCall := computeService.Instances.List(project, zone.Name)
instanceListCall.Filter(strings.Join(filters[:], " "))
instanceList, err := instanceListCall.Do()
if err != nil {
fmt.Println("Error", err)
} else {
for _, instance := range instanceList.Items {
if workerType, isWorker := instance.Labels["worker-type"]; isWorker {
m := strings.Split(instance.MachineType, "/")
fmt.Printf("cloud: gcp, zone: %v, name: %v, instance id: %v, machine type: %v, worker type: %v, launch time: %v\n",
zone.Name,
instance.Name,
instance.Id,
m[len(m)-1],
workerType,
instance.CreationTimestamp)
}
}
}
}
}
}
}
You can also use Aggregated List which will search every zone for you. This saves you having to do nested loops or figuring out what the zones are.
https://pkg.go.dev/cloud.google.com/go/compute/apiv1#InstancesClient.AggregatedList
The below assumes you have logged into gcloud and set your ADC.
$ gcloud init
$ gcloud auth application-default login
Using a service account key is also possible but not demonstrated below.
package main
import (
"context"
"fmt"
"log"
compute "cloud.google.com/go/compute/apiv1"
"google.golang.org/api/iterator"
protobuf "google.golang.org/genproto/googleapis/cloud/compute/v1"
)
func main() {
ctx := context.Background()
c, err := compute.NewInstancesRESTClient(ctx)
if err != nil {
log.Fatalln(err)
}
defer c.Close()
project := "my-project"
req := &protobuf.AggregatedListInstancesRequest{
Project: project,
}
it := c.client.AggregatedList(ctx, req)
for {
resp, err := it.Next()
if err == iterator.Done {
break
}
if err != nil {
log.Fatalln(err)
}
fmt.Println(resp)
}
}
You can also use AggregatedList and cloud cred in golang and can retrieve all instance information
package main
import (
"context"
"flag"
"fmt"
"log"
"github.com/binxio/gcloudconfig"
"golang.org/x/oauth2/google"
"google.golang.org/api/compute/v1"
"google.golang.org/api/option"
)
func main() {
//gcp session
var credentials *google.Credentials
name := flag.String("configuration", "", "`kunets` of the configuration to use")
project := flag.String("project", "", "`kunets` of the project to query")
flag.Parse()
credentials, _ = gcloudconfig.GetCredentials(*name)
if project == nil || *project == "" {
project = &credentials.ProjectID
}
if *project == "" {
log.Printf("%v", credentials)
log.Fatal("no -project specified")
}
computeService, err := compute.NewService(context.Background(), option.WithCredentials(credentials))
if err != nil {
log.Fatal(err)
}
token := ""
var list *compute.InstanceAggregatedList
if list, err = computeService.Instances.AggregatedList(*project).PageToken(token).Do(); err != nil {
log.Fatal(err)
}
for _, instances := range list.Items {
for _, instance := range instances.Instances {
EXTERNAL_IP := instance.NetworkInterfaces[0].AccessConfigs[0].NatIP
fmt.Printf("%s \n", EXTERNAL_IP)
INTERNAL_IP := instance.NetworkInterfaces[0].NetworkIP
fmt.Printf("%s \n", INTERNAL_IP)
fmt.Printf("%s \n", instance.Name)
}
}
}

How can I create a simple client app with the Kubernetes Go library?

I'm struggling with the Kubernetes Go library. The docs--at least the ones I found--appear out-of-date with the library itself. The example provided does not build because of issues with the imports. I'm just trying to do something simple: get a Service object by name and print some attributes (like nodePort). I just need a simple example of library usage to get me going.
I could easily do this using the RESTful API but that feels like re-inventing the wheel.
So after a little experimentation and a hint from the k8s Slack channel, I have this example. Perhaps someone can update the example with a proper import path.
package main
import (
"fmt"
"log"
"github.com/kubernetes/kubernetes/pkg/api"
client "github.com/kubernetes/kubernetes/pkg/client/unversioned"
)
func main() {
config := client.Config{
Host: "http://my-kube-api-server.me:8080",
}
c, err := client.New(&config)
if err != nil {
log.Fatalln("Can't connect to Kubernetes API:", err)
}
s, err := c.Services(api.NamespaceDefault).Get("some-service-name")
if err != nil {
log.Fatalln("Can't get service:", err)
}
fmt.Println("Name:", s.Name)
for p, _ := range s.Spec.Ports {
fmt.Println("Port:", s.Spec.Ports[p].Port)
fmt.Println("NodePort:", s.Spec.Ports[p].NodePort)
}
}
Here's how to do it with the latest Go client.
If you're inside the k8s cluster:
package main
import (
"fmt"
"k8s.io/client-go/1.5/kubernetes"
"k8s.io/client-go/1.5/pkg/api/v1"
"k8s.io/client-go/1.5/rest"
)
func main() {
config, err = rest.InClusterConfig()
if err != nil {
return nil, err
}
c, err := kubernetes.NewForConfig(config)
if err != nil {
return nil, err
}
// Get Pod by name
pod, err := c.Pods(v1.NamespaceDefault).Get("my-pod")
if err != nil {
fmt.Println(err)
return
}
// Print its creation time
fmt.Println(pod.GetCreationTimestamp())
}
And if you're outside of the cluster:
package main
import (
"fmt"
"k8s.io/client-go/1.5/kubernetes"
"k8s.io/client-go/1.5/pkg/api/v1"
"k8s.io/client-go/1.5/tools/clientcmd"
)
func main() {
config, err := clientcmd.BuildConfigFromFlags("", <kube-config-path>)
if err != nil {
return nil, err
}
c, err := kubernetes.NewForConfig(config)
if err != nil {
return nil, err
}
// Get Pod by name
pod, err := c.Pods(v1.NamespaceDefault).Get("my-pod")
if err != nil {
fmt.Println(err)
return
}
// Print its creation time
fmt.Println(pod.GetCreationTimestamp())
}
I have gone into more detail on this in a blog post.
With kubernetes go client, it could be done this way:
package main
import (
"flag"
"fmt"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/pkg/api/v1"
"k8s.io/client-go/tools/clientcmd"
)
var (
kubeconfig = flag.String("kubeconfig", "./config", "absolute path to the kubeconfig file")
)
func main() {
flag.Parse()
// uses the current context in kubeconfig
config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
if err != nil {
panic(err.Error())
}
// creates the clientset
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
panic(err.Error())
}
services, err := clientset.Core().Services("").List(v1.ListOptions{})
if err != nil {
panic(err.Error())
}
fmt.Printf("There are %d pods in the cluster\n", len(services.Items))
for _, s := range services.Items {
for p, _ := range s.Spec.Ports {
fmt.Println("Port:", s.Spec.Ports[p].Port)
fmt.Println("NodePort:", s.Spec.Ports[p].NodePort)
}
}
}

How to retrieve address of current machine?

The following grabs the local IP addresses:
package main
import (
"fmt"
"net"
)
func main() {
a, _ := net.LookupHost("localhost")
fmt.Printf("Addresses: %#+v\n",a)
}
Is this how you would normally get the local IP address, filtering the slice manually according to need?
Here's a quick and dirty modification of a code snippet originally posted by Russ Cox to the golang-nuts google group:
package main
import (
"fmt"
"net"
"os"
)
func main() {
tt, err := net.Interfaces()
if err != nil {
panic(err)
}
for _, t := range tt {
aa, err := t.Addrs()
if err != nil {
panic(err)
}
for _, a := range aa {
ipnet, ok := a.(*net.IPNet)
if !ok {
continue
}
v4 := ipnet.IP.To4()
if v4 == nil || v4[0] == 127 { // loopback address
continue
}
fmt.Printf("%v\n", v4)
}
os.Exit(0)
}
os.Exit(1)
}
Finding the correct IP address can be a problem because a typical server and development machine may have multiple interfaces. For example $ifconfig on my Mac returns the following interfaces lo0, gif0, stf0, en0, en1, en2, bridge0, p2p0, vmnet1, vmnet8, tap0, fw0, en4
Basically, you need to know your environment.
It's not pretty, but for what it's worth, this is what I use on a production Ubuntu server. It also works on my development Mac 10.9.2, who know what it does on Windows.
package main
import (
"net"
"strings"
)
func findIPAddress() string {
if interfaces, err := net.Interfaces(); err == nil {
for _, interfac := range interfaces {
if interfac.HardwareAddr.String() != "" {
if strings.Index(interfac.Name, "en") == 0 ||
strings.Index(interfac.Name, "eth") == 0 {
if addrs, err := interfac.Addrs(); err == nil {
for _, addr := range addrs {
if addr.Network() == "ip+net" {
pr := strings.Split(addr.String(), "/")
if len(pr) == 2 && len(strings.Split(pr[0], ".")) == 4 {
return pr[0]
}
}
}
}
}
}
}
}
return ""
}
func main() {
println(findIPAddress())
}
I have one addition: The current solutions shown above are not working at least on FreeBSD 10 because the system returns the addresses as CIDR notation e.g. 192.168.1.2/32! Therefore, it is necessary to change the solution a little bit:
package main
import (
"fmt"
"net"
"os"
"strings"
)
func main() {
addrs, err := net.InterfaceAddrs()
if err != nil {
fmt.Println("Error: " + err.Error())
os.Exit(1)
}
for _, a := range addrs {
text := a.String()
if strings.Contains(text, `/`) {
text = text[:strings.Index(text, `/`)]
}
ip := net.ParseIP(text)
if !ip.IsLoopback() && !ip.IsUnspecified() {
fmt.Println(ip)
}
}
}
The part ...
if strings.Contains(text, `/`) {
text = text[:strings.Index(text, `/`)]
}
... detects if / is part of the address and delete this part!
Best regards,
Thorsten
These slight modifications worked for me:
package main
import (
"fmt"
"net"
"os"
)
func myip() {
os.Stdout.WriteString("myip:\n")
addrs, err := net.InterfaceAddrs()
if err != nil {
fmt.Errorf("error: %v\n", err.Error())
return
}
for _, a := range addrs {
ip := net.ParseIP(a.String())
fmt.Printf("addr: %v loopback=%v\n", a, ip.IsLoopback())
}
fmt.Println()
}
func myip2() {
os.Stdout.WriteString("myip2:\n")
tt, err := net.Interfaces()
if err != nil {
fmt.Errorf("error: %v\n", err.Error())
return
}
for _, t := range tt {
aa, err := t.Addrs()
if err != nil {
fmt.Errorf("error: %v\n", err.Error())
continue
}
for _, a := range aa {
ip := net.ParseIP(a.String())
fmt.Printf("%v addr: %v loopback=%v\n", t.Name, a, ip.IsLoopback())
}
}
fmt.Println()
}
func main() {
fmt.Println("myip -- begin")
myip()
myip2()
fmt.Println("myip -- end")
}

Resources