github.com/hyperledger/fabric-ca@v2.0.0-alpha.0.20201120210307-7b4f34729db1+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  	var res []string
    41  	const funcName = "MigrateUsersTable"
    42  	if curLevel < 1 {
    43  		log.Debug("Upgrade identity table to level 1")
    44  		_, 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)")
    45  		if err != nil {
    46  			return err
    47  		}
    48  		_, err = tx.Exec(funcName, "ALTER TABLE users ALTER COLUMN attributes TYPE TEXT")
    49  		if err != nil {
    50  			return err
    51  		}
    52  		query := "SELECT column_name  FROM information_schema.columns WHERE table_name='users' and column_name='level'"
    53  		err = tx.Select(funcName, &res, tx.Rebind(query))
    54  		if err != nil {
    55  			return err
    56  		}
    57  		if len(res) == 0 {
    58  			_, err = tx.Exec(funcName, "ALTER TABLE users ADD COLUMN level INTEGER DEFAULT 0")
    59  			if err != nil {
    60  				if !strings.Contains(err.Error(), "already exists") {
    61  					return err
    62  				}
    63  			}
    64  		}
    65  		curLevel++
    66  	}
    67  	if curLevel < 2 {
    68  		log.Debug("Upgrade identity table to level 2")
    69  		query := "SELECT column_name  FROM information_schema.columns WHERE table_name='users' and column_name='incorrect_password_attempts'"
    70  		err := tx.Select(funcName, &res, tx.Rebind(query))
    71  		if err != nil {
    72  			return err
    73  		}
    74  		if len(res) == 0 {
    75  			_, err = tx.Exec(funcName, "ALTER TABLE users ADD COLUMN incorrect_password_attempts INTEGER DEFAULT 0")
    76  			if err != nil {
    77  				if !strings.Contains(err.Error(), "already exists") {
    78  					return err
    79  				}
    80  			}
    81  		}
    82  		curLevel++
    83  	}
    84  
    85  	users, err := user.GetUserLessThanLevel(tx, m.SrvLevels.Identity)
    86  	if err != nil {
    87  		return err
    88  	}
    89  
    90  	for _, u := range users {
    91  		err := u.Migrate(tx)
    92  		if err != nil {
    93  			return err
    94  		}
    95  	}
    96  
    97  	_, err = tx.Exec(funcName, tx.Rebind("UPDATE properties SET value = ? WHERE (property = 'identity.level')"), m.SrvLevels.Identity)
    98  	if err != nil {
    99  		return err
   100  	}
   101  	return nil
   102  }
   103  
   104  // MigrateCertificatesTable is responsible for migrating certificates table
   105  func (m *Migrator) MigrateCertificatesTable() error {
   106  	tx := m.Tx
   107  	const funcName = "MigrateCertificatesTable"
   108  	// Future schema updates should add to the logic below to handle other levels
   109  	if m.CurLevels.Certificate < 1 {
   110  		log.Debug("Upgrade certificates table to level 1")
   111  		var res []string
   112  		query := "SELECT column_name  FROM information_schema.columns WHERE table_name='certificates' and column_name='level'"
   113  		err := tx.Select(funcName, &res, tx.Rebind(query))
   114  		if err != nil {
   115  			return err
   116  		}
   117  		if len(res) == 0 {
   118  			_, err := tx.Exec(funcName, "ALTER TABLE certificates ADD COLUMN level INTEGER DEFAULT 0")
   119  			if err != nil {
   120  				if !strings.Contains(err.Error(), "already exists") {
   121  					return err
   122  				}
   123  			}
   124  		}
   125  		_, err = tx.Exec(funcName, "ALTER TABLE certificates ALTER COLUMN id TYPE VARCHAR(255)")
   126  		if err != nil {
   127  			return err
   128  		}
   129  	}
   130  	_, err := tx.Exec(funcName, tx.Rebind("UPDATE properties SET value = ? WHERE (property = 'certificate.level')"), m.SrvLevels.Certificate)
   131  	if err != nil {
   132  		return err
   133  	}
   134  	return nil
   135  }
   136  
   137  // MigrateAffiliationsTable is responsible for migrating affiliations table
   138  func (m *Migrator) MigrateAffiliationsTable() error {
   139  	tx := m.Tx
   140  	const funcName = "MigrateAffiliationsTable"
   141  	// Future schema updates should add to the logic below to handle other levels
   142  	if m.CurLevels.Affiliation < 1 {
   143  		log.Debug("Upgrade affiliations table to level 1")
   144  		var res []string
   145  		query := "SELECT column_name  FROM information_schema.columns WHERE table_name='affiliations' and column_name='level'"
   146  		err := tx.Select(funcName, &res, tx.Rebind(query))
   147  		if err != nil {
   148  			return err
   149  		}
   150  		if len(res) == 0 {
   151  			_, err := tx.Exec(funcName, "ALTER TABLE affiliations ADD COLUMN level INTEGER DEFAULT 0")
   152  			if err != nil {
   153  				if !strings.Contains(err.Error(), "already exists") {
   154  					return err
   155  				}
   156  			}
   157  		}
   158  		_, err = tx.Exec(funcName, "ALTER TABLE affiliations ALTER COLUMN name TYPE VARCHAR(1024), ALTER COLUMN prekey TYPE VARCHAR(1024)")
   159  		if err != nil {
   160  			return err
   161  		}
   162  	}
   163  	_, err := tx.Exec(funcName, tx.Rebind("UPDATE properties SET value = ? WHERE (property = 'affiliation.level')"), m.SrvLevels.Affiliation)
   164  	if err != nil {
   165  		return err
   166  	}
   167  	return nil
   168  }
   169  
   170  // MigrateCredentialsTable is responsible for migrating credentials table
   171  func (m *Migrator) MigrateCredentialsTable() error {
   172  	_, err := m.Tx.Exec("MigrateCredentialsTable", m.Tx.Rebind("UPDATE properties SET value = ? WHERE (property = 'credential.level')"), m.SrvLevels.Credential)
   173  	return err
   174  }
   175  
   176  // MigrateRAInfoTable is responsible for migrating rainfo table
   177  func (m *Migrator) MigrateRAInfoTable() error {
   178  	_, err := m.Tx.Exec("MigrateRAInfoTable", m.Tx.Rebind("UPDATE properties SET value = ? WHERE (property = 'rcinfo.level')"), m.SrvLevels.RAInfo)
   179  	return err
   180  }
   181  
   182  // MigrateNoncesTable is responsible for migrating nonces table
   183  func (m *Migrator) MigrateNoncesTable() error {
   184  	_, err := m.Tx.Exec("MigrateNoncesTable", m.Tx.Rebind("UPDATE properties SET value = ? WHERE (property = 'nonce.level')"), m.SrvLevels.Nonce)
   185  	return err
   186  }
   187  
   188  // Rollback is responsible for rollback transaction if an error is encountered
   189  func (m *Migrator) Rollback() error {
   190  	err := m.Tx.Rollback("Migration")
   191  	if err != nil {
   192  		log.Errorf("Error encountered while rolling back database migration changes: %s", err)
   193  		return err
   194  	}
   195  	return nil
   196  }
   197  
   198  // Commit is responsible for committing the migration db transcation
   199  func (m *Migrator) Commit() error {
   200  	err := m.Tx.Commit("Migration")
   201  	if err != nil {
   202  		return errors.Wrap(err, "Error encountered while committing database migration changes")
   203  	}
   204  	return nil
   205  }