mirror of https://github.com/docker/docs.git
Merge pull request #338 from cyli/keydbstore-error
KeyDBStore refactor so that it just directly takes the DB arguments.
This commit is contained in:
commit
3e96684ba1
|
@ -4,7 +4,6 @@ package main
|
|||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"database/sql"
|
||||
"errors"
|
||||
_ "expvar"
|
||||
"flag"
|
||||
|
@ -93,18 +92,12 @@ func setUpCryptoservices(configuration *viper.Viper, allowedBackends []string) (
|
|||
}
|
||||
logrus.Debug("Default Alias: ", defaultAlias)
|
||||
|
||||
dbSQL, err := sql.Open(storeConfig.Backend, storeConfig.Source)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to open the %s database: %s, %v",
|
||||
storeConfig.Backend, storeConfig.Source, err)
|
||||
}
|
||||
logrus.Debugf("Using %s DB: %s", storeConfig.Backend, storeConfig.Source)
|
||||
|
||||
dbStore, err := keydbstore.NewKeyDBStore(
|
||||
passphraseRetriever, defaultAlias, storeConfig.Backend, dbSQL)
|
||||
passphraseRetriever, defaultAlias, storeConfig.Backend, storeConfig.Source)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create a new keydbstore: %v", err)
|
||||
}
|
||||
logrus.Debugf("Using %s DB: %s", storeConfig.Backend, storeConfig.Source)
|
||||
|
||||
health.RegisterPeriodicFunc(
|
||||
"DB operational", dbStore.HealthCheck, time.Second*60)
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package keydbstore
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
@ -46,13 +45,17 @@ func (g GormPrivateKey) TableName() string {
|
|||
}
|
||||
|
||||
// NewKeyDBStore returns a new KeyDBStore backed by a SQL database
|
||||
func NewKeyDBStore(passphraseRetriever passphrase.Retriever, defaultPassAlias, dbType string, dbSQL *sql.DB) (*KeyDBStore, error) {
|
||||
func NewKeyDBStore(passphraseRetriever passphrase.Retriever, defaultPassAlias string,
|
||||
dbDialect string, dbArgs ...interface{}) (*KeyDBStore, error) {
|
||||
cachedKeys := make(map[string]data.PrivateKey)
|
||||
|
||||
// Open a connection to our database
|
||||
db, _ := gorm.Open(dbType, dbSQL)
|
||||
db, err := gorm.Open(dbDialect, dbArgs...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &KeyDBStore{db: db,
|
||||
return &KeyDBStore{
|
||||
db: db,
|
||||
defaultPassAlias: defaultPassAlias,
|
||||
retriever: passphraseRetriever,
|
||||
cachedKeys: cachedKeys}, nil
|
||||
|
@ -88,7 +91,7 @@ func (s *KeyDBStore) AddKey(name, alias string, privKey data.PrivateKey) error {
|
|||
|
||||
// Add encrypted private key to the database
|
||||
s.db.Create(&gormPrivKey)
|
||||
// Value will be false if Create suceeds
|
||||
// Value will be false if Create succeeds
|
||||
failure := s.db.NewRecord(gormPrivKey)
|
||||
if failure {
|
||||
return fmt.Errorf("failed to add private key to database: %s", privKey.ID())
|
||||
|
|
|
@ -2,13 +2,15 @@ package keydbstore
|
|||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/notary/trustmanager"
|
||||
"github.com/docker/notary/tuf/data"
|
||||
"github.com/jinzhu/gorm"
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
@ -27,97 +29,126 @@ var anotherRetriever = func(keyName, alias string, createNew bool, attempts int)
|
|||
return "", false, errors.New("password alias no found")
|
||||
}
|
||||
|
||||
func TestCreateRead(t *testing.T) {
|
||||
tempBaseDir, err := ioutil.TempDir("", "notary-test-")
|
||||
defer os.RemoveAll(tempBaseDir)
|
||||
|
||||
testKey, err := trustmanager.GenerateECDSAKey(rand.Reader)
|
||||
// Create a temporary file, open a database connection to it, and create the
|
||||
// necessary table. Return the file name to use and clean up.
|
||||
func initializeDB(t *testing.T) (tmpfilename string) {
|
||||
tmpFile, err := ioutil.TempFile("/tmp", "notary-test-sqlite-db-")
|
||||
assert.NoError(t, err)
|
||||
tmpFile.Close()
|
||||
|
||||
// We are using SQLite for the tests
|
||||
db, err := sql.Open("sqlite3", tempBaseDir+"test_db")
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Create a new KeyDB store
|
||||
dbStore, err := NewKeyDBStore(retriever, "", "sqlite3", db)
|
||||
gormDB, err := gorm.Open("sqlite3", tmpFile.Name())
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Ensure that the private_key table exists
|
||||
dbStore.db.CreateTable(&GormPrivateKey{})
|
||||
gormDB.CreateTable(&GormPrivateKey{})
|
||||
|
||||
// Test writing new key in database/cache
|
||||
err = dbStore.AddKey("", "", testKey)
|
||||
return tmpFile.Name()
|
||||
}
|
||||
|
||||
// gets a key from the DB store, and asserts that the key is the expected key
|
||||
func testGetSuccess(t *testing.T, dbStore *KeyDBStore, expectedKey data.PrivateKey) {
|
||||
retrKey, _, err := dbStore.GetKey(expectedKey.ID())
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, retrKey, expectedKey)
|
||||
}
|
||||
|
||||
// closes the DB connection first so we can test that the successful get was
|
||||
// from the cache
|
||||
func testGetSuccessFromCache(t *testing.T, dbStore *KeyDBStore,
|
||||
expectedKey data.PrivateKey) {
|
||||
|
||||
err := dbStore.db.Close()
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Test retrieval of key from DB
|
||||
delete(dbStore.cachedKeys, testKey.ID())
|
||||
testGetSuccess(t, dbStore, expectedKey)
|
||||
}
|
||||
|
||||
retrKey, _, err := dbStore.GetKey(testKey.ID())
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, retrKey, testKey)
|
||||
// Creating a new KeyDBStore propogates any db opening error
|
||||
func TestNewKeyDBStorePropogatesDBError(t *testing.T) {
|
||||
dbStore, err := NewKeyDBStore(retriever, "ignoredalias", "nodb", "somestring")
|
||||
assert.Error(t, err)
|
||||
assert.Nil(t, dbStore)
|
||||
}
|
||||
|
||||
// Tests retrieval of key from Cache
|
||||
// Close database connection
|
||||
err = dbStore.db.Close()
|
||||
// Creating a key, on succcess, populates the cache.
|
||||
func TestCreateSuccessPopulatesCache(t *testing.T) {
|
||||
testKey, err := trustmanager.GenerateECDSAKey(rand.Reader)
|
||||
assert.NoError(t, err)
|
||||
|
||||
retrKey, _, err = dbStore.GetKey(testKey.ID())
|
||||
tmpFilename := initializeDB(t)
|
||||
defer os.Remove(tmpFilename)
|
||||
|
||||
// Create a new KeyDB store
|
||||
dbStore, err := NewKeyDBStore(retriever, "ignoredalias", "sqlite3", tmpFilename)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, retrKey, testKey)
|
||||
|
||||
// Test writing new key in database
|
||||
err = dbStore.AddKey("gun/ignored", data.CanonicalTimestampRole, testKey)
|
||||
assert.NoError(t, err)
|
||||
|
||||
testGetSuccessFromCache(t, dbStore, testKey)
|
||||
}
|
||||
|
||||
// Getting a key, on succcess, populates the cache.
|
||||
func TestGetSuccessPopulatesCache(t *testing.T) {
|
||||
testKey, err := trustmanager.GenerateECDSAKey(rand.Reader)
|
||||
assert.NoError(t, err)
|
||||
|
||||
tmpFilename := initializeDB(t)
|
||||
defer os.Remove(tmpFilename)
|
||||
|
||||
// Create a new KeyDB store and add a key
|
||||
dbStore, err := NewKeyDBStore(retriever, "ignoredalias", "sqlite3", tmpFilename)
|
||||
assert.NoError(t, err)
|
||||
err = dbStore.AddKey("gun/ignored", data.CanonicalTimestampRole, testKey)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// delete the cache
|
||||
dbStore.cachedKeys = make(map[string]data.PrivateKey)
|
||||
|
||||
testGetSuccess(t, dbStore, testKey)
|
||||
testGetSuccessFromCache(t, dbStore, testKey)
|
||||
}
|
||||
|
||||
func TestDoubleCreate(t *testing.T) {
|
||||
tempBaseDir, err := ioutil.TempDir("", "notary-test-")
|
||||
defer os.RemoveAll(tempBaseDir)
|
||||
|
||||
testKey, err := trustmanager.GenerateECDSAKey(rand.Reader)
|
||||
assert.NoError(t, err)
|
||||
|
||||
anotherTestKey, err := trustmanager.GenerateECDSAKey(rand.Reader)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// We are using SQLite for the tests
|
||||
db, err := sql.Open("sqlite3", tempBaseDir+"test_db")
|
||||
assert.NoError(t, err)
|
||||
tmpFilename := initializeDB(t)
|
||||
defer os.Remove(tmpFilename)
|
||||
|
||||
// Create a new KeyDB store
|
||||
dbStore, err := NewKeyDBStore(retriever, "", "sqlite3", db)
|
||||
// Create a new KeyDB store and add a key
|
||||
dbStore, err := NewKeyDBStore(retriever, "ignoredalias", "sqlite3", tmpFilename)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Ensure that the private_key table exists
|
||||
dbStore.db.CreateTable(&GormPrivateKey{})
|
||||
|
||||
// Test writing new key in database/cache
|
||||
err = dbStore.AddKey("", "", testKey)
|
||||
err = dbStore.AddKey("gun/ignored", data.CanonicalTimestampRole, testKey)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Test writing the same key in the database. Should fail.
|
||||
err = dbStore.AddKey("", "", testKey)
|
||||
err = dbStore.AddKey("gun/ignored", data.CanonicalTimestampRole, testKey)
|
||||
assert.Error(t, err, "failed to add private key to database:")
|
||||
|
||||
// Test writing new key succeeds
|
||||
err = dbStore.AddKey("", "", anotherTestKey)
|
||||
err = dbStore.AddKey("gun/ignored", data.CanonicalTimestampRole, anotherTestKey)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestCreateDelete(t *testing.T) {
|
||||
tempBaseDir, err := ioutil.TempDir("", "notary-test-")
|
||||
defer os.RemoveAll(tempBaseDir)
|
||||
|
||||
testKey, err := trustmanager.GenerateECDSAKey(rand.Reader)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// We are using SQLite for the tests
|
||||
db, err := sql.Open("sqlite3", tempBaseDir+"test_db")
|
||||
assert.NoError(t, err)
|
||||
tmpFilename := initializeDB(t)
|
||||
defer os.Remove(tmpFilename)
|
||||
|
||||
// Create a new KeyDB store
|
||||
dbStore, err := NewKeyDBStore(retriever, "", "sqlite3", db)
|
||||
dbStore, err := NewKeyDBStore(retriever, "ignoredalias", "sqlite3", tmpFilename)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Ensure that the private_key table exists
|
||||
dbStore.db.CreateTable(&GormPrivateKey{})
|
||||
|
||||
// Test writing new key in database/cache
|
||||
err = dbStore.AddKey("", "", testKey)
|
||||
assert.NoError(t, err)
|
||||
|
@ -126,31 +157,24 @@ func TestCreateDelete(t *testing.T) {
|
|||
err = dbStore.RemoveKey(testKey.ID())
|
||||
assert.NoError(t, err)
|
||||
|
||||
// This should fail
|
||||
// This should fail, since it is neither in the cache nor the DB
|
||||
_, _, err = dbStore.GetKey(testKey.ID())
|
||||
assert.Error(t, err, "signing key not found:")
|
||||
}
|
||||
|
||||
func TestKeyRotation(t *testing.T) {
|
||||
tempBaseDir, err := ioutil.TempDir("", "notary-test-")
|
||||
defer os.RemoveAll(tempBaseDir)
|
||||
|
||||
testKey, err := trustmanager.GenerateECDSAKey(rand.Reader)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// We are using SQLite for the tests
|
||||
db, err := sql.Open("sqlite3", tempBaseDir+"test_db")
|
||||
assert.NoError(t, err)
|
||||
tmpFilename := initializeDB(t)
|
||||
defer os.Remove(tmpFilename)
|
||||
|
||||
// Create a new KeyDB store
|
||||
dbStore, err := NewKeyDBStore(anotherRetriever, "alias_1", "sqlite3", db)
|
||||
dbStore, err := NewKeyDBStore(anotherRetriever, "alias_1", "sqlite3", tmpFilename)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Ensure that the private_key table exists
|
||||
dbStore.db.CreateTable(&GormPrivateKey{})
|
||||
|
||||
// Test writing new key in database/cache
|
||||
err = dbStore.AddKey("", "", testKey)
|
||||
err = dbStore.AddKey("gun/ignore", data.CanonicalTimestampRole, testKey)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Try rotating the key to alias-2
|
||||
|
@ -159,19 +183,16 @@ func TestKeyRotation(t *testing.T) {
|
|||
|
||||
// Try rotating the key to alias-3
|
||||
err = dbStore.RotateKeyPassphrase(testKey.ID(), "alias_3")
|
||||
assert.Error(t, err, "password alias no found")
|
||||
assert.Error(t, err, "there should be no password for alias_3")
|
||||
}
|
||||
|
||||
func TestDBHealthCheck(t *testing.T) {
|
||||
tempBaseDir, err := ioutil.TempDir("", "notary-test-")
|
||||
tempBaseDir, err := ioutil.TempDir("/tmp", "notary-test-")
|
||||
defer os.RemoveAll(tempBaseDir)
|
||||
|
||||
// We are using SQLite for the tests
|
||||
db, err := sql.Open("sqlite3", tempBaseDir+"test_db")
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Create a new KeyDB store
|
||||
dbStore, err := NewKeyDBStore(retriever, "", "sqlite3", db)
|
||||
dbStore, err := NewKeyDBStore(retriever, "ignoredalias",
|
||||
"sqlite3", filepath.Join(tempBaseDir, "test_db"))
|
||||
assert.NoError(t, err)
|
||||
|
||||
// No key table, health check fails
|
||||
|
|
Loading…
Reference in New Issue