2024-05-30 09:35:30 +00:00
package mirror
import (
"bytes"
_ "embed"
"strings"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/zitadel/logging"
"github.com/zitadel/zitadel/cmd/key"
)
var (
instanceIDs [ ] string
isSystem bool
shouldReplace bool
)
2024-07-18 14:00:58 +00:00
func New ( configFiles * [ ] string ) * cobra . Command {
2024-05-30 09:35:30 +00:00
cmd := & cobra . Command {
Use : "mirror" ,
Short : "mirrors all data of ZITADEL from one database to another" ,
Long : ` mirrors all data of ZITADEL from one database to another
ZITADEL needs to be initialized and set up with -- for - mirror
The command does mirror all data needed and recomputes the projections .
For more details call the help functions of the sub commands .
Order of execution :
1. mirror system tables
2. mirror auth tables
3. mirror event store tables
4. recompute projections
5. verify ` ,
2024-06-10 09:46:28 +00:00
PersistentPreRun : func ( cmd * cobra . Command , args [ ] string ) {
err := viper . MergeConfig ( bytes . NewBuffer ( defaultConfig ) )
logging . OnError ( err ) . Fatal ( "unable to read default config" )
2024-07-18 14:00:58 +00:00
for _ , file := range * configFiles {
viper . SetConfigFile ( file )
err := viper . MergeInConfig ( )
logging . WithFields ( "file" , file ) . OnError ( err ) . Warn ( "unable to read config file" )
}
2024-06-10 09:46:28 +00:00
} ,
2024-05-30 09:35:30 +00:00
Run : func ( cmd * cobra . Command , args [ ] string ) {
config := mustNewMigrationConfig ( viper . GetViper ( ) )
projectionConfig := mustNewProjectionsConfig ( viper . GetViper ( ) )
masterKey , err := key . MasterKey ( cmd )
logging . OnError ( err ) . Fatal ( "unable to read master key" )
copySystem ( cmd . Context ( ) , config )
copyAuth ( cmd . Context ( ) , config )
copyEventstore ( cmd . Context ( ) , config )
projections ( cmd . Context ( ) , projectionConfig , masterKey )
verifyMigration ( cmd . Context ( ) , config )
} ,
}
mirrorFlags ( cmd )
cmd . Flags ( ) . BoolVar ( & shouldIgnorePrevious , "ignore-previous" , false , "ignores previous migrations of the events table" )
cmd . Flags ( ) . BoolVar ( & shouldReplace , "replace" , false , ` replaces all data of the following tables for the provided instances or all if the "--system" - flag is set :
* system . assets
* auth . auth_requests
* eventstore . unique_constraints
The flag should be provided if you want to execute the mirror command multiple times so that the static data are also mirrored to prevent inconsistent states . ` )
migrateProjectionsFlags ( cmd )
cmd . AddCommand (
eventstoreCmd ( ) ,
systemCmd ( ) ,
projectionsCmd ( ) ,
authCmd ( ) ,
verifyCmd ( ) ,
)
return cmd
}
func mirrorFlags ( cmd * cobra . Command ) {
cmd . PersistentFlags ( ) . StringSliceVar ( & instanceIDs , "instance" , nil , "id or comma separated ids of the instance(s) to migrate. Either this or the `--system`-flag must be set. Make sure to always use the same flag if you execute the command multiple times." )
cmd . PersistentFlags ( ) . BoolVar ( & isSystem , "system" , false , "migrates the whole system. Either this or the `--instance`-flag must be set. Make sure to always use the same flag if you execute the command multiple times." )
cmd . MarkFlagsOneRequired ( "system" , "instance" )
cmd . MarkFlagsMutuallyExclusive ( "system" , "instance" )
}
func instanceClause ( ) string {
if isSystem {
return "WHERE instance_id <> ''"
}
for i := range instanceIDs {
instanceIDs [ i ] = "'" + instanceIDs [ i ] + "'"
}
// COPY does not allow parameters so we need to set them directly
return "WHERE instance_id IN (" + strings . Join ( instanceIDs , ", " ) + ")"
}