mirror of https://github.com/docker/docs.git
Add JSON marshalling and unmarshalling specify model types as a field on a Table object
Signed-off-by: Ying Li <ying.li@docker.com>
This commit is contained in:
parent
0826dbe201
commit
2f62e8d260
|
@ -3,6 +3,7 @@ package storage
|
|||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"sort"
|
||||
"time"
|
||||
|
@ -43,6 +44,47 @@ func (r RDBKey) TableName() string {
|
|||
return "tuf_keys"
|
||||
}
|
||||
|
||||
// gorethink can't handle an UnmarshalJSON function (see https://github.com/dancannon/gorethink/issues/201),
|
||||
// so do this here in an anonymous struct
|
||||
func rdbTUFFileFromJSON(data []byte) (interface{}, error) {
|
||||
a := struct {
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
DeletedAt time.Time `json:"deleted_at"`
|
||||
Gun string `json:"gun"`
|
||||
Role string `json:"role"`
|
||||
Version int `json:"version"`
|
||||
Sha256 string `json:"sha256"`
|
||||
Data []byte `json:"data"`
|
||||
TSchecksum string `json:"timestamp_checksum"`
|
||||
}{}
|
||||
if err := json.Unmarshal(data, &a); err != nil {
|
||||
return RDBTUFFile{}, err
|
||||
}
|
||||
return RDBTUFFile{
|
||||
Timing: rethinkdb.Timing{
|
||||
CreatedAt: a.CreatedAt,
|
||||
UpdatedAt: a.UpdatedAt,
|
||||
DeletedAt: a.DeletedAt,
|
||||
},
|
||||
GunRoleVersion: []interface{}{a.Gun, a.Role, a.Version},
|
||||
Gun: a.Gun,
|
||||
Role: a.Role,
|
||||
Version: a.Version,
|
||||
Sha256: a.Sha256,
|
||||
Data: a.Data,
|
||||
TSchecksum: a.TSchecksum,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func rdbKeyFromJSON(data []byte) (interface{}, error) {
|
||||
rdb := RDBKey{}
|
||||
if err := json.Unmarshal(data, &rdb); err != nil {
|
||||
return RDBKey{}, err
|
||||
}
|
||||
return rdb, nil
|
||||
}
|
||||
|
||||
// RethinkDB implements a MetaStore against the Rethink Database
|
||||
type RethinkDB struct {
|
||||
dbName string
|
||||
|
|
|
@ -27,6 +27,7 @@ var (
|
|||
Config: map[string]string{
|
||||
"write_acks": "majority",
|
||||
},
|
||||
JSONUnmarshaller: rdbTUFFileFromJSON,
|
||||
}
|
||||
|
||||
// PubKeysRethinkTable is the table definition of notary server's public key information for TUF roles
|
||||
|
@ -36,5 +37,6 @@ var (
|
|||
SecondaryIndexes: map[string][]string{
|
||||
rdbGunRoleIdx: {"gun", "role"},
|
||||
},
|
||||
JSONUnmarshaller: rdbKeyFromJSON,
|
||||
}
|
||||
)
|
||||
|
|
|
@ -0,0 +1,97 @@
|
|||
package storage
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/docker/notary/storage/rethinkdb"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestRDBTUFFileMarshalling(t *testing.T) {
|
||||
created := time.Now().AddDate(-1, -1, -1)
|
||||
updated := time.Now().AddDate(0, -5, 0)
|
||||
deleted := time.Time{}
|
||||
data := []byte("Hello world")
|
||||
|
||||
createdMarshalled, err := json.Marshal(created)
|
||||
require.NoError(t, err)
|
||||
updatedMarshalled, err := json.Marshal(updated)
|
||||
require.NoError(t, err)
|
||||
deletedMarshalled, err := json.Marshal(deleted)
|
||||
require.NoError(t, err)
|
||||
dataMarshalled, err := json.Marshal(data)
|
||||
require.NoError(t, err)
|
||||
|
||||
jsonBytes := []byte(fmt.Sprintf(`
|
||||
{
|
||||
"created_at": %s,
|
||||
"updated_at": %s,
|
||||
"deleted_at": %s,
|
||||
"gun_role_version": ["completely", "invalid", "garbage"],
|
||||
"gun": "namespaced/name",
|
||||
"role": "timestamp",
|
||||
"version": 5,
|
||||
"sha256": "56ee4a23129fc22c6cb4b4ba5f78d730c91ab6def514e80d807c947bb21f0d63",
|
||||
"data": %s,
|
||||
"timestamp_checksum": "ebe6b6e082c94ef24043f1786a7046432506c3d193a47c299ed48ff4413ad7b0"
|
||||
}
|
||||
`, createdMarshalled, updatedMarshalled, deletedMarshalled, dataMarshalled))
|
||||
|
||||
unmarshalledAnon, err := TUFFilesRethinkTable.JSONUnmarshaller(jsonBytes)
|
||||
require.NoError(t, err)
|
||||
unmarshalled, ok := unmarshalledAnon.(RDBTUFFile)
|
||||
require.True(t, ok)
|
||||
|
||||
// There is some weirdness with comparing time.Time due to a location pointer,
|
||||
// so let's use time.Time's equal function to compare times, and then re-assign
|
||||
// the timing struct to compare the rest of the RDBTUFFile struct
|
||||
require.True(t, created.Equal(unmarshalled.CreatedAt))
|
||||
require.True(t, updated.Equal(unmarshalled.UpdatedAt))
|
||||
require.True(t, deleted.Equal(unmarshalled.DeletedAt))
|
||||
|
||||
expected := RDBTUFFile{
|
||||
Timing: unmarshalled.Timing,
|
||||
GunRoleVersion: []interface{}{"namespaced/name", "timestamp", 5},
|
||||
Gun: "namespaced/name",
|
||||
Role: "timestamp",
|
||||
Version: 5,
|
||||
Sha256: "56ee4a23129fc22c6cb4b4ba5f78d730c91ab6def514e80d807c947bb21f0d63",
|
||||
Data: data,
|
||||
TSchecksum: "ebe6b6e082c94ef24043f1786a7046432506c3d193a47c299ed48ff4413ad7b0",
|
||||
}
|
||||
require.Equal(t, expected, unmarshalled)
|
||||
}
|
||||
|
||||
func TestRDBTUFKeyMarshalling(t *testing.T) {
|
||||
rdb := RDBKey{
|
||||
Timing: rethinkdb.Timing{
|
||||
CreatedAt: time.Now().AddDate(-1, -1, -1),
|
||||
UpdatedAt: time.Now().AddDate(0, -5, 0),
|
||||
DeletedAt: time.Time{},
|
||||
},
|
||||
Gun: "namespaced/name",
|
||||
Role: "timestamp",
|
||||
Cipher: "ecdsa",
|
||||
Public: []byte("Hello world"),
|
||||
}
|
||||
jsonBytes, err := json.Marshal(rdb)
|
||||
require.NoError(t, err)
|
||||
|
||||
unmarshalledAnon, err := PubKeysRethinkTable.JSONUnmarshaller(jsonBytes)
|
||||
require.NoError(t, err)
|
||||
unmarshalled, ok := unmarshalledAnon.(RDBKey)
|
||||
require.True(t, ok)
|
||||
|
||||
// There is some weirdness with comparing time.Time due to a location pointer,
|
||||
// so let's use time.Time's equal function to compare times, and then re-assign
|
||||
// the timing struct to compare the rest of the RDBTUFFile struct
|
||||
require.True(t, rdb.CreatedAt.Equal(unmarshalled.CreatedAt))
|
||||
require.True(t, rdb.UpdatedAt.Equal(unmarshalled.UpdatedAt))
|
||||
require.True(t, rdb.DeletedAt.Equal(unmarshalled.DeletedAt))
|
||||
unmarshalled.Timing = rdb.Timing
|
||||
|
||||
require.Equal(t, rdb, unmarshalled)
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
package keydbstore
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
@ -39,10 +40,46 @@ type RDBPrivateKey struct {
|
|||
Private string `gorethink:"private"`
|
||||
}
|
||||
|
||||
// gorethink can't handle an UnmarshalJSON function (see https://github.com/dancannon/gorethink/issues/201),
|
||||
// so do this here in an anonymous struct
|
||||
func rdbPrivateKeyFromJSON(data []byte) (interface{}, error) {
|
||||
a := struct {
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
DeletedAt time.Time `json:"deleted_at"`
|
||||
KeyID string `json:"key_id"`
|
||||
EncryptionAlg string `json:"encryption_alg"`
|
||||
KeywrapAlg string `json:"keywrap_alg"`
|
||||
Algorithm string `json:"algorithm"`
|
||||
PassphraseAlias string `json:"passphrase_alias"`
|
||||
Public string `json:"public"`
|
||||
Private string `json:"private"`
|
||||
}{}
|
||||
if err := json.Unmarshal(data, &a); err != nil {
|
||||
return RDBPrivateKey{}, err
|
||||
}
|
||||
return RDBPrivateKey{
|
||||
Timing: rethinkdb.Timing{
|
||||
CreatedAt: a.CreatedAt,
|
||||
UpdatedAt: a.UpdatedAt,
|
||||
DeletedAt: a.DeletedAt,
|
||||
},
|
||||
KeyID: a.KeyID,
|
||||
EncryptionAlg: a.EncryptionAlg,
|
||||
KeywrapAlg: a.KeywrapAlg,
|
||||
Algorithm: a.Algorithm,
|
||||
PassphraseAlias: a.PassphraseAlias,
|
||||
Public: a.Public,
|
||||
Private: a.Private,
|
||||
}, nil
|
||||
|
||||
}
|
||||
|
||||
// PrivateKeysRethinkTable is the table definition for notary signer's key information
|
||||
var PrivateKeysRethinkTable = rethinkdb.Table{
|
||||
Name: RDBPrivateKey{}.TableName(),
|
||||
PrimaryKey: RDBPrivateKey{}.KeyID,
|
||||
Name: RDBPrivateKey{}.TableName(),
|
||||
PrimaryKey: RDBPrivateKey{}.KeyID,
|
||||
JSONUnmarshaller: rdbPrivateKeyFromJSON,
|
||||
}
|
||||
|
||||
// TableName sets a specific table name for our RDBPrivateKey
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
package keydbstore
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestRDBTUFFileMarshalling(t *testing.T) {
|
||||
created := time.Now().AddDate(-1, -1, -1)
|
||||
updated := time.Now().AddDate(0, -5, 0)
|
||||
deleted := time.Time{}
|
||||
|
||||
createdMarshalled, err := json.Marshal(created)
|
||||
require.NoError(t, err)
|
||||
updatedMarshalled, err := json.Marshal(updated)
|
||||
require.NoError(t, err)
|
||||
deletedMarshalled, err := json.Marshal(deleted)
|
||||
require.NoError(t, err)
|
||||
|
||||
jsonBytes := []byte(fmt.Sprintf(`
|
||||
{
|
||||
"created_at": %s,
|
||||
"updated_at": %s,
|
||||
"deleted_at": %s,
|
||||
"key_id": "56ee4a23129fc22c6cb4b4ba5f78d730c91ab6def514e80d807c947bb21f0d63",
|
||||
"encryption_alg": "A256GCM",
|
||||
"keywrap_alg": "PBES2-HS256+A128KW",
|
||||
"algorithm": "ecdsa",
|
||||
"passphrase_alias": "timestamp_1",
|
||||
"public": "Hello world public",
|
||||
"private": "Hello world private"
|
||||
}
|
||||
`, createdMarshalled, updatedMarshalled, deletedMarshalled))
|
||||
fmt.Println(string(jsonBytes))
|
||||
|
||||
unmarshalledAnon, err := PrivateKeysRethinkTable.JSONUnmarshaller(jsonBytes)
|
||||
require.NoError(t, err)
|
||||
unmarshalled, ok := unmarshalledAnon.(RDBPrivateKey)
|
||||
require.True(t, ok)
|
||||
|
||||
// There is some weirdness with comparing time.Time due to a location pointer,
|
||||
// so let's use time.Time's equal function to compare times, and then re-assign
|
||||
// the timing struct to compare the rest of the RDBTUFFile struct
|
||||
require.True(t, created.Equal(unmarshalled.CreatedAt))
|
||||
require.True(t, updated.Equal(unmarshalled.UpdatedAt))
|
||||
require.True(t, deleted.Equal(unmarshalled.DeletedAt))
|
||||
|
||||
expected := RDBPrivateKey{
|
||||
Timing: unmarshalled.Timing,
|
||||
KeyID: "56ee4a23129fc22c6cb4b4ba5f78d730c91ab6def514e80d807c947bb21f0d63",
|
||||
EncryptionAlg: "A256GCM",
|
||||
KeywrapAlg: "PBES2-HS256+A128KW",
|
||||
Algorithm: "ecdsa",
|
||||
PassphraseAlias: "timestamp_1",
|
||||
Public: "Hello world public",
|
||||
Private: "Hello world private",
|
||||
}
|
||||
require.Equal(t, expected, unmarshalled)
|
||||
}
|
|
@ -31,6 +31,9 @@ type Table struct {
|
|||
// on the list of fields in the corrensponding slice value.
|
||||
SecondaryIndexes map[string][]string
|
||||
Config map[string]string
|
||||
//JSONUnmarshaller takes a byte slice representing JSON data and knows how
|
||||
//to unmarshal them into a model representing this table
|
||||
JSONUnmarshaller func([]byte) (interface{}, error)
|
||||
}
|
||||
|
||||
func (t Table) term(dbName string) gorethink.Term {
|
||||
|
|
Loading…
Reference in New Issue