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.
This commit is contained in:
Ingo Weinhold 2014-10-30 16:17:54 +01:00
parent c00e34900a
commit 96a321df07
3 changed files with 151 additions and 0 deletions

View File

@ -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) ;

View File

@ -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)

View File

@ -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)