1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890
|
# Copyright (c) 2009, 2016, 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 as
# published by the Free Software Foundation; version 2 of the
# License.
#
# 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 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
from wb import DefineModule, wbinputs
import grt
import os
import sys
from mforms import Utilities, newButton, newLabel, newBox
import mforms
import wb_admin_main
import wb_admin_utils
import wba_ssh_ui
import wb_admin_ssh
import wb_admin_control
from wb_server_control import PasswordHandler
from wb_server_control import ServerProfile
from workbench.db_utils import MySQLConnection, MySQLError, escape_sql_string
from wb_common import OperationCancelledError, InvalidPasswordError, NoDriverInConnection
from workbench.utils import Version
from workbench.notifications import NotificationCenter
from workbench.log import log_info, log_warning, log_error, log_debug, log_debug2
# How the Administrator Module Works
# ----------------------------------
#
# = Initial Setup
#
# When the Workbench starts up, the initialize() function from this module is called.
# That will do the following:
# - register an observer for the GRNSQLEditorOpened notification.
# - register all built-in pages of the administrator
# - register all extension pages of the administrator
#
# = When GRNSQLEditorOpened is received
#
# An instance of AdministratorContext is created, which will hook the various admin
# page sections to the SQL Editor sidebar and save a reference to itself in the SQL Editor
# object's customData dictionary.
# No other initialization is done at this time (ie, no DB connections or GUI is setup).
#
# = When an admin item is selected in the sidebar
#
# - Setup the main admin GUI view and dock it to the SQL Editor.
# - If the entry requires a ssh connection, it will try to open that connection and the
# admin specific DB connection, unless it's already connected.
# If not, it will open the DB connection only.
# - Then it will setup the GUI for the requested admin page and dock it/switch to it.
#
# define this Python module as a GRT module
ModuleInfo = DefineModule(name= "WbAdmin", author= "Oracle Corp.", version="2.0")
class DBError(Exception):
pass
#-------------------------------------------------------------------------------
wba_page_modules = []
#===============================================================================
#
#===============================================================================
class AdministratorContext:
"""
An instance of the WBA, associated to a SQL Editor.
This is created when a GRNSQLEditorOpened notification is received.
Initially, only the different sections of the WBA are added to the sidebar
and the GUI itself is not initialized until the user enters each section.
"""
def __init__(self, editor):
self.editor = editor
self.connection = self.editor.connection
self.server_profile = None
self.admin_pages = {}
self.page_instances = {}
self.page_titles = {}
self.disabled_pages = {}
self.admin_tab = None
self.error_box = None
self.ctrl_be = None
self.admin_access_status = None # None means OK
self.sidebar = mforms.fromgrt(editor.sidebar)
self.sidebar.add_on_section_command_callback(self._sidebar_entry_clicked)
self.sidebar_sections = [("wba_management", "MANAGEMENT", []), ("wba_instance", "INSTANCE", []), ("wba_performance", "PERFORMANCE", [])]
self.shown_in_sidebar = False
for mod in wba_page_modules:
mod.wba_register(self)
# create server profile now, since we need it to be able to tell whether instance items should be enabled in sidebar
self._check_instance_profile()
self.show_in_sidebar()
@property
def instance_profile(self):
for instance in grt.root.wb.rdbmsMgmt.storedInstances:
if instance.connection == self.connection:
return instance
return None
@property
def instance_management_enabled(self):
return self.instance_profile != None
def handle_close(self):
grt.root.wb.options.options['Administrator:sidebar_collapsed_sections'] = self.sidebar.get_collapse_states()
#del self.editor.customData["adminContext"]
self.admin_tab = None
self.ctrl_be = None
self.admin_access_status = None
self.page_instances = {}
self.sidebar.clear_selection()
def handle_reconnect(self):
# Called when SQL Editor sends a reconnected notification
if self.ctrl_be:
self.ctrl_be.event_from_main("server_started")
def _check_instance_profile(self):
self.server_profile = ServerProfile(self.connection, self.instance_profile, False)
# if no instance info exists, try to auto-detect them
if self.instance_profile is None:
if self.server_profile.is_local:
if autoDetectLocalInstance(self.connection):
grt.log_info("Admin", "Auto-created instance profile for connection %s\n" % self.connection.name)
# Retry
self.server_profile = ServerProfile(self.connection, self.instance_profile, False)
else:
if autoDetectRemoteInstance(self.connection):
grt.log_info("Admin", "Auto-created dummy instance profile for remote connection %s\n" % self.connection.name)
# Retry
self.server_profile = ServerProfile(self.connection, self.instance_profile, False)
def _acquire_admin_access(self):
if not self._validate_remote_admin_settings():
self.admin_access_status = "Remote management settings are invalid"
return
while True:
try:
mforms.App.get().set_status_text("Acquiring management access to target host...")
self.ctrl_be.acquire_admin_access()
mforms.App.get().set_status_text("Management support for target host enabled successfully.")
return True
except wb_admin_ssh.ConnectionError, exc:
self.admin_access_status = "Remote management capabilities are currently unavailable.\nSSH connection could not be established\n\n%s" % str(exc)
Utilities.show_error("Error opening SSH connection to server (%s@%s)" % (self.instance_profile.loginInfo["ssh.userName"], self.instance_profile.loginInfo["ssh.hostName"]), str(exc), "OK", "", "")
return None
except OperationCancelledError, exc:
self.admin_access_status = "Remote management capabilities are currently unavailable.\nSSH connection was cancelled"
mforms.App.get().set_status_text("Cancelled SSH connection (%s)"%exc)
return None
except InvalidPasswordError, exc:
self.admin_access_status = "Remote management capabilities are currently unavailable.\nCould not acquire management access to the server\n\n%s" % exc
if Utilities.show_error("Could not acquire management access for administration", "%s" % exc, "Retry", "Cancel", "") == mforms.ResultOk:
continue
mforms.App.get().set_status_text("Could not Open WB Admin")
return None
except Exception, exc:
import traceback
traceback.print_exc()
self.admin_access_status = "Remote management capabilities are currently unavailable.\nCould not acquire management access to the server\n\n%s" % exc
mforms.App.get().set_status_text("Could not Open WB Admin")
if Utilities.show_error("Could not acquire management access for administration", "%s: %s" % (type(exc).__name__, exc), "Settings...", "Cancel", "") == mforms.ResultOk:
grt.modules.Workbench.showInstanceManagerFor(self.connection)
return None
def acquire_admin_access(self, ignore_failure=False):
if not self._acquire_admin_access():
if ignore_failure:
return True
if not self.error_box:
self.error_box = mforms.newBox(True)
self.error_box.set_padding(50)
error_label = mforms.newLabel(self.admin_access_status)
error_label.set_style(mforms.BigBoldStyle)
self.error_box.add(error_label, False, True)
self.admin_tab.add_page(self.error_box)
else:
self.admin_tab.select_page(self.error_box)
return False
else:
if self.error_box:
self.admin_tab.remove_page(self.error_box)
self.error_box = None
return True
def _validate_remote_admin_settings(self):
server_instance = self.instance_profile
if not server_instance:
return False
def validate_setting(settings, option, norm_cb, msg):
if settings.has_key(option):
if norm_cb is not None:
norm_cb(settings, option)
else:
if msg is not None:
Utilities.show_warning("WB Administrator", msg, "OK", "", "")
norm_cb(settings, option)
def norm_to_switch(settings, option):
value = 0
if settings.has_key(option):
value = settings[option]
if value > 0:
value = 1
else:
value = 0
settings[option] = value
def make_str_existing(settings, option):
if not settings.has_key(option):
settings[option] = ""
validate_setting(server_instance.serverInfo, "sys.usesudo", norm_to_switch, None)#"Server profile has no indication of sudo usage")
validate_setting(server_instance.serverInfo, "sys.usesudostatus", norm_to_switch, None)
return True
def _dock_admin_tab(self):
app = mforms.App.get()
try:
self.ctrl_be = wb_admin_control.WbAdminControl(self.server_profile, self.editor, connect_sql=True)
self.ctrl_be.init()
self.admin_tab = wb_admin_main.AdministratorTab(self.ctrl_be, self.server_profile, self, self.editor)
except MySQLError, exc:
if exc.message:
Utilities.show_error("Error Connecting to MySQL Server (%s)" % exc.location, str(exc), "OK", "", "")
app.set_status_text("Could not Open WB Admin")
return None
except OperationCancelledError, exc:
app.set_status_text("Cancelled (%s)"%exc)
return None
except NoDriverInConnection, exc:
Utilities.show_error('Missing connection driver', str(exc), 'OK', '', '')
app.set_status_text("Could not Open WB Admin")
return None
except Exception, exc:
import traceback
traceback.print_exc()
Utilities.show_error("Error Starting Workbench Administrator", "%s: %s" % (type(exc).__name__, exc), "OK", "", "")
app.set_status_text("Could not Open WB Admin")
return None
dp = mforms.fromgrt(self.editor.dockingPoint)
dp.dock_view(self.admin_tab, "", 0)
dp.select_view(self.admin_tab)
self.admin_tab.set_title("Administrator")
return self.admin_tab
def become_active_tab(self):
dp = mforms.fromgrt(self.editor.dockingPoint)
dp.select_view(self.admin_tab)
def _sidebar_entry_clicked(self, entry_id):
if entry_id == "configure":
openConnectionSettings(self.editor)
else:
if entry_id in self.disabled_pages:
Utilities.show_error(self.page_titles[entry_id],
self.disabled_pages[entry_id],
"OK", "", "")
return
self.open_into_section(entry_id)
def refresh_admin_links(self):
for ident in self.disabled_pages.keys():
if (not self.server_profile or (self.server_profile and not self.server_profile.is_local and not self.server_profile.remote_admin_enabled)):
pass
else:
del self.disabled_pages[ident]
self.sidebar.set_section_entry_enabled(ident, True)
def open_into_section(self, entry_id, select_item=False):
page_class, needs_remote_access = self.admin_pages.get(entry_id, (None, None))
if page_class is None: # unknown entry from sidebar, not our business
return
# if this is the 1st time opening the WBA, init the main tab and dock it
if self.admin_tab is None:
if not self._dock_admin_tab():
return
page = self.page_instances.get(entry_id)
if not page:
if (needs_remote_access or entry_id == "admin_server_status") and not self.ctrl_be.admin_access_available:
if not self.acquire_admin_access(entry_id == "admin_server_status"):
return
page = page_class(self.ctrl_be, self.server_profile, self.admin_tab)
self.page_instances[entry_id] = page
self.admin_tab.add_page(page)
for sname, stitle, sitems in self.sidebar_sections:
for ident, title, icon_path in sitems:
if ident == entry_id:
self.admin_tab.set_content_label("Administration - %s" % title)
break
self.admin_tab.select_page(page)
def add_section(self, name, title):
if not any(x[0] == name for x in self.sidebar_sections):
self.sidebar_sections.append((name, title, []))
def register_page(self, page_class, section_id, title, needs_remote_access = False):
if not section_id:
section_id = "wba_management" # the default
self.page_titles[page_class.identifier()] = title
self.admin_pages[page_class.identifier()] = (page_class, needs_remote_access)
icon_path = page_class.identifier()+".png"
for sname, stitle, sitems in self.sidebar_sections:
if sname == section_id:
sitems.append((page_class.identifier(), title, icon_path))
break
def show_in_sidebar(self):
if not self.shown_in_sidebar:
if self.editor.serverVersion:
server_version = Version.fromgrt(self.editor.serverVersion)
else:
server_version = None
self.shown_in_sidebar = True
first = True
self.disabled_pages = {}
for sname, stitle, sitems in self.sidebar_sections:
flags = mforms.TaskSectionShowConfigButton if sname == "wba_instance" else mforms.TaskSectionPlain
if first:
flags |= mforms.TaskSectionToggleModeButton
first = False
if grt.root.wb.options.options['DbSqlEditor:SidebarModeCombined'] == 1:
flags |= mforms.TaskSectionToggleModeButtonPreSelected
self.sidebar.add_section(sname, stitle, flags)
for ident, ititle, icon_path in sitems:
self.sidebar.add_section_entry(sname, ident, ititle, icon_path, mforms.TaskEntryAlwaysActiveLink)
mod, requires_remote_access = self.admin_pages.get(ident, (None, True))
enabled = True
if requires_remote_access and (not self.server_profile or (self.server_profile and not self.server_profile.is_local and not self.server_profile.remote_admin_enabled)):
enabled = False
self.disabled_pages[ident] = "Feature requires remote host access.\nClick the wrench icon to configure a remote administration method for this connection."
elif getattr(mod, "min_server_version", None):
if server_version and not server_version.is_supported_mysql_version_at_least(*mod.min_server_version):
enabled = False
self.disabled_pages[ident] = "This feature requires MySQL version %s or newer" % ".".join([str(x) for x in mod.min_server_version])
self.sidebar.set_section_entry_enabled(ident, enabled)
self.sidebar.set_collapse_states(grt.root.wb.options.options.get('Administrator:sidebar_collapsed_sections', ''))
def page_with_id(self, entry_id):
return self.page_instances.get(entry_id)
#-------------------------------------------------------------------------------
def attachToSQLEditor(name, sender, args):
if sender.connection:
# this is called when a new SQL Editor tab is created
# attach our WBA related things to it
context = AdministratorContext(sender)
sender.customData["adminContext"] = grt.togrt(context)
if sender.isConnected <= 0:
ignore = mforms.Utilities.add_timeout(0.1, lambda:context.open_into_section("admin_server_status", True))
del ignore
#-------------------------------------------------------------------------------
def handleReconnect(name, sender, args):
context = grt.fromgrt(sender.customData["adminContext"])
if context and args['connected']:
context.handle_reconnect()
#-------------------------------------------------------------------------------
@ModuleInfo.export(grt.INT)
def initialize():
# this is called when WB finishes initializing itself
# register ourselves for when SQL Editor tabs are opened
nc = NotificationCenter()
nc.add_observer(attachToSQLEditor, name = "GRNSQLEditorOpened")
nc.add_observer(handleReconnect, name = "GRNSQLEditorReconnected")
return 1
# scan for WBA modules at module load time
wba_page_modules = wb_admin_main.scan_admin_modules()
#-------------------------------------------------------------------------------
@ModuleInfo.export(grt.classes.db_mgmt_ServerInstance, grt.classes.db_mgmt_Connection)
def autoDetectLocalInstance(connection):
"""Create a Instance profile for the local server from the connection."""
instance = grt.classes.db_mgmt_ServerInstance()
instance.connection = connection
instance.name = connection.name
instance.serverInfo["setupPending"] = True
version = connection.parameterValues.get("serverVersion", None)
if version:
version = ".".join(version.split(".")[:2])
def get_profiles_for(system, version):
path = mforms.App.get().get_resource_path("mysql.profiles")
if not path:
path = mforms.App.get().get_resource_path("")
if not path:
log_error("Could not find mysql.profiles dir\n")
return []
path += "/mysql.profiles"
version = Version.fromstr(version or "5.6")
files = [f for f in os.listdir(path) if f.endswith(".xml")]
profiles = []
matched_profiles = []
for f in files:
data = grt.unserialize(os.path.join(path, f))
if data and data.has_key("sys.system") and data["sys.system"] == system:
profiles.append(data)
profile_version = Version.fromstr(data.get("serverVersion"))
if version.majorNumber == profile_version.majorNumber or version.minorNumber == profile_version.minorNumber:
matched_profiles.append(data)
if matched_profiles:
return matched_profiles
return profiles
def pick_suitable_linux_profile(profiles):
return profiles[0]
if sys.platform.lower().startswith("win"):
profiles = get_profiles_for("Windows", version)
if profiles:
if version:
profiles = [prof for prof in profiles if prof.get("serverVersion", None) == version]
if profiles:
instance.serverInfo.update(profiles[0])
instance.serverInfo["windowsAdmin"] = 1 # this forces WMI admin for localhost Windows
elif sys.platform.lower() == "darwin":
profiles = get_profiles_for("MacOS X", version)
if profiles:
instance.serverInfo.update(profiles[0])
possible_paths = [instance.serverInfo.get("sys.config.path"), "/etc/my.cnf", "/etc/mysql/my.cnf"]
for p in possible_paths:
if os.path.exists(p):
instance.serverInfo["sys.config.path"] = p
break
elif "linux" in sys.platform.lower():
profiles = get_profiles_for("Linux", version)
if profiles:
profile = pick_suitable_linux_profile(profiles)
instance.serverInfo.update(profile)
possible_paths = [instance.serverInfo.get("sys.config.path"), "/etc/my.cnf", "/etc/mysql/my.cnf"]
for p in possible_paths:
if os.path.exists(p):
instance.serverInfo["sys.config.path"] = p
break
instance.loginInfo["ssh.hostName"] = ""
instance.loginInfo["ssh.localPort"] = "3306"
instance.loginInfo["ssh.userName"] = "mysql"
instance.loginInfo["ssh.useKey"] = 0
if sys.platform.lower().startswith("win"):
homedir = mforms.Utilities.get_special_folder(mforms.ApplicationData)
else:
homedir = "~"
instance.loginInfo["ssh.key"] = homedir + "/.ssh/ssh_private_key"
instance.owner = grt.root.wb.rdbmsMgmt
grt.root.wb.rdbmsMgmt.storedInstances.append(instance)
grt.modules.Workbench.saveInstances()
return instance
@ModuleInfo.export(grt.classes.db_mgmt_ServerInstance, grt.classes.db_mgmt_Connection)
def autoDetectRemoteInstance(connection):
"""Create an Instance profile for the remove server from the connection.
Remote admin will be left disabled, to be filled by the user."""
instance = grt.classes.db_mgmt_ServerInstance()
instance.connection = connection
instance.name = connection.name
instance.serverInfo["setupPending"] = True
instance.owner = grt.root.wb.rdbmsMgmt
grt.root.wb.rdbmsMgmt.storedInstances.append(instance)
grt.modules.Workbench.saveInstances()
return instance
#-------------------------------------------------------------------------------
@ModuleInfo.export(grt.INT, grt.classes.db_mgmt_Connection)
def checkConnectionForRemoteAdmin(conn):
the_instance = None
for instance in grt.root.wb.rdbmsMgmt.storedInstances:
if instance.connection == conn:
the_instance = instance
break
profile = ServerProfile(conn, the_instance)
return profile.is_local or profile.remote_admin_enabled
@ModuleInfo.export(grt.STRING, grt.DICT)
def listWindowsServices(server_instance):
return wb_admin_utils.list_windows_services(server_instance)
@ModuleInfo.export(grt.STRING, grt.classes.db_mgmt_Connection, grt.classes.db_mgmt_ServerInstance)
def openRemoteFileSelector(connection, serverInstance):
profile = ServerProfile(connection, serverInstance)
return wba_ssh_ui.remote_file_selector(profile, PasswordHandler(profile))
class PasswordExpiredDialog(mforms.Form):
def __init__(self, conn):
mforms.Form.__init__(self, None)
self._conn = conn
self.set_title("Password Expired")
vbox = mforms.newBox(False)
vbox.set_padding(20)
vbox.set_spacing(18)
user = conn.parameterValues["userName"]
l = newLabel("Password for MySQL account '%s'@%s expired.\nPlease pick a new password:" % (user, conn.hostIdentifier.replace("Mysql@", "")))
l.set_style(mforms.BoldStyle)
vbox.add(l, False, True)
box = mforms.newTable()
box.set_padding(1)
box.set_row_count(3)
box.set_column_count(2)
box.set_column_spacing(7)
box.set_row_spacing(8)
hbox = mforms.newBox(True)
hbox.set_spacing(12)
icon = mforms.newImageBox()
icon.set_image(mforms.App.get().get_resource_path("wb_lock.png"))
hbox.add(icon, False, True)
hbox.add(box, True, True)
vbox.add(hbox, False, True)
self.old_password = mforms.newTextEntry(mforms.PasswordEntry)
box.add(newLabel("Old Password:", True), 0, 1, 0, 1, mforms.HFillFlag)
box.add(self.old_password, 1, 2, 0, 1, mforms.HFillFlag|mforms.HExpandFlag)
self.password = mforms.newTextEntry(mforms.PasswordEntry)
box.add(newLabel("New Password:", True), 0, 1, 1, 2, mforms.HFillFlag)
box.add(self.password, 1, 2, 1, 2, mforms.HFillFlag|mforms.HExpandFlag)
self.confirm = mforms.newTextEntry(mforms.PasswordEntry)
box.add(newLabel("Confirm:", True), 0, 1, 2, 3, mforms.HFillFlag)
box.add(self.confirm, 1, 2, 2, 3, mforms.HFillFlag|mforms.HExpandFlag)
bbox = newBox(True)
bbox.set_spacing(8)
self.ok = newButton()
self.ok.set_text("OK")
self.cancel = newButton()
self.cancel.set_text("Cancel")
mforms.Utilities.add_end_ok_cancel_buttons(bbox, self.ok, self.cancel)
vbox.add_end(bbox, False, True)
self.set_content(vbox)
self.set_size(500, 260)
self.center()
def run(self):
if self.run_modal(self.ok, self.cancel):
if self.password.get_string_value() != self.confirm.get_string_value():
mforms.Utilities.show_error("Reset Password", "The password and its confirmation do not match. Please try again.", "OK", "", "")
return self.run()
con = self._conn
old_multi_statements = con.parameterValues.get("CLIENT_MULTI_STATEMENTS")
old_script = con.parameterValues.get("preInit")
con.parameterValues["CLIENT_MULTI_STATEMENTS"] = 1
con.parameterValues["preInit"] = "SET PASSWORD = PASSWORD('%s')" % escape_sql_string(self.password.get_string_value())
retry = False
result = 1
c = MySQLConnection(con, password = self.old_password.get_string_value())
# connect to server so that preInitScript will do the password reset work
try:
c.connect()
except MySQLError, e:
if mforms.Utilities.show_error("Reset Password", str(e), "Retry", "Cancel", "") == mforms.ResultOk:
retry = True
result = 0
finally:
if old_script is not None:
con.parameterValues["preInit"] = old_script
else:
del con.parameterValues["preInit"]
if old_multi_statements is not None:
con.parameterValues["CLIENT_MULTI_STATEMENTS"] = old_multi_statements
else:
del con.parameterValues["CLIENT_MULTI_STATEMENTS"]
if retry:
return self.run()
return result
return 0
@ModuleInfo.export(grt.INT, grt.classes.db_mgmt_Connection)
def handleExpiredPassword(conn):
dlg = PasswordExpiredDialog(conn)
return dlg.run()
#-------------------------------------------------------------------------------
@ModuleInfo.export(grt.INT, grt.STRING)
def testAdministrator(what):
import wb_admin_test
wb_admin_test.run()
import sys
sys.exit(0) # TODO return code here
return 1
def check_if_config_file_has_section(config_file, section):
for line in config_file:
if line.strip() == "[%s]"%section:
return True
return False
test_ssh_connection = None
test_ssh_connection_is_windows = None
@ModuleInfo.export(grt.STRING, grt.STRING, grt.classes.db_mgmt_Connection, grt.classes.db_mgmt_ServerInstance)
def testInstanceSettingByName(what, connection, server_instance):
global test_ssh_connection
log_debug("Test %s in %s\n" % (what, connection.name))
profile = ServerProfile(connection, server_instance)
if what == "connect_to_host":
if test_ssh_connection:
test_ssh_connection = None
log_info("Instance test: Connecting to %s\n" % profile.ssh_hostname)
try:
test_ssh_connection = wb_admin_control.WbAdminControl(profile, None, connect_sql=False, test_only = True)
test_ssh_connection.init()
grt.send_info("connected.")
except Exception, exc:
log_error("Exception: %s" % exc.message)
import traceback
log_debug2("Backtrace was: " % traceback.format_stack())
return "ERROR "+str(exc)
except:
return "ERROR"
try:
test_ssh_connection.acquire_admin_access()
except Exception, exc:
log_error("Exception: %s" % exc.message)
import traceback
log_debug2("Backtrace was: " % traceback.format_stack())
return "ERROR "+str(exc)
os_info = test_ssh_connection.detect_operating_system_version()
if os_info:
os_type, os_name, os_variant, os_version = os_info
log_info("Instance test: detected remote OS: %s (%s), %s, %s\n" % (os_info))
# check if the admin access error was because of wrong OS set
if os_type != profile.target_os:
return "ERROR Wrong Remote OS configured for connection. Set to %s, but was detected as %s" % (profile.target_os, os_type)
else:
log_warning("Instance test: could not determine OS version information\n")
return "ERROR Could not determine remote OS details"
return "OK"
elif what == "disconnect":
if test_ssh_connection:
test_ssh_connection = None
return "OK"
elif what == "check_privileges":
return "ERROR"
elif what in ("find_config_file", "check_config_path", "check_config_section"):
config_file = profile.config_file_path
print "Check if %s exists in remote host" % config_file
try:
if not test_ssh_connection.ssh.file_exists(config_file):
return "ERROR File %s doesn't exist" % config_file
else:
print "File was found in expected location"
except IOError:
return 'ERROR Could not verify the existence of the file %s' % config_file
if what == "check_config_path":
return "OK"
section = profile.config_file_section
cfg_file_content = ""
print "Check if %s section exists in %s" % (section, config_file)
try:
#local_file = test_ssh_connection.fetch_file(config_file)
cfg_file_content = test_ssh_connection.server_helper.get_file_content(path=config_file)
except Exception, exc:
import traceback
traceback.print_exc()
return "ERROR "+str(exc)
if ("[" + section + "]") in cfg_file_content:
return "OK"
return "ERROR Couldn't find section %s in the remote config file %s" % (section, config_file)
elif what in ("find_config_file/local", "check_config_path/local", "check_config_section/local"):
config_file = profile.config_file_path
config_file = wb_admin_control.WbAdminControl(profile, None, connect_sql=False).expand_path_variables(config_file)
print "Check if %s can be accessed" % config_file
if os.path.exists(config_file):
print "File was found at the expected location"
else:
return "ERROR File %s doesn't exist" % config_file
if what == "check_config_path/local":
return "OK"
section = profile.config_file_section
print "Check if section for instance %s exists in %s" % (section, config_file)
if check_if_config_file_has_section(open(config_file, "r"), section):
print "[%s] section found in configuration file" % section
return "OK"
return "ERROR Couldn't find section [%s] in the config file %s" % (section, config_file)
elif what == "find_error_files":
return "ERROR"
elif what == "check_admin_commands":
path = profile.start_server_cmd
cmd_start= None
if path.startswith("/"):
cmd_start = path.split()[0]
if not test_ssh_connection.ssh.file_exists(cmd_start):
return "ERROR %s is invalid" % path
path = profile.stop_server_cmd
if path.startswith("/"):
cmd = path.split()[0]
if cmd != cmd_start and not test_ssh_connection.ssh.file_exists(cmd):
return "ERROR %s is invalid" % path
return "OK"
elif what == "check_admin_commands/local":
path = profile.start_server_cmd
cmd_start= None
if path.startswith("/"):
cmd_start = path.split()[0]
if not os.path.exists(cmd_start):
return "ERROR %s is invalid" % path
path = profile.stop_server_cmd
if path.startswith("/"):
cmd = path.split()[0]
if cmd != cmd_start and not os.path.exists(cmd):
return "ERROR %s is invalid" % path
return "OK"
return "ERROR bad command"
@ModuleInfo.export(grt.DICT, grt.classes.db_mgmt_ServerInstance)
def detectInstanceSettings(server_instance):
#form = Form()
#form.run(None, None)
return {}
@ModuleInfo.export(grt.STRING, grt.classes.db_mgmt_ServerInstance)
def testInstanceSettings(server_instance):
error = testInstanceSettingByName("connect_to_host", server_instance.connection, server_instance)
testInstanceSettingByName("disconnect", server_instance.connection, server_instance)
return error
##------------------------------------------------------------------------------------------------------------------------
@ModuleInfo.plugin("wb.admin.open_into", type="standalone", input=[wbinputs.currentSQLEditor(), wbinputs.string()])
@ModuleInfo.export(grt.INT, grt.classes.db_query_Editor, grt.STRING)
def openAdminSection(editor, section):
context = grt.fromgrt(editor.customData["adminContext"])
if context:
context.open_into_section(section, True)
else:
log_error("No context found for editor in call to openAdminSection\n")
# Hack to make this plugin only appear if SE modules are available
try:
import wba_meb # noqa
@ModuleInfo.plugin("wb.admin.open_into_se", type="standalone", input=[wbinputs.currentSQLEditor(), wbinputs.string()])
@ModuleInfo.export(grt.INT, grt.classes.db_query_Editor, grt.STRING)
def openAdminSectionSE(editor, section):
context = grt.fromgrt(editor.customData["adminContext"])
if context:
context.open_into_section(section, True)
else:
log_error("No context found for editor in call to openAdminSection\n")
except ImportError:
pass
@ModuleInfo.plugin("wb.admin.settings", type="standalone", input=[wbinputs.currentSQLEditor()])
@ModuleInfo.export(grt.INT, grt.classes.db_query_Editor)
def openConnectionSettings(editor):
grt.modules.Workbench.showInstanceManagerFor(editor.connection)
context = grt.fromgrt(editor.customData["adminContext"])
if context:
context.refresh_admin_links()
@ModuleInfo.plugin("wb.admin.reset_password_cache", type="standalone", input=[wbinputs.currentSQLEditor()])
@ModuleInfo.export(grt.INT, grt.classes.db_query_Editor)
def resetPasswordCache(editor):
context = grt.fromgrt(editor.customData["adminContext"])
if context:
handler = PasswordHandler(context.server_profile)
if context.ctrl_be and context.ctrl_be.password_handler:
context.ctrl_be.password_handler.pwd_store = {}
for service_type in ["local", "ssh", "sshkey", "file", "service.startstop", "remoteshell"]:
details = handler.get_password_parameters(service_type)
if details and details != "UAC":
title, service, account = details
mforms.Utilities.forget_password(service, account)
mforms.Utilities.show_message("Reset Saved Passwords", "Saved passwords for this connection were deleted.", "OK", "", "")
|