Commit 7f2dfede authored by Geoff Simmons's avatar Geoff Simmons

Refactor and fix spec.DeepHash().

We don't need a binary-to-text encoding for the hash, we just test
the binary result. We also don't need to sort []Endpoint or hash
Service.
parent 1e748e72
......@@ -32,7 +32,6 @@ import (
"crypto/sha512"
"encoding/binary"
"hash"
"math/big"
"sort"
"time"
)
......@@ -62,18 +61,6 @@ func (ep Endpoint) hash(hash hash.Hash) {
hash.Write(portBytes)
}
// interface for sorting []Endpoint
type byIPPort []Endpoint
func (a byIPPort) Len() int { return len(a) }
func (a byIPPort) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a byIPPort) Less(i, j int) bool {
if a[i].IP < a[j].IP {
return true
}
return a[i].Port < a[j].Port
}
// Service represents a backend Service, where the Endpoints are
// indexed by the Pod names to which they correspond.
type Service struct {
......@@ -81,13 +68,6 @@ type Service struct {
Endpoints map[string]Endpoint
}
func (svc Service) hash(hash hash.Hash) {
for name, ep := range svc.Endpoints {
hash.Write([]byte(name))
ep.hash(hash)
}
}
// ConfigMap represents metadata about the ConfigMap that contains
// VCL sources.
type ConfigMap struct {
......@@ -115,13 +95,20 @@ type Spec struct {
Created time.Time
}
// DeepHash computes a alphanumerically encoded hash value from a Spec
// such that, almost certainly, two Specs are deeply equal iff their
// hash values are equal (unless we've discovered a SHA512 collision).
func (spec Spec) DeepHash() string {
// DeepHash computes a hash value from a Spec such that, almost
// certainly, two Specs are equivalent iff their hash values are equal
// (unless we've discovered a SHA512 collision).
//
// The Created field is ignored for equivalence checks. Metadata are
// only checked for the ConfigMap -- the Spec changes when the
// ConfigMap metadata change, but Services and Endpoints are checked
// for equivalence by content, and are considered unchanged when only
// their metadata change.
func (spec Spec) DeepHash() []byte {
hash := sha512.New512_224()
hash.Write([]byte(spec.Version))
hash.Write([]byte(spec.Main))
hash.Write([]byte(spec.CfgMap.Namespace))
hash.Write([]byte(spec.CfgMap.Name))
......@@ -130,21 +117,26 @@ func (spec Spec) DeepHash() string {
svcs := make([]string, len(spec.Services))
i := 0
for k := range spec.Services {
svcs[i] = k
for svc := range spec.Services {
svcs[i] = svc
i++
}
sort.Strings(svcs)
for _, svc := range svcs {
hash.Write([]byte(svc))
spec.Services[svc].hash(hash)
epNames := make([]string, len(spec.Services[svc].Endpoints))
i = 0
for epName := range spec.Services[svc].Endpoints {
epNames[i] = epName
i++
}
sort.Strings(epNames)
for _, epName := range epNames {
spec.Services[svc].Endpoints[epName].hash(hash)
}
}
hash.Write([]byte(spec.Main))
h := new(big.Int)
h.SetBytes(hash.Sum(nil))
return h.Text(62)
return (hash.Sum(nil))
}
// FQVersion returns a fully qualified version -- the version string
......
......@@ -87,6 +87,16 @@ func TestMain(m *testing.M) {
var testSpec = Spec{
Version: "4.7.11",
Created: time.Unix(1136239445, 123456000),
Main: "default.vcl",
CfgMap: ConfigMap{
Name: "vcl-cfgmap",
Version: "4.7.11",
Meta: Meta{
Namespace: "default",
UID: "513e6391-079b-11ea-b351-bab55b1b33a8",
ResourceVersion: "520822",
},
},
Services: map[string]Service{
"bar-service": Service{
Meta: Meta{
......@@ -214,3 +224,11 @@ func TestConfigName(t *testing.T) {
t.Fatal("ConfigName() result is an illegal VCL name:", cfgName)
}
}
func TestDeepHash(t *testing.T) {
specCopy := testSpec
if !bytes.Equal(specCopy.DeepHash(), testSpec.DeepHash()) {
t.Fatalf("DeepHash(%+v)=%+v != DeepHash(%+v)=%+v", testSpec,
testSpec.DeepHash(), specCopy, specCopy.DeepHash())
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment