Patch: support for deleted/disabled jobs

Johan Kiviniemi netsplit.com-upstart-devel at johan.kiviniemi.name
Sun Sep 3 16:47:26 BST 2006


Hi

I already sent this to Scott, but i thought i might as well post it
here, in case anyone's interested.

This patch adds support for deletion of jobs, i.e. when you delete a
file from /etc/event.d, upstart will kill its process (if one's running)
and then forget about the job.

It also adds support for a "disabled" stanza, which allows a sysadmin to
disable jobs easily without having to delete them. Adding the line
"disabled" to an event.d file has the same effect as deleting the file
(the file will still be parsed for valid syntax, though).

-- 
Jοhan Kiviniemi  http://johan.kiviniemi.name/
-------------- next part --------------
=== modified file 'init/cfgfile.c'
--- init/cfgfile.c	2006-09-01 18:47:39 +0000
+++ init/cfgfile.c	2006-09-02 19:29:50 +0000
@@ -249,6 +249,13 @@
 		nih_list_free (&old_job->entry);
 	}
 
+	/* A "disabled" stanza was found; the job should be deleted */
+	if (job->disabled) {
+		nih_debug ("Job %s is disabled", job->name);
+		if (job_delete (job))
+			return NULL;  /* Job was destroyed immediately */
+	}
+
 	return job;
 }
 
@@ -350,6 +357,14 @@
 				  _("expected version string"));
 		}
 
+	} else if (! strncmp (file + tok_start, "disabled", tok_len)) {
+		/* disabled
+		 *
+		 * indicates that the job should be ignored
+		 */
+
+		job->disabled = TRUE;
+
 	} else if (! strncmp (file + tok_start, "depends", tok_len)) {
 		/* depends WS <job name>...
 		 *
@@ -1646,11 +1661,15 @@
 
 	/* FIXME better name checking required */
 
-	/* FIXME we don't handle DELETE yet ... that should probably mark
-	 * the running job as an instance or delete a stopped one
-	 */
 	if (events & IN_DELETE) {
-		nih_debug ("Delete of %s/%s (ignored)", watch->path, name);
+		Job *job;
+
+		nih_debug ("Delete of %s/%s", watch->path, name);
+
+		job = job_find_by_name (name);
+		if (job)
+			job_delete (job);
+
 		return;
 	}
 

=== modified file 'init/job.c'
--- init/job.c	2006-09-01 18:47:39 +0000
+++ init/job.c	2006-09-02 19:56:38 +0000
@@ -138,6 +138,8 @@
 	job->author = NULL;
 	job->version = NULL;
 
+	job->disabled = 0;
+
 	job->goal = JOB_STOP;
 	job->state = JOB_WAITING;
 
@@ -269,6 +271,8 @@
 job_change_state (Job      *job,
 		  JobState  state)
 {
+	int destroy = FALSE;
+
 	nih_assert (job != NULL);
 	nih_assert (job->process_state == PROCESS_NONE);
 
@@ -291,8 +295,9 @@
 			nih_assert (old_state == JOB_STOPPING);
 			nih_assert (job->goal == JOB_STOP);
 
-			/* FIXME
-			 * instances need to be cleaned up */
+			/* instances need to be cleaned up */
+			if (job->is_instance)
+				destroy = TRUE;
 
 			NIH_MUST (event = nih_sprintf (job, "%s/stopped",
 						       job->name));
@@ -407,6 +412,11 @@
 		if (job_event)
 			event_queue (job->name);
 	}
+
+	if (destroy) {
+		nih_info (_("destroying job %s"), job->name);
+		nih_list_free (&job->entry);
+	}
 }
 
 /**
@@ -826,7 +836,10 @@
 		 * If a list of "normal" exit codes is provided, this is
 		 * the list of exit codes that _prevent_ a respawn
 		 */
-		if (job->respawn) {
+		if (job->disabled) {
+			nih_info (_("%s is disabled, not respawning"),
+					job->name);
+		} else if (job->respawn) {
 			size_t i;
 
 			for (i = 0; i < job->normalexit_len; i++)
@@ -884,6 +897,11 @@
 
 	job_init ();
 
+	if (job->disabled) {
+		nih_info (_("%s is disabled, not starting"), job->name);
+		return;
+	}
+
 	if (job->goal == JOB_START)
 		return;
 
@@ -1016,6 +1034,38 @@
 
 
 /**
+ * job_delete:
+ * @job: job to be deleted.
+ *
+ * Stop and destroy the job.
+ *
+ * Returns: %TRUE if the job was destroyed immediately, %FALSE if not.
+ **/
+int
+job_delete (Job *job)
+{
+	nih_assert (job != NULL);
+
+	/* The job will be destroyed as soon as it reaches the "waiting"
+	 * state */
+	job->is_instance = TRUE;
+	/* Any attempts to start or respawn the job will be prevented */
+	job->disabled    = TRUE;
+
+	if (job->state == JOB_WAITING) {
+		nih_info (_("destroying job %s"), job->name);
+		nih_list_free (&job->entry);
+
+		return TRUE;
+	} else {
+		job_stop (job);
+
+		return FALSE;
+	}
+}
+
+
+/**
  * job_catch_runaway
  * @job: job respawning.
  *

=== modified file 'init/job.h'
--- init/job.h	2006-09-01 01:14:47 +0000
+++ init/job.h	2006-09-02 19:28:21 +0000
@@ -85,6 +85,7 @@
  * @name: string name of the job; namespace shared with events,
  * @description: description of the job; intended for humans,
  * @author: author of the job; intended for humans,
+ * @disabled: whether attempts to start or respawn the job should be prevented,
  * @version: version of the job; intended for humans,
  * @goal: whether the job is to be stopped or started,
  * @state: actual state of the job,
@@ -136,6 +137,8 @@
 	char          *author;
 	char          *version;
 
+	int            disabled;
+
 	JobGoal        goal;
 	JobState       state;
 
@@ -217,6 +220,8 @@
 void        job_start           (Job *job);
 void        job_stop            (Job *job);
 
+int         job_delete          (Job *job);
+
 void        job_release_depends (Job *job);
 
 void        job_start_event     (Job *job, Event *event);

=== modified file 'init/tests/test_cfgfile.c'
--- init/tests/test_cfgfile.c	2006-08-31 21:08:56 +0000
+++ init/tests/test_cfgfile.c	2006-09-02 20:03:32 +0000
@@ -24,8 +24,10 @@
 
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <sys/wait.h>
 
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 
@@ -55,10 +57,11 @@
 int
 test_read_job (void)
 {
-	Job  *job;
-	FILE *jf, *output;
-	char  dirname[25], filename[35], text[161];
-	int   ret = 0, i, oldstderr;
+	Job   *job;
+	FILE  *jf, *output;
+	char   dirname[25], filename[35], text[161];
+	pid_t  pid;
+	int    ret = 0, i, oldstderr;
 
 	printf ("Testing cfg_read_job()\n");
 	sprintf (dirname, "/tmp/test_cfgfile.%d", getpid ());
@@ -750,6 +753,47 @@
 	nih_list_free (&job->entry);
 
 
+	printf ("...with disabled\n");
+	jf = fopen (filename, "w");
+	fprintf (jf, "exec /usr/bin/foo\n");
+	fprintf (jf, "disabled\n");
+	fclose (jf);
+
+	job = cfg_read_job (NULL, filename, "test");
+	if (job) {
+		printf ("BAD: job wasn't destroyed immediately.\n");
+		ret = 1;
+	}
+
+
+	printf ("...with re-reading job file that has became disabled\n");
+	job = job_new (NULL, "test");
+	job->goal = JOB_START;
+	job->state = JOB_RUNNING;
+	job->process_state = PROCESS_ACTIVE;
+	job->pid = pid = fork ();
+	if (pid == 0) {
+		select (0, NULL, NULL, NULL, NULL);
+
+		exit (0);
+	}
+
+	jf = fopen (filename, "w");
+	fprintf (jf, "exec /usr/bin/foo\n");
+	fprintf (jf, "disabled\n");
+	fclose (jf);
+
+	job = cfg_read_job (NULL, filename, "test");
+	if (! job) {
+		printf ("BAD: job was destroyed immediately.\n");
+		ret = 1;
+	} else {
+		nih_list_free (&job->entry);
+	}
+
+	waitpid (pid, NULL, 0);
+
+
 	printf ("...with interesting formatting\n");
 	jf = fopen (filename, "w");
 	fprintf (jf, "    description   \"foo\n");

=== modified file 'init/tests/test_job.c'
--- init/tests/test_job.c	2006-09-01 01:14:47 +0000
+++ init/tests/test_job.c	2006-09-02 20:47:12 +0000
@@ -3029,6 +3029,102 @@
 	return ret;
 }
 
+int
+test_delete (void)
+{
+	Job      *job;
+	NihTimer *timer;
+	pid_t     pid;
+	int       ret = 0;
+
+	printf ("Testing job_delete()\n");
+
+
+	printf ("...with waiting job\n");
+	job = job_new (NULL, "test");
+
+	was_called = 0;
+	nih_alloc_set_destructor (job, destructor_called);
+	job_delete (job);
+
+	if (! was_called) {
+		printf ("BAD: job exists after job_delete.\n");
+		ret = 1;
+	}
+
+
+	printf ("...with running job\n");
+	job = job_new (NULL, "test");
+	job->goal = JOB_START;
+	job->state = JOB_RUNNING;
+	job->process_state = PROCESS_ACTIVE;
+	job->pid = pid = fork ();
+	if (pid == 0) {
+		select (0, NULL, NULL, NULL, NULL);
+
+		exit (0);
+	}
+
+	was_called = 0;
+	nih_alloc_set_destructor (job, destructor_called);
+	job_delete (job);
+
+	if (was_called) {
+		printf ("BAD: job was destroyed immediately.\n");
+		ret = 1;
+	} else {
+		/* Job still exists, therefore we can run more tests */
+
+		if (job->is_instance != TRUE) {
+			printf ("BAD: job->is_instance isn't TRUE.\n");
+			ret = 1;
+		}
+
+		if (job->disabled != TRUE) {
+			printf ("BAD: job->disabled isn't TRUE.\n");
+			ret = 1;
+		}
+
+		/* Kill job immediately */
+		timer = job->kill_timer;
+		timer->callback (timer->data, timer);
+
+		if (! was_called) {
+			printf ("BAD: job exists after process being killed.\n");
+			ret = 1;
+		}
+	}
+
+
+	waitpid (pid, NULL, 0);
+
+	return ret;
+}
+
+int
+test_disabled (void)
+{
+	Job *job;
+	int  ret = 0;
+
+	printf ("Testing disabled job\n");
+
+	job = job_new (NULL, "test");
+	job->disabled = TRUE;
+
+	job_start (job);
+
+	if (job->goal == JOB_START) {
+		printf ("BAD: job was started.\n");
+		ret = 1;
+	}
+
+	nih_list_free (&job->entry);
+
+
+	return ret;
+}
+
 
 int
 main (int   argc,
@@ -3054,6 +3150,8 @@
 	ret |= test_detect_idle ();
 	ret |= test_read_state ();
 	ret |= test_write_state ();
+	ret |= test_delete ();
+	ret |= test_disabled ();
 
 	return ret;
 }

-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: not available
Url : https://lists.ubuntu.com/archives/upstart-devel/attachments/20060903/0bf1eca4/attachment.pgp 


More information about the Upstart-devel mailing list