1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 """
17 Contains repo management (backend) classes.
18 """
19
20 import os
21 from iniparse import ConfigParser as Parser
22 from pulp.client import ConsumerId
23 from pulp.client.connection import ConsumerConnection, RepoConnection
24 from pulp.client.lock import Lock
25 from pulp.client.config import Config
26 from pulp.client.logutil import getLogger
27
28 log = getLogger(__name__)
29
30
32 """
33 Action lock.
34 @cvar PATH: The lock file absolute path.
35 @type PATH: str
36 """
37
38 PATH = '/var/run/subsys/pulp/repolib.pid'
39
42
43
45 """
46 Library for performing yum repo management.
47 @ivar lock: The action lock. Ensures only 1 instance updating repos.
48 @type lock: L{Lock}
49 """
50
52 """
53 @param lock: A lock.
54 @type lock: L{Lock}
55 """
56 self.lock = lock
57
69
70
72 """
73 The pulp server.
74 """
80
97
100
101
103 """
104 Action base class.
105 """
106
110
111
113 """
114 Update the yum repositores based on pulp bindings (subscription).
115 """
116
145
147 """
148 Get the B{unique} content sets from pulp.
149 @return: A unique set L{Repo} objects reported by pulp.
150 @rtype: [L{Repo},...]
151 """
152 unique = set()
153 products = self.pulp.getProducts()
154 baseurl = self.cfg.cds.baseurl
155 for product in products:
156 for r in self.getContent(product, baseurl):
157 unique.add(r)
158 return unique
159
160 - def getContent(self, product, baseurl):
161 """
162 Get L{Repo} object(s) for a given subscription.
163 @param product: A product (contains content sets).
164 @type product: dict
165 @param baseurl: The yum base url to be joined with relative url.
166 @type baseurl: str
167 @return: A list of L{Repo} objects for the specified product.
168 @rtype: [L{Repo},...]
169 """
170 lst = []
171 for cont in product['content']:
172 if not cont:
173 continue
174 id = cont['id']
175 path = cont['relative_path']
176 repo = Repo(id)
177 repo['name'] = cont['name']
178 repo['baseurl'] = self.join(baseurl, path)
179 repo['enabled'] = cont.get('enabled', '1')
180 lst.append(repo)
181 return lst
182
183 - def join(self, base, url):
184 """
185 Join the base and url.
186 @param base: The URL base (protocol, host & port).
187 @type base: str
188 @param url: The relative url.
189 @type url: str
190 @return: The complete (joined) url.
191 @rtype: str
192 """
193 if '://' in url:
194 return url
195 else:
196 return os.path.join(base, url)
197
198
200 """
201 A yum repo (content set).
202 @cvar CA: The absolute path to the CA.
203 @type CA: str
204 @cvar PROPERTIES: Yum repo property definitions.
205 @type PROPERTIES: tuple.
206 """
207
208 CA = None
209
210
211 PROPERTIES = (
212 ('name', 0, None),
213 ('baseurl', 0, None),
214 ('enabled', 1, '1'),
215 ('sslverify', 0, '0'),
216 )
217
219 """
220 @param id: The repo (unique) id.
221 @type id: str
222 """
223 self.id = id
224 for k,m,d in self.PROPERTIES:
225 self[k] = d
226
228 """
229 Get I{ordered} items.
230 @return: A list of ordered items.
231 @rtype: list
232 """
233 lst = []
234 for k,m,d in self.PROPERTIES:
235 v = self[k]
236 lst.append((k,v))
237 return tuple(lst)
238
240 """
241 Update (merge) based on property definitions.
242 @param other: The object to merge.
243 @type other: L{Repo}.
244 @return: The number of properties updated.
245 @rtype: int
246 """
247 count = 0
248 for k,m,d in self.PROPERTIES:
249 v = other.get(k)
250 if not m:
251 if self[k] == v:
252 continue
253 self[k] = v
254 count += 1
255 return count
256
258 s = []
259 s.append('[%s]' % self.id)
260 for k in self.PROPERTIES:
261 v = self.get(k)
262 if v is None:
263 continue
264 s.append('%s=%s' % (k, v))
265
266 return '\n'.join(s)
267
269 return ( self.id == other.id )
270
273
274
276 """
277 Represents a .repo file and is primarily a wrapper around
278 I{iniparse} to get around its short comings and understand L{Repo} objects.
279 @cvar PATH: The absolute path to a .repo file.
280 @type PATH: str
281 """
282
283 PATH = '/etc/yum.repos.d/'
284
286 """
287 @param name: The absolute path to a .repo file.
288 @type name: str
289 """
290 Parser.__init__(self)
291 self.path = os.path.join(self.PATH, name)
292 self.create()
293
295 """
296 Read and parse the file.
297 """
298 r = Reader(self.path)
299 Parser.readfp(self, r)
300
302 """
303 Write the file.
304 """
305 f = open(self.path, 'w')
306 Parser.write(self, f)
307 f.close()
308
309 - def add(self, repo):
310 """
311 Add a repo and create section if needed.
312 @param repo: A repo to add.
313 @type repo: L{Repo}
314 """
315 self.add_section(repo.id)
316 self.update(repo)
317
319 """
320 Delete a section (repo name).
321 @return: self
322 @rtype: L{RepoFile}
323 """
324 return self.remove_section(section)
325
327 """
328 Update the repo section using the specified repo.
329 @param repo: A repo used to update.
330 @type repo: L{Repo}
331 """
332 for k,v in repo.items():
333 Parser.set(self, repo.id, k, v)
334
336 """
337 Get a L{Repo} (section) by name.
338 @param section: A section (repo) name.
339 @type section: str
340 @return: A repo for the section name.
341 @rtype: L{Repo}
342 """
343 if self.has_section(section):
344 repo = Repo(section)
345 for k,v in self.items(section):
346 repo[k] = v
347 return repo
348
350 """
351 Create the .repo file with appropriate header/footer
352 if it does not already exist.
353 """
354 if os.path.exists(self.path):
355 return
356 f = open(self.path, 'w')
357 s = []
358 s.append('#')
359 s.append('# Pulp Repositories')
360 s.append('# Managed by Pulp client')
361 s.append('#')
362 f.write('\n'.join(s))
363 f.close()
364
365
367 """
368 Reader object used to mitigate annoying behavior of
369 iniparse of leaving blank lines when removing sections.
370 """
371
373 """
374 @param path: The absolute path to a .repo file.
375 @type path: str
376 """
377 f = open(path)
378 bfr = f.read()
379 self.idx = 0
380 self.lines = bfr.split('\n')
381 f.close()
382
384 """
385 Read the next line.
386 Strips annoying blank lines left by iniparse when
387 removing sections.
388 @return: The next line (or None).
389 @rtype: str
390 """
391 nl = 0
392 i = self.idx
393 eof = len(self.lines)
394 while 1:
395 if i == eof:
396 return
397 ln = self.lines[i]
398 i += 1
399 if not ln:
400 nl += 1
401 else:
402 break
403 if nl:
404 i -= 1
405 ln = '\n'
406 self.idx = i
407 return ln
408
409
411 print 'Updating Pulp repository'
412 repolib = RepoLib()
413 updates = repolib.update()
414 print '%d updates required' % updates
415 print 'done'
416
417 if __name__ == '__main__':
418 main()
419