Skip to content

Commit

Permalink
Add a types package to better organize types
Browse files Browse the repository at this point in the history
  • Loading branch information
raphink committed Aug 2, 2017
1 parent 579bb86 commit f8ca6ee
Show file tree
Hide file tree
Showing 5 changed files with 140 additions and 111 deletions.
48 changes: 12 additions & 36 deletions compare/compare.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,36 +5,12 @@ import (
"strings"

log "github.com/Sirupsen/logrus"
"github.com/camptocamp/terraboard/db"
"github.com/camptocamp/terraboard/types"
"github.com/pmezard/go-difflib/difflib"
)

type StateInfo struct {
VersionID string `json:"version_id"`
ResourceCount int `json:"resource_count"`
}

type ResourceDiff struct {
OnlyInOld map[string]string `json:"only_in_old"`
OnlyInNew map[string]string `json:"only_in_new"`
UnifiedDiff string `json:"unified_diff"`
}

type StateCompare struct {
Stats struct {
From StateInfo `json:"from"`
To StateInfo `json:"to"`
} `json:"stats"`
Differences struct {
OnlyInOld []string `json:"only_in_old"`
OnlyInNew []string `json:"only_in_new"`
InBoth []string `json:"in_both"`
ResourceDiff map[string]ResourceDiff `json:"resource_diff"`
} `json:"differences"`
}

