xref: /OK3568_Linux_fs/yocto/poky/bitbake/lib/bb/server/xmlrpcclient.py (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun#
2*4882a593Smuzhiyun# BitBake XMLRPC Client Interface
3*4882a593Smuzhiyun#
4*4882a593Smuzhiyun# Copyright (C) 2006 - 2007  Michael 'Mickey' Lauer
5*4882a593Smuzhiyun# Copyright (C) 2006 - 2008  Richard Purdie
6*4882a593Smuzhiyun#
7*4882a593Smuzhiyun# SPDX-License-Identifier: GPL-2.0-only
8*4882a593Smuzhiyun#
9*4882a593Smuzhiyun
10*4882a593Smuzhiyunimport socket
11*4882a593Smuzhiyunimport http.client
12*4882a593Smuzhiyunimport xmlrpc.client
13*4882a593Smuzhiyun
14*4882a593Smuzhiyunimport bb
15*4882a593Smuzhiyunfrom bb.ui import uievent
16*4882a593Smuzhiyun
17*4882a593Smuzhiyunclass BBTransport(xmlrpc.client.Transport):
18*4882a593Smuzhiyun    def __init__(self, timeout):
19*4882a593Smuzhiyun        self.timeout = timeout
20*4882a593Smuzhiyun        self.connection_token = None
21*4882a593Smuzhiyun        xmlrpc.client.Transport.__init__(self)
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun    # Modified from default to pass timeout to HTTPConnection
24*4882a593Smuzhiyun    def make_connection(self, host):
25*4882a593Smuzhiyun        #return an existing connection if possible.  This allows
26*4882a593Smuzhiyun        #HTTP/1.1 keep-alive.
27*4882a593Smuzhiyun        if self._connection and host == self._connection[0]:
28*4882a593Smuzhiyun            return self._connection[1]
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun        # create a HTTP connection object from a host descriptor
31*4882a593Smuzhiyun        chost, self._extra_headers, x509 = self.get_host_info(host)
32*4882a593Smuzhiyun        #store the host argument along with the connection object
33*4882a593Smuzhiyun        self._connection = host, http.client.HTTPConnection(chost, timeout=self.timeout)
34*4882a593Smuzhiyun        return self._connection[1]
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun    def set_connection_token(self, token):
37*4882a593Smuzhiyun        self.connection_token = token
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun    def send_content(self, h, body):
40*4882a593Smuzhiyun        if self.connection_token:
41*4882a593Smuzhiyun            h.putheader("Bitbake-token", self.connection_token)
42*4882a593Smuzhiyun        xmlrpc.client.Transport.send_content(self, h, body)
43*4882a593Smuzhiyun
44*4882a593Smuzhiyundef _create_server(host, port, timeout = 60):
45*4882a593Smuzhiyun    t = BBTransport(timeout)
46*4882a593Smuzhiyun    s = xmlrpc.client.ServerProxy("http://%s:%d/" % (host, port), transport=t, allow_none=True, use_builtin_types=True)
47*4882a593Smuzhiyun    return s, t
48*4882a593Smuzhiyun
49*4882a593Smuzhiyundef check_connection(remote, timeout):
50*4882a593Smuzhiyun    try:
51*4882a593Smuzhiyun        host, port = remote.split(":")
52*4882a593Smuzhiyun        port = int(port)
53*4882a593Smuzhiyun    except Exception as e:
54*4882a593Smuzhiyun        bb.warn("Failed to read remote definition (%s)" % str(e))
55*4882a593Smuzhiyun        raise e
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun    server, _transport = _create_server(host, port, timeout)
58*4882a593Smuzhiyun    try:
59*4882a593Smuzhiyun        ret, err =  server.runCommand(['getVariable', 'TOPDIR'])
60*4882a593Smuzhiyun        if err or not ret:
61*4882a593Smuzhiyun            return False
62*4882a593Smuzhiyun    except ConnectionError:
63*4882a593Smuzhiyun        return False
64*4882a593Smuzhiyun    return True
65*4882a593Smuzhiyun
66*4882a593Smuzhiyunclass BitBakeXMLRPCServerConnection(object):
67*4882a593Smuzhiyun    def __init__(self, host, port, clientinfo=("localhost", 0), observer_only = False, featureset = None):
68*4882a593Smuzhiyun        self.connection, self.transport = _create_server(host, port)
69*4882a593Smuzhiyun        self.clientinfo = clientinfo
70*4882a593Smuzhiyun        self.observer_only = observer_only
71*4882a593Smuzhiyun        if featureset:
72*4882a593Smuzhiyun            self.featureset = featureset
73*4882a593Smuzhiyun        else:
74*4882a593Smuzhiyun            self.featureset = []
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun        self.events = uievent.BBUIEventQueue(self.connection, self.clientinfo)
77*4882a593Smuzhiyun
78*4882a593Smuzhiyun        _, error = self.connection.runCommand(["setFeatures", self.featureset])
79*4882a593Smuzhiyun        if error:
80*4882a593Smuzhiyun            # disconnect the client, we can't make the setFeature work
81*4882a593Smuzhiyun            self.connection.removeClient()
82*4882a593Smuzhiyun            # no need to log it here, the error shall be sent to the client
83*4882a593Smuzhiyun            raise BaseException(error)
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun    def connect(self, token = None):
86*4882a593Smuzhiyun        if token is None:
87*4882a593Smuzhiyun            if self.observer_only:
88*4882a593Smuzhiyun                token = "observer"
89*4882a593Smuzhiyun            else:
90*4882a593Smuzhiyun                token = self.connection.addClient()
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun        if token is None:
93*4882a593Smuzhiyun            return None
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun        self.transport.set_connection_token(token)
96*4882a593Smuzhiyun        return self
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun    def removeClient(self):
99*4882a593Smuzhiyun        if not self.observer_only:
100*4882a593Smuzhiyun            self.connection.removeClient()
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun    def terminate(self):
103*4882a593Smuzhiyun        # Don't wait for server indefinitely
104*4882a593Smuzhiyun        socket.setdefaulttimeout(2)
105*4882a593Smuzhiyun        try:
106*4882a593Smuzhiyun            self.events.system_quit()
107*4882a593Smuzhiyun        except:
108*4882a593Smuzhiyun            pass
109*4882a593Smuzhiyun        try:
110*4882a593Smuzhiyun            self.connection.removeClient()
111*4882a593Smuzhiyun        except:
112*4882a593Smuzhiyun            pass
113*4882a593Smuzhiyun
114*4882a593Smuzhiyundef connectXMLRPC(remote, featureset, observer_only = False, token = None):
115*4882a593Smuzhiyun    # The format of "remote" must be "server:port"
116*4882a593Smuzhiyun    try:
117*4882a593Smuzhiyun        [host, port] = remote.split(":")
118*4882a593Smuzhiyun        port = int(port)
119*4882a593Smuzhiyun    except Exception as e:
120*4882a593Smuzhiyun        bb.warn("Failed to parse remote definition %s (%s)" % (remote, str(e)))
121*4882a593Smuzhiyun        raise e
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun    # We need our IP for the server connection. We get the IP
124*4882a593Smuzhiyun    # by trying to connect with the server
125*4882a593Smuzhiyun    try:
126*4882a593Smuzhiyun        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
127*4882a593Smuzhiyun        s.connect((host, port))
128*4882a593Smuzhiyun        ip = s.getsockname()[0]
129*4882a593Smuzhiyun        s.close()
130*4882a593Smuzhiyun    except Exception as e:
131*4882a593Smuzhiyun        bb.warn("Could not create socket for %s:%s (%s)" % (host, port, str(e)))
132*4882a593Smuzhiyun        raise e
133*4882a593Smuzhiyun    try:
134*4882a593Smuzhiyun        connection = BitBakeXMLRPCServerConnection(host, port, (ip, 0), observer_only, featureset)
135*4882a593Smuzhiyun        return connection.connect(token)
136*4882a593Smuzhiyun    except Exception as e:
137*4882a593Smuzhiyun        bb.warn("Could not connect to server at %s:%s (%s)" % (host, port, str(e)))
138*4882a593Smuzhiyun        raise e
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun
142