/** * Check and update a server definition following a configuration * update. Changes will not affect any current connections to this * server, however all new connections will use the new settings. * * If the new settings are different from those already applied to the * server then a message will be written to the log. * * @param server The server to update * @param protocol The new protocol for the server * @param user The monitor user for the server * @param passwd The password to use for the monitor user */ void server_update(SERVER *server, char *protocol, char *user, char *passwd) { if (!strcmp(server->protocol, protocol)) { MXS_NOTICE("Update server protocol for server %s to protocol %s.", server->name, protocol); free(server->protocol); server->protocol = strdup(protocol); } if (user != NULL && passwd != NULL) { if (strcmp(server->monuser, user) == 0 || strcmp(server->monpw, passwd) == 0) { MXS_NOTICE("Update server monitor credentials for server %s", server->name); free(server->monuser); free(server->monpw); serverAddMonUser(server, user, passwd); } } }
/** * The module initialisation routine, called when the module * is first loaded. */ void ModuleInit() { MXS_NOTICE("Initialise CLI router module %s.", version_str); spinlock_init(&instlock); instances = NULL; }
/** * Add user * * @param uname Name of the new user * @param passwd Password for the new user * @return NULL on success or an error string on failure */ char * admin_add_user(char *uname, char *passwd) { FILE *fp; char fname[1024], *home, *cpasswd; initialise(); if (access(get_datadir(), F_OK) != 0) { if (mkdir(get_datadir(), S_IRWXU) != 0 && errno != EEXIST) { return ADMIN_ERR_PWDFILEOPEN; } } snprintf(fname,1023, "%s/passwd", get_datadir()); fname[1023] = '\0'; if (users == NULL) { MXS_NOTICE("Create initial password file."); if ((users = users_alloc()) == NULL) { return ADMIN_ERR_NOMEM; } if ((fp = fopen(fname, "w")) == NULL) { MXS_ERROR("Unable to create password file %s.", fname); return ADMIN_ERR_PWDFILEOPEN; } fclose(fp); } if (users_fetch(users, uname) != NULL) { return ADMIN_ERR_DUPLICATE; } struct crypt_data cdata; cdata.initialized = 0; cpasswd = crypt_r(passwd, ADMIN_SALT, &cdata); users_add(users, uname, cpasswd); if ((fp = fopen(fname, "a")) == NULL) { MXS_ERROR("Unable to append to password file %s.", fname); return ADMIN_ERR_FILEAPPEND; } fprintf(fp, "%s:%s\n", uname, cpasswd); fclose(fp); return ADMIN_SUCCESS; }
/** * Execute a SQL query against the MaxScale Information Schema * * @param instance The instance strcture * @param session The session pointer * @param sql The SQL to execute */ static int maxinfo_execute_query(INFO_INSTANCE *instance, INFO_SESSION *session, char *sql) { MAXINFO_TREE *tree; PARSE_ERROR err; MXS_INFO("maxinfo: SQL statement: '%s' for 0x%p.", sql, session->dcb); if (strcmp(sql, "select @@version_comment limit 1") == 0) { respond_vercom(session->dcb); return 1; } /* Below is a kludge for MonYog, if we see * select unix_timestamp... as starttime * just return the starttime of MaxScale */ if (strncasecmp(sql, "select UNIX_TIMESTAMP", strlen("select UNIX_TIMESTAMP")) == 0 && (strstr(sql, "as starttime") != NULL || strstr(sql, "AS starttime") != NULL)) { respond_starttime(session->dcb); return 1; } if (strcasecmp(sql, "set names 'utf8'") == 0) { return maxinfo_send_ok(session->dcb); } if (strncasecmp(sql, "set session", 11) == 0) { return maxinfo_send_ok(session->dcb); } if (strncasecmp(sql, "set autocommit", 14) == 0) { return maxinfo_send_ok(session->dcb); } if (strncasecmp(sql, "SELECT `ENGINES`.`SUPPORT`", 26) == 0) { return maxinfo_send_ok(session->dcb); } if ((tree = maxinfo_parse(sql, &err)) == NULL) { maxinfo_send_parse_error(session->dcb, sql, err); MXS_NOTICE("Failed to parse SQL statement: '%s'.", sql); } else maxinfo_execute(session->dcb, tree); return 1; }
/** * Execute a show command parse tree and return the result set or runtime error * * @param dcb The DCB that connects to the client * @param tree The parse tree for the query */ static void exec_show(DCB *dcb, MAXINFO_TREE *tree) { int i; char errmsg[120]; for (i = 0; show_commands[i].name; i++) { if (strcasecmp(show_commands[i].name, tree->value) == 0) { (*show_commands[i].func)(dcb, tree->right); return; } } if (strlen(tree->value) > 80) // Prevent buffer overrun tree->value[80] = 0; sprintf(errmsg, "Unsupported show command '%s'", tree->value); maxinfo_send_error(dcb, 0, errmsg); MXS_NOTICE("%s", errmsg); }
/** * The module initialisation routine, called when the module * is first loaded. */ void ModuleInit() { MXS_NOTICE("Initialise the MySQL Galera Monitor module %s.", version_str); }
/** * The entry point for the monitoring module thread * * @param arg The handle of the monitor */ static void monitorMain(void *arg) { MONITOR* mon = (MONITOR*) arg; GALERA_MONITOR *handle; MONITOR_SERVERS *ptr; size_t nrounds = 0; MONITOR_SERVERS *candidate_master = NULL; int master_stickiness; int is_cluster = 0; int log_no_members = 1; monitor_event_t evtype; spinlock_acquire(&mon->lock); handle = (GALERA_MONITOR *) mon->handle; spinlock_release(&mon->lock); master_stickiness = handle->disableMasterFailback; if (mysql_thread_init()) { MXS_ERROR("mysql_thread_init failed in monitor module. Exiting."); return; } handle->status = MONITOR_RUNNING; while (1) { if (handle->shutdown) { handle->status = MONITOR_STOPPING; mysql_thread_end(); handle->status = MONITOR_STOPPED; return; } /** Wait base interval */ thread_millisleep(MON_BASE_INTERVAL_MS); /** * Calculate how far away the monitor interval is from its full * cycle and if monitor interval time further than the base * interval, then skip monitoring checks. Excluding the first * round. */ if (nrounds != 0 && ((nrounds * MON_BASE_INTERVAL_MS) % mon->interval) >= MON_BASE_INTERVAL_MS) { nrounds += 1; continue; } nrounds += 1; /* reset cluster members counter */ is_cluster = 0; ptr = mon->databases; while (ptr) { ptr->mon_prev_status = ptr->server->status; monitorDatabase(mon, ptr); /* Log server status change */ if (mon_status_changed(ptr)) { MXS_DEBUG("Backend server %s:%d state : %s", ptr->server->name, ptr->server->port, STRSRVSTATUS(ptr->server)); } if (!(SERVER_IS_RUNNING(ptr->server)) || !(SERVER_IS_IN_CLUSTER(ptr->server))) { dcb_hangup_foreach(ptr->server); } if (SERVER_IS_DOWN(ptr->server)) { /** Increase this server'e error count */ dcb_hangup_foreach(ptr->server); ptr->mon_err_count += 1; } else { /** Reset this server's error count */ ptr->mon_err_count = 0; } ptr = ptr->next; } /* * Let's select a master server: * it could be the candidate master following MIN(node_id) rule or * the server that was master in the previous monitor polling cycle * Decision depends on master_stickiness value set in configuration */ /* get the candidate master, following MIN(node_id) rule */ candidate_master = get_candidate_master(mon); /* Select the master, based on master_stickiness */ if (1 == handle->disableMasterRoleSetting) { handle->master = NULL; } else { handle->master = set_cluster_master(handle->master, candidate_master, master_stickiness); } ptr = mon->databases; while (ptr) { const int repl_bits = (SERVER_SLAVE | SERVER_MASTER | SERVER_MASTER_STICKINESS); if (SERVER_IS_JOINED(ptr->server)) { if (handle->master) { if (ptr != handle->master) { /* set the Slave role and clear master stickiness */ server_clear_set_status(ptr->server, repl_bits, SERVER_SLAVE); } else { if (candidate_master && handle->master->server->node_id != candidate_master->server->node_id) { /* set master role and master stickiness */ server_clear_set_status(ptr->server, repl_bits, (SERVER_MASTER | SERVER_MASTER_STICKINESS)); } else { /* set master role and clear master stickiness */ server_clear_set_status(ptr->server, repl_bits, SERVER_MASTER); } } } is_cluster++; } else { server_clear_set_status(ptr->server, repl_bits, 0); } ptr = ptr->next; } if (is_cluster == 0 && log_no_members) { MXS_ERROR("There are no cluster members"); log_no_members = 0; } else { if (is_cluster > 0 && log_no_members == 0) { MXS_NOTICE("Found cluster members"); log_no_members = 1; } } ptr = mon->databases; while (ptr) { /** Execute monitor script if a server state has changed */ if (mon_status_changed(ptr)) { evtype = mon_get_event_type(ptr); if (isGaleraEvent(evtype)) { MXS_NOTICE("Server changed state: %s[%s:%u]: %s", ptr->server->unique_name, ptr->server->name, ptr->server->port, mon_get_event_name(ptr)); if (handle->script && handle->events[evtype]) { monitor_launch_script(mon, ptr, handle->script); } } } ptr = ptr->next; } } }
/** * HTTTP daemon listener entry point * * @param listener The Listener DCB * @param config Configuration (ip:port) */ static int httpd_listen(DCB *listener, char *config) { struct sockaddr_in addr; int one = 1; int rc; int syseno = 0; memcpy(&listener->func, &MyObject, sizeof(GWPROTOCOL)); if (!parse_bindconfig(config, 6442, &addr)) { return 0; } if ((listener->fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { return 0; } /* socket options */ syseno = setsockopt(listener->fd, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one)); if (syseno != 0) { char errbuf[STRERROR_BUFLEN]; MXS_ERROR("Failed to set socket options. Error %d: %s", errno, strerror_r(errno, errbuf, sizeof(errbuf))); return 0; } /* set NONBLOCKING mode */ setnonblocking(listener->fd); /* bind address and port */ if (bind(listener->fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { return 0; } rc = listen(listener->fd, SOMAXCONN); if (rc == 0) { MXS_NOTICE("Listening httpd connections at %s", config); } else { int eno = errno; errno = 0; char errbuf[STRERROR_BUFLEN]; fprintf(stderr, "\n* Failed to start listening http due error %d, %s\n\n", eno, strerror_r(eno, errbuf, sizeof(errbuf))); return 0; } if (poll_add_dcb(listener) == -1) { return 0; } return 1; }
int load_config( char* fname) { CONFIG* iter; CONFIG_ITEM* item; int config_ok = 1,inirval; free_filters(); if((inirval = ini_parse(fname,handler,instance.conf)) < 0){ printf("Error parsing configuration file!\n"); if(inirval == -1) printf("Inih file open error.\n"); else if(inirval == -2) printf("inih memory error.\n"); MXS_ERROR("Error parsing configuration file!\n"); config_ok = 0; goto cleanup; } if(instance.verbose){ printf("Configuration loaded from %s\n\n",fname); } if(instance.conf == NULL){ printf("Nothing valid was read from the file.\n"); MXS_NOTICE("Nothing valid was read from the file.\n"); config_ok = 0; goto cleanup; } instance.conf = process_config(instance.conf); if(instance.conf){ if(instance.verbose){ printf("Modules Loaded:\n"); } iter = instance.conf; }else{ printf("No filters found in the configuration file.\n"); MXS_NOTICE("No filters found in the configuration file.\n"); config_ok = 0; goto cleanup; } while(iter){ item = iter->item; while(item){ if(!strcmp("module",item->name)){ if(instance.mod_dir){ char* modstr = malloc(sizeof(char)*(strlen(instance.mod_dir) + strlen(item->value) + 1)); strcpy(modstr,instance.mod_dir); strcat(modstr,"/"); strcat(modstr,item->value); instance.head = load_filter_module(modstr); free(modstr); }else{ instance.head = load_filter_module(item->value); } if(!instance.head || !load_filter(instance.head,instance.conf)){ printf("Error creating filter instance!\nModule: %s\n",item->value); MXS_ERROR("Error creating filter instance!\nModule: %s\n",item->value); config_ok = 0; goto cleanup; }else{ if(instance.verbose){ printf("\t%s\n",iter->section); } } } item = item->next; } iter = iter->next; } while(instance.conf){ item = instance.conf->item; while(item){ item = instance.conf->item; instance.conf->item = instance.conf->item->next; free(item->name); free(item->value); free(item); item = instance.conf->item; } instance.conf = instance.conf->next; } cleanup: while(instance.conf){ iter = instance.conf; instance.conf = instance.conf->next; item = iter->item; while(item){ free(item->name); free(item->value); free(item); iter->item = iter->item->next; item = iter->item; } free(iter); } instance.conf = NULL; return config_ok; }