summaryrefslogtreecommitdiffstats
path: root/bitbake/lib/bb/server/xmlrpcclient.py
diff options
context:
space:
mode:
authorRichard Purdie <richard.purdie@linuxfoundation.org>2017-07-18 22:28:40 +0100
committerRichard Purdie <richard.purdie@linuxfoundation.org>2017-07-21 08:41:11 +0100
commit4602408c69132315c3784718fe4ce155b12464cf (patch)
tree2262f6d8b5e89930b4da4efd72e226ae8f740611 /bitbake/lib/bb/server/xmlrpcclient.py
parent21a19e0e0bf1b39969f6f2ec37a5784d0069715b (diff)
downloadpoky-4602408c69132315c3784718fe4ce155b12464cf.tar.gz
bitbake: server: Rework the server API so process and xmlrpc servers coexist
This changes the way bitbake server works quite radically. Now, the server is always a process based server with the option of starting an XMLRPC listener on a specific inferface/port. Behind the scenes this is done with a "bitbake.sock" file alongside the bitbake.lock file. If we can obtain the lock, we know we need to start a server. The server always listens on the socket and UIs can then connect to this. UIs connect by sending a set of three file descriptors over the domain socket, one for sending commands, one for receiving command results and the other for receiving events. These changes meant we can throw away all the horrid server abstraction code, the plugable transport option to bitbake and the code becomes much more readable and debuggable. It also likely removes a ton of ways you could hang the UI/cooker in weird ways due to all the race conditions that existed with previous processes. Changes: * The foreground option for bitbake-server was dropped. Just tail the log if you really want this, the codepaths were complicated enough without adding one for this. * BBSERVER="autodetect" was dropped. The server will autostart and autoconnect in process mode. You have to specify an xmlrpc server address since that can't be autodetected. I can't see a use case for autodetect now. * The transport/servetype option to bitbake was dropped. * A BB_SERVER_TIMEOUT variable is added which allows the server to stay resident for a period of time after the last client disconnects before unloading. This is used if the -T/--idle-timeout option is not passed to bitbake. This change is invasive and may well introduce new issues however I believe the codebase is in a much better position for further development and debugging. (Bitbake rev: 72a3dbe13a23588e24c0baca6d58c35cdeba3f63) Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'bitbake/lib/bb/server/xmlrpcclient.py')
-rw-r--r--bitbake/lib/bb/server/xmlrpcclient.py154
1 files changed, 154 insertions, 0 deletions
diff --git a/bitbake/lib/bb/server/xmlrpcclient.py b/bitbake/lib/bb/server/xmlrpcclient.py
new file mode 100644
index 0000000000..4661a9e5a0
--- /dev/null
+++ b/bitbake/lib/bb/server/xmlrpcclient.py
@@ -0,0 +1,154 @@
1#
2# BitBake XMLRPC Client Interface
3#
4# Copyright (C) 2006 - 2007 Michael 'Mickey' Lauer
5# Copyright (C) 2006 - 2008 Richard Purdie
6#
7# This program is free software; you can redistribute it and/or modify
8# it under the terms of the GNU General Public License version 2 as
9# published by the Free Software Foundation.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License along
17# with this program; if not, write to the Free Software Foundation, Inc.,
18# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20import os
21import sys
22
23import socket
24import http.client
25import xmlrpc.client
26
27import bb
28from bb.ui import uievent
29
30class BBTransport(xmlrpc.client.Transport):
31 def __init__(self, timeout):
32 self.timeout = timeout
33 self.connection_token = None
34 xmlrpc.client.Transport.__init__(self)
35
36 # Modified from default to pass timeout to HTTPConnection
37 def make_connection(self, host):
38 #return an existing connection if possible. This allows
39 #HTTP/1.1 keep-alive.
40 if self._connection and host == self._connection[0]:
41 return self._connection[1]
42
43 # create a HTTP connection object from a host descriptor
44 chost, self._extra_headers, x509 = self.get_host_info(host)
45 #store the host argument along with the connection object
46 self._connection = host, http.client.HTTPConnection(chost, timeout=self.timeout)
47 return self._connection[1]
48
49 def set_connection_token(self, token):
50 self.connection_token = token
51
52 def send_content(self, h, body):
53 if self.connection_token:
54 h.putheader("Bitbake-token", self.connection_token)
55 xmlrpc.client.Transport.send_content(self, h, body)
56
57def _create_server(host, port, timeout = 60):
58 t = BBTransport(timeout)
59 s = xmlrpc.client.ServerProxy("http://%s:%d/" % (host, port), transport=t, allow_none=True, use_builtin_types=True)
60 return s, t
61
62def check_connection(remote, timeout):
63 try:
64 host, port = remote.split(":")
65 port = int(port)
66 except Exception as e:
67 bb.warn("Failed to read remote definition (%s)" % str(e))
68 raise e
69
70 server, _transport = _create_server(host, port, timeout)
71 try:
72 ret, err = server.runCommand(['getVariable', 'TOPDIR'])
73 if err or not ret:
74 return False
75 except ConnectionError:
76 return False
77 return True
78
79class BitBakeXMLRPCServerConnection(object):
80 def __init__(self, host, port, clientinfo=("localhost", 0), observer_only = False, featureset = None):
81 self.connection, self.transport = _create_server(host, port)
82 self.clientinfo = clientinfo
83 self.observer_only = observer_only
84 if featureset:
85 self.featureset = featureset
86 else:
87 self.featureset = []
88
89 self.events = uievent.BBUIEventQueue(self.connection, self.clientinfo)
90
91 _, error = self.connection.runCommand(["setFeatures", self.featureset])
92 if error:
93 # disconnect the client, we can't make the setFeature work
94 self.connection.removeClient()
95 # no need to log it here, the error shall be sent to the client
96 raise BaseException(error)
97
98 def connect(self, token = None):
99 if token is None:
100 if self.observer_only:
101 token = "observer"
102 else:
103 token = self.connection.addClient()
104
105 if token is None:
106 return None
107
108 self.transport.set_connection_token(token)
109 return self
110
111 def removeClient(self):
112 if not self.observer_only:
113 self.connection.removeClient()
114
115 def terminate(self):
116 # Don't wait for server indefinitely
117 socket.setdefaulttimeout(2)
118 try:
119 self.events.system_quit()
120 except:
121 pass
122 try:
123 self.connection.removeClient()
124 except:
125 pass
126
127def connectXMLRPC(remote, featureset, observer_only = False, token = None):
128 # The format of "remote" must be "server:port"
129 try:
130 [host, port] = remote.split(":")
131 port = int(port)
132 except Exception as e:
133 bb.warn("Failed to parse remote definition %s (%s)" % (remote, str(e)))
134 raise e
135
136 # We need our IP for the server connection. We get the IP
137 # by trying to connect with the server
138 try:
139 s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
140 s.connect((host, port))
141 ip = s.getsockname()[0]
142 s.close()
143 except Exception as e:
144 bb.warn("Could not create socket for %s:%s (%s)" % (host, port, str(e)))
145 raise e
146 try:
147 connection = BitBakeXMLRPCServerConnection(host, port, (ip, 0), observer_only, featureset)
148 return connection.connect(token)
149 except Exception as e:
150 bb.warn("Could not connect to server at %s:%s (%s)" % (host, port, str(e)))
151 raise e
152
153
154