File: C:/Program Files/MySQL/MySQL Workbench 8.0/modules/db_copy_source_target.py
# Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License, version 2.0,
# as published by the Free Software Foundation.
#
# This program is also distributed with certain software (including
# but not limited to OpenSSL) that is licensed under separate terms, as
# designated in a particular file or component or in included license
# documentation. The authors of MySQL hereby grant you an additional
# permission to link the program and your derivative works with the
# separately licensed software that they have included with MySQL.
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
# the GNU General Public License, version 2.0, for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
import functools
import grt
import mforms
from grt import DBLoginError
from workbench.ui import WizardPage
from migration_source_selection import request_password, test_connectivity
class SourceTargetMainView(WizardPage):
def __init__(self, main):
super(SourceTargetMainView, self).__init__(main, 'Connection Selection')
self._connections = []
def create_ui(self):
self.content.set_padding(20)
self.content.add(mforms.newLabel('''Select the connection for the source MySQL server where databases will be copied from
and the destination server where they should be copied to.'''), False, True)
source_panel = mforms.newPanel(mforms.TitledBoxPanel)
source_panel.set_title('Source MySQL Server')
box = mforms.newBox(False)
box.set_spacing(12)
box.set_padding(8)
box.add(mforms.newLabel('Select the connection for the source MySQL server instance'), False, True)
source_hbox = mforms.newBox(True)
source_hbox.set_spacing(8)
source_hbox.add(mforms.newLabel('Source Connection:'), False, True)
self.source_selector = mforms.newSelector()
source_hbox.add(self.source_selector, True, True)
box.add(source_hbox, False, True)
self.source_connection_status = mforms.newLabel('')
self.source_connection_status.set_color('#aa3333')
box.add(self.source_connection_status, True, True)
self.source_selector.add_changed_callback(functools.partial(self.selector_changed, label=self.source_connection_status, selector=self.source_selector))
source_panel.add(box)
self.content.add(source_panel, False, True)
target_panel = mforms.newPanel(mforms.TitledBoxPanel)
target_panel.set_title('Destination MySQL Server')
tbox = mforms.newBox(False)
tbox.set_spacing(12)
tbox.set_padding(8)
tbox.add(mforms.newLabel('Select the connection object for the destination MySQL server instance'), False, True)
target_hbox = mforms.newBox(True)
target_hbox.set_spacing(8)
target_hbox.add(mforms.newLabel('Target Connection:'), False, True)
self.target_selector = mforms.newSelector()
target_hbox.add(self.target_selector, True, True)
tbox.add(target_hbox, False, True)
self.target_connection_status = mforms.newLabel('')
self.target_connection_status.set_color('#aa3333')
tbox.add(self.target_connection_status, True, True)
self.target_selector.add_changed_callback(functools.partial(self.selector_changed, label=self.target_connection_status, selector=self.target_selector))
target_panel.add(tbox)
self.content.add(target_panel, False, True)
self.advanced_button.set_text('Test Connections')
self.back_button.set_enabled(False)
self.load_connections()
def selector_changed(self, label, selector):
self.connections_ok = False
label.set_text('')
if selector.get_selected_index() == selector.get_item_count()-1:
grt.modules.Workbench.showConnectionManager()
self.load_connections()
def load_connections(self):
def formatConnection(conn):
i = conn.hostIdentifier
return i[i.find('@')+1:]
self._connections = [conn for conn in grt.root.wb.rdbmsMgmt.storedConns if conn.driver]
selector_items = ( ['Pick a Connection'] +
['%s (%s)' % (conn.name, formatConnection(conn)) for conn in self._connections] +
['-', 'Edit Connections...'] )
self.source_selector.clear()
self.source_selector.add_items(selector_items)
self.source_connection_status.set_text('')
self.source_selector.set_selected(0)
self.target_selector.clear()
self.target_selector.add_items(selector_items)
self.target_connection_status.set_text('')
self.target_selector.set_selected(0)
self.connections_ok = False
def test_connection(self, source, caption):
info_label = self.source_connection_status if caption=='Source' else self.target_connection_status
info_label.set_text('Testing network connectivity...')
info_label.set_color('#aa3333')
if test_connectivity(source.connection, 'Test %s DBMS Connection' % caption) == False:
info_label.set_text('Server could not be contacted')
return
info_label.set_text('Testing connection to DBMS...')
force_password = False
attempt = 0
while True:
try:
if not source.connect():
info_label.set_text('Could not connect to DBMS')
self.connections_ok = False
return
info_label.set_color('#33aa33')
info_label.set_text('Connection succeeded.')
self.connections_ok = True
break
except (DBLoginError, SystemError) as e:
if attempt > 0:
if isinstance(e, DBLoginError) and not force_password:
force_password = True
else:
etext = str(e)
if etext.startswith('Error(') and ': error calling ' in etext:
try:
etext = eval(etext[7:etext.rfind('):')-1], {}, {})[1]
except:
pass
info_label.set_text('Could not connect to DBMS: %s' % etext)
self.connections_ok = False
return
attempt += 1
username = source.connection.parameterValues.userName
storage_string = source.connection.hostIdentifier
source.password = request_password(source.connection, username, storage_string, force_password)
except Exception as e:
etext = str(e)
if etext.startswith('Error(') and etext.endswith(')'):
etext = eval(etext[6:-1], {}, {})[1]
info_label.set_text('Could not connect to DBMS: %s' % etext)
self.connections_ok = False
@property
def source_connection(self):
i = self.source_selector.get_selected_index()
return self._connections[i-1] if 0 < i < len(self._connections)+1 else None
@property
def target_connection(self):
i = self.target_selector.get_selected_index()
return self._connections[i-1] if 0 < i < len(self._connections)+1 else None
def go_advanced(self):
if self.source_connection:
self.main.plan.setSourceConnection(self.source_connection)
self.test_connection(self.main.plan.migrationSource, 'Source')
else:
self.source_connection_status.set_text('Please select a connection')
self.source_connection_status.set_color('#aa3333')
self.connections_ok = False
if self.target_connection and self.source_connection == self.target_connection:
self.target_connection_status.set_text('Select different connections for source and target')
self.target_connection_status.set_color('#aa3333')
self.connections_ok = False
elif self.target_connection:
self.main.plan.setTargetConnection(self.target_connection)
self.test_connection(self.main.plan.migrationTarget, 'Target')
else:
self.target_connection_status.set_text('Please select a connection')
self.target_connection_status.set_color('#aa3333')
self.connections_ok = False
def go_next(self):
if not self.connections_ok:
self.go_advanced()
if not self.connections_ok:
return
set_status_text = mforms.App.get().set_status_text
set_status_text('Connecting to source DBMS...')
# Set source connection and connect:
self.main.plan.setSourceConnection(self.source_connection)
self.main.plan.migrationSource.connect()
# Set target connection and connect:
set_status_text('Connecting to target DBMS...')
self.main.plan.setTargetConnection(self.target_connection)
self.main.plan.migrationTarget.connect()
# Fetch schema names:
set_status_text('Fetching schema names...')
self.main.plan.migrationSource.doFetchSchemaNames()
set_status_text('Ready')
super(SourceTargetMainView, self).go_next()