Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 58
0.00% covered (danger)
0.00%
0 / 2
CRAP
0.00% covered (danger)
0.00%
0 / 1
MigrateCentralWiki
0.00% covered (danger)
0.00%
0 / 52
0.00% covered (danger)
0.00%
0 / 2
90
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
2
 execute
0.00% covered (danger)
0.00%
0 / 43
0.00% covered (danger)
0.00%
0 / 1
72
1<?php
2
3namespace MediaWiki\Extension\OAuth;
4
5/**
6 * Migrate oauth_registered_consumer and oauth_accepted_consumer tables to a
7 * new database with minimal downtime. This script assumes relatively small tables
8 * (The WMF has <100 consumers and aout 1000 authorizations right now).
9 *
10 * To migrate to a new central wiki within your cluster, you roughly want to:
11 * 1. Set $wgMWOAuthReadOnly = true for all wikis in your running config
12 * 2. Move the oauth_registered_consumer and oauth_accepted_consumer tables with this script
13 * 3. Update the cluster config to point to the new central wiki
14 * 4. Set $wgMWOAuthReadOnly back to false, so users can manage their consumers as normal.
15 * 5. Migrate the OAuth logs using importCentralWikiLogs.php.
16 * 6. Done!
17 *
18 * @ingroup Maintenance
19 */
20if ( getenv( 'MW_INSTALL_PATH' ) ) {
21    $IP = getenv( 'MW_INSTALL_PATH' );
22} else {
23    $IP = __DIR__ . '/../../..';
24}
25
26require_once "$IP/maintenance/Maintenance.php";
27
28use Maintenance;
29use MediaWiki\Extension\OAuth\Backend\Consumer;
30use MediaWiki\Extension\OAuth\Backend\ConsumerAcceptance;
31use MediaWiki\Extension\OAuth\Backend\MWOAuthDAO;
32use MediaWiki\MediaWikiServices;
33
34class MigrateCentralWiki extends Maintenance {
35    public function __construct() {
36        parent::__construct();
37        $this->addDescription( "Migrate central wiki from one wiki to another. " .
38            "OAuth should be in Read Only mode while this is running." );
39        $this->addOption( 'old', 'Previous central wiki', true, true );
40        $this->addOption( 'target', 'New central wiki', true, true );
41        $this->addOption( 'table',
42            'Table name (oauth_registered_consumer or oauth_accepted_consumer)', true, true );
43        $this->setBatchSize( 200 );
44        $this->requireExtension( "OAuth" );
45    }
46
47    public function execute() {
48        $oldWiki = $this->getOption( 'old' );
49        $targetWiki = $this->getOption( 'target' );
50        $table = $this->getOption( 'table' );
51
52        if ( $table === 'oauth_registered_consumer' ) {
53            $idKey = 'oarc_id';
54            $cmrClass = Consumer::class;
55            $type = 'consumer';
56        } elseif ( $table === 'oauth_accepted_consumer' ) {
57            $idKey = 'oaac_id';
58            $cmrClass = ConsumerAcceptance::class;
59            $type = 'grant';
60        } else {
61            $this->fatalError( "Invalid table name. Must be one of 'oauth_registered_consumer' " .
62                "or 'oauth_accepted_consumer'.\n" );
63        }
64
65        $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
66        $oldDb = $lbFactory->getMainLB( $oldWiki )->getConnection( DB_PRIMARY, [], $oldWiki );
67        $targetDb = $lbFactory->getMainLB( $targetWiki )
68            ->getConnection( DB_PRIMARY, [], $targetWiki );
69
70        $newMax = $targetDb->selectField(
71            $table,
72            "MAX($idKey)",
73            [],
74            __METHOD__
75        );
76
77        $oldMax = $oldDb->selectField(
78            $table,
79            "MAX($idKey)",
80            [],
81            __METHOD__
82        );
83
84        if ( $newMax >= $oldMax ) {
85            $this->output( "No new rows.\n" );
86        }
87
88        $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
89
90        for ( $currentId = $newMax + 1, $i = 1; $currentId <= $oldMax; ++$currentId, ++$i ) {
91            $this->output( "Migrating $type $currentId..." );
92            /** @var MWOAuthDAO $cmrClass */
93            $cmr = $cmrClass::newFromId( $oldDb, $currentId );
94            if ( $cmr ) {
95                $cmr->updateOrigin( 'new' );
96                $cmr->setPending( true );
97                $cmr->save( $targetDb );
98                $this->output( "done.\n" );
99            } else {
100                $this->output( "missing.\n" );
101            }
102
103            if ( $this->mBatchSize && $i % $this->mBatchSize === 0 ) {
104                $lbFactory->waitForReplication( [ 'domain' => $targetWiki ] );
105            }
106        }
107    }
108
109}
110
111$maintClass = MigrateCentralWiki::class;
112require_once RUN_MAINTENANCE_IF_MAIN;