// Return all resources of a state
func stateResources(state db.State) (res []string) {
func stateResources(state types.State) (res []string) {
for _, m := range state.Modules {
for _, r := range m.Resources {
res = append(res, fmt.Sprintf("%s.%s.%s", m.Path, r.Type, r.Name))
Expand All @@ -44,7 +20,7 @@ func stateResources(state db.State) (res []string) {
}

// Return all attributes of a resource
func resourceAttributes(res db.Resource) (attrs []string) {
func resourceAttributes(res types.Resource) (attrs []string) {
for _, a := range res.Attributes {
attrs = append(attrs, a.Key)
}
Expand Down Expand Up @@ -82,7 +58,7 @@ func sliceInter(s1, s2 []string) (inter []string) {
return
}

func getResource(state db.State, key string) (res db.Resource) {
func getResource(state types.State, key string) (res types.Resource) {
for _, m := range state.Modules {
if strings.HasPrefix(key, m.Path) {
for _, r := range m.Resources {
Expand All @@ -97,7 +73,7 @@ func getResource(state db.State, key string) (res db.Resource) {
return
}

func getResourceAttribute(res db.Resource, key string) (val string) {
func getResourceAttribute(res types.Resource, key string) (val string) {
for _, attr := range res.Attributes {
if attr.Key == key {
return attr.Value
Expand All @@ -106,7 +82,7 @@ func getResourceAttribute(res db.Resource, key string) (val string) {
return
}

func formatResource(res db.Resource) (out string) {
func formatResource(res types.Resource) (out string) {
out = fmt.Sprintf("resource \"%s\" \"%s\" {\n", res.Type, res.Name)
for _, attr := range res.Attributes {
out += fmt.Sprintf(" %s = \"%s\"\n", attr.Key, attr.Value)
Expand All @@ -116,12 +92,12 @@ func formatResource(res db.Resource) (out string) {
return
}

func stateInfo(state db.State) (info string) {
func stateInfo(state types.State) (info string) {
return fmt.Sprintf("%s (%s)", state.Path, state.Version.LastModified)
}

// Compare a resource in two states
func compareResource(st1, st2 db.State, key string) (comp ResourceDiff) {
func compareResource(st1, st2 types.State, key string) (comp types.ResourceDiff) {
res1 := getResource(st1, key)
attrs1 := resourceAttributes(res1)
res2 := getResource(st2, key)
Expand Down Expand Up @@ -154,13 +130,13 @@ func compareResource(st1, st2 db.State, key string) (comp ResourceDiff) {
return
}

func Compare(from, to db.State) (comp StateCompare, err error) {
func Compare(from, to types.State) (comp types.StateCompare, err error) {
if from.Path == "" {
err = fmt.Errorf("from version is unknown")
return
}
fromResources := stateResources(from)
comp.Stats.From = StateInfo{
comp.Stats.From = types.StateInfo{
VersionID: from.Version.VersionID,
ResourceCount: len(fromResources),
}
Expand All @@ -170,15 +146,15 @@ func Compare(from, to db.State) (comp StateCompare, err error) {
return
}
toResources := stateResources(to)
comp.Stats.To = StateInfo{
comp.Stats.To = types.StateInfo{
VersionID: to.Version.VersionID,
ResourceCount: len(toResources),
}

comp.Differences.OnlyInOld = sliceDiff(fromResources, toResources)
comp.Differences.OnlyInNew = sliceDiff(toResources, fromResources)
comp.Differences.InBoth = sliceInter(toResources, fromResources)
comp.Differences.ResourceDiff = make(map[string]ResourceDiff)
comp.Differences.ResourceDiff = make(map[string]types.ResourceDiff)

for _, r := range comp.Differences.InBoth {
comp.Differences.ResourceDiff[r] = compareResource(to, from, r)
Expand Down
90 changes: 15 additions & 75 deletions db/db.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
package db

import (
"database/sql"
"encoding/base64"
"fmt"
"net/url"
"strconv"
"strings"
"time"

log "github.com/Sirupsen/logrus"
"github.com/aws/aws-sdk-go/service/s3"
"github.com/camptocamp/terraboard/types"
"github.com/hashicorp/terraform/terraform"

"github.com/jinzhu/gorm"
Expand All @@ -21,44 +20,6 @@ type Database struct {
*gorm.DB
}

type Version struct {
ID uint `sql:"AUTO_INCREMENT" gorm:"primary_key" json:"-"`
VersionID string `gorm:"index" json:"version_id"`
LastModified time.Time `json:"last_modified"`
}

type State struct {
gorm.Model `json:"-"`
Path string `gorm:"index" json:"path"`
Version Version `json:"version"`
VersionID sql.NullInt64 `gorm:"index" json:"-"`
TFVersion string `json:"terraform_version"`
Serial int64 `json:"serial"`
Modules []Module `json:"modules"`
}

type Module struct {
ID uint `sql:"AUTO_INCREMENT" gorm:"primary_key" json:"-"`
StateID sql.NullInt64 `gorm:"index" json:"-"`
Path string `json:"path"`
Resources []Resource `json:"resources"`
}

type Resource struct {
ID uint `sql:"AUTO_INCREMENT" gorm:"primary_key" json:"-"`
ModuleID sql.NullInt64 `gorm:"index" json:"-"`
Type string `gorm:"index" json:"type"`
Name string `gorm:"index" json:"name"`
Attributes []Attribute `json:"attributes"`
}

type Attribute struct {
ID uint `sql:"AUTO_INCREMENT" gorm:"primary_key" json:"-"`
ResourceID sql.NullInt64 `gorm:"index" json:"-"`
Key string `gorm:"index" json:"key"`
Value string `gorm:"index" json:"value"`
}

var pageSize = 20

func Init(host, user, dbname, password, logLevel string) *Database {
Expand All @@ -70,30 +31,30 @@ func Init(host, user, dbname, password, logLevel string) *Database {
}

log.Infof("Automigrate")
db.AutoMigrate(&Version{}, &State{}, &Module{}, &Resource{}, &Attribute{})
db.AutoMigrate(&types.Version{}, &types.State{}, &types.Module{}, &types.Resource{}, &types.Attribute{})

if logLevel == "debug" {
db.LogMode(true)
}
return &Database{db}
}

func (db *Database) stateS3toDB(state *terraform.State, path string, versionId string) (st State) {
var version Version
db.First(&version, Version{VersionID: versionId})
st = State{
func (db *Database) stateS3toDB(state *terraform.State, path string, versionId string) (st types.State) {
var version types.Version
db.First(&version, types.Version{VersionID: versionId})
st = types.State{
Path: path,
Version: version,
TFVersion: state.TFVersion,
Serial: state.Serial,
}

for _, m := range state.Modules {
mod := Module{
mod := types.Module{
Path: strings.Join(m.Path, "/"),
}
for n, r := range m.Resources {
res := Resource{
res := types.Resource{
Type: r.Type,
Name: n,
}
Expand All @@ -106,7 +67,7 @@ func (db *Database) stateS3toDB(state *terraform.State, path string, versionId s
}).Info("Attribute has non-ASCII value, skipping")
continue
}
res.Attributes = append(res.Attributes, Attribute{
res.Attributes = append(res.Attributes, types.Attribute{
Key: k,
Value: v,
})
Expand Down Expand Up @@ -135,22 +96,22 @@ func (db *Database) InsertState(path string, versionId string, state *terraform.
}

func (db *Database) InsertVersion(version *s3.ObjectVersion) error {
var v Version
db.FirstOrCreate(&v, Version{
var v types.Version
db.FirstOrCreate(&v, types.Version{
VersionID: *version.VersionId,
LastModified: *version.LastModified,
})
return nil
}

func (db *Database) GetState(path, versionId string) (state State) {
func (db *Database) GetState(path, versionId string) (state types.State) {
db.Joins("JOIN versions on states.version_id=versions.id").
Preload("Version").Preload("Modules").Preload("Modules.Resources").Preload("Modules.Resources.Attributes").
Find(&state, "states.path = ? AND versions.version_id = ?", path, versionId)
return
}

func (db *Database) GetStateActivity(path string) (states []StateStat) {
func (db *Database) GetStateActivity(path string) (states []types.StateStat) {
sql := "SELECT t.path, t.serial, t.tf_version, t.version_id, t.last_modified, count(resources.*) as resource_count" +
fmt.Sprintf(" FROM (SELECT states.id, states.path, states.serial, states.tf_version, versions.version_id, versions.last_modified FROM states JOIN versions ON versions.id = states.version_id WHERE states.path = '%s' ORDER BY states.path, versions.last_modified ASC) t", path) +
" JOIN modules ON modules.state_id = t.id" +
Expand All @@ -174,19 +135,7 @@ func (db *Database) KnownVersions() (versions []string) {
return
}

type SearchResult struct {
Path string `gorm:"column:path" json:"path"`
VersionId string `gorm:"column:version_id" json:"version_id"`
TFVersion string `gorm:"column:tf_version" json:"tf_version"`
Serial int64 `gorm:"column:serial" json:"serial"`
ModulePath string `gorm:"column:module_path" json:"module_path"`
ResourceType string `gorm:"column:type" json:"resource_type"`
ResourceName string `gorm:"column:name" json:"resource_name"`
AttributeKey string `gorm:"column:key" json:"attribute_key"`
AttributeValue string `gorm:"column:value" json:"attribute_value"`
}

func (db *Database) SearchAttribute(query url.Values) (results []SearchResult, page int, total int) {
func (db *Database) SearchAttribute(query url.Values) (results []types.SearchResult, page int, total int) {
log.WithFields(log.Fields{
"query": query,
}).Info("Searching for attribute with query")
Expand Down Expand Up @@ -309,16 +258,7 @@ func (db *Database) ListTerraformVersionsWithCount(query url.Values) (results []
return
}

type StateStat struct {
Path string `json:"path"`
TFVersion string `json:"terraform_version"`
Serial int64 `json:"serial"`
VersionID string `json:"version_id"`
LastModified time.Time `json:"last_modified"`
ResourceCount int `json:"resource_count"`
}

func (db *Database) ListStateStats(query url.Values) (states []StateStat, page int, total int) {
func (db *Database) ListStateStats(query url.Values) (states []types.StateStat, page int, total int) {
row := db.Table("states").Select("count(DISTINCT path)").Row()
row.Scan(&total)

Expand Down
31 changes: 31 additions & 0 deletions types/compare.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package types

/*******************************************************
* Compare types
*
* Used to compute the diff between two state versions
*******************************************************/

type StateInfo struct {
VersionID string `json:"version_id"`
ResourceCount int `json:"resource_count"`
}

type ResourceDiff struct {
OnlyInOld map[string]string `json:"only_in_old"`
OnlyInNew map[string]string `json:"only_in_new"`
UnifiedDiff string `json:"unified_diff"`
}

type StateCompare struct {
Stats struct {
From StateInfo `json:"from"`
To StateInfo `json:"to"`
} `json:"stats"`
Differences struct {
OnlyInOld []string `json:"only_in_old"`
OnlyInNew []string `json:"only_in_new"`
InBoth []string `json:"in_both"`
ResourceDiff map[string]ResourceDiff `json:"resource_diff"`
} `json:"differences"`
}
52 changes: 52 additions & 0 deletions types/db.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package types

import (
"database/sql"
"time"

"github.com/jinzhu/gorm"
)

/*********************************************
* Database object types
*
* Each type corresponds to a table in the DB
*********************************************/

type Version struct {
ID uint `sql:"AUTO_INCREMENT" gorm:"primary_key" json:"-"`
VersionID string `gorm:"index" json:"version_id"`
LastModified time.Time `json:"last_modified"`
}

type State struct {
gorm.Model `json:"-"`
Path string `gorm:"index" json:"path"`
Version Version `json:"version"`
VersionID sql.NullInt64 `gorm:"index" json:"-"`
TFVersion string `json:"terraform_version"`
Serial int64 `json:"serial"`
Modules []Module `json:"modules"`
}

type Module struct {
ID uint `sql:"AUTO_INCREMENT" gorm:"primary_key" json:"-"`
StateID sql.NullInt64 `gorm:"index" json:"-"`
Path string `json:"path"`
Resources []Resource `json:"resources"`
}

type Resource struct {
ID uint `sql:"AUTO_INCREMENT" gorm:"primary_key" json:"-"`
ModuleID sql.NullInt64 `gorm:"index" json:"-"`
Type string `gorm:"index" json:"type"`
Name string `gorm:"index" json:"name"`
Attributes []Attribute `json:"attributes"`
}

type Attribute struct {
ID uint `sql:"AUTO_INCREMENT" gorm:"primary_key" json:"-"`
ResourceID sql.NullInt64 `gorm:"index" json:"-"`
Key string `gorm:"index" json:"key"`
Value string `gorm:"index" json:"value"`
}
Loading

0 comments on commit f8ca6ee

Please sign in to comment.