Skip to content

Commit

Permalink
[FAB-6508] Unique db names for cacount option
Browse files Browse the repository at this point in the history
If using the --cacount option when starting up
fabric-ca-server, each CA instance created will
have a unique database name.

Change-Id: I3633b948e725df8dcce9328acab353c996529618
Signed-off-by: Saad Karim <[email protected]>
  • Loading branch information
Saad Karim committed Oct 20, 2017
1 parent 2886abd commit 5d2f1b5
Show file tree
Hide file tree
Showing 7 changed files with 81 additions and 30 deletions.
2 changes: 1 addition & 1 deletion cmd/fabric-ca-server/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ func TestDefaultMultiCAs(t *testing.T) {
t.Error("Failed to start server with multiple default CAs using the --cacount flag from command line: ", err)
}

if !util.FileExists("ca/ca4/fabric-ca-server.db") {
if !util.FileExists("ca/ca4/fabric-ca-server_ca4.db") {
t.Error("Failed to create 4 default CA instances")
}

Expand Down
13 changes: 13 additions & 0 deletions lib/caconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,19 @@ ca:
# Name of this CA
name: <<<CANAME>>>
#############################################################################
# Database section
# Supported types are: "sqlite3", "postgres", and "mysql".
# The datasource value depends on the type.
# If the type is "sqlite3", the datasource value is a file name to use
# as the database store. Since "sqlite3" is an embedded database, it
# may not be used if you want to run the fabric-ca-server in a cluster.
# To run the fabric-ca-server in a cluster, you must choose "postgres"
# or "mysql".
#############################################################################
db:
datasource: <<<DATASOURCE>>>
###########################################################################
# Certificate Signing Request section for generating the CA certificate
###########################################################################
Expand Down
20 changes: 17 additions & 3 deletions lib/dbutil/dbutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package dbutil

import (
"fmt"
"path/filepath"
"regexp"
"strings"

Expand Down Expand Up @@ -65,7 +66,7 @@ func NewUserRegistrySQLLite3(datasource string) (*sqlx.DB, error) {
}

func createSQLiteDBTables(datasource string) error {
log.Debug("Creating SQLite database (%s) if it does not exist...", datasource)
log.Debugf("Creating SQLite database (%s) if it does not exist...", datasource)
db, err := sqlx.Open("sqlite3", datasource)
if err != nil {
return errors.Wrap(err, "Failed to open SQLite database")
Expand Down Expand Up @@ -180,7 +181,7 @@ func NewUserRegistryMySQL(datasource string, clientTLSConfig *tls.ClientTLSConfi
dbName := getDBName(datasource)
log.Debug("Database Name: ", dbName)

re := regexp.MustCompile(`\/([a-zA-z]+)`)
re := regexp.MustCompile(`\/([0-9,a-z,A-Z$_]+)`)
connStr := re.ReplaceAllString(datasource, "/")

if clientTLSConfig.Enabled {
Expand Down Expand Up @@ -259,7 +260,7 @@ func createMySQLTables(dbName string, db *sqlx.DB) error {
return nil
}

// GetDBName gets database name from connection string
// getDBName gets database name from connection string
func getDBName(datasource string) string {
var dbName string
datasource = strings.ToLower(datasource)
Expand All @@ -276,6 +277,19 @@ func getDBName(datasource string) string {
return dbName
}

// GetCADataSource returns a datasource with a unqiue database name
func GetCADataSource(dbtype, datasource string, cacount int) string {
if dbtype == "sqlite3" {
ext := filepath.Ext(datasource)
dbName := strings.TrimSuffix(filepath.Base(datasource), ext)
datasource = fmt.Sprintf("%s_ca%d%s", dbName, cacount, ext)
} else {
dbName := getDBName(datasource)
datasource = strings.Replace(datasource, dbName, fmt.Sprintf("%s_ca%d", dbName, cacount), 1)
}
return datasource
}

// GetConnStr gets connection string without database
func getConnStr(datasource string) string {
re := regexp.MustCompile(`(dbname=)([^\s]+)`)
Expand Down
4 changes: 4 additions & 0 deletions lib/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import (
"github.com/cloudflare/cfssl/log"
"github.com/cloudflare/cfssl/revoke"
"github.com/cloudflare/cfssl/signer"
"github.com/hyperledger/fabric-ca/lib/dbutil"
stls "github.com/hyperledger/fabric-ca/lib/tls"
"github.com/hyperledger/fabric-ca/util"
"github.com/spf13/viper"
Expand Down Expand Up @@ -433,6 +434,9 @@ func (s *Server) createDefaultCAConfigs(cacount int) error {
cn := fmt.Sprintf("fabric-ca-server-ca%d", i)
cfg = strings.Replace(cfg, "<<<COMMONNAME>>>", cn, 1)

datasource := dbutil.GetCADataSource(s.CA.Config.DB.Type, s.CA.Config.DB.Datasource, i)
cfg = strings.Replace(cfg, "<<<DATASOURCE>>>", datasource, 1)

s.Config.CAfiles = append(s.Config.CAfiles, cfgFileName)

// Now write the file
Expand Down
27 changes: 13 additions & 14 deletions scripts/fvt/db_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -167,13 +167,13 @@ mysql --host=localhost --user=root --password=mysql --database=$DBNAME -e "CREAT

# Starting server first time with one bootstrap user
$SCRIPTDIR/fabric-ca_setup.sh -S -X -g $MYSQLSERVERCONFIG 2>&1 | tee $SERVERLOG &
pollServer fabric-ca-server 127.0.0.1 17054 10 start
pollServer fabric-ca-server 127.0.0.1 17054 20 start
pid=$(pidof fabric-ca-server)
killserver $pid

# Starting server second time with a second bootstrap user
$SCRIPTDIR/fabric-ca_setup.sh -S -X -g $MYSQLSERVERCONFIG2 2>&1 | tee $SERVERLOG &
pollServer fabric-ca-server 127.0.0.1 17054 10 start
pollServer fabric-ca-server 127.0.0.1 17054 20 start
pid=$(pidof fabric-ca-server)
killserver $pid

Expand All @@ -192,7 +192,7 @@ echo "Dropping and creating an empty '$DBNAME' database"
mysql --host=localhost --user=root --password=mysql -e "drop database fabric_ca;" -e "create database fabric_ca;" &> /dev/null

$SCRIPTDIR/fabric-ca_setup.sh -S -X -g $MYSQLSERVERCONFIG2 2>&1 | tee $SERVERLOG &
pollServer fabric-ca-server 127.0.0.1 17054 10 start
pollServer fabric-ca-server 127.0.0.1 17054 20 start
pid=$(pidof fabric-ca-server)
killserver $pid

Expand All @@ -208,7 +208,7 @@ echo "Dropping '$DBNAME' database"
mysql --host=localhost --user=root --password=mysql -e "drop database fabric_ca;" &> /dev/null

$SCRIPTDIR/fabric-ca_setup.sh -S -X -g $MYSQLSERVERCONFIG2 2>&1 | tee $SERVERLOG &
pollServer fabric-ca-server 127.0.0.1 17054 10 start
pollServer fabric-ca-server 127.0.0.1 17054 20 start
pid=$(pidof fabric-ca-server)
killserver $pid

Expand All @@ -230,15 +230,14 @@ psql -d fabric_ca -c "CREATE TABLE users (id VARCHAR(64), token bytea, type VARC

# Starting server first time with one bootstrap user
$SCRIPTDIR/fabric-ca_setup.sh -S -X -g $PGSQLSERVERCONFIG 2>&1 | tee $SERVERLOG &

pollServer fabric-ca-server 127.0.0.1 17054 10 start
pollServer fabric-ca-server 127.0.0.1 17054 20 start
pid=$(pidof fabric-ca-server)
killserver $pid

sleep 1
# Starting server second time with a second bootstrap user
$SCRIPTDIR/fabric-ca_setup.sh -S -X -g $PGSQLSERVERCONFIG2 2>&1 | tee $SERVERLOG &
pollServer fabric-ca-server 127.0.0.1 17054 10 start
pollServer fabric-ca-server 127.0.0.1 17054 20 start
pid=$(pidof fabric-ca-server)
killserver $pid

Expand All @@ -257,7 +256,7 @@ psql -c "drop database $DBNAME"
psql -c "create database $DBNAME"

$SCRIPTDIR/fabric-ca_setup.sh -S -X -g $PGSQLSERVERCONFIG2 2>&1 | tee $SERVERLOG &
pollServer fabric-ca-server 127.0.0.1 17054 10 start
pollServer fabric-ca-server 127.0.0.1 17054 20 start
pid=$(pidof fabric-ca-server)
killserver $pid

Expand All @@ -273,7 +272,7 @@ psql -c "drop database $DBNAME"

$SCRIPTDIR/fabric-ca_setup.sh -S -X -g $PGSQLSERVERCONFIG2 2>&1 | tee $SERVERLOG &
sleep 6 # Need to allow for Postgres to complete database and table creation
pollServer fabric-ca-server 127.0.0.1 17054 10 start
pollServer fabric-ca-server 127.0.0.1 17054 20 start
pid=$(pidof fabric-ca-server)
killserver $pid

Expand All @@ -287,7 +286,7 @@ pollServer postgres 127.0.0.1 5432 5 stop # Wait for PostgreSQL to stop

# Start fabric-ca server connecting to postgres, this will fail
$SCRIPTDIR/fabric-ca_setup.sh -S -X -g $PGSQLSERVERCONFIG2
pollServer fabric-ca-server 127.0.0.1 17054 10 start
pollServer fabric-ca-server 127.0.0.1 17054 20 start

# Enroll with a server that does not have a DB initialized, should expect to get back error
enroll a b 2>&1 | grep "Failed to create user registry for PostgreSQL"
Expand All @@ -297,8 +296,8 @@ fi

# Start postgres server
su postgres -c 'postgres -D /usr/local/pgsql/data' &
pollServer postgres 127.0.0.1 5432 10 start # Wait for PostgreSQL to start
sleep 1 # Postgres port is available but sometimes get back 'pq: the database system is starting up' error. Putting in sleep to allow for start up to complete
pollServer postgres 127.0.0.1 5432 20 start # Wait for PostgreSQL to start
sleep 5 # Postgres port is available but sometimes get back 'pq: the database system is starting up' error. Putting in sleep to allow for start up to complete

# Enroll again, this time the server should try to reinitialize the DB before processing enroll request and this should succeed
enroll a b 2>&1 | grep "Stored client certificate"
Expand All @@ -315,7 +314,7 @@ pollServer mysql 127.0.0.1 3306 2 stop # Wait for MySQL to stop

# Start fabric-ca server connecting to MySQL, this will fail
$SCRIPTDIR/fabric-ca_setup.sh -S -X -g $MYSQLSERVERCONFIG2
pollServer fabric-ca-server 127.0.0.1 17054 10 start
pollServer fabric-ca-server 127.0.0.1 17054 20 start

# Enroll with a server that does not have a DB initialized, should expect to get back error
enroll a b 2>&1 | grep "Failed to create user registry for MySQL"
Expand All @@ -325,7 +324,7 @@ fi

# Start mysql server
/usr/bin/mysqld_safe --sql-mode=STRICT_TRANS_TABLES &
pollServer mysql 127.0.0.1 3306 5 start # Wait for MySQL to start
pollServer mysql 127.0.0.1 3306 20 start # Wait for MySQL to start

# Enroll again, this time the server should try to reinitialize the DB before processing enroll request and this should succeed
enroll a b 2>&1 | grep "Stored client certificate"
Expand Down
14 changes: 8 additions & 6 deletions scripts/fvt/fabric-ca_utils
Original file line number Diff line number Diff line change
Expand Up @@ -771,23 +771,25 @@ function testStatus() {
local user="$1"
local driver="$2"
local ca_cfg_path="$3"
local dbname="$4"
: ${driver:="sqlite3"}
: ${ca_cfg_path:="$CA_CFG_PATH"}
: ${dbname:="fabric_ca"}
case $driver in
sqlite3)
user_status="$(sqlite3 $ca_cfg_path/$DB "SELECT * FROM users WHERE (id=\"$user\");")"
cert_status="$(sqlite3 $ca_cfg_path/$DB "SELECT * FROM certificates WHERE (id=\"$user\");")"
user_status="$(sqlite3 $ca_cfg_path/$dbname "SELECT * FROM users WHERE (id=\"$user\");")"
cert_status="$(sqlite3 $ca_cfg_path/$dbname "SELECT * FROM certificates WHERE (id=\"$user\");")"

user_status_code="$(printf "$user_status" | awk -F'|' -v s=$user '$1~s {print $6}')"
cert_status_code="$(printf "$cert_status" | awk -F'|' -v s=$user '$1~s {print $5}')"
;;
mysql)
user_status_code=$(mysql --host=localhost --user=root --password=mysql -e "SELECT * FROM users WHERE (id=\"$user\");" $DB| awk -F'\t' -v u=$user '$1==u {print $6}')
cert_status_code=$(mysql --host=localhost --user=root --password=mysql -e "SELECT * FROM certificates WHERE (id=\"$user\") order by revoked_at;" $DB| awk -F'\t' -v u=$user '$1==u {print $5}')
user_status_code=$(mysql --host=localhost --user=root --password=mysql -e "SELECT * FROM users WHERE (id=\"$user\");" $dbname| awk -F'\t' -v u=$user '$1==u {print $6}')
cert_status_code=$(mysql --host=localhost --user=root --password=mysql -e "SELECT * FROM certificates WHERE (id=\"$user\") order by revoked_at;" $dbname| awk -F'\t' -v u=$user '$1==u {print $5}')
;;
postgres)
user_status_code=$(/usr/bin/psql -U postgres -h localhost -c "SELECT id,state FROM users WHERE id='$user';" --dbname=fabric_ca | awk -v u=$user -F'|' '$1~u {gsub(/ /,"");print $2}')
cert_status_code=$(/usr/bin/psql -U postgres -h localhost -c "SELECT id,encode(status,'escape') FROM certificates WHERE id='$user' order by revoked_at;" --dbname=fabric_ca | awk -v u=$user -F'|' '$1~u {gsub(/ /,"");print $2}')
user_status_code=$(/usr/bin/psql -U postgres -h localhost -c "SELECT id,state FROM users WHERE id='$user';" --dbname=$dbname | awk -v u=$user -F'|' '$1~u {gsub(/ /,"");print $2}')
cert_status_code=$(/usr/bin/psql -U postgres -h localhost -c "SELECT id,encode(status,'escape') FROM certificates WHERE id='$user' order by revoked_at;" --dbname=$dbname | awk -v u=$user -F'|' '$1~u {gsub(/ /,"");print $2}')
;;
esac
echo "$user_status_code $cert_status_code"
Expand Down
31 changes: 25 additions & 6 deletions scripts/fvt/multica_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ TDIR=/tmp/$TESTCASE
FABRIC_CA="$GOPATH/src/github.com/hyperledger/fabric-ca"
SCRIPTDIR="$FABRIC_CA/scripts/fvt"
TESTDATA="$FABRIC_CA/testdata"
export DB="fabric_ca"
. $SCRIPTDIR/fabric-ca_utils
PROTO="http://"
ROOT_CA_ADDR=localhost
Expand Down Expand Up @@ -107,6 +106,25 @@ function revokeUser() {
return $?
}

function resetDB() {
local driver=$1
if [ $driver = "mysql" ]; then
i=0;while test $((i++)) -lt $NUMINTCAS; do
mysql --host=localhost --user=root --password=mysql -e "drop database fabric_ca_ca$i;"
done
fi

if [ $driver = "postgres" ]; then
i=0;while test $((i++)) -lt $NUMINTCAS; do
psql -c "drop database fabric_ca_ca$i"
done
fi

if [ $driver = "sqlite3" ]; then
rm -rf $TDIR
fi
}

#function setTLS() {
#: ${FABRIC_TLS:="false"}
#if $($FABRIC_TLS); then
Expand All @@ -133,6 +151,7 @@ for driver in sqlite3 postgres mysql; do

# if ENV FABRIC_TLS=true, use TLS
setTLS
resetDB $driver

createRootCA || ErrorExit "Failed to create root CA"

Expand All @@ -141,7 +160,7 @@ for driver in sqlite3 postgres mysql; do
# roundrobin through all servers in pool and enroll users
u=-1; while test $((u++)) -lt ${#USERS[u]}; do
i=0;while test $((i++)) -lt $NUMINTCAS; do
for iter in {0..1}; do
for iter in $(seq 1 $MAXENROLL); do
# Issue duplicate enroll to ensure proper processing of multiple requests
enrollUser ${USERS[u]} ${PSWDS[u]} ca$i || ErrorExit "Failed to enroll ${USERS[u]} to ca$i"
done
Expand All @@ -151,7 +170,7 @@ for driver in sqlite3 postgres mysql; do
# enrolling beyond the configured MAXENROLL should fail
u=-1; while test $((u++)) -lt ${#USERS[u]}; do
i=0;while test $((i++)) -lt $NUMINTCAS; do
enrollUser ${USERS[u]} ${PSWDS[u]} ca$i && ErrorExit "Should have failedto enroll ${USERS[u]} to ca$i"
enrollUser ${USERS[u]} ${PSWDS[u]} ca$i && ErrorExit "Should have failed to enroll ${USERS[u]} to ca$i"
done
done

Expand All @@ -178,7 +197,7 @@ for driver in sqlite3 postgres mysql; do
# Check the DB contents
i=0;while test $((i++)) -lt $NUMINTCAS; do
j=0;while test $((j++)) -lt $NUMUSERS; do
test "$(testStatus user$i$j $driver $TDIR/ca0 )" = "$enrolledGood" ||
test "$(testStatus user$i$j $driver $TDIR/ca0/ca/ca$i fabric_ca_ca$i )" = "$enrolledGood" ||
ErrorMsg "Incorrect user/certificate status for $user$i$j" RC
done
done
Expand All @@ -197,7 +216,7 @@ for driver in sqlite3 postgres mysql; do
#### Ensure that revoking an already revoked cert doesn't blow up
echo "=========================> Issuing duplicate revoke by -s -a"
revokeUser admin user$i$j ca$i "$SN_UC" "$AKI_UC"
test "$(testStatus user$i$j $driver $TDIR/ca0 )" = "$enrolledRevoked" ||
test "$(testStatus user$i$j $driver $TDIR/ca0/ca/ca$i fabric_ca_ca$i )" = "$enrolledRevoked" ||
ErrorMsg "Incorrect user/certificate status for user$i$j" RC
done
done
Expand All @@ -209,7 +228,7 @@ for driver in sqlite3 postgres mysql; do
#### Ensure that revoking an already revoked cert doesn't blow up
echo "=========================> Issuing duplicate revoke by -s -a"
revokeUser admin user$i$j ca$i
test "$(testStatus user$i$j $driver $TDIR/ca0 )" = "$revokedRevoked" ||
test "$(testStatus user$i$j $driver $TDIR/ca0/ca/ca$i fabric_ca_ca$i )" = "$revokedRevoked" ||
ErrorMsg "Incorrect user/certificate status for user$i$j" RC
done
done
Expand Down

0 comments on commit 5d2f1b5

Please sign in to comment.