Esempio n. 1
0
// this is the monitor for glob patterns
void uwsgi_imperial_monitor_glob(struct uwsgi_emperor_scanner *ues) {

	glob_t g;
	int i;
	struct stat st;
	struct uwsgi_instance *ui_current;

	if (glob(ues->arg, GLOB_MARK | GLOB_NOCHECK, NULL, &g)) {
		uwsgi_error("glob()");
		return;
	}

	for (i = 0; i < (int) g.gl_pathc; i++) {

		if (!uwsgi_emperor_is_valid(g.gl_pathv[i]))
			continue;

		if (stat(g.gl_pathv[i], &st))
			continue;

		if (!S_ISREG(st.st_mode))
			continue;

		ui_current = emperor_get(g.gl_pathv[i]);

		if (ui_current) {
			// check if uid or gid are changed, in such case, stop the instance
			if (uwsgi.emperor_tyrant) {
				if (st.st_uid != ui_current->uid || st.st_gid != ui_current->gid) {
					uwsgi_log("!!! permissions of file %s changed. stopping the instance... !!!\n", g.gl_pathv[i]);
					emperor_stop(ui_current);
					continue;
				}
			}
			// check if mtime is changed and the uWSGI instance must be reloaded
			if (st.st_mtime > ui_current->last_mod) {
				emperor_respawn(ui_current, st.st_mtime);
			}
		}
		else {
			emperor_add(ues, g.gl_pathv[i], st.st_mtime, NULL, 0, st.st_uid, st.st_gid);
		}

	}
	globfree(&g);

	// now check for removed instances
	struct uwsgi_instance *c_ui = ui->ui_next;

	while (c_ui) {
		if (c_ui->scanner == ues) {
			if (stat(c_ui->name, &st)) {
				emperor_stop(c_ui);
			}
		}
		c_ui = c_ui->ui_next;
	}


}
Esempio n. 2
0
void uwsgi_emperor_simple_do(struct uwsgi_emperor_scanner *ues, char *name, char *config, time_t ts, uid_t uid, gid_t gid) {

	if (!uwsgi_emperor_is_valid(name))
		return;

	struct uwsgi_instance *ui_current = emperor_get(name);

	if (ui_current) {
		// check if uid or gid are changed, in such case, stop the instance
		if (uwsgi.emperor_tyrant) {
			if (uid != ui_current->uid || gid != ui_current->gid) {
				uwsgi_log("[emperor-tyrant] !!! permissions of vassal %s changed. stopping the instance... !!!\n", name);
				emperor_stop(ui_current);
				return;
			}
		}
		// check if mtime is changed and the uWSGI instance must be reloaded
		if (ts > ui_current->last_mod) {
			// make a new config (free the old one)
			free(ui_current->config);
			ui_current->config = config;
			ui_current->config_len = strlen(config);
			// always respawn (no need for amqp-style rules)
			emperor_respawn(ui_current, ts);
		}
	}
	else {
		// make a copy of the config as it will be freed
		emperor_add(ues, name, ts, uwsgi_str(config), strlen((const char *) config), uid, gid);
	}
}
Esempio n. 3
0
// this is the monitor for non-glob directories
void uwsgi_imperial_monitor_directory(struct uwsgi_emperor_scanner *ues) {
	struct uwsgi_instance *ui_current;
	struct dirent *de;
	struct stat st;

	if (chdir(ues->arg)) {
		uwsgi_error("chdir()");
		return;
	}

	DIR *dir = opendir(".");
	while ((de = readdir(dir)) != NULL) {

		if (!uwsgi_emperor_is_valid(de->d_name))
			continue;

		if (stat(de->d_name, &st))
			continue;

		if (!S_ISREG(st.st_mode))
			continue;

		ui_current = emperor_get(de->d_name);

		if (ui_current) {
			// check if uid or gid are changed, in such case, stop the instance
			if (uwsgi.emperor_tyrant) {
				if (st.st_uid != ui_current->uid || st.st_gid != ui_current->gid) {
					uwsgi_log("!!! permissions of file %s changed. stopping the instance... !!!\n", de->d_name);
					emperor_stop(ui_current);
					continue;
				}
			}
			// check if mtime is changed and the uWSGI instance must be reloaded
			if (st.st_mtime > ui_current->last_mod) {
				emperor_respawn(ui_current, st.st_mtime);
			}
		}
		else {
			emperor_add(ues, de->d_name, st.st_mtime, NULL, 0, st.st_uid, st.st_gid);
		}
	}
	closedir(dir);

	// now check for removed instances
	struct uwsgi_instance *c_ui = ui->ui_next;

	while (c_ui) {
		if (c_ui->scanner == ues) {
			if (stat(c_ui->name, &st)) {
				emperor_stop(c_ui);
			}
		}
		c_ui = c_ui->ui_next;
	}
}
Esempio n. 4
0
File: emperor.c Progetto: ahua/c
void uwsgi_emperor_simple_do(struct uwsgi_emperor_scanner *ues, char *name, char *config, time_t ts, uid_t uid, gid_t gid, char *socket_name) {

	if (!uwsgi_emperor_is_valid(name))
		return;

	struct uwsgi_instance *ui_current = emperor_get(name);

	if (ui_current) {
		// check if uid or gid are changed, in such case, stop the instance
		if (uwsgi.emperor_tyrant) {
			if (uid != ui_current->uid || gid != ui_current->gid) {
				uwsgi_log("[emperor-tyrant] !!! permissions of vassal %s changed. stopping the instance... !!!\n", name);
				emperor_stop(ui_current);
				return;
			}
		}
		// check if mtime is changed and the uWSGI instance must be reloaded
		if (ts > ui_current->last_mod) {
			// make a new config (free the old one) if needed
			if (config) {
				if (ui_current->config)
					free(ui_current->config);
				ui_current->config = uwsgi_str(config);
				ui_current->config_len = strlen(ui_current->config);
			}
			// reload the instance
			emperor_respawn(ui_current, ts);
		}
	}
	else {
		// make a copy of the config as it will be freed
		char *new_config = NULL;
		size_t new_config_len = 0;
		if (config) {
			new_config = uwsgi_str(config);
			new_config_len = strlen(new_config);
		}
		emperor_add(ues, name, ts, new_config, new_config_len, uid, gid, socket_name);
	}
}
Esempio n. 5
0
void uwsgi_imperial_monitor_amqp_event(struct uwsgi_emperor_scanner *ues) {

	uint64_t msgsize;
	char *amqp_routing_key = NULL;
	struct uwsgi_instance *ui_current;
	struct stat st;

	char *config = uwsgi_amqp_consume(ues->fd, &msgsize, &amqp_routing_key);
				
	if (!config) {
		uwsgi_log("problem with RabbitMQ server, trying reconnection...\n");
		close(ues->fd);
		ues->fd = -1;
		return;
	}

	// having a routing key means the body will be mapped to a config chunk
	if (amqp_routing_key) {
		uwsgi_log("AMQP routing_key = %s\n", amqp_routing_key);

		ui_current = emperor_get(amqp_routing_key);

                if (ui_current) {
			// make a new config
			free(ui_current->config);
			ui_current->config = config;
			ui_current->config_len = msgsize;
			if (!msgsize) {
				emperor_stop(ui_current);
			}
			else {
                               	emperor_respawn(ui_current, uwsgi_now());
			}
			goto end0;
                }

		if (msgsize > 0) {
                	emperor_add(ues, amqp_routing_key, uwsgi_now(), config, msgsize, 0, 0);
		}

end0:
		free(config);
                free(amqp_routing_key);
                return;
	}


	// no routing key means the body contains a path to a config file
	if (msgsize >= 0xff || !msgsize) goto end;

	char *config_file = uwsgi_concat2n(config, msgsize, "", 0);

	ui_current = emperor_get(config_file);

	// if non-http check for file existance
	if (strncmp(config_file, "http://", 7)) {
		if (stat(config_file, &st)) {
			free(config_file);
			if (ui_current)
				emperor_stop(ui_current);
			goto end;
		}

		if (!S_ISREG(st.st_mode)) {
			free(config_file);
			if (ui_current)
				emperor_stop(ui_current);
			goto end;
		}
	}


	if (ui_current) {
		emperor_respawn(ui_current, uwsgi_now());
	}
	else {
		emperor_add(ues, config_file, uwsgi_now(), NULL, 0, 0, 0);
	}

	free(config_file);

end:
	free(config);

}
Esempio n. 6
0
void emperor_loop() {

	// monitor a directory

	struct uwsgi_instance ui_base;
	struct uwsgi_instance *ui_current;

	pid_t diedpid;
	int waitpid_status;
	int has_children = 0;
	int i_am_alone = 0;
	int i;

	void *events;
	int nevents;
	int interesting_fd;
	char notification_message[64];
	struct rlimit rl;

	uwsgi.emperor_stats_fd = -1;

	if (uwsgi.emperor_pidfile) {
		uwsgi_write_pidfile(uwsgi.emperor_pidfile);
	}

	signal(SIGPIPE, SIG_IGN);
	uwsgi_unix_signal(SIGINT, royal_death);
	uwsgi_unix_signal(SIGTERM, royal_death);
	uwsgi_unix_signal(SIGQUIT, royal_death);
	uwsgi_unix_signal(SIGUSR1, emperor_stats);
	uwsgi_unix_signal(SIGHUP, emperor_massive_reload);

	memset(&ui_base, 0, sizeof(struct uwsgi_instance));

	if (getrlimit(RLIMIT_NOFILE, &rl)) {
		uwsgi_error("getrlimit()");
		exit(1);
	}

	uwsgi.max_fd = rl.rlim_cur;

	emperor_throttle_level = uwsgi.emperor_throttle;

	// the queue must be initialized before adding scanners
	uwsgi.emperor_queue = event_queue_init();

	emperor_build_scanners();

	events = event_queue_alloc(64);

	if (uwsgi.has_emperor) {
		uwsgi_log("*** starting uWSGI sub-Emperor ***\n");
	}
	else {
		uwsgi_log("*** starting uWSGI Emperor ***\n");
	}

	if (uwsgi.emperor_stats) {
		char *tcp_port = strchr(uwsgi.emperor_stats, ':');
		if (tcp_port) {
			// disable deferred accept for this socket
			int current_defer_accept = uwsgi.no_defer_accept;
			uwsgi.no_defer_accept = 1;
			uwsgi.emperor_stats_fd = bind_to_tcp(uwsgi.emperor_stats, uwsgi.listen_queue, tcp_port);
			uwsgi.no_defer_accept = current_defer_accept;
		}
		else {
			uwsgi.emperor_stats_fd = bind_to_unix(uwsgi.emperor_stats, uwsgi.listen_queue, uwsgi.chmod_socket, uwsgi.abstract_socket);
		}

		event_queue_add_fd_read(uwsgi.emperor_queue, uwsgi.emperor_stats_fd);
		uwsgi_log("*** Emperor stats server enabled on %s fd: %d ***\n", uwsgi.emperor_stats, uwsgi.emperor_stats_fd);
	}

	ui = &ui_base;

	int freq = 0;

	for (;;) {


		if (!i_am_alone) {
			diedpid = waitpid(uwsgi.emperor_pid, &waitpid_status, WNOHANG);
			if (diedpid < 0 || diedpid > 0) {
				i_am_alone = 1;
			}
		}

		nevents = event_queue_wait_multi(uwsgi.emperor_queue, freq, events, 64);
		freq = uwsgi.emperor_freq;

		for (i = 0; i < nevents; i++) {
			interesting_fd = event_queue_interesting_fd(events, i);

			if (uwsgi.emperor_stats && uwsgi.emperor_stats_fd > -1 && interesting_fd == uwsgi.emperor_stats_fd) {
				emperor_send_stats(uwsgi.emperor_stats_fd);
				continue;
			}

			// check if a monitor is mapped to that file descriptor
			if (uwsgi_emperor_scanner_event(interesting_fd))
				continue;


			ui_current = emperor_get_by_fd(interesting_fd);
			if (ui_current) {
				char byte;
				ssize_t rlen = read(interesting_fd, &byte, 1);
				if (rlen <= 0) {
					// SAFE
					if (!ui_current->config_len) {
						emperor_del(ui_current);
					}
				}
				else {
					if (byte == 17) {
						ui_current->loyal = 1;
						ui_current->last_loyal = uwsgi_now();
						uwsgi_log("[emperor] vassal %s is now loyal\n", ui_current->name);
						// remove it from the blacklist
						uwsgi_emperor_blacklist_remove(ui_current->name);
						// TODO post-start hook
					}
					// heartbeat can be used for spotting blocked instances
					else if (byte == 26) {
						ui_current->last_heartbeat = uwsgi_now();
					}
					else if (byte == 22) {
						emperor_stop(ui_current);
					}
					else if (byte == 30 && uwsgi.emperor_broodlord > 0 && uwsgi.emperor_broodlord_count < uwsgi.emperor_broodlord) {
						uwsgi_log("[emperor] going in broodlord mode: launching zergs for %s\n", ui_current->name);
						char *zerg_name = uwsgi_concat3(ui_current->name, ":", "zerg");
						emperor_add(NULL, zerg_name, uwsgi_now(), NULL, 0, ui_current->uid, ui_current->gid);
						free(zerg_name);
					}
				}
			}
			else {
				uwsgi_log("[emperor] unrecognized vassal event on fd %d\n", interesting_fd);
				close(interesting_fd);
			}

		}

		uwsgi_emperor_run_scanners();

		// check for heartbeat (if required)
		ui_current = ui->ui_next;
		while (ui_current) {
			if (ui_current->last_heartbeat > 0) {
				if ((ui_current->last_heartbeat + uwsgi.emperor_heartbeat) < uwsgi_now()) {
					uwsgi_log("[emperor] vassal %s sent no heartbeat in last %d seconds, respawning it...\n", ui_current->name, uwsgi.emperor_heartbeat);
					// set last_heartbeat to 0 avoiding races
					ui_current->last_heartbeat = 0;
					emperor_respawn(ui_current, uwsgi_now());
				}
			}
			ui_current = ui_current->ui_next;
		}

		// check for removed instances
		ui_current = ui;
		has_children = 0;
		while (ui_current->ui_next) {
			ui_current = ui_current->ui_next;
			has_children++;
		}

		if (uwsgi.notify) {
			if (snprintf(notification_message, 64, "The Emperor is governing %d vassals", has_children) >= 34) {
				uwsgi_notify(notification_message);
			}
		}

		if (has_children) {
			diedpid = waitpid(WAIT_ANY, &waitpid_status, WNOHANG);
		}
		else {
			// vacuum
			waitpid(WAIT_ANY, &waitpid_status, WNOHANG);
			diedpid = 0;
		}
		if (diedpid < 0) {
			// it looks like it happens when OOM is triggered to Linux cgroup, but it could be a uWSGI bug :P
			// by the way, fallback to a clean situation...
			if (errno == ECHILD) {
				uwsgi_log("--- MUTINY DETECTED !!! IMPALING VASSALS... ---\n");
				ui_current = ui->ui_next;
				while (ui_current) {
					struct uwsgi_instance *rebel_vassal = ui_current;
					ui_current = ui_current->ui_next;
					emperor_del(rebel_vassal);
				}
			}
			else {
				uwsgi_error("waitpid()");
			}
		}
		ui_current = ui;
		while (ui_current->ui_next) {
			ui_current = ui_current->ui_next;
			if (ui_current->status == 1) {
				if (ui_current->config)
					free(ui_current->config);
				// SAFE
				emperor_del(ui_current);
				break;
			}
			else if (ui_current->pid == diedpid) {
				if (ui_current->status == 0) {
					// respawn an accidentally dead instance if its exit code is not UWSGI_EXILE_CODE
					if (WIFEXITED(waitpid_status) && WEXITSTATUS(waitpid_status) == UWSGI_EXILE_CODE) {
						// SAFE
						emperor_del(ui_current);
					}
					else {
						// UNSAFE
						emperor_add(ui_current->scanner, ui_current->name, ui_current->last_mod, ui_current->config, ui_current->config_len, ui_current->uid, ui_current->gid);
						emperor_del(ui_current);
					}
					break;
				}
				else if (ui_current->status == 1) {
					// remove 'marked for dead' instance
					if (ui_current->config)
						free(ui_current->config);
					// SAFE
					emperor_del(ui_current);
					break;
				}
			}
		}


	}

}
Esempio n. 7
0
File: emperor.c Progetto: ahua/c
// this is the monitor for glob patterns
void uwsgi_imperial_monitor_glob(struct uwsgi_emperor_scanner *ues) {

	glob_t g;
	int i;
	struct stat st;
	struct uwsgi_instance *ui_current;

	if (glob(ues->arg, GLOB_MARK | GLOB_NOCHECK, NULL, &g)) {
		uwsgi_error("glob()");
		return;
	}

	for (i = 0; i < (int) g.gl_pathc; i++) {

		if (!uwsgi_emperor_is_valid(g.gl_pathv[i]))
			continue;

		if (stat(g.gl_pathv[i], &st))
			continue;

		if (!S_ISREG(st.st_mode))
			continue;

		ui_current = emperor_get(g.gl_pathv[i]);

		uid_t t_uid = st.st_uid;
                gid_t t_gid = st.st_gid;

                if (uwsgi.emperor_tyrant && uwsgi.emperor_tyrant_nofollow) {
                        struct stat lst;
                        if (lstat(g.gl_pathv[i], &lst)) {
                                uwsgi_error("[emperor-tyrant]/lstat()");
                                if (ui_current) {
                                        uwsgi_log("!!! availability of file %s changed. stopping the instance... !!!\n", g.gl_pathv[i]);
                                        emperor_stop(ui_current);
                                }
                                continue;
                        }
                        t_uid = lst.st_uid;
                        t_gid = lst.st_gid;
                }

		if (ui_current) {
			// check if uid or gid are changed, in such case, stop the instance
			if (uwsgi.emperor_tyrant) {
				if (t_uid != ui_current->uid || t_gid != ui_current->gid) {
					uwsgi_log("!!! permissions of file %s changed. stopping the instance... !!!\n", g.gl_pathv[i]);
					emperor_stop(ui_current);
					continue;
				}
			}
			// check if mtime is changed and the uWSGI instance must be reloaded
			if (st.st_mtime > ui_current->last_mod) {
				emperor_respawn(ui_current, st.st_mtime);
			}
		}
		else {
			char *socket_name = emperor_check_on_demand_socket(g.gl_pathv[i]);
			emperor_add(ues, g.gl_pathv[i], st.st_mtime, NULL, 0, t_uid, t_gid, socket_name);
			if (socket_name) free(socket_name);
		}

	}
	globfree(&g);

	// now check for removed instances
	struct uwsgi_instance *c_ui = ui->ui_next;

	while (c_ui) {
		if (c_ui->scanner == ues) {
			if (c_ui->zerg) {
                                char *colon = strrchr(c_ui->name, ':');
                                if (!colon) {
                                        emperor_stop(c_ui);
                                }
                                else {
                                        char *filename = uwsgi_calloc(0xff);
                                        memcpy(filename, c_ui->name, colon - c_ui->name);
                                        if (stat(filename, &st)) {
                                                emperor_stop(c_ui);
                                        }
                                        free(filename);
                                }
                        }
                        else {
                                if (stat(c_ui->name, &st)) { 
                                        emperor_stop(c_ui);
                                }       
                        }
		}
		c_ui = c_ui->ui_next;
	}


}
Esempio n. 8
0
File: emperor.c Progetto: ahua/c
// this is the monitor for non-glob directories
void uwsgi_imperial_monitor_directory(struct uwsgi_emperor_scanner *ues) {
	struct uwsgi_instance *ui_current;
	struct dirent *de;
	struct stat st;

	if (chdir(ues->arg)) {
		uwsgi_error("chdir()");
		return;
	}

	DIR *dir = opendir(".");
	while ((de = readdir(dir)) != NULL) {

		if (!uwsgi_emperor_is_valid(de->d_name))
			continue;

		if (stat(de->d_name, &st))
			continue;

		if (!S_ISREG(st.st_mode))
			continue;

		ui_current = emperor_get(de->d_name);

		uid_t t_uid = st.st_uid;
		gid_t t_gid = st.st_gid;

		if (uwsgi.emperor_tyrant && uwsgi.emperor_tyrant_nofollow) {
			struct stat lst;
			if (lstat(de->d_name, &lst)) {
				uwsgi_error("[emperor-tyrant]/lstat()");
				if (ui_current) {
					uwsgi_log("!!! availability of file %s changed. stopping the instance... !!!\n", de->d_name);
					emperor_stop(ui_current);
				}
				continue;
			}
			t_uid = lst.st_uid;
			t_gid = lst.st_gid;
		}

		if (ui_current) {
			// check if uid or gid are changed, in such case, stop the instance
			if (uwsgi.emperor_tyrant) {
				if (t_uid != ui_current->uid || t_gid != ui_current->gid) {
					uwsgi_log("!!! permissions of file %s changed. stopping the instance... !!!\n", de->d_name);
					emperor_stop(ui_current);
					continue;
				}
			}
			// check if mtime is changed and the uWSGI instance must be reloaded
			if (st.st_mtime > ui_current->last_mod) {
				emperor_respawn(ui_current, st.st_mtime);
			}
		}
		else {
			char *socket_name = emperor_check_on_demand_socket(de->d_name);
			emperor_add(ues, de->d_name, st.st_mtime, NULL, 0, t_uid, t_gid, socket_name);
			if (socket_name) free(socket_name);
		}
	}
	closedir(dir);

	// now check for removed instances
	struct uwsgi_instance *c_ui = ui->ui_next;

	while (c_ui) {
		if (c_ui->scanner == ues) {
			if (c_ui->zerg) {
				char *colon = strrchr(c_ui->name, ':');
				if (!colon) {
					emperor_stop(c_ui);
				}
				else {
					char *filename = uwsgi_calloc(0xff);
					memcpy(filename, c_ui->name, colon - c_ui->name);
					if (stat(filename, &st)) {
						emperor_stop(c_ui);
					}
					free(filename);
				}
			}
			else {
                                if (stat(c_ui->name, &st)) {
                                       	emperor_stop(c_ui);
                                }
			}
		}
		c_ui = c_ui->ui_next;
	}
}