netrender (features coded by Philippe van Hecke)

Support for secure connections between Master/client/slave using SSL/HTTPS

Fixed a bug with total job time on web interface (wrong value)
This commit is contained in:
Martin Poirier 2012-01-30 01:17:06 +00:00
parent 88085b624c
commit 8b56ce969d
8 changed files with 92 additions and 48 deletions

View File

@ -112,10 +112,10 @@ def fillCommonJobSettings(job, job_name, netsettings):
elif netsettings.job_type == "JOB_VCS":
job.type = netrender.model.JOB_VCS
def sendJob(conn, scene, anim = False):
def sendJob(conn, scene, anim = False, can_save = True):
netsettings = scene.network_render
if netsettings.job_type == "JOB_BLENDER":
return sendJobBlender(conn, scene, anim)
return sendJobBlender(conn, scene, anim, can_save)
elif netsettings.job_type == "JOB_VCS":
return sendJobVCS(conn, scene, anim)
@ -171,7 +171,7 @@ def sendJobVCS(conn, scene, anim = False):
return job_id
def sendJobBaking(conn, scene):
def sendJobBaking(conn, scene, can_save = True):
netsettings = scene.network_render
job = netrender.model.RenderJob()
@ -179,6 +179,9 @@ def sendJobBaking(conn, scene):
if not os.path.exists(filename):
raise RuntimeError("Current file path not defined\nSave your file before sending a job")
if can_save and netsettings.save_before_job:
bpy.ops.wm.save_mainfile(filepath=filename, check_existing=False)
job.addFile(filename)
@ -248,7 +251,7 @@ def sendJobBaking(conn, scene):
return job_id
def sendJobBlender(conn, scene, anim = False):
def sendJobBlender(conn, scene, anim = False, can_save = True):
netsettings = scene.network_render
job = netrender.model.RenderJob()
@ -263,7 +266,7 @@ def sendJobBlender(conn, scene, anim = False):
if not os.path.exists(filename):
raise RuntimeError("Current file path not defined\nSave your file before sending a job")
if netsettings.save_before_job:
if can_save and netsettings.save_before_job:
bpy.ops.wm.save_mainfile(filepath=filename, check_existing=False)
job.addFile(filename)
@ -371,7 +374,10 @@ class NetworkRenderEngine(bpy.types.RenderEngine):
force = netsettings.use_master_force_upload,
path = bpy.path.abspath(netsettings.path),
update_stats = self.update_stats,
test_break = self.test_break)
test_break = self.test_break,
use_ssl=netsettings.use_ssl,
cert_path=netsettings.cert_path,
key_path=netsettings.key_path)
def render_slave(self, scene):
@ -382,7 +388,7 @@ class NetworkRenderEngine(bpy.types.RenderEngine):
self.update_stats("", "Network render client initiation")
conn = clientConnection(netsettings.server_address, netsettings.server_port)
conn = clientConnection(netsettings)
if conn:
# Sending file
@ -404,7 +410,7 @@ class NetworkRenderEngine(bpy.types.RenderEngine):
if response.status == http.client.NO_CONTENT:
new_job = True
netsettings.job_id = sendJob(conn, scene)
netsettings.job_id = sendJob(conn, scene, can_save = False)
job_id = netsettings.job_id
requestResult(conn, job_id, scene.frame_current)

View File

