github.com/hyperledger/fabric-ca@v2.0.0-alpha.0.20201120210307-7b4f34729db1+incompatible/lib/server/db/mysql/migrator.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package mysql
     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  	const funcName = "MigrateUsersTable"
    39  	// Future schema updates should add to the logic below to handle other levels
    40  	curLevel := m.CurLevels.Identity
    41  	if curLevel < 1 {
    42  		log.Debug("Upgrade identity table to level 1")
    43  		_, err := tx.Exec(funcName, "ALTER TABLE users MODIFY id VARCHAR(255), MODIFY type VARCHAR(256), MODIFY affiliation VARCHAR(1024)")
    44  		if err != nil {
    45  			return err
    46  		}
    47  		_, err = tx.Exec(funcName, "ALTER TABLE users MODIFY attributes TEXT")
    48  		if err != nil {
    49  			return err
    50  		}
    51  		_, err = tx.Exec(funcName, "ALTER TABLE users ADD COLUMN level INTEGER DEFAULT 0 AFTER max_enrollments")
    52  		if err != nil {
    53  			if !strings.Contains(err.Error(), "1060") { // Already using the latest schema
    54  				return err
    55  			}
    56  		}
    57  		curLevel++
    58  	}
    59  	if curLevel < 2 {
    60  		log.Debug("Upgrade identity table to level 2")
    61  		_, err := tx.Exec(funcName, "ALTER TABLE users ADD COLUMN incorrect_password_attempts INTEGER DEFAULT 0 AFTER level")
    62  		if err != nil {
    63  			if !strings.Contains(err.Error(), "1060") { // Already using the latest schema
    64  				return err
    65  			}
    66  		}
    67  		curLevel++
    68  	}
    69  
    70  	users, err := user.GetUserLessThanLevel(tx, m.SrvLevels.Identity)
    71  	if err != nil {
    72  		return err
    73  	}
    74  
    75  	for _, u := range users {
    76  		err := u.Migrate(tx)
    77  		if err != nil {
    78  			return err
    79  		}
    80  	}
    81  
    82  	_, err = tx.Exec(funcName, tx.Rebind("UPDATE properties SET value = ? WHERE (property = 'identity.level')"), m.SrvLevels.Identity)
    83  	if err != nil {
    84  		return err
    85  	}
    86  	return nil
    87  }
    88  
    89  // MigrateCertificatesTable is responsible for migrating certificates table
    90  func (m *Migrator) MigrateCertificatesTable() error {
    91  	tx := m.Tx
    92  	const funcName = "MigrateCertificatesTable"
    93  	// Future schema updates should add to the logic below to handle other levels
    94  	curLevel := m.CurLevels.Certificate
    95  	if curLevel < 1 {
    96  		log.Debug("Upgrade certificates table to level 1")
    97  		_, err := tx.Exec(funcName, "ALTER TABLE certificates ADD COLUMN level INTEGER DEFAULT 0 AFTER pem")
    98  		if err != nil {
    99  			if !strings.Contains(err.Error(), "1060") { // Already using the latest schema
   100  				return err
   101  			}
   102  		}
   103  		_, err = tx.Exec(funcName, "ALTER TABLE certificates MODIFY id VARCHAR(255)")
   104  		if err != nil {
   105  			return err
   106  		}
   107  		curLevel++
   108  	}
   109  	if curLevel < 2 {
   110  		log.Debug("Upgrade certificates table to level 2")
   111  		_, err := tx.Exec(funcName, "ALTER TABLE certificates MODIFY pem varbinary(8192)")
   112  		if err != nil {
   113  			return err
   114  		}
   115  		curLevel++
   116  	}
   117  
   118  	_, err := tx.Exec(funcName, tx.Rebind("UPDATE properties SET value = ? WHERE (property = 'certificate.level')"), m.SrvLevels.Certificate)
   119  	if err != nil {
   120  		return err
   121  	}
   122  	return nil
   123  }
   124  
   125  // MigrateAffiliationsTable is responsible for migrating affiliations table
   126  func (m *Migrator) MigrateAffiliationsTable() error {
   127  	tx := m.Tx
   128  	const funcName = "MigrateAffiliationsTable"
   129  	// Future schema updates should add to the logic below to handle other levels
   130  	if m.CurLevels.Affiliation < 1 {
   131  		log.Debug("Upgrade affiliations table to level 1")
   132  		_, err := tx.Exec(funcName, "ALTER TABLE affiliations ADD COLUMN level INTEGER DEFAULT 0 AFTER prekey")
   133  		if err != nil {
   134  			if !strings.Contains(err.Error(), "1060") { // Already using the latest schema
   135  				return err
   136  			}
   137  		}
   138  		_, err = tx.Exec(funcName, "ALTER TABLE affiliations DROP INDEX name;")
   139  		if err != nil {
   140  			if !strings.Contains(err.Error(), "Error 1091") { // Indicates that index not found
   141  				return err
   142  			}
   143  		}
   144  		_, err = tx.Exec(funcName, "ALTER TABLE affiliations ADD COLUMN id INT NOT NULL PRIMARY KEY AUTO_INCREMENT FIRST")
   145  		if err != nil {
   146  			if !strings.Contains(err.Error(), "1060") { // Already using the latest schema
   147  				return err
   148  			}
   149  		}
   150  		_, err = tx.Exec(funcName, "ALTER TABLE affiliations MODIFY name VARCHAR(1024), MODIFY prekey VARCHAR(1024)")
   151  		if err != nil {
   152  			return err
   153  		}
   154  		_, err = tx.Exec(funcName, "ALTER TABLE affiliations ADD INDEX name_index (name)")
   155  		if err != nil {
   156  			if !strings.Contains(err.Error(), "Error 1061") { // Error 1061: Duplicate key name, index already exists
   157  				return err
   158  			}
   159  		}
   160  	}
   161  
   162  	_, err := tx.Exec(funcName, tx.Rebind("UPDATE properties SET value = ? WHERE (property = 'affiliation.level')"), m.SrvLevels.Affiliation)
   163  	if err != nil {
   164  		return err
   165  	}
   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  }