[haiku-commits] haiku: hrev48167 - in build: scripts jam/images/definitions

  • From: ingo_weinhold@xxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Thu, 30 Oct 2014 16:45:26 +0100 (CET)

hrev48167 adds 1 changeset to branch 'master'
old head: c00e34900ac5c53613c733bd7667f4e8f7b5c6f7
new head: 96a321df07ea530287c8b55f82304783c9725aee
overview: http://cgit.haiku-os.org/haiku/log/?qt=range&q=96a321d+%5Ec00e349

----------------------------------------------------------------------------

96a321d: bootstrap image: Add remote command execution script
  
  In order to automate the complete bootstrap build process we need a
  mechanism to control the second phase which builds the final packages
  on the booted bootstrap Haiku. To avoid additional dependencies
  (buildbot slave, ssh, rsh,...) we'd have to cross-build, there's now a
  pair of simple python scripts that allows executing commands on a remote
  machine. The server script (bootstrap_daemon.py) is added to the
  bootstrap image and started automatically during the boot.

                                    [ Ingo Weinhold <ingo_weinhold@xxxxxx> ]

----------------------------------------------------------------------------

Revision:    hrev48167
Commit:      96a321df07ea530287c8b55f82304783c9725aee
URL:         http://cgit.haiku-os.org/haiku/commit/?id=96a321d
Author:      Ingo Weinhold <ingo_weinhold@xxxxxx>
Date:        Thu Oct 30 15:17:54 2014 UTC

----------------------------------------------------------------------------

3 files changed, 151 insertions(+)
build/jam/images/definitions/bootstrap |  5 ++
build/scripts/bootstrap_client.py      | 85 ++++++++++++++++++++++++++++++
build/scripts/bootstrap_daemon.py      | 61 +++++++++++++++++++++

----------------------------------------------------------------------------

diff --git a/build/jam/images/definitions/bootstrap 
b/build/jam/images/definitions/bootstrap
index 78986c7..e82dfaa 100644
--- a/build/jam/images/definitions/bootstrap
+++ b/build/jam/images/definitions/bootstrap
@@ -14,3 +14,8 @@ AddFilesToHaikuImage home haikuports
 local formatVersionsFile = <haikuports>FormatVersions ;
 SEARCH on $(formatVersionsFile) = $(HAIKU_PORTS) ;
 AddFilesToHaikuImage home haikuports : $(formatVersionsFile) ;
+
+# bootstrap daemon
+local bootstrapDaemon = <haiku-image>bootstrap_daemon.py ;
+SEARCH on $(bootstrapDaemon) = [ FDirName $(HAIKU_TOP) build scripts ] ;
+AddFilesToHaikuImage home config settings boot launch : $(bootstrapDaemon) ;
diff --git a/build/scripts/bootstrap_client.py 
b/build/scripts/bootstrap_client.py
new file mode 100755
index 0000000..9ac12f7
--- /dev/null
+++ b/build/scripts/bootstrap_client.py
@@ -0,0 +1,85 @@
+#!/usr/bin/env python
+#
+# Usage: bootstrap_client.py <address>[:port] <command> ...
+#
+# <command> and the following arguments are concatenated (separated by a space)
+# and passed to a shell on the server.
+
+import os
+import select
+import socket
+import sys
+
+
+port = 4242
+bufferSize = 4 * 1024
+
+# interpret command line args
+if len(sys.argv) < 3:
+       sys.exit('Usage: ' + sys.argv[0] + ' <address>[:<port>] <command>')
+
+address = sys.argv[1]
+portIndex = address.find(':')
+if portIndex >= 0:
+       port = int(address[portIndex + 1:])
+       address = address[:portIndex]
+
+commandToRun = " ".join(sys.argv[2:])
+
+# create sockets and connect to server
+controlConnection = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+stdioConnection = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+stderrConnection = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+
+try:
+       controlConnection.connect((address, port))
+       stdioConnection.connect((address, port))
+       stderrConnection.connect((address, port))
+except socket.error, msg:
+       sys.exit('Failed to connect to %s port %d: %s' % (address, port, 
msg[1]))
+
+# send command length and command
+controlConnection.send("%08d" % len(commandToRun))
+controlConnection.send(commandToRun)
+
+# I/O loop. We quit when all sockets have been closed.
+exitCode = ''
+connections = [controlConnection, stdioConnection, stderrConnection, sys.stdin]
+
+while connections and (len(connections) > 1 or not sys.stdin in connections):
+       (readable, writable, exceptions) = select.select(connections, [],
+               connections)
+
+       if sys.stdin in readable:
+               data = sys.stdin.readline(bufferSize)
+               if data:
+                       stdioConnection.send(data)
+               else:
+                       connections.remove(sys.stdin)
+                       stdioConnection.shutdown(socket.SHUT_WR)
+
+       if stdioConnection in readable:
+               data = stdioConnection.recv(bufferSize)
+               if data:
+                       sys.stdout.write(data)
+               else:
+                       connections.remove(stdioConnection)
+               
+       if stderrConnection in readable:
+               data = stderrConnection.recv(bufferSize)
+               if data:
+                       sys.stderr.write(data)
+               else:
+                       connections.remove(stderrConnection)
+               
+       if controlConnection in readable:
+               data = controlConnection.recv(bufferSize)
+               if data:
+                       exitCode += data
+               else:
+                       connections.remove(controlConnection)
+
+# either an exit code has been sent or we consider this an error
+if exitCode:
+       sys.exit(int(exitCode))
+sys.exit(1)
diff --git a/build/scripts/bootstrap_daemon.py 
b/build/scripts/bootstrap_daemon.py
new file mode 100755
index 0000000..f36df67
--- /dev/null
+++ b/build/scripts/bootstrap_daemon.py
@@ -0,0 +1,61 @@
+#!/usr/bin/env python
+
+import socket
+import subprocess
+import sys
+
+
+address = '0.0.0.0'
+port = 4242
+
+
+def receiveExactly(connection, size):
+       data = '';
+       while size > 0:
+               dataReceived = connection.recv(size)
+               if not dataReceived:
+                       raise EOFError()
+               data += dataReceived
+               size -= len(dataReceived)
+       return data
+
+
+def handleConnection(listenerSocket):
+       (controlConnection, controlAddress) = listenerSocket.accept()
+       (stdioConnection, stdioAddress) = listenerSocket.accept()
+       (stderrConnection, stderrAddress) = listenerSocket.accept()
+
+       print 'accepted client connections'
+
+       try:
+               commandLength = receiveExactly(controlConnection, 8)
+               commandToRun = receiveExactly(controlConnection, 
int(commandLength))
+
+               print 'received command: ' + commandToRun
+
+               exitCode = subprocess.call(commandToRun, stdin=stdioConnection,
+                       stdout=stdioConnection, stderr=stderrConnection, 
shell=True)
+
+               controlConnection.send(str(exitCode))
+       finally:
+               controlConnection.close()
+               stdioConnection.close()
+               stderrConnection.close()
+
+       print 'client connections closed'
+
+
+listenerSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+listenerSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+
+try:
+       listenerSocket.bind((address, port))
+except socket.error, msg:
+       sys.exit('Failed to bind to %s port %d: %s' % (address, port, msg[1]))
+
+listenerSocket.listen(3)
+
+print 'started listening on adddress %s port %s' % (address, port)
+
+while True:
+       handleConnection(listenerSocket)


Other related posts:

  • » [haiku-commits] haiku: hrev48167 - in build: scripts jam/images/definitions - ingo_weinhold