@ -23,7 +23,7 @@ var jobTableHeader = ["action", "id", "name", "category", "tags", "type", "chunk
var framesTableHeader = ["no", "status", "render time", "slave", "log", "result"];
var JOB_TYPES = ["None", "Blender", "Process", "Versioned"];
var JOB_STATUS_TEXT = ["Waiting", "Paused", "Finished", "Queued"];
var JOB_SUBTYPE = ["BLENDER", "CYCLE"];
var JOB_SUBTYPE = ["None", "BLENDER", "CYCLE"];
var FRAME_STATUS_TEXT = ["Queued", "Dispatched", "Done", "error"];
var JOB_TYPE_NONE = 0;
var JOB_TYPE_BLENDER = 1;
@ -86,7 +86,7 @@ function changeJobsTable(jobs) {
}
if(name == "type") {
return JOB_TYPES[row.type] + "[" + JOB_SUBTYPE[row.subtype] + "]";
return JOB_TYPES[row.type] + "[" + row.render + "]";
}
if(name == "status") {
@ -283,14 +283,13 @@ function changeConfigureTable(rules) {
function showJob(id, name) {
var job = {};
function general(tab_name) {
var rendertime = 0;
var cumulate_rendertime = 0;
$.each(job.frames, function(index, frame) {
rendertime += frame.time;
cumulate_rendertime += frame.time;
});
var info = [new namevalue("resolution", job.resolution[0] + 'x' + job.resolution[1] + ' at ' + job.resolution[2] + '%'), new namevalue("tags", job.tags), new namevalue("result", getresult(id)), new namevalue("frames", job.frames.length), new namevalue("status", job.status), new namevalue("job name", job.name), new namevalue("type", job.type), new namevalue("render", job.subtype), new namevalue("render time:", secondsToHms(rendertime))];
var info = [new namevalue("resolution", job.resolution[0] + 'x' + job.resolution[1] + ' at ' + job.resolution[2] + '%'), new namevalue("tags", job.tags), new namevalue("result", getresult(id)), new namevalue("frames", job.frames.length), new namevalue("status", job.status), new namevalue("job name", job.name), new namevalue("type", job.type), new namevalue("render", job.subtype), new namevalue("render time", secondsToHms(job.wktime)), new namevalue("cumulate render time", secondsToHms(cumulate_rendertime))];
function cellview(name, row) {
@ -313,7 +312,7 @@ function showJob(id, name) {
case "type":
return JOB_TYPES[job.type];
case "render":
return JOB_SUBTYPE[job.subtype];
return job.render;
default:
return row.value;

View File

@ -4,7 +4,7 @@
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
#s
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@ -24,6 +24,7 @@ import zipfile
import select # for select.error
import json
from netrender.utils import *
import netrender.model
import netrender.balancing
@ -59,6 +60,7 @@ class MRenderSlave(netrender.model.RenderSlave):
super().__init__(slave_info)
self.id = hashlib.md5(bytes(repr(slave_info.name) + repr(slave_info.address), encoding='utf8')).hexdigest()
self.last_seen = time.time()
self.job = None
self.job_frames = []
@ -82,7 +84,8 @@ class MRenderJob(netrender.model.RenderJob):
super().__init__(job_info)
self.id = job_id
self.last_dispatched = time.time()
self.start_time = time.time()
self.finish_time = self.start_time
# force one chunk for process jobs
if self.type == netrender.model.JOB_PROCESS:
self.chunks = 1
@ -136,6 +139,7 @@ class MRenderJob(netrender.model.RenderJob):
break
else:
self.status = JOB_FINISHED
self.finish_time=time.time()
def pause(self, status = None):
if self.status not in {JOB_PAUSED, JOB_QUEUED}:
@ -150,6 +154,7 @@ class MRenderJob(netrender.model.RenderJob):
def start(self):
self.status = JOB_QUEUED
def addLog(self, frames):
frames = sorted(frames)
@ -1149,11 +1154,13 @@ def saveMaster(path, httpd):
with open(filepath, 'wb') as f:
pickle.dump((httpd.path, httpd.jobs, httpd.slaves), f, pickle.HIGHEST_PROTOCOL)
def runMaster(address, broadcast, clear, force, path, update_stats, test_break):
def runMaster(address, broadcast, clear, force, path, update_stats, test_break,use_ssl=False,cert_path="",key_path=""):
httpd = createMaster(address, clear, force, path)
httpd.timeout = 1
httpd.stats = update_stats
if use_ssl:
import ssl
httpd.socket=ssl.wrap_socket(httpd.socket,certfile=cert_path,server_side=True,keyfile=key_path,ciphers="ALL",ssl_version=ssl.PROTOCOL_SSLv3)
if broadcast:
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)

View File

@ -142,7 +142,8 @@ def get(handler):
tot_cache, tot_fluid, tot_other = countFiles(job)
serializedJob["totcache"] = tot_cache
serializedJob["totfluid"] = tot_fluid
serializedJob["totother"] = tot_other
serializedJob["totother"] = tot_other
serializedJob["wktime"] = (time.time()-job.start_time ) if job.status != JOB_FINISHED else (job.finish_time-job.start_time)
else:
serializedJob={"name":"invalid job"}

View File

@ -42,7 +42,7 @@ class RENDER_OT_netclientsendbake(bpy.types.Operator):
netsettings = scene.network_render
try:
conn = clientConnection(netsettings.server_address, netsettings.server_port, self.report)
conn = clientConnection(netsettings, report = self.report)
if conn:
# Sending file
@ -70,7 +70,7 @@ class RENDER_OT_netclientanim(bpy.types.Operator):
scene = context.scene
netsettings = scene.network_render
conn = clientConnection(netsettings.server_address, netsettings.server_port, self.report)
conn = clientConnection(netsettings, report = self.report)
if conn:
# Sending file
@ -115,7 +115,7 @@ class RENDER_OT_netclientsend(bpy.types.Operator):
netsettings = scene.network_render
try:
conn = clientConnection(netsettings.server_address, netsettings.server_port, self.report)
conn = clientConnection(netsettings, report = self.report)
if conn:
# Sending file
@ -145,7 +145,7 @@ class RENDER_OT_netclientsendframe(bpy.types.Operator):
netsettings = scene.network_render
try:
conn = clientConnection(netsettings.server_address, netsettings.server_port, self.report)
conn = clientConnection(netsettings, report = self.report)
if conn:
# Sending file
@ -172,7 +172,7 @@ class RENDER_OT_netclientstatus(bpy.types.Operator):
def execute(self, context):
netsettings = context.scene.network_render
conn = clientConnection(netsettings.server_address, netsettings.server_port, self.report)
conn = clientConnection(netsettings, report = self.report)
if conn:
with ConnectionContext():
@ -274,7 +274,7 @@ class RENDER_OT_netclientslaves(bpy.types.Operator):
def execute(self, context):
netsettings = context.scene.network_render
conn = clientConnection(netsettings.server_address, netsettings.server_port, self.report)
conn = clientConnection(netsettings, report = self.report)
if conn:
with ConnectionContext():
@ -326,7 +326,7 @@ class RENDER_OT_netclientcancel(bpy.types.Operator):
def execute(self, context):
netsettings = context.scene.network_render
conn = clientConnection(netsettings.server_address, netsettings.server_port, self.report)
conn = clientConnection(netsettings, report = self.report)
if conn:
job = netrender.jobs[netsettings.active_job_index]
@ -355,7 +355,7 @@ class RENDER_OT_netclientcancelall(bpy.types.Operator):
def execute(self, context):
netsettings = context.scene.network_render
conn = clientConnection(netsettings.server_address, netsettings.server_port, self.report)
conn = clientConnection(netsettings, report = self.report)
if conn:
with ConnectionContext():
@ -385,7 +385,7 @@ class netclientdownload(bpy.types.Operator):
def execute(self, context):
netsettings = context.scene.network_render
conn = clientConnection(netsettings.server_address, netsettings.server_port, self.report)
conn = clientConnection(netsettings, report = self.report)
if conn:
job_id = netrender.jobs[netsettings.active_job_index].id
@ -530,13 +530,14 @@ class netclientweb(bpy.types.Operator):
# open connection to make sure server exists
conn = clientConnection(netsettings.server_address, netsettings.server_port, self.report)
conn = clientConnection(netsettings, report = self.report)
if conn:
conn.close()
webbrowser.open("http://%s:%i" % (netsettings.server_address, netsettings.server_port))
if netsettings.use_ssl:
webbrowser.open("https://%s:%i" % (netsettings.server_address, netsettings.server_port))
else:
webbrowser.open("http://%s:%i" % (netsettings.server_address, netsettings.server_port))
return {'FINISHED'}
def invoke(self, context, event):

View File

@ -118,8 +118,8 @@ def render_slave(engine, netsettings, threads):
if not os.access(slave_path, os.W_OK):
print("Slave working path ( %s ) is not writable" % netsettings.path)
return
conn = clientConnection(netsettings.server_address, netsettings.server_port)
conn = clientConnection(netsettings)
if not conn:
print("Connection failed, will try connecting again at most %i times" % MAX_CONNECT_TRY)
@ -128,7 +128,7 @@ def render_slave(engine, netsettings, threads):
for i in range(MAX_CONNECT_TRY):
bisleep.sleep()
conn = clientConnection(netsettings.server_address, netsettings.server_port)
conn = clientConnection(netsettings)
if conn or engine.test_break():
break

View File

@ -70,7 +70,7 @@ def verify_address(netsettings, force=False):
LAST_ADDRESS_TEST = time.time()
try:
conn = clientConnection(netsettings.server_address, netsettings.server_port, scan = False, timeout = 1)
conn = clientConnection(netsettings, scan = False, timeout = 1)
except:
conn = None
@ -120,25 +120,34 @@ class RENDER_PT_network_settings(NetRenderButtonsPanel, bpy.types.Panel):
layout.operator("render.netclientstart", icon='PLAY')
layout.prop(netsettings, "path")
row = layout.row()
split = layout.split(percentage=0.7)
split = layout.split(percentage=0.5)
col = split.column()
col.label(text="Server Address:")
col.prop(netsettings, "server_address", text="")
col.prop(netsettings, "server_address", text="Address")
col = split.column()
col.label(text="Port:")
col.prop(netsettings, "server_port", text="")
row = col.row()
row.prop(netsettings, "server_port", text="Port")
row.prop(netsettings, "use_ssl", text="SSL")
if netsettings.mode != "RENDER_MASTER":
layout.operator("render.netclientscan", icon='FILE_REFRESH', text="")
if not netrender.valid_address:
layout.label(text="No master at specified address")
if netsettings.use_ssl and netsettings.mode == "RENDER_MASTER":
layout.prop(netsettings, "cert_path", text="Certificate")
layout.prop(netsettings, "key_path", text="Key")
layout.operator("render.netclientweb", icon='QUESTION')
class RENDER_PT_network_slave_settings(NetRenderButtonsPanel, bpy.types.Panel):
bl_label = "Slave Settings"
COMPAT_ENGINES = {'NET_RENDER'}
@ -403,6 +412,22 @@ class NetRenderSettings(bpy.types.PropertyGroup):
name="Broadcast",
description="broadcast master server address on local network",
default = True)
NetRenderSettings.use_ssl = BoolProperty(
name="use ssl",
description="use ssl encryption for communication",
default = False)
NetRenderSettings.cert_path = StringProperty(
name="CertPath",
description="Path to ssl certifcate",
maxlen = 128,
default = "",
subtype='FILE_PATH')
NetRenderSettings.key_path = StringProperty(
name="key",
description="Path to ssl key file",
maxlen = 128,
default = "",
subtype='FILE_PATH')
NetRenderSettings.use_slave_clear = BoolProperty(
name="Clear on exit",

View File

@ -186,8 +186,12 @@ def clientScan(report = None):
return ("", 8000) # return default values
def clientConnection(address, port, report = None, scan = True, timeout = 5):
if address == "[default]":
def clientConnection(netsettings, report = None, scan = True, timeout = 5):
address = netsettings.server_address
port = netsettings.server_port
use_ssl = netsettings.use_ssl
if address== "[default]":
# calling operator from python is fucked, scene isn't in context
# if bpy:
# bpy.ops.render.netclientscan()
@ -198,13 +202,14 @@ def clientConnection(address, port, report = None, scan = True, timeout = 5):
address, port = clientScan()
if address == "":
return None
conn = None
try:
HTTPConnection = http.client.HTTPSConnection if use_ssl else http.client.HTTPConnection
if platform.system() == "Darwin":
with ConnectionContext(timeout):
conn = http.client.HTTPConnection(address, port)
conn = HTTPConnection(address, port)
else:
conn = http.client.HTTPConnection(address, port, timeout = timeout)
conn = HTTPConnection(address, port, timeout = timeout)
if conn:
if clientVerifyVersion(conn):