github.com/adecaro/fabric-ca@v2.0.0-alpha+incompatible/lib/server/db/postgres/migrator.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package postgres
     8  
     9  import (
    10  	"strings"
    11  
    12  	"github.com/cloudflare/cfssl/log"
    13  	"github.com/hyperledger/fabric-ca/lib/server/db"
    14  	"github.com/hyperledger/fabric-ca/lib/server/db/util"
    15  	"github.com/hyperledger/fabric-ca/lib/server/user"
    16  	"github.com/pkg/errors"
    17  )
    18  
    19  // Migrator defines migrator
    20  type Migrator struct {
    21  	Tx        db.FabricCATx
    22  	CurLevels *util.Levels
    23  	SrvLevels *util.Levels
    24  }
    25  
    26  // NewMigrator returns a migrator instance
    27  func NewMigrator(tx db.FabricCATx, curLevels, srvLevels *util.Levels) *Migrator {
    28  	return &Migrator{
    29  		Tx:        tx,
    30  		CurLevels: curLevels,
    31  		SrvLevels: srvLevels,
    32  	}
    33  }
    34  
    35  // MigrateUsersTable is responsible for migrating users table
    36  func (m *Migrator) MigrateUsersTable() error {
    37  	tx := m.Tx
    38  	// Future schema updates should add to the logic below to handle other levels
    39  	curLevel := m.CurLevels.Identity
    40  	res := []struct {
    41  		columnName string `db:"column_name"`
    42  	}{}
    43  	const funcName = "MigrateUsersTable"
    44  	if curLevel < 1 {
    45  		log.Debug("Upgrade identity table to level 1")
    46  		_, err := tx.Exec(funcName, "ALTER TABLE users ALTER COLUMN id TYPE VARCHAR(255), ALTER COLUMN type TYPE VARCHAR(256), ALTER COLUMN affiliation TYPE VARCHAR(1024)")
    47  		if err != nil {
    48  			return err
    49  		}
    50  		_, err = tx.Exec(funcName, "ALTER TABLE users ALTER COLUMN attributes TYPE TEXT")
    51  		if err != nil {
    52  			return err
    53  		}
    54  		query := "SELECT column_name  FROM information_schema.columns WHERE table_name='users' and column_name='level'"
    55  		err = tx.Select(funcName, &res, tx.Rebind(query))
    56  		if err != nil {
    57  			return err
    58  		}
    59  		if len(res) == 0 {
    60  			_, err = tx.Exec(funcName, "ALTER TABLE users ADD COLUMN level INTEGER DEFAULT 0")
    61  			if err != nil {
    62  				if !strings.Contains(err.Error(), "already exists") {
    63  					return err
    64  				}
    65  			}
    66  		}
    67  		curLevel++
    68  	}
    69  	if curLevel < 2 {
    70  		log.Debug("Upgrade identity table to level 2")
    71  		query := "SELECT column_name  FROM information_schema.columns WHERE table_name='users' and column_name='incorrect_password_attempts'"
    72  		err := tx.Select(funcName, &res, tx.Rebind(query))
    73  		if err != nil {
    74  			return err
    75  		}
    76  		if len(res) == 0 {
    77  			_, err = tx.Exec(funcName, "ALTER TABLE users ADD COLUMN incorrect_password_attempts INTEGER DEFAULT 0")
    78  			if err != nil {
    79  				if !strings.Contains(err.Error(), "already exists") {
    80  					return err
    81  				}
    82  			}
    83  		}
    84  		curLevel++
    85  	}
    86  
    87  	users, err := user.GetUserLessThanLevel(tx, m.SrvLevels.Identity)
    88  	if err != nil {
    89  		return err
    90  	}
    91  
    92  	for _, u := range users {
    93  		err := u.Migrate(tx)
    94  		if err != nil {
    95  			return err
    96  		}
    97  	}
    98  
    99  	_, err = tx.Exec(funcName, tx.Rebind("UPDATE properties SET value = ? WHERE (property = 'identity.level')"), m.SrvLevels.Identity)
   100  	if err != nil {
   101  		return err
   102  	}
   103  	return nil
   104  }
   105  
   106  // MigrateCertificatesTable is responsible for migrating certificates table
   107  func (m *Migrator) MigrateCertificatesTable() error {
   108  	tx := m.Tx
   109  	const funcName = "MigrateCertificatesTable"
   110  	// Future schema updates should add to the logic below to handle other levels
   111  	if m.CurLevels.Certificate < 1 {
   112  		log.Debug("Upgrade certificates table to level 1")
   113  		res := []struct {
   114  			columnName string `db:"column_name"`
   115  		}{}
   116  		query := "SELECT column_name  FROM information_schema.columns WHERE table_name='certificates' and column_name='level'"
   117  		err := tx.Select(funcName, &res, tx.Rebind(query))
   118  		if err != nil {
   119  			return err
   120  		}
   121  		if len(res) == 0 {
   122  			_, err := tx.Exec(funcName, "ALTER TABLE certificates ADD COLUMN level INTEGER DEFAULT 0")
   123  			if err != nil {
   124  				if !strings.Contains(err.Error(), "already exists") {
   125  					return err
   126  				}
   127  			}
   128  		}
   129  		_, err = tx.Exec(funcName, "ALTER TABLE certificates ALTER COLUMN id TYPE VARCHAR(255)")
   130  		if err != nil {
   131  			return err
   132  		}
   133  	}
   134  	_, err := tx.Exec(funcName, tx.Rebind("UPDATE properties SET value = ? WHERE (property = 'certificate.level')"), m.SrvLevels.Certificate)
   135  	if err != nil {
   136  		return err
   137  	}
   138  	return nil
   139  }
   140  
   141  // MigrateAffiliationsTable is responsible for migrating affiliations table
   142  func (m *Migrator) MigrateAffiliationsTable() error {
   143  	tx := m.Tx
   144  	const funcName = "MigrateAffiliationsTable"
   145  	// Future schema updates should add to the logic below to handle other levels
   146  	if m.CurLevels.Affiliation < 1 {
   147  		log.Debug("Upgrade affiliations table to level 1")
   148  		res := []struct {
   149  			columnName string `db:"column_name"`
   150  		}{}
   151  		query := "SELECT column_name  FROM information_schema.columns WHERE table_name='affiliations' and column_name='level'"
   152  		err := tx.Select(funcName, &res, tx.Rebind(query))
   153  		if err != nil {
   154  			return err
   155  		}
   156  		if len(res) == 0 {
   157  			_, err := tx.Exec(funcName, "ALTER TABLE affiliations ADD COLUMN level INTEGER DEFAULT 0")
   158  			if err != nil {
   159  				if !strings.Contains(err.Error(), "already exists") {
   160  					return err
   161  				}
   162  			}
   163  		}
   164  		_, err = tx.Exec(funcName, "ALTER TABLE affiliations ALTER COLUMN name TYPE VARCHAR(1024), ALTER COLUMN prekey TYPE VARCHAR(1024)")
   165  		if err != nil {
   166  			return err
   167  		}
   168  	}
   169  	_, err := tx.Exec(funcName, tx.Rebind("UPDATE properties SET value = ? WHERE (property = 'affiliation.level')"), m.SrvLevels.Affiliation)
   170  	if err != nil {
   171  		return err
   172  	}
   173  	return nil
   174  }
   175  
   176  // MigrateCredentialsTable is responsible for migrating credentials table
   177  func (m *Migrator) MigrateCredentialsTable() error {
   178  	_, err := m.Tx.Exec("MigrateCredentialsTable", m.Tx.Rebind("UPDATE properties SET value = ? WHERE (property = 'credential.level')"), m.SrvLevels.Credential)
   179  	return err
   180  }
   181  
   182  // MigrateRAInfoTable is responsible for migrating rainfo table
   183  func (m *Migrator) MigrateRAInfoTable() error {
   184  	_, err := m.Tx.Exec("MigrateRAInfoTable", m.Tx.Rebind("UPDATE properties SET value = ? WHERE (property = 'rcinfo.level')"), m.SrvLevels.RAInfo)
   185  	return err
   186  }
   187  
   188  // MigrateNoncesTable is responsible for migrating nonces table
   189  func (m *Migrator) MigrateNoncesTable() error {
   190  	_, err := m.Tx.Exec("MigrateNoncesTable", m.Tx.Rebind("UPDATE properties SET value = ? WHERE (property = 'nonce.level')"), m.SrvLevels.Nonce)
   191  	return err
   192  }
   193  
   194  // Rollback is responsible for rollback transaction if an error is encountered
   195  func (m *Migrator) Rollback() error {
   196  	err := m.Tx.Rollback("Migration")
   197  	if err != nil {
   198  		log.Errorf("Error encountered while rolling back database migration changes: %s", err)
   199  		return err
   200  	}
   201  	return nil
   202  }
   203  
   204  // Commit is responsible for committing the migration db transcation
   205  func (m *Migrator) Commit() error {
   206  	err := m.Tx.Commit("Migration")
   207  	if err != nil {
   208  		return errors.Wrap(err, "Error encountered while committing database migration changes")
   209  	}
   210  	return nil
   211  }