def work(self, files): try: if self.ctrl_be.target_version >= Version(5, 7, 10): self.importer.reset_schemas() else: location = download_server_install_script(self.ctrl_be) if location: workbench_version_string = get_current_sys_version(None) server_version_string = get_sys_version_from_script(location) maj, min, rel = [int(i) for i in workbench_version_string.split(".")] workbench_version = Version(maj, min, rel) maj, min, rel = [int(i) for i in server_version_string.split(".")] server_version = Version(maj, min, rel) if server_version >= workbench_version: log_info("Installing sys schema supplied by the server: %s\n" % str(location)) self.install_scripts([(location, None)], "Installing server script") return else: log_info("Server sys schema install script exists but it's outdated compared to the one supplied by Workbench...\n") log_info("Installing sys schema supplied by workbench\n") self.install_scripts(files, "Installing Workbench script") except Exception as e: log_error("Runtime error when installing the sys schema: %s\n" % str(e)) self._worker_queue.put(e) # This makes the screen refresh self._worker_queue.put(None)
def install_helper(self): self.installer_panel = HelperInstallPanel(self._owner, self._main_view.editor, self._ctrl_be) self._content.add(self.installer_panel, 1, 2, 2, 3, 0) self._owner.relayout() # needed b/c of layout bug in Mac if self._ctrl_be.target_version >= Version(5, 7, 10): filechooser = FileChooser(mforms.OpenFile) filechooser.set_title("Specify the location of mysql_upgrade") if filechooser.run_modal(): self.installer_panel.importer._upgrade_tool_path = filechooser.get_path() self.installer_panel.importer.set_password(self._ctrl_be.get_mysql_password()) self.installer_panel.start()
def save(self): queries = [] if self.password != self.confirm_password: raise WBSecurityValidationError("The new password and its confirmation don't match. Please re-enter them.") # workaround for server bug with replication #14358854 queries.append("use mysql") #if not self.username: # raise WBSecurityValidationError("Username must not be blank") if not self.host: raise WBSecurityValidationError("Host name must not be blank") # check if username + host is duplicated if self.is_commited and (self.username != self._orig_username or self.host != self._orig_host): if (self.username, self.host) in self._owner.account_names: raise WBSecurityValidationError("The '%s' account already exists and cannot be saved." % (self.formatted_name())) elif not self.is_commited: if (self.username, self.host, True) in self._owner.account_names: raise WBSecurityValidationError("The '%s' account already exists and cannot be saved." % (self.formatted_name())) fields = { "old_user" : escape_sql_string(self._orig_username) if self._orig_username else self._orig_username, "old_host" : escape_sql_string(self._orig_host) if self._orig_host else self._orig_host, "user" : escape_sql_string(self.username) or "NULL", "host" : escape_sql_string(self.host) or "", "password" : escape_sql_string(self.password or ""), "auth_plugin" : escape_sql_string(self.auth_plugin) if self.auth_plugin else None, "auth_string" : escape_sql_string(self.auth_string) if self.auth_string else None } password_already_set = False if not self.is_commited: # This is a new account if self.auth_plugin: if self.auth_string is None: create_query = CREATE_USER_QUERY_PLUGIN elif self.auth_plugin == 'mysql_native_password': if (self._owner.ctrl_be.target_version and self._owner.ctrl_be.target_version < Version(5, 7, 0)): create_query = CREATE_USER_QUERY_PLUGIN else: create_query = CREATE_USER_QUERY_PLUGIN_AUTH_NATIVE elif self.auth_plugin == 'caching_sha2_password': create_query = CREATE_USER_QUERY_PLUGIN_AUTH_CACHING else: create_query = CREATE_USER_QUERY_PLUGIN_AUTH_STRING else: create_query = CREATE_USER_QUERY password_already_set = True queries[:0] = [ create_query % fields ] # This query should be the first in the batch # WARNING: Now the pwd is sent in clear text else: # The account already exists assert self._orig_username is not None and self._orig_host is not None if self._orig_username != self.username or self._orig_host != self.host: # Rename the user queries[:0] = [ RENAME_USER_QUERY % fields ] # This query should be the first in the batch names = ["MAX_QUERIES_PER_HOUR", "MAX_UPDATES_PER_HOUR", "MAX_CONNECTIONS_PER_HOUR"] + (self._owner.has_max_user_connections and ["MAX_USER_CONNECTIONS"] or []) values = [str(s) for s in [self.max_questions, self.max_updates, self.max_connections] + (self._owner.has_max_user_connections and [self.max_user_connections] or [])] account_limits = dict(zip(names, values)) limits_changed = account_limits != self._orig_account_limits is_normal_priv = lambda priv: ( PrivilegeInfo.get(priv, (None,None))[0] and PrivilegeInfo.get(priv, (None,None))[0][0] != '*' ) all_normal_privs = set( priv for priv in self._owner.global_privilege_names if is_normal_priv(priv) ) new_granted_privs = (self._global_privs - self._orig_global_privs) & all_normal_privs orig_revoked_privs = all_normal_privs - self._orig_global_privs new_revoked_privs = all_normal_privs - self._global_privs - orig_revoked_privs if new_granted_privs or limits_changed: if 'Grant_priv' in new_granted_privs: account_limits['GRANT'] = 'OPTION' new_granted_privs.remove('Grant_priv') if (all_normal_privs - new_granted_privs) <= set(['Grant_priv']): priv_list = ['ALL PRIVILEGES'] else: priv_list = [ PrivilegeInfo[priv][0] for priv in new_granted_privs ] fields['granted_privs'] = ', '.join(priv_list) or 'USAGE' grant_query = GRANT_GLOBAL_PRIVILEGES_QUERY % fields with_clause = '' for key, value in account_limits.iteritems(): #name, value in zip(names, values): if value != self._orig_account_limits.get(key): if key == "GRANT" and value == "OPTION": queries.append(grant_query + "WITH GRANT OPTION") continue if not with_clause: with_clause = ' WITH ' with_clause += "%s %s "%(key, value) if self._owner.ctrl_be.target_version and self._owner.ctrl_be.target_version >= Version(8, 0, 5): queries.append(grant_query) queries.append((ALTER_USER_RESOURCES % fields) + with_clause) else: queries.append(grant_query + with_clause) if new_revoked_privs: if all_normal_privs - new_revoked_privs: #set(self._owner.global_privilege_names) - revoked_privs_set: # Revoke a subset of all privs priv_list = [ PrivilegeInfo[priv][0] for priv in new_revoked_privs ] fields['revoked_privs'] = ', '.join(priv_list) queries.append(REVOKE_GLOBAL_PRIVILEGES_QUERY % fields) else: # All privs are to be revoked so use the revoke all query queries.append(REVOKE_ALL % fields) if self.password != self._orig_password and not password_already_set: change_pw = CHANGE_PASSWORD_QUERY if self._owner.ctrl_be.target_version and self._owner.ctrl_be.target_version < Version(5,7,6) else CHANGE_PASSWORD_QUERY_576 blank_pw = BLANK_PASSWORD_QUERY if self._owner.ctrl_be.target_version and self._owner.ctrl_be.target_version < Version(5,7,6) else BLANK_PASSWORD_QUERY # special hack required by server to handle sha256 password accounts if self._owner.ctrl_be.target_version and self._owner.ctrl_be.target_version < Version(8, 0, 5): if self.auth_plugin == "sha256_password": queries.append("SET old_passwords = 2") else: queries.append("SET old_passwords = 0") if fields["password"]: queries.append(change_pw % fields) else: queries.append(blank_pw % fields) action = "changing" if self.is_commited else "creating" for query in queries: try: self._owner.ctrl_be.exec_sql(query) except QueryError, e: if e.error == 1142: raise Exception("Error %s account %s@%s: Insufficient rights to perform operation"%(action, self.username, self.host)) else: raise Exception("Error %s account %s@%s: %s"%(action, self.username, self.host, e.errortext or e)) except Exception, e: raise Exception("Error %s account %s@%s: %s"%(action, self.username, self.host, e))
def upgrade_password_format(self): queries = [] if self.password != self.confirm_password: raise WBSecurityValidationError("The new password and its confirmation don't match. Please re-enter them.") queries.append("use mysql") if not self.host: raise WBSecurityValidationError("Host name must not be blank") fields = { "user" : escape_sql_string(self.username) or "NULL", "host" : escape_sql_string(self.host) or "", "password" : escape_sql_string(self.password or ""), } queries.append("SET old_passwords = 0") if self._owner.ctrl_be.target_version and self._owner.ctrl_be.target_version.is_supported_mysql_version_at_least(5, 5, 7): queries.append("UPDATE mysql.user SET plugin = 'mysql_native_password' WHERE user = '******' AND host = '%(host)s'" % fields) queries.append("FLUSH PRIVILEGES") change_pw = CHANGE_PASSWORD_QUERY if self._owner.ctrl_be.target_version and self._owner.ctrl_be.target_version < Version(5,7,6) else CHANGE_PASSWORD_QUERY_576 queries.append(change_pw % fields) queries.append("FLUSH PRIVILEGES") action = "changing" for query in queries: try: self._owner.ctrl_be.exec_sql(query) except QueryError, e: if e.error == 1142: raise Exception("Error %s account %s@%s: Insufficient rights to perform operation"%(action, self.username, self.host)) else: raise Exception("Error %s account %s@%s: %s"%(action, self.username, self.host, e.errortext or e)) except Exception, e: raise Exception("Error %s account %s@%s: %s"%(action, self.username, self.host, e))
"MAX_QUERIES_PER_HOUR" : str(self.max_questions), "MAX_UPDATES_PER_HOUR" : str(self.max_updates), "MAX_CONNECTIONS_PER_HOUR" : str(self.max_connections), } if self._owner.has_max_user_connections: self.max_user_connections = result.intByName("max_user_connections") self._orig_account_limits["MAX_USER_CONNECTIONS"] = str(self.max_user_connections) if self._owner.has_plugin: self.auth_plugin = result.stringByName("plugin") if self._owner.has_authentication_string: self.auth_string = result.stringByName("authentication_string") self.password_expired = False if self._owner.has_password_expired: self.password_expired = result.stringByName("password_expired") == 'Y' password_column = 'password' if self._owner.ctrl_be.target_version and self._owner.ctrl_be.target_version < Version(5,7,6) else 'authentication_string' self.old_authentication = len(result.stringByName(password_column)) == 16 self.blank_password = len(result.stringByName(password_column)) == 0 self._global_privs = set() for priv in self._owner.global_privilege_names: if result.stringByName(priv) == 'Y': self._global_privs.add(priv) self.forget_custom_privs() """ not necessary, IS is accessible to all # privs from information_schema tables query = GET_ACCOUNT_IS_TABLE_PRIVS_QUERY % {"user":username,"host":hostname} result = modules.DbMySQLQuery.executeQuery(self._owner._connection, query) if result < 0:
def setup_info_table(self, info_table, info, params): info_table.set_row_count(len(info) + 1) for i, item in enumerate(info): (label, value_source) = item if callable(value_source): value = value_source(*params) else: value = value_source if self.controls.has_key(label): info_table.remove(self.controls[label][0]) else: l = mforms.newLabel(label + ":") l.set_name(label) info_table.add(l, 0, 1, i, i + 1, mforms.VFillFlag | mforms.HFillFlag) is_gtid_mode_setable = label == 'GTID Mode:' and self.ctrl_be.target_version >= Version( 5, 7, 6) if type(value) is bool or value is None: b = StateIcon() if label and label != '': b.set_name(label + " Value") b.set_state(value) info_table.add( b, 1, 2, i, i + 1, mforms.HFillFlag | mforms.HExpandFlag | mforms.VFillFlag) self.controls[label] = (b, value_source) elif type(value) is tuple: b = StateIcon() if label and label != '': b.set_name(label + " Value") b.set_state(value[0]) if value[0] and value[1]: b.set_text(value[1]) info_table.add( b, 1, 2, i, i + 1, mforms.HFillFlag | mforms.HExpandFlag | mforms.VFillFlag) self.controls[label] = (b, value_source) else: if is_gtid_mode_setable: self.gtid_mode_selector = mforms.newSelector() if label and label != '': self.gtid_mode_selector.set_name(label + " Value") self.gtid_mode_selector.add_items( ["OFF", "UPGRADE_STEP_1", "UPGRADE_STEP_1", "ON"]) self.gtid_mode_selector.set_selected( self.gtid_mode_selector.index_of_item_with_title( value_source)) self.gtid_mode_selector.add_changed_callback( self._gtid_mode_changed) info_table.add( self.gtid_mode_selector, 1, 2, i, i + 1, mforms.HFillFlag | mforms.HExpandFlag | mforms.VFillFlag) self.controls[label] = (self.gtid_mode_selector, value_source) else: l2 = mforms.newLabel(value or "") if label and label != '': l2.set_name(label + " Value") l2.set_style(mforms.BoldStyle) info_table.add( l2, 1, 2, i, i + 1, mforms.HFillFlag | mforms.HExpandFlag | mforms.VFillFlag) self.controls[label] = (l2, value_source) info_table.add(mforms.newLabel(""), 0, 1, len(info), len(info) + 1, mforms.HFillFlag) # blank space return info_table
def __init__(self, owner, json_text, context, server_version): mforms.Box.__init__(self, False) self.set_managed() self.set_release_on_add() self._context = context get_resource_path = mforms.App.get().get_resource_path self.toolbar = mforms.newToolBar(mforms.SecondaryToolBar) self.toolbar.set_back_color("#ffffff") self.switcher_item = newToolBarItem(mforms.SelectorItem) self.toolbar.add_item(self.switcher_item) s = newToolBarItem(mforms.SeparatorItem) self.toolbar.add_item(s) l = newToolBarItem(mforms.LabelItem) l.set_text("Display Info:") self.toolbar.add_item(l) item = newToolBarItem(mforms.SelectorItem) item.set_selector_items(["Read + Eval cost", "Data Read per Join"]) item.add_activated_callback(self.display_cost) self.toolbar.add_item(item) cost_type_item = item # cost info was added in 5.7.2 has_cost_info = server_version >= Version(5, 7) if not has_cost_info: item.set_enabled(False) #item = newToolBarItem(mforms.SelectorItem) # item.set_selector_items(["Show Aggregated Costs", "Show Individual Costs"]) # item.add_activated_callback(self.toggle_aggregated) # self.toolbar.add_item(item) #btn = newToolBarItem(mforms.SegmentedToggleItem) #btn.set_icon(get_resource_path("qe_resultset-tb-switcher_grid_off_mac.png")) #btn.set_alt_icon(get_resource_path("qe_resultset-tb-switcher_grid_on_mac.png")) #self.toolbar.add_item(btn) #btn = newToolBarItem(mforms.SegmentedToggleItem) #btn.set_icon(get_resource_path("qe_resultset-tb-switcher_explain_off.png")) #btn.set_alt_icon(get_resource_path("qe_resultset-tb-switcher_explain_on.png")) #self.toolbar.add_item(btn) s = newToolBarItem(mforms.SeparatorItem) self.toolbar.add_item(s) btn = newToolBarItem(mforms.ActionItem) btn.set_icon(get_resource_path("tiny_saveas.png")) btn.add_activated_callback(self.save) btn.set_tooltip("Save image to an external file.") self.toolbar.add_item(btn) s = newToolBarItem(mforms.SeparatorItem) self.toolbar.add_item(s) l = newToolBarItem(mforms.LabelItem) l.set_text("Overview:") self.toolbar.add_item(l) btn = newToolBarItem(mforms.ActionItem) btn.set_icon( get_resource_path("qe_sql-editor-explain-tb-overview.png")) btn.add_activated_callback(self.overview) btn.set_tooltip("Zoom out the diagram.") self.toolbar.add_item(btn) s = newToolBarItem(mforms.SeparatorItem) self.toolbar.add_item(s) l = newToolBarItem(mforms.LabelItem) l.set_text("View Source:") self.toolbar.add_item(l) btn = newToolBarItem(mforms.ToggleItem) btn.set_icon(get_resource_path("statusbar_output.png")) btn.set_alt_icon(get_resource_path("statusbar_output.png")) btn.add_activated_callback(self.switch_to_raw) btn.set_tooltip("View the raw JSON explain data.") self.toolbar.add_item(btn) self.add(self.toolbar, False, True) # Query Plan diagram self.scroll = mforms.newScrollPanel(mforms.ScrollPanelNoFlags) self.scroll.set_visible_scrollers(True, True) #self.img = mforms.newImageBox() self.drawbox = RenderBox(self._context, self.scroll) self.scroll.add(self.drawbox) self.drawbox.node_spacing = self.node_spacing self.drawbox.vertical = self.vertical self.add(self.scroll, True, True) self.display_cost(cost_type_item) # textbox to view the json data self._raw_explain = mforms.CodeEditor() self._raw_explain.set_value(json_text) self._raw_explain.set_language(mforms.LanguageJson) self._raw_explain.set_features( mforms.FeatureReadOnly | mforms.FeatureFolding, True) self.add(self._raw_explain, True, True) self._raw_explain.show(False) nc.add_observer(self.updateColors, "GNColorsChanged") backgroundColor = Color.getSystemColor(TextBackgroundColor) self.scroll.set_back_color(backgroundColor.to_html())