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 }