| 
									
										
										
										
											2009-09-16 14:02:01 +00:00
										 |  |  | import sys, os, platform | 
					
						
							| 
									
										
										
										
											2009-08-29 17:25:22 +00:00
										 |  |  | import http, http.client, http.server, urllib | 
					
						
							|  |  |  | import subprocess, time | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | from netrender.utils import * | 
					
						
							|  |  |  | import netrender.model | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | CANCEL_POLL_SPEED = 2 | 
					
						
							|  |  |  | MAX_TIMEOUT = 10 | 
					
						
							|  |  |  | INCREMENT_TIMEOUT = 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def slave_Info(): | 
					
						
							| 
									
										
										
										
											2009-09-16 14:02:01 +00:00
										 |  |  | 	sysname, nodename, release, version, machine, processor = platform.uname() | 
					
						
							| 
									
										
										
										
											2009-08-30 02:40:42 +00:00
										 |  |  | 	slave = netrender.model.RenderSlave() | 
					
						
							|  |  |  | 	slave.name = nodename | 
					
						
							| 
									
										
										
										
											2009-09-16 14:02:01 +00:00
										 |  |  | 	slave.stats = sysname + " " + release + " " + machine + " " + processor | 
					
						
							| 
									
										
										
										
											2009-08-30 02:40:42 +00:00
										 |  |  | 	return slave | 
					
						
							| 
									
										
										
										
											2009-08-29 17:25:22 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def testCancel(conn, job_id): | 
					
						
							|  |  |  | 		conn.request("HEAD", "status", headers={"job-id":job_id}) | 
					
						
							|  |  |  | 		response = conn.getresponse() | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 		# cancelled if job isn't found anymore | 
					
						
							| 
									
										
										
										
											2009-09-01 01:09:05 +00:00
										 |  |  | 		if response.status == http.client.NO_CONTENT: | 
					
						
							| 
									
										
										
										
											2009-08-29 17:25:22 +00:00
										 |  |  | 			return True | 
					
						
							|  |  |  | 		else: | 
					
						
							|  |  |  | 			return False | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-09-16 19:47:58 +00:00
										 |  |  | def testFile(conn, job_id, slave_id, JOB_PREFIX, file_path, main_path = None): | 
					
						
							| 
									
										
										
										
											2009-09-02 00:07:55 +00:00
										 |  |  | 	job_full_path = prefixPath(JOB_PREFIX, file_path, main_path) | 
					
						
							| 
									
										
										
										
											2009-09-01 01:09:05 +00:00
										 |  |  | 	 | 
					
						
							|  |  |  | 	if not os.path.exists(job_full_path): | 
					
						
							| 
									
										
										
										
											2009-09-08 01:18:06 +00:00
										 |  |  | 		temp_path = JOB_PREFIX + "slave.temp.blend" | 
					
						
							| 
									
										
										
										
											2009-09-16 19:47:58 +00:00
										 |  |  | 		conn.request("GET", "file", headers={"job-id": job_id, "slave-id":slave_id, "job-file":file_path}) | 
					
						
							| 
									
										
										
										
											2009-09-01 01:09:05 +00:00
										 |  |  | 		response = conn.getresponse() | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 		if response.status != http.client.OK: | 
					
						
							|  |  |  | 			return None # file for job not returned by server, need to return an error code to server | 
					
						
							|  |  |  | 		 | 
					
						
							| 
									
										
										
										
											2009-09-08 01:18:06 +00:00
										 |  |  | 		f = open(temp_path, "wb") | 
					
						
							| 
									
										
										
										
											2009-09-01 01:09:05 +00:00
										 |  |  | 		buf = response.read(1024) | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 		while buf: | 
					
						
							|  |  |  | 			f.write(buf) | 
					
						
							|  |  |  | 			buf = response.read(1024) | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 		f.close() | 
					
						
							|  |  |  | 		 | 
					
						
							| 
									
										
										
										
											2009-09-08 01:18:06 +00:00
										 |  |  | 		os.renames(temp_path, job_full_path) | 
					
						
							|  |  |  | 		 | 
					
						
							| 
									
										
										
										
											2009-09-01 01:09:05 +00:00
										 |  |  | 	return job_full_path | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-08-29 17:25:22 +00:00
										 |  |  | def render_slave(engine, scene): | 
					
						
							| 
									
										
										
										
											2009-09-01 01:09:05 +00:00
										 |  |  | 	netsettings = scene.network_render | 
					
						
							| 
									
										
										
										
											2009-08-29 17:25:22 +00:00
										 |  |  | 	timeout = 1 | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	engine.update_stats("", "Network render node initiation") | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	conn = clientConnection(scene) | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	if conn: | 
					
						
							| 
									
										
										
										
											2009-08-30 02:40:42 +00:00
										 |  |  | 		conn.request("POST", "slave", repr(slave_Info().serialize())) | 
					
						
							| 
									
										
										
										
											2009-08-29 17:25:22 +00:00
										 |  |  | 		response = conn.getresponse() | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 		slave_id = response.getheader("slave-id") | 
					
						
							|  |  |  | 		 | 
					
						
							| 
									
										
										
										
											2009-09-02 00:07:55 +00:00
										 |  |  | 		NODE_PREFIX = netsettings.path + "slave_" + slave_id + os.sep | 
					
						
							| 
									
										
										
										
											2009-09-01 01:09:05 +00:00
										 |  |  | 		if not os.path.exists(NODE_PREFIX): | 
					
						
							|  |  |  | 			os.mkdir(NODE_PREFIX) | 
					
						
							|  |  |  | 	 | 
					
						
							| 
									
										
										
										
											2009-08-29 17:25:22 +00:00
										 |  |  | 		while not engine.test_break(): | 
					
						
							|  |  |  | 			 | 
					
						
							|  |  |  | 			conn.request("GET", "job", headers={"slave-id":slave_id}) | 
					
						
							|  |  |  | 			response = conn.getresponse() | 
					
						
							|  |  |  | 			 | 
					
						
							|  |  |  | 			if response.status == http.client.OK: | 
					
						
							|  |  |  | 				timeout = 1 # reset timeout on new job | 
					
						
							|  |  |  | 				 | 
					
						
							|  |  |  | 				job = netrender.model.RenderJob.materialize(eval(str(response.read(), encoding='utf8'))) | 
					
						
							|  |  |  | 				 | 
					
						
							| 
									
										
										
										
											2009-09-01 01:09:05 +00:00
										 |  |  | 				JOB_PREFIX = NODE_PREFIX + "job_" + job.id + os.sep | 
					
						
							|  |  |  | 				if not os.path.exists(JOB_PREFIX): | 
					
						
							|  |  |  | 					os.mkdir(JOB_PREFIX) | 
					
						
							| 
									
										
										
										
											2009-08-29 17:25:22 +00:00
										 |  |  | 				 | 
					
						
							| 
									
										
										
										
											2009-09-09 02:25:14 +00:00
										 |  |  | 				job_path = job.files[0][0] # data in files have format (path, start, end) | 
					
						
							| 
									
										
										
										
											2009-09-01 01:09:05 +00:00
										 |  |  | 				main_path, main_file = os.path.split(job_path) | 
					
						
							| 
									
										
										
										
											2009-08-29 17:25:22 +00:00
										 |  |  | 				 | 
					
						
							| 
									
										
										
										
											2009-09-16 19:47:58 +00:00
										 |  |  | 				job_full_path = testFile(conn, job.id, slave_id, JOB_PREFIX, job_path) | 
					
						
							| 
									
										
										
										
											2009-09-01 01:09:05 +00:00
										 |  |  | 				print("Fullpath", job_full_path) | 
					
						
							|  |  |  | 				print("File:", main_file, "and %i other files" % (len(job.files) - 1,)) | 
					
						
							|  |  |  | 				engine.update_stats("", "Render File", main_file, "for job", job.id) | 
					
						
							|  |  |  | 				 | 
					
						
							| 
									
										
										
										
											2009-09-09 02:25:14 +00:00
										 |  |  | 				for file_path, start, end in job.files[1:]: | 
					
						
							|  |  |  | 					print("\t", file_path) | 
					
						
							| 
									
										
										
										
											2009-09-16 19:47:58 +00:00
										 |  |  | 					testFile(conn, job.id, slave_id, JOB_PREFIX, file_path, main_path) | 
					
						
							| 
									
										
										
										
											2009-08-29 17:25:22 +00:00
										 |  |  | 				 | 
					
						
							|  |  |  | 				frame_args = [] | 
					
						
							|  |  |  | 				 | 
					
						
							|  |  |  | 				for frame in job.frames: | 
					
						
							| 
									
										
										
										
											2009-09-01 01:09:05 +00:00
										 |  |  | 					print("frame", frame.number) | 
					
						
							| 
									
										
										
										
											2009-08-29 17:25:22 +00:00
										 |  |  | 					frame_args += ["-f", str(frame.number)] | 
					
						
							|  |  |  | 					 | 
					
						
							|  |  |  | 				start_t = time.time() | 
					
						
							|  |  |  | 				 | 
					
						
							| 
									
										
										
										
											2009-09-01 01:09:05 +00:00
										 |  |  | 				process = subprocess.Popen([sys.argv[0], "-b", job_full_path, "-o", JOB_PREFIX + "######", "-E", "BLENDER_RENDER", "-F", "MULTILAYER"] + frame_args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)	 | 
					
						
							| 
									
										
										
										
											2009-08-29 17:25:22 +00:00
										 |  |  | 				 | 
					
						
							| 
									
										
										
										
											2009-09-15 19:53:18 +00:00
										 |  |  | 				headers = {"job-id":job.id, "slave-id":slave_id} | 
					
						
							|  |  |  | 				 | 
					
						
							| 
									
										
										
										
											2009-08-29 17:25:22 +00:00
										 |  |  | 				cancelled = False | 
					
						
							|  |  |  | 				stdout = bytes() | 
					
						
							|  |  |  | 				run_t = time.time() | 
					
						
							|  |  |  | 				while process.poll() == None and not cancelled: | 
					
						
							|  |  |  | 					stdout += process.stdout.read(32) | 
					
						
							|  |  |  | 					current_t = time.time() | 
					
						
							|  |  |  | 					cancelled = engine.test_break() | 
					
						
							|  |  |  | 					if current_t - run_t > CANCEL_POLL_SPEED: | 
					
						
							| 
									
										
										
										
											2009-09-15 19:53:18 +00:00
										 |  |  | 						 | 
					
						
							|  |  |  | 						# update logs. Eventually, it should support one log file for many frames | 
					
						
							|  |  |  | 						for frame in job.frames: | 
					
						
							|  |  |  | 							headers["job-frame"] = str(frame.number) | 
					
						
							|  |  |  | 							conn.request("PUT", "log", stdout, headers=headers) | 
					
						
							|  |  |  | 							response = conn.getresponse() | 
					
						
							|  |  |  | 						 | 
					
						
							|  |  |  | 						stdout = bytes() | 
					
						
							|  |  |  | 						 | 
					
						
							|  |  |  | 						run_t = current_t | 
					
						
							| 
									
										
										
										
											2009-08-29 17:25:22 +00:00
										 |  |  | 						if testCancel(conn, job.id): | 
					
						
							|  |  |  | 							cancelled = True | 
					
						
							|  |  |  | 				 | 
					
						
							|  |  |  | 				if cancelled: | 
					
						
							| 
									
										
										
										
											2009-09-09 20:56:49 +00:00
										 |  |  | 					# kill process if needed | 
					
						
							|  |  |  | 					if process.poll() == None: | 
					
						
							|  |  |  | 						process.terminate() | 
					
						
							| 
									
										
										
										
											2009-08-29 17:25:22 +00:00
										 |  |  | 					continue # to next frame | 
					
						
							|  |  |  | 				 | 
					
						
							|  |  |  | 				total_t = time.time() - start_t | 
					
						
							|  |  |  | 				 | 
					
						
							|  |  |  | 				avg_t = total_t / len(job.frames) | 
					
						
							|  |  |  | 				 | 
					
						
							|  |  |  | 				status = process.returncode | 
					
						
							|  |  |  | 				 | 
					
						
							|  |  |  | 				print("status", status) | 
					
						
							|  |  |  | 				 | 
					
						
							| 
									
										
										
										
											2009-09-15 19:53:18 +00:00
										 |  |  | 				# flush the rest of the logs | 
					
						
							|  |  |  | 				if stdout: | 
					
						
							|  |  |  | 					for frame in job.frames: | 
					
						
							|  |  |  | 						headers["job-frame"] = str(frame.number) | 
					
						
							|  |  |  | 						conn.request("PUT", "log", stdout, headers=headers) | 
					
						
							|  |  |  | 						response = conn.getresponse() | 
					
						
							|  |  |  | 				 | 
					
						
							| 
									
										
										
										
											2009-08-29 17:25:22 +00:00
										 |  |  | 				headers = {"job-id":job.id, "slave-id":slave_id, "job-time":str(avg_t)} | 
					
						
							|  |  |  | 				 | 
					
						
							|  |  |  | 				if status == 0: # non zero status is error | 
					
						
							|  |  |  | 					headers["job-result"] = str(DONE) | 
					
						
							|  |  |  | 					for frame in job.frames: | 
					
						
							|  |  |  | 						headers["job-frame"] = str(frame.number) | 
					
						
							|  |  |  | 						# send result back to server | 
					
						
							| 
									
										
										
										
											2009-09-01 01:09:05 +00:00
										 |  |  | 						f = open(JOB_PREFIX + "%06d" % frame.number + ".exr", 'rb') | 
					
						
							| 
									
										
										
										
											2009-08-29 17:25:22 +00:00
										 |  |  | 						conn.request("PUT", "render", f, headers=headers) | 
					
						
							|  |  |  | 						f.close() | 
					
						
							|  |  |  | 						response = conn.getresponse() | 
					
						
							|  |  |  | 				else: | 
					
						
							|  |  |  | 					headers["job-result"] = str(ERROR) | 
					
						
							|  |  |  | 					for frame in job.frames: | 
					
						
							|  |  |  | 						headers["job-frame"] = str(frame.number) | 
					
						
							|  |  |  | 						# send error result back to server | 
					
						
							|  |  |  | 						conn.request("PUT", "render", headers=headers) | 
					
						
							|  |  |  | 						response = conn.getresponse() | 
					
						
							|  |  |  | 			else: | 
					
						
							|  |  |  | 				if timeout < MAX_TIMEOUT: | 
					
						
							|  |  |  | 					timeout += INCREMENT_TIMEOUT | 
					
						
							|  |  |  | 				 | 
					
						
							|  |  |  | 				for i in range(timeout): | 
					
						
							|  |  |  | 					time.sleep(1) | 
					
						
							|  |  |  | 					if engine.test_break(): | 
					
						
							|  |  |  | 						conn.close() | 
					
						
							|  |  |  | 						return | 
					
						
							|  |  |  | 			 | 
					
						
							|  |  |  | 		conn.close() |