]>
Commit | Line | Data |
---|---|---|
c62d93f1 MT |
1 | #!/usr/bin/python |
2 | ||
3 | from __future__ import division | |
4 | ||
5 | import os | |
6 | import socket | |
7 | import urlparse | |
8 | import xmlrpclib | |
9 | ||
10 | import pakfire.util | |
11 | import pakfire.packages as packages | |
12 | from pakfire.system import system | |
13 | ||
14 | # Local modules. | |
15 | import transport | |
16 | ||
17 | from pakfire.constants import * | |
38ba21f9 | 18 | from pakfire.i18n import _ |
c62d93f1 MT |
19 | |
20 | import logging | |
21 | log = logging.getLogger("pakfire.client") | |
22 | ||
23 | class PakfireClient(object): | |
24 | type = None | |
25 | ||
26 | def __init__(self, server, username, password): | |
27 | self.url = self._join_url(server, username, password) | |
28 | ||
29 | # Create a secure XMLRPC connection to the server. | |
30 | self.conn = transport.Connection(self.url) | |
31 | ||
32 | def _join_url(self, server, username, password): | |
33 | """ | |
34 | Construct a right URL out of the given | |
35 | server, username and password. | |
36 | ||
37 | Basicly this just adds the credentials | |
38 | to the URL. | |
39 | """ | |
40 | assert self.type | |
41 | ||
42 | # Parse the given URL. | |
43 | url = urlparse.urlparse(server) | |
44 | assert url.scheme in ("http", "https") | |
45 | ||
46 | # Build new URL. | |
47 | ret = "%s://" % url.scheme | |
48 | ||
49 | # Add credentials if provided. | |
50 | if username and password: | |
51 | ret += "%s:%s@" % (username, password) | |
52 | ||
53 | # Add host and path components. | |
54 | ret += "%s/pakfirehub/%s" % (url.netloc, self.type) | |
55 | ||
56 | return ret | |
57 | ||
58 | ### Misc. actions | |
59 | ||
60 | def noop(self): | |
61 | """ | |
62 | No operation. Just to check if the connection is | |
63 | working. Returns a random number. | |
64 | """ | |
65 | return self.conn.noop() | |
66 | ||
67 | def get_my_address(self): | |
68 | """ | |
69 | Get my own address (as seen by the hub). | |
70 | """ | |
71 | return self.conn.get_my_address() | |
72 | ||
73 | def get_hub_status(self): | |
74 | """ | |
75 | Get some status information about the hub. | |
76 | """ | |
77 | return self.conn.get_hub_status() | |
78 | ||
79 | ||
80 | class BuildMixin(object): | |
81 | ### Build actions | |
82 | ||
83 | def build_create(self, filename, arches=None, distro=None): | |
84 | """ | |
85 | Create a new build on the hub. | |
86 | """ | |
87 | ||
88 | # Upload the source file to the server. | |
89 | upload_id = self._upload_file(filename) | |
90 | ||
91 | # Then create the build. | |
92 | build = self.conn.build_create(upload_id, distro, arches) | |
93 | ||
94 | print build | |
95 | ||
96 | def _upload_file(self, filename): | |
97 | # Get the hash of the file. | |
98 | hash = pakfire.util.calc_hash1(filename) | |
99 | ||
100 | # Get the size of the file. | |
101 | size = os.path.getsize(filename) | |
102 | ||
103 | # Get an upload ID from the server. | |
104 | upload_id = self.conn.upload_create(os.path.basename(filename), | |
105 | size, hash) | |
106 | ||
38ba21f9 MT |
107 | # Make a nice progressbar. |
108 | pb = pakfire.util.make_progress(os.path.basename(filename), size, speed=True, eta=True) | |
109 | ||
c62d93f1 MT |
110 | try: |
111 | # Calculate the number of chunks. | |
112 | chunks = (size // CHUNK_SIZE) + 1 | |
38ba21f9 | 113 | transferred = 0 |
c62d93f1 MT |
114 | |
115 | # Cut the file in pieces and upload them one after another. | |
116 | with open(filename) as f: | |
117 | chunk = 0 | |
118 | while True: | |
119 | data = f.read(CHUNK_SIZE) | |
120 | if not data: | |
121 | break | |
122 | ||
123 | chunk += 1 | |
38ba21f9 MT |
124 | if pb: |
125 | transferred += len(data) | |
126 | pb.update(transferred) | |
c62d93f1 MT |
127 | |
128 | data = xmlrpclib.Binary(data) | |
129 | self.conn.upload_chunk(upload_id, data) | |
130 | ||
131 | # Tell the server, that we finished the upload. | |
132 | ret = self.conn.upload_finished(upload_id) | |
133 | ||
134 | except: | |
135 | # If anything goes wrong, try to delete the upload and raise | |
136 | # the exception. | |
137 | self.conn.upload_remove(upload_id) | |
138 | ||
139 | raise | |
140 | ||
38ba21f9 MT |
141 | finally: |
142 | if pb: | |
143 | pb.finish() | |
144 | ||
c62d93f1 MT |
145 | # If the server sends false, something happened with the upload that |
146 | # could not be recovered. | |
38ba21f9 | 147 | if not ret: |
c62d93f1 MT |
148 | logging.error("Upload of %s was not successful." % filename) |
149 | raise Exception, "Upload failed." | |
150 | ||
151 | return upload_id | |
152 | ||
153 | ||
154 | class PakfireUserClient(BuildMixin, PakfireClient): | |
155 | type = "user" | |
156 | ||
157 | def check_auth(self): | |
158 | """ | |
159 | Check if the user was successfully authenticated. | |
160 | """ | |
161 | return self.conn.check_auth() | |
162 | ||
163 | def get_user_profile(self): | |
164 | """ | |
165 | Get information about the user profile. | |
166 | """ | |
167 | return self.conn.get_user_profile() | |
168 | ||
25a98632 MT |
169 | def get_builds(self, type=None, limit=10, offset=0): |
170 | return self.conn.get_builds(type=type, limit=limit, offset=offset) | |
171 | ||
172 | def get_build(self, build_id): | |
173 | return self.conn.get_build(build_id) | |
174 | ||
175 | def get_builder(self, builder_id): | |
176 | return self.conn.get_builder(builder_id) | |
177 | ||
178 | def get_job(self, job_id): | |
179 | return self.conn.get_job(job_id) | |
180 | ||
181 | def get_latest_jobs(self): | |
182 | return self.conn.get_latest_jobs() | |
183 | ||
184 | def get_active_jobs(self): | |
185 | return self.conn.get_active_jobs() | |
186 | ||
c62d93f1 MT |
187 | |
188 | class PakfireBuilderClient(BuildMixin, PakfireClient): | |
189 | type = "builder" | |
190 | ||
191 | def send_keepalive(self, overload=None): | |
192 | """ | |
193 | Sends a little keepalive to the server and | |
194 | updates the hardware information if the server | |
195 | requests it. | |
196 | """ | |
197 | log.debug("Sending keepalive to the hub.") | |
198 | ||
199 | # Collect the current loadavg and send it to the hub. | |
200 | loadavg = ", ".join(("%.2f" % round(l, 2) for l in os.getloadavg())) | |
201 | ||
202 | needs_update = self.conn.send_keepalive(loadavg, overload) | |
203 | ||
204 | if needs_update: | |
205 | log.debug("The hub is requesting an update.") | |
206 | self.send_update() | |
207 | ||
208 | def send_update(self): | |
209 | log.info("Sending host information update to hub...") | |
210 | ||
211 | self.conn.send_update( | |
212 | # Supported architectures. | |
213 | system.supported_arches, | |
214 | ||
215 | # CPU information. | |
216 | system.cpu_model, | |
217 | system.cpu_count, | |
218 | ||
219 | # Amount of memory in bytes. | |
220 | system.memory / 1024, | |
fc69babd MT |
221 | |
222 | # Send the currently running version of Pakfire. | |
223 | PAKFIRE_VERSION, | |
c62d93f1 | 224 | ) |