Skip to content

Commit

Permalink
Dedicated logger
Browse files Browse the repository at this point in the history
Use a logger for everyting we used to Printf/Fatalf to the console:
this makes handling Quiet mode much easier.
  • Loading branch information
bpineau committed Mar 17, 2018
1 parent 16bfd4a commit cfd98b9
Show file tree
Hide file tree
Showing 7 changed files with 84 additions and 57 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ cloud-floating-ip -i 10.200.0.50 status

When `cloud-floating-ip` runs on the target instance, most settings (region,
instance id, cloud provider, ...) can be guessed from the instance metadata.

To act on a remote instance, we must be more explicit :

```bash
cloud-floating-ip -o aws -i 10.200.0.50 -t i-0e3f4ac17545ce580 -r eu-west-1 status
cloud-floating-ip -o aws -i 10.200.0.50 -t i-0e3f4ac17545ce580 -r eu-west-1 preempt
Expand Down
44 changes: 18 additions & 26 deletions pkg/hoster/aws/aws.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ package aws

import (
"fmt"
"log"

"github.com/bpineau/cloud-floating-ip/config"
"github.com/bpineau/cloud-floating-ip/pkg/log"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/ec2metadata"
Expand All @@ -18,6 +18,7 @@ type Hoster struct {
sess *session.Session
ec2s *ec2.EC2
routes []*ec2.RouteTable
log log.Logger
enid *string
cidr *string
vpc string
Expand All @@ -33,24 +34,25 @@ const (
)

// Init prepare an aws hoster for usage
func (h *Hoster) Init(conf *config.CfiConfig) {
func (h *Hoster) Init(conf *config.CfiConfig, logger log.Logger) {
h.conf = conf
h.log = logger
err := h.checkMissingParam()
if err != nil {
log.Fatalf("Missing param: %v", err)
h.log.Fatalf("Missing param: %v", err)
}

h.sess, err = session.NewSession(aws.NewConfig().WithMaxRetries(3))
if err != nil {
log.Fatalf("Failed to initialize an AWS session: %v", err)
h.log.Fatalf("Failed to initialize an AWS session: %v", err)
}

metadata := ec2metadata.New(h.sess)

if h.conf.Region == "" {
h.conf.Region, err = metadata.Region()
if err != nil {
log.Fatalf("Failed to collect region from instance metadata: %v", err)
h.log.Fatalf("Failed to collect region from instance metadata: %v", err)
}
}

Expand All @@ -59,15 +61,15 @@ func (h *Hoster) Init(conf *config.CfiConfig) {
if h.conf.Instance == "" {
h.conf.Instance, err = metadata.GetMetadata("instance-id")
if err != nil {
log.Fatalf("Failed to collect instanceid from instance metadata: %v", err)
h.log.Fatalf("Failed to collect instanceid from instance metadata: %v", err)
}
}

h.ec2s = ec2.New(h.sess)

err = h.getNetworkInfo()
if err != nil {
log.Fatalf("Failed to collect network infos: %v", err)
h.log.Fatalf("Failed to collect network infos: %v", err)
}
}

Expand Down Expand Up @@ -127,15 +129,11 @@ func (h *Hoster) OnThisHoster() bool {
// Preempt takes over the floating IP address
func (h *Hoster) Preempt() error {
if h.Status() {
if !h.conf.Quiet {
fmt.Printf("Already primary, nothing to do\n")
}
h.log.Infof("Already primary, nothing to do\n")
return nil
}

if !h.conf.Quiet {
fmt.Printf("Preempting %s route(s)\n", h.conf.IP)
}
h.log.Infof("Preempting %s route(s)\n", h.conf.IP)

// contrary to GCE, an EC2 VPC can have several routes tables
for _, table := range h.routes {
Expand All @@ -157,7 +155,7 @@ func (h *Hoster) Preempt() error {
}

if err != nil {
log.Fatalf("Failed to create a route: %v", err)
h.log.Fatalf("Failed to create a route: %v", err)
}
}

Expand Down Expand Up @@ -196,10 +194,8 @@ func (h *Hoster) Destroy() error {
DestinationCidrBlock: h.cidr,
}

if !h.conf.Quiet {
fmt.Printf("Deleting route to %s from %s table\n",
*h.cidr, *table.RouteTableId)
}
h.log.Infof("Deleting route to %s from %s table\n",
*h.cidr, *table.RouteTableId)

if h.conf.DryRun {
continue
Expand Down Expand Up @@ -267,10 +263,8 @@ func (h *Hoster) addRouteInTable(table *ec2.RouteTable, cidr *string, eni *strin
NetworkInterfaceId: eni,
}

if !h.conf.Quiet {
fmt.Printf("Creating route to %s via ENI %s in table %s\n",
*cidr, *eni, *table.RouteTableId)
}
h.log.Infof("Creating route to %s via ENI %s in table %s\n",
*cidr, *eni, *table.RouteTableId)

if h.conf.DryRun {
return nil
Expand All @@ -287,10 +281,8 @@ func (h *Hoster) replaceRouteInTable(table *ec2.RouteTable, cidr *string, eni *s
NetworkInterfaceId: eni,
}

if !h.conf.Quiet {
fmt.Printf("Replacing route to %s via ENI %s in table %s\n",
*cidr, *eni, *table.RouteTableId)
}
h.log.Infof("Replacing route to %s via ENI %s in table %s\n",
*cidr, *eni, *table.RouteTableId)

if h.conf.DryRun {
return nil
Expand Down
47 changes: 20 additions & 27 deletions pkg/hoster/gce/gce.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ package gce
import (
"context"
"fmt"
"log"
"net/http"
"strings"
"time"

"github.com/bpineau/cloud-floating-ip/config"
"github.com/bpineau/cloud-floating-ip/pkg/log"

"cloud.google.com/go/compute/metadata"
"golang.org/x/oauth2/google"
Expand All @@ -33,40 +33,42 @@ type Hoster struct {
client *http.Client
svc *compute.Service
ctx *context.Context
log log.Logger
network string
rname string
selflink string
}

// Init prepare a gce hoster for usage
func (h *Hoster) Init(conf *config.CfiConfig) {
func (h *Hoster) Init(conf *config.CfiConfig, logger log.Logger) {
var err error
ctx := context.Background()
h.conf = conf
h.log = logger

err = h.checkMissingParam()
if err != nil {
log.Fatalf("Missing param: %v", err)
h.log.Fatalf("Missing param: %v\n", err)
}

if h.conf.Project == "" {
h.conf.Project, err = metadata.ProjectID()
if err != nil {
log.Fatalf("Failed to guess project id: %v", err)
h.log.Fatalf("Failed to guess project id: %v\n", err)
}
}

if h.conf.Instance == "" {
h.conf.Instance, err = metadata.InstanceName()
if err != nil {
log.Fatalf("Failed to guess instance id: %v", err)
h.log.Fatalf("Failed to guess instance id: %v", err)
}
}

if h.conf.Zone == "" {
h.conf.Zone, err = metadata.Zone()
if err != nil {
log.Fatalf("Failed to guess instance zone: %v", err)
h.log.Fatalf("Failed to guess instance zone: %v", err)
}
}

Expand All @@ -76,12 +78,12 @@ func (h *Hoster) Init(conf *config.CfiConfig) {

h.client, err = google.DefaultClient(*h.ctx, compute.CloudPlatformScope)
if err != nil {
log.Fatal(err)
h.log.Fatalf("Failed to get default client %s", err)
}

h.svc, err = compute.New(h.client)
if err != nil {
log.Fatal(err)
h.log.Fatalf("Failed to instantiate a compute client: %s", err)
}

h.network = h.getNetworkInterface()
Expand All @@ -90,12 +92,12 @@ func (h *Hoster) Init(conf *config.CfiConfig) {
func (h *Hoster) getNetworkInterface() string {
inst, err := h.svc.Instances.Get(h.conf.Project, h.conf.Zone, h.conf.Instance).Context(*h.ctx).Do()
if err != nil {
log.Fatalf("Failed to guess network link: %v", err)
h.log.Fatalf("Failed to guess network link: %v", err)
}

// TODO: support instances with several interfaces
if len(inst.NetworkInterfaces) != 1 {
log.Fatal("For now, we don't support more than one interface")
h.log.Fatalf("For now, we don't support more than one interface")
}

return inst.NetworkInterfaces[0].Network
Expand All @@ -109,15 +111,11 @@ func (h *Hoster) OnThisHoster() bool {
// Preempt takes over the floating IP address
func (h *Hoster) Preempt() error {
if h.Status() {
if !h.conf.Quiet {
fmt.Printf("Already primary, nothing to do\n")
}
h.log.Infof("Already primary, nothing to do\n")
return nil
}

if !h.conf.Quiet {
fmt.Printf("Preempting %s route(s)\n", h.conf.IP)
}
h.log.Infof("Preempting %s route(s)\n", h.conf.IP)

rb := &compute.Route{
Name: h.rname,
Expand All @@ -129,21 +127,19 @@ func (h *Hoster) Preempt() error {
// There's no "update" or "replace" in GCP routes API.
err := h.Destroy()
if err != nil {
log.Fatalf("Failed to delete the route: %v", err)
h.log.Fatalf("Failed to delete the route: %v", err)
}

if !h.conf.Quiet {
fmt.Printf("Creating a route %s to %s via %s on %s network\n",
h.rname, h.conf.IP, h.selflink, h.network)
}
h.log.Infof("Creating a route %s to %s via %s on %s network\n",
h.rname, h.conf.IP, h.selflink, h.network)

if h.conf.DryRun {
return nil
}

err = h.blockingWait(h.svc.Routes.Insert(h.conf.Project, rb).Do())
if err != nil {
log.Fatalf("Failed to create the route: %v", err)
h.log.Fatalf("Failed to create the route: %v", err)
}

return nil
Expand All @@ -164,17 +160,14 @@ func (h *Hoster) Status() bool {
}
}

log.Fatalf("Failed to get route status: %v", err)
h.log.Fatalf("Failed to get route status: %v", err)

return false
}

// Destroy remove route to the IP from our VPC
func (h *Hoster) Destroy() error {
if !h.conf.Quiet {
fmt.Printf("Deleting route to %s from %s network\n",
h.conf.IP, h.network)
}
h.log.Infof("Deleting route to %s from %s network\n", h.conf.IP, h.network)

if h.conf.DryRun {
return nil
Expand Down
3 changes: 2 additions & 1 deletion pkg/hoster/hoster.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ import (
"github.com/bpineau/cloud-floating-ip/config"
"github.com/bpineau/cloud-floating-ip/pkg/hoster/aws"
"github.com/bpineau/cloud-floating-ip/pkg/hoster/gce"
"github.com/bpineau/cloud-floating-ip/pkg/log"
)

// Hoster represents an hosting provider (aws or gce)
type Hoster interface {
Init(conf *config.CfiConfig)
Init(conf *config.CfiConfig, logger log.Logger)
OnThisHoster() bool
Preempt() error
Status() bool
Expand Down
31 changes: 31 additions & 0 deletions pkg/log/console/console.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package console

import (
"fmt"
"os"
)

// Logger implements Logger interface, display logs on stdout
type Logger struct {
Quiet bool
}

// Infof displays a formated string, honoring the Quiet config setting
func (l *Logger) Infof(format string, v ...interface{}) {
if l.Quiet {
return
}
fmt.Printf(format, v...)
}

// Fatal displays a message then exit the program
func (l *Logger) Fatal(v ...interface{}) {
fmt.Print(v...)
os.Exit(1)
}

// Fatalf displays a formated string then exit the program
func (l *Logger) Fatalf(format string, v ...interface{}) {
fmt.Printf(format, v...)
os.Exit(1)
}
8 changes: 8 additions & 0 deletions pkg/log/log.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package log

// Logger handle logs, ideally honoring the Quiet config parameter
type Logger interface {
Infof(format string, v ...interface{})
Fatalf(format string, v ...interface{})
Fatal(v ...interface{})
}
6 changes: 4 additions & 2 deletions pkg/run/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,25 @@ package run

import (
"fmt"
"log"

"github.com/bpineau/cloud-floating-ip/config"
"github.com/bpineau/cloud-floating-ip/pkg/hoster"
"github.com/bpineau/cloud-floating-ip/pkg/log/console"
"github.com/bpineau/cloud-floating-ip/pkg/operation"
)

// Run launchs the effective operations
func Run(conf *config.CfiConfig, op operation.CfiOperation) {
var err error

log := &console.Logger{Quiet: conf.Quiet}

h, err := hoster.GuessHoster(conf.Hoster)
if err != nil {
log.Fatalf("Can't guess hoster, please specify '-o' option: %v", err)
}

h.Init(conf)
h.Init(conf, log)

switch op {
case operation.CfiPreempt:
Expand Down

0 comments on commit cfd98b9

Please sign in to comment.