~racb/ubuntu/precise/cobbler/858860

« back to all changes in this revision

Viewing changes to .pc/47_ubuntu_add_oneiric_codename.patch/cobbler/modules/manage_import_debian_ubuntu.py

  • Committer: Package Import Robot
  • Author(s): Chuck Short, Chuck Short, Clint Byrum, Robie Basak
  • Date: 2011-11-15 12:35:40 UTC
  • mfrom: (1.1.8)
  • Revision ID: package-import@ubuntu.com-20111115123540-5g139uuhg7z0hv5d
Tags: 2.2.2-0ubuntu1
[Chuck Short]
* New upstream release:
  + Use dh_python2 everywhere.
  + Folded debian/patches/49_ubuntu_add_arm_arch_support.patch
    and debian/patches/56_ubuntu_arm_generate_pxe_files.patch
    into one patch for easier upstreaming.
  + Dropped debian/patches/50_fix_cobbler_timezone.patch:
    Fix upstream.
  + Dropped debian/patches/47_ubuntu_add_oneiric_codename.patch
    in favor of debian/patches/47_ubuntu_add_codenames.patch:
    It adds "precise" and drops unsupported releases as well.
  + Dropped debian/patches/41_update_tree_path_with_arch.patch:
    No longer needed.
  + Dropped debian/patches/55_ubuntu_branding.patch: Will be moved
    to orchestra

 [Clint Byrum]
 * debian/cobbler.postinst: create users.digest mode 0600 so it
   is not world readable. (LP: #858860)
 * debian/control: cobbler needs to depend on python-cobbler
   (LP: #863738)
 * debian/patches/58_fix_egg_cache.patch: Do not point dangerous
   PYTHON_EGG_CACHE at world writable directory. (LP: #858875)
 * debian/cobbler-common.install: remove users.digest as it is
   not required and contains a known password that would leave
   cobblerd vulnerable if started before configuration is done
 * debian/cobbler-web.postinst: fix perms on webui_sessions to
   be more secure (LP: #863755)

 [Robie Basak]
 * Backport safe YAML load from upstream. (LP: #858883)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
"""
2
 
This is some of the code behind 'cobbler sync'.
3
 
 
4
 
Copyright 2006-2009, Red Hat, Inc
5
 
Michael DeHaan <mdehaan@redhat.com>
6
 
John Eckersberg <jeckersb@redhat.com>
7
 
 
8
 
This program is free software; you can redistribute it and/or modify
9
 
it under the terms of the GNU General Public License as published by
10
 
the Free Software Foundation; either version 2 of the License, or
11
 
(at your option) any later version.
12
 
 
13
 
This program is distributed in the hope that it will be useful,
14
 
but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 
GNU General Public License for more details.
17
 
 
18
 
You should have received a copy of the GNU General Public License
19
 
along with this program; if not, write to the Free Software
20
 
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21
 
02110-1301  USA
22
 
"""
23
 
 
24
 
import os
25
 
import os.path
26
 
import shutil
27
 
import time
28
 
import sys
29
 
import glob
30
 
import traceback
31
 
import errno
32
 
import re
33
 
from utils import popen2
34
 
from shlex import shlex
35
 
 
36
 
 
37
 
import utils
38
 
from cexceptions import *
39
 
import templar
40
 
 
41
 
import item_distro
42
 
import item_profile
43
 
import item_repo
44
 
import item_system
45
 
 
46
 
from utils import _
47
 
 
48
 
# Import aptsources module if available to obtain repo mirror.
49
 
try:
50
 
    from aptsources import distro
51
 
    from aptsources import sourceslist
52
 
    apt_available = True
53
 
except:
54
 
    apt_available = False
55
 
 
56
 
def register():
57
 
   """
58
 
   The mandatory cobbler module registration hook.
59
 
   """
60
 
   return "manage/import"
61
 
 
62
 
 
63
 
class ImportDebianUbuntuManager:
64
 
 
65
 
    def __init__(self,config,logger):
66
 
        """
67
 
        Constructor
68
 
        """
69
 
        self.logger        = logger
70
 
        self.config        = config
71
 
        self.api           = config.api
72
 
        self.distros       = config.distros()
73
 
        self.profiles      = config.profiles()
74
 
        self.systems       = config.systems()
75
 
        self.settings      = config.settings()
76
 
        self.repos         = config.repos()
77
 
        self.templar       = templar.Templar(config)
78
 
 
79
 
    # required function for import modules
80
 
    def what(self):
81
 
        return "import/debian_ubuntu"
82
 
 
83
 
    # required function for import modules
84
 
    def check_for_signature(self,path,cli_breed):
85
 
       signatures = [
86
 
           'pool',
87
 
       ]
88
 
 
89
 
       #self.logger.info("scanning %s for a debian/ubuntu distro signature" % path)
90
 
       for signature in signatures:
91
 
           d = os.path.join(path,signature)
92
 
           if os.path.exists(d):
93
 
               self.logger.info("Found a debian/ubuntu compatible signature: %s" % signature)
94
 
               return (True,signature)
95
 
 
96
 
       if cli_breed and cli_breed in self.get_valid_breeds():
97
 
           self.logger.info("Warning: No distro signature for kernel at %s, using value from command line" % path)
98
 
           return (True,None)
99
 
 
100
 
       return (False,None)
101
 
 
102
 
    # required function for import modules
103
 
    def run(self,pkgdir,mirror,mirror_name,network_root=None,kickstart_file=None,rsync_flags=None,arch=None,breed=None,os_version=None):
104
 
        self.pkgdir = pkgdir
105
 
        self.mirror = mirror
106
 
        self.mirror_name = mirror_name
107
 
        self.network_root = network_root
108
 
        self.kickstart_file = kickstart_file
109
 
        self.rsync_flags = rsync_flags
110
 
        self.arch = arch
111
 
        self.breed = breed
112
 
        self.os_version = os_version
113
 
 
114
 
        # some fixups for the XMLRPC interface, which does not use "None"
115
 
        if self.arch == "":           self.arch           = None
116
 
        if self.mirror == "":         self.mirror         = None
117
 
        if self.mirror_name == "":    self.mirror_name    = None
118
 
        if self.kickstart_file == "": self.kickstart_file = None
119
 
        if self.os_version == "":     self.os_version     = None
120
 
        if self.rsync_flags == "":    self.rsync_flags    = None
121
 
        if self.network_root == "":   self.network_root   = None
122
 
 
123
 
        # If no breed was specified on the command line, figure it out
124
 
        if self.breed == None:
125
 
            self.breed = self.get_breed_from_directory()
126
 
            if not self.breed:
127
 
                utils.die(self.logger,"import failed - could not determine breed of debian-based distro")
128
 
               
129
 
        # debug log stuff for testing
130
 
        #self.logger.info("DEBUG: self.pkgdir = %s" % str(self.pkgdir))
131
 
        #self.logger.info("DEBUG: self.mirror = %s" % str(self.mirror))
132
 
        #self.logger.info("DEBUG: self.mirror_name = %s" % str(self.mirror_name))
133
 
        #self.logger.info("DEBUG: self.network_root = %s" % str(self.network_root))
134
 
        #self.logger.info("DEBUG: self.kickstart_file = %s" % str(self.kickstart_file))
135
 
        #self.logger.info("DEBUG: self.rsync_flags = %s" % str(self.rsync_flags))
136
 
        #self.logger.info("DEBUG: self.arch = %s" % str(self.arch))
137
 
        #self.logger.info("DEBUG: self.breed = %s" % str(self.breed))
138
 
        #self.logger.info("DEBUG: self.os_version = %s" % str(self.os_version))
139
 
 
140
 
        # both --import and --name are required arguments
141
 
 
142
 
        if self.mirror is None:
143
 
            utils.die(self.logger,"import failed.  no --path specified")
144
 
        if self.mirror_name is None:
145
 
            utils.die(self.logger,"import failed.  no --name specified")
146
 
 
147
 
        # if --arch is supplied, validate it to ensure it's valid
148
 
 
149
 
        if self.arch is not None and self.arch != "":
150
 
            self.arch = self.arch.lower()
151
 
            if self.arch == "x86":
152
 
                # be consistent
153
 
                self.arch = "i386"
154
 
            if self.arch not in self.get_valid_arches():
155
 
                utils.die(self.logger,"arch must be one of: %s" % string.join(self.get_valid_arches(),", "))
156
 
 
157
 
        # if we're going to do any copying, set where to put things
158
 
        # and then make sure nothing is already there.
159
 
 
160
 
        self.path = os.path.normpath( "%s/ks_mirror/%s" % (self.settings.webdir, self.mirror_name) )
161
 
        if os.path.exists(self.path) and self.arch is None:
162
 
            # FIXME : Raise exception even when network_root is given ?
163
 
            utils.die(self.logger,"Something already exists at this import location (%s).  You must specify --arch to avoid potentially overwriting existing files." % self.path)
164
 
 
165
 
        # import takes a --kickstart for forcing selection that can't be used in all circumstances
166
 
 
167
 
        if self.kickstart_file and not self.breed:
168
 
            utils.die(self.logger,"Kickstart file can only be specified when a specific breed is selected")
169
 
 
170
 
        if self.os_version and not self.breed:
171
 
            utils.die(self.logger,"OS version can only be specified when a specific breed is selected")
172
 
 
173
 
        if self.breed and self.breed.lower() not in self.get_valid_breeds():
174
 
            utils.die(self.logger,"Supplied import breed is not supported by this module")
175
 
 
176
 
        # if --arch is supplied, make sure the user is not importing a path with a different
177
 
        # arch, which would just be silly.
178
 
 
179
 
        if self.arch:
180
 
            # append the arch path to the name if the arch is not already
181
 
            # found in the name.
182
 
            for x in self.get_valid_arches():
183
 
                if self.path.lower().find(x) != -1:
184
 
                    if self.arch != x :
185
 
                        utils.die(self.logger,"Architecture found on pathname (%s) does not fit the one given in command line (%s)"%(x,self.arch))
186
 
                    break
187
 
            else:
188
 
                # FIXME : This is very likely removed later at get_proposed_name, and the guessed arch appended again
189
 
                self.path += ("-%s" % self.arch)
190
 
                # If arch is specified we also need to update the mirror name.
191
 
                self.mirror_name = self.mirror_name + "-" + self.arch
192
 
 
193
 
        # make the output path and mirror content but only if not specifying that a network
194
 
        # accessible support location already exists (this is --available-as on the command line)
195
 
 
196
 
        if self.network_root is None:
197
 
            # we need to mirror (copy) the files
198
 
 
199
 
            utils.mkdir(self.path)
200
 
 
201
 
            if self.mirror.startswith("http://") or self.mirror.startswith("ftp://") or self.mirror.startswith("nfs://"):
202
 
 
203
 
                # http mirrors are kind of primative.  rsync is better.
204
 
                # that's why this isn't documented in the manpage and we don't support them.
205
 
                # TODO: how about adding recursive FTP as an option?
206
 
 
207
 
                utils.die(self.logger,"unsupported protocol")
208
 
 
209
 
            else:
210
 
 
211
 
                # good, we're going to use rsync..
212
 
                # we don't use SSH for public mirrors and local files.
213
 
                # presence of user@host syntax means use SSH
214
 
 
215
 
                # kick off the rsync now
216
 
 
217
 
                if not utils.rsync_files(self.mirror, self.path, self.rsync_flags, self.logger):
218
 
                    utils.die(self.logger, "failed to rsync the files")
219
 
 
220
 
        else:
221
 
 
222
 
            # rather than mirroring, we're going to assume the path is available
223
 
            # over http, ftp, and nfs, perhaps on an external filer.  scanning still requires
224
 
            # --mirror is a filesystem path, but --available-as marks the network path
225
 
 
226
 
            if not os.path.exists(self.mirror):
227
 
                utils.die(self.logger, "path does not exist: %s" % self.mirror)
228
 
 
229
 
            # find the filesystem part of the path, after the server bits, as each distro
230
 
            # URL needs to be calculated relative to this.
231
 
 
232
 
            if not self.network_root.endswith("/"):
233
 
                self.network_root = self.network_root + "/"
234
 
            self.path = os.path.normpath( self.mirror )
235
 
            valid_roots = [ "nfs://", "ftp://", "http://" ]
236
 
            for valid_root in valid_roots:
237
 
                if self.network_root.startswith(valid_root):
238
 
                    break
239
 
            else:
240
 
                utils.die(self.logger, "Network root given to --available-as must be nfs://, ftp://, or http://")
241
 
            if self.network_root.startswith("nfs://"):
242
 
                try:
243
 
                    (a,b,rest) = self.network_root.split(":",3)
244
 
                except:
245
 
                    utils.die(self.logger, "Network root given to --available-as is missing a colon, please see the manpage example.")
246
 
 
247
 
        # now walk the filesystem looking for distributions that match certain patterns
248
 
 
249
 
        self.logger.info("adding distros")
250
 
        distros_added = []
251
 
        # FIXME : search below self.path for isolinux configurations or known directories from TRY_LIST
252
 
        os.path.walk(self.path, self.distro_adder, distros_added)
253
 
 
254
 
        # find out if we can auto-create any repository records from the install tree
255
 
 
256
 
        if self.network_root is None:
257
 
            self.logger.info("associating repos")
258
 
            # FIXME: this automagic is not possible (yet) without mirroring
259
 
            self.repo_finder(distros_added)
260
 
 
261
 
        # find the most appropriate answer files for each profile object
262
 
 
263
 
        self.logger.info("associating kickstarts")
264
 
        self.kickstart_finder(distros_added)
265
 
 
266
 
        # ensure bootloaders are present
267
 
        self.api.pxegen.copy_bootloaders()
268
 
 
269
 
        return True
270
 
 
271
 
    # required function for import modules
272
 
    def get_valid_arches(self):
273
 
        return ["i386", "ppc", "x86_64", "x86",]
274
 
 
275
 
    # required function for import modules
276
 
    def get_valid_breeds(self):
277
 
        return ["debian","ubuntu"]
278
 
 
279
 
    # required function for import modules
280
 
    def get_valid_os_versions(self):
281
 
        if self.breed == "debian":
282
 
            return ["etch", "lenny", "squeeze", "sid", "stable", "testing", "unstable", "experimental",]
283
 
        elif self.breed == "ubuntu":
284
 
            return ["dapper", "hardy", "karmic", "lucid", "maverick", "natty",]
285
 
        else:
286
 
            return []
287
 
 
288
 
    def get_valid_repo_breeds(self):
289
 
        return ["apt",]
290
 
 
291
 
    def get_release_files(self):
292
 
        """
293
 
        Find distro release packages.
294
 
        """
295
 
        return glob.glob(os.path.join(self.get_rootdir(), "dists/*"))
296
 
 
297
 
    def get_breed_from_directory(self):
298
 
        for breed in self.get_valid_breeds():
299
 
            # NOTE : Although we break the loop after the first match,
300
 
            # multiple debian derived distros can actually live at the same pool -- JP
301
 
            d = os.path.join(self.mirror, breed)
302
 
            if (os.path.islink(d) and os.path.isdir(d) and os.path.realpath(d) == os.path.realpath(self.mirror)) or os.path.basename(self.mirror) == breed:
303
 
                return breed
304
 
        else:
305
 
            return None
306
 
 
307
 
    def get_tree_location(self, distro):
308
 
        """
309
 
        Once a distribution is identified, find the part of the distribution
310
 
        that has the URL in it that we want to use for kickstarting the
311
 
        distribution, and create a ksmeta variable $tree that contains this.
312
 
        """
313
 
 
314
 
        base = self.get_rootdir()
315
 
 
316
 
        if self.network_root is None:
317
 
            dists_path = os.path.join(self.path, "dists")
318
 
            if os.path.isdir(dists_path):
319
 
                tree = "http://@@http_server@@/cblr/ks_mirror/%s" % (self.mirror_name)
320
 
            else:
321
 
                tree = "http://@@http_server@@/cblr/repo_mirror/%s" % (distro.name)
322
 
            self.set_install_tree(distro, tree)
323
 
        else:
324
 
            # where we assign the kickstart source is relative to our current directory
325
 
            # and the input start directory in the crawl.  We find the path segments
326
 
            # between and tack them on the network source path to find the explicit
327
 
            # network path to the distro that Anaconda can digest.
328
 
            tail = self.path_tail(self.path, base)
329
 
            tree = self.network_root[:-1] + tail
330
 
            self.set_install_tree(distro, tree)
331
 
 
332
 
        return
333
 
 
334
 
    def repo_finder(self, distros_added):
335
 
        for distro in distros_added:
336
 
            self.logger.info("traversing distro %s" % distro.name)
337
 
            # FIXME : Shouldn't decide this the value of self.network_root ?
338
 
            if distro.kernel.find("ks_mirror") != -1:
339
 
                basepath = os.path.dirname(distro.kernel)
340
 
                top = self.get_rootdir()
341
 
                self.logger.info("descent into %s" % top)
342
 
                dists_path = os.path.join(self.path, "dists")
343
 
                if not os.path.isdir(dists_path):
344
 
                    self.process_repos(self, distro)
345
 
            else:
346
 
                self.logger.info("this distro isn't mirrored")
347
 
 
348
 
    def get_repo_mirror_from_apt(self):
349
 
        """
350
 
        This tries to determine the apt mirror/archive to use (when processing repos)
351
 
        if the host machine is Debian or Ubuntu.
352
 
        """
353
 
        try:
354
 
            sources = sourceslist.SourcesList()
355
 
            release = distro.get_distro()
356
 
            release.get_sources(sources)
357
 
            mirrors = release.get_server_list()
358
 
            for mirror in mirrors:
359
 
                if mirror[2] == True:
360
 
                    mirror = mirror[1]
361
 
                    break
362
 
        except:
363
 
            return False
364
 
 
365
 
        return mirror
366
 
 
367
 
    def distro_adder(self,distros_added,dirname,fnames):
368
 
        """
369
 
        This is an os.path.walk routine that finds distributions in the directory
370
 
        to be scanned and then creates them.
371
 
        """
372
 
 
373
 
        # FIXME: If there are more than one kernel or initrd image on the same directory,
374
 
        # results are unpredictable
375
 
 
376
 
        initrd = None
377
 
        kernel = None
378
 
 
379
 
        for x in fnames:
380
 
            adtls = []
381
 
 
382
 
            fullname = os.path.join(dirname,x)
383
 
            if os.path.islink(fullname) and os.path.isdir(fullname):
384
 
                if fullname.startswith(self.path):
385
 
                    self.logger.warning("avoiding symlink loop")
386
 
                    continue
387
 
                self.logger.info("following symlink: %s" % fullname)
388
 
                os.path.walk(fullname, self.distro_adder, distros_added)
389
 
 
390
 
            if ( x.startswith("initrd.gz") ) and x != "initrd.size":
391
 
                initrd = os.path.join(dirname,x)
392
 
            if ( x.startswith("linux") ) and x.find("initrd") == -1:
393
 
                kernel = os.path.join(dirname,x)
394
 
 
395
 
            # if we've collected a matching kernel and initrd pair, turn the in and add them to the list
396
 
            if initrd is not None and kernel is not None:
397
 
                adtls.append(self.add_entry(dirname,kernel,initrd))
398
 
                kernel = None
399
 
                initrd = None
400
 
 
401
 
            for adtl in adtls:
402
 
                distros_added.extend(adtl)
403
 
 
404
 
    def add_entry(self,dirname,kernel,initrd):
405
 
        """
406
 
        When we find a directory with a valid kernel/initrd in it, create the distribution objects
407
 
        as appropriate and save them.  This includes creating xen and rescue distros/profiles
408
 
        if possible.
409
 
        """
410
 
 
411
 
        proposed_name = self.get_proposed_name(dirname,kernel)
412
 
        proposed_arch = self.get_proposed_arch(dirname)
413
 
 
414
 
        if self.arch and proposed_arch and self.arch != proposed_arch:
415
 
            utils.die(self.logger,"Arch from pathname (%s) does not match with supplied one %s"%(proposed_arch,self.arch))
416
 
 
417
 
        archs = self.learn_arch_from_tree()
418
 
        if not archs:
419
 
            if self.arch:
420
 
                archs.append( self.arch )
421
 
        else:
422
 
            if self.arch and self.arch not in archs:
423
 
                utils.die(self.logger, "Given arch (%s) not found on imported tree %s"%(self.arch,self.get_pkgdir()))
424
 
        if proposed_arch:
425
 
            if archs and proposed_arch not in archs:
426
 
                self.logger.warning("arch from pathname (%s) not found on imported tree %s" % (proposed_arch,self.get_pkgdir()))
427
 
                return
428
 
 
429
 
            archs = [ proposed_arch ]
430
 
 
431
 
        if len(archs)>1:
432
 
            self.logger.warning("- Warning : Multiple archs found : %s" % (archs))
433
 
 
434
 
        distros_added = []
435
 
 
436
 
        for pxe_arch in archs:
437
 
            name = proposed_name + "-" + pxe_arch
438
 
            existing_distro = self.distros.find(name=name)
439
 
 
440
 
            if existing_distro is not None:
441
 
                self.logger.warning("skipping import, as distro name already exists: %s" % name)
442
 
                continue
443
 
 
444
 
            else:
445
 
                self.logger.info("creating new distro: %s" % name)
446
 
                distro = self.config.new_distro()
447
 
 
448
 
            if name.find("-autoboot") != -1:
449
 
                # this is an artifact of some EL-3 imports
450
 
                continue
451
 
 
452
 
            distro.set_name(name)
453
 
            distro.set_kernel(kernel)
454
 
            distro.set_initrd(initrd)
455
 
            distro.set_arch(pxe_arch)
456
 
            distro.set_breed(self.breed)
457
 
            # If a version was supplied on command line, we set it now
458
 
            if self.os_version:
459
 
                distro.set_os_version(self.os_version)
460
 
 
461
 
            self.distros.add(distro,save=True)
462
 
            distros_added.append(distro)
463
 
 
464
 
            existing_profile = self.profiles.find(name=name)
465
 
 
466
 
            # see if the profile name is already used, if so, skip it and
467
 
            # do not modify the existing profile
468
 
 
469
 
            if existing_profile is None:
470
 
                self.logger.info("creating new profile: %s" % name)
471
 
                #FIXME: The created profile holds a default kickstart, and should be breed specific
472
 
                profile = self.config.new_profile()
473
 
            else:
474
 
                self.logger.info("skipping existing profile, name already exists: %s" % name)
475
 
                continue
476
 
 
477
 
            # save our minimal profile which just points to the distribution and a good
478
 
            # default answer file
479
 
 
480
 
            profile.set_name(name)
481
 
            profile.set_distro(name)
482
 
            profile.set_kickstart(self.kickstart_file)
483
 
 
484
 
            # depending on the name of the profile we can define a good virt-type
485
 
            # for usage with koan
486
 
 
487
 
            if name.find("-xen") != -1:
488
 
                profile.set_virt_type("xenpv")
489
 
            elif name.find("vmware") != -1:
490
 
                profile.set_virt_type("vmware")
491
 
            else:
492
 
                profile.set_virt_type("qemu")
493
 
 
494
 
            # save our new profile to the collection
495
 
 
496
 
            self.profiles.add(profile,save=True)
497
 
 
498
 
        return distros_added
499
 
 
500
 
    def get_proposed_name(self,dirname,kernel=None):
501
 
        """
502
 
        Given a directory name where we have a kernel/initrd pair, try to autoname
503
 
        the distribution (and profile) object based on the contents of that path
504
 
        """
505
 
 
506
 
        if self.network_root is not None:
507
 
            name = self.mirror_name + "-".join(self.path_tail(os.path.dirname(self.path),dirname).split("/"))
508
 
        else:
509
 
            # remove the part that says /var/www/cobbler/ks_mirror/name
510
 
            name = "-".join(dirname.split("/")[5:])
511
 
 
512
 
        if kernel is not None and kernel.find("PAE") != -1:
513
 
            name = name + "-PAE"
514
 
 
515
 
        # These are all Ubuntu's doing, the netboot images are buried pretty
516
 
        # deep. ;-) -JC
517
 
        name = name.replace("-netboot","")
518
 
        name = name.replace("-ubuntu-installer","")
519
 
        name = name.replace("-amd64","")
520
 
        name = name.replace("-i386","")
521
 
 
522
 
        # we know that some kernel paths should not be in the name
523
 
 
524
 
        name = name.replace("-images","")
525
 
        name = name.replace("-pxeboot","")
526
 
        name = name.replace("-install","")
527
 
        name = name.replace("-isolinux","")
528
 
 
529
 
        # some paths above the media root may have extra path segments we want
530
 
        # to clean up
531
 
 
532
 
        name = name.replace("-os","")
533
 
        name = name.replace("-tree","")
534
 
        name = name.replace("var-www-cobbler-", "")
535
 
        name = name.replace("ks_mirror-","")
536
 
        name = name.replace("--","-")
537
 
 
538
 
        # remove any architecture name related string, as real arch will be appended later
539
 
 
540
 
        name = name.replace("chrp","ppc64")
541
 
 
542
 
        for separator in [ '-' , '_'  , '.' ] :
543
 
            for arch in [ "i386" , "x86_64" , "ia64" , "ppc64", "ppc32", "ppc", "x86" , "s390x", "s390" , "386" , "amd" ]:
544
 
                name = name.replace("%s%s" % ( separator , arch ),"")
545
 
 
546
 
        return name
547
 
 
548
 
    def get_proposed_arch(self,dirname):
549
 
        """
550
 
        Given an directory name, can we infer an architecture from a path segment?
551
 
        """
552
 
        if dirname.find("x86_64") != -1 or dirname.find("amd") != -1:
553
 
            return "x86_64"
554
 
        if dirname.find("ia64") != -1:
555
 
            return "ia64"
556
 
        if dirname.find("i386") != -1 or dirname.find("386") != -1 or dirname.find("x86") != -1:
557
 
            return "i386"
558
 
        if dirname.find("s390x") != -1:
559
 
            return "s390x"
560
 
        if dirname.find("s390") != -1:
561
 
            return "s390"
562
 
        if dirname.find("ppc64") != -1 or dirname.find("chrp") != -1:
563
 
            return "ppc64"
564
 
        if dirname.find("ppc32") != -1:
565
 
            return "ppc"
566
 
        if dirname.find("ppc") != -1:
567
 
            return "ppc"
568
 
        return None
569
 
 
570
 
    def arch_walker(self,foo,dirname,fnames):
571
 
        """
572
 
        See docs on learn_arch_from_tree.
573
 
 
574
 
        The TRY_LIST is used to speed up search, and should be dropped for default importer
575
 
        Searched kernel names are kernel-header, linux-headers-, kernel-largesmp, kernel-hugemem
576
 
 
577
 
        This method is useful to get the archs, but also to package type and a raw guess of the breed
578
 
        """
579
 
 
580
 
        # try to find a kernel header RPM and then look at it's arch.
581
 
        for x in fnames:
582
 
            if self.match_kernelarch_file(x):
583
 
                for arch in self.get_valid_arches():
584
 
                    if x.find(arch) != -1:
585
 
                        foo[arch] = 1
586
 
                for arch in [ "i686" , "amd64" ]:
587
 
                    if x.find(arch) != -1:
588
 
                        foo[arch] = 1
589
 
 
590
 
    def kickstart_finder(self,distros_added):
591
 
        """
592
 
        For all of the profiles in the config w/o a kickstart, use the
593
 
        given kickstart file, or look at the kernel path, from that,
594
 
        see if we can guess the distro, and if we can, assign a kickstart
595
 
        if one is available for it.
596
 
        """
597
 
        for profile in self.profiles:
598
 
            distro = self.distros.find(name=profile.get_conceptual_parent().name)
599
 
            if distro is None or not (distro in distros_added):
600
 
                continue
601
 
 
602
 
            kdir = os.path.dirname(distro.kernel)
603
 
            if self.kickstart_file == None:
604
 
                for file in self.get_release_files():
605
 
                    results = self.scan_pkg_filename(file)
606
 
                    # FIXME : If os is not found on tree but set with CLI, no kickstart is searched
607
 
                    if results is None:
608
 
                        self.logger.warning("skipping %s" % file)
609
 
                        continue
610
 
                    (flavor, major, minor, release) = results
611
 
                    # Why use set_variance()? scan_pkg_filename() does everything we need now - jcammarata
612
 
                    #version , ks = self.set_variance(flavor, major, minor, distro.arch)
613
 
                    if self.os_version:
614
 
                        if self.os_version != flavor:
615
 
                            utils.die(self.logger,"CLI version differs from tree : %s vs. %s" % (self.os_version,flavor))
616
 
                    distro.set_comment("%s %s (%s.%s.%s) %s" % (self.breed,flavor,major,minor,release,self.arch))
617
 
                    distro.set_os_version(flavor)
618
 
                    # is this even valid for debian/ubuntu? - jcammarata
619
 
                    #ds = self.get_datestamp()
620
 
                    #if ds is not None:
621
 
                    #    distro.set_tree_build_time(ds)
622
 
                    profile.set_kickstart("/var/lib/cobbler/kickstarts/sample.seed")
623
 
                    self.profiles.add(profile,save=True)
624
 
 
625
 
            self.configure_tree_location(distro)
626
 
            self.distros.add(distro,save=True) # re-save
627
 
            self.api.serialize()
628
 
 
629
 
    def configure_tree_location(self, distro):
630
 
        """
631
 
        Once a distribution is identified, find the part of the distribution
632
 
        that has the URL in it that we want to use for kickstarting the
633
 
        distribution, and create a ksmeta variable $tree that contains this.
634
 
        """
635
 
 
636
 
        base = self.get_rootdir()
637
 
 
638
 
        if self.network_root is None:
639
 
            dists_path = os.path.join( self.path , "dists" )
640
 
            if os.path.isdir( dists_path ):
641
 
                tree = "http://@@http_server@@/cblr/ks_mirror/%s" % (self.mirror_name)
642
 
            else:
643
 
                tree = "http://@@http_server@@/cblr/repo_mirror/%s" % (distro.name)
644
 
            self.set_install_tree(distro, tree)
645
 
        else:
646
 
            # where we assign the kickstart source is relative to our current directory
647
 
            # and the input start directory in the crawl.  We find the path segments
648
 
            # between and tack them on the network source path to find the explicit
649
 
            # network path to the distro that Anaconda can digest.
650
 
            tail = utils.path_tail(self.path, base)
651
 
            tree = self.network_root[:-1] + tail
652
 
            self.set_install_tree(distro, tree)
653
 
 
654
 
    def get_rootdir(self):
655
 
        return self.mirror
656
 
 
657
 
    def get_pkgdir(self):
658
 
        if not self.pkgdir:
659
 
            return None
660
 
        return os.path.join(self.get_rootdir(),self.pkgdir)
661
 
 
662
 
    def set_install_tree(self, distro, url):
663
 
        distro.ks_meta["tree"] = url
664
 
 
665
 
    def learn_arch_from_tree(self):
666
 
        """
667
 
        If a distribution is imported from DVD, there is a good chance the path doesn't
668
 
        contain the arch and we should add it back in so that it's part of the
669
 
        meaningful name ... so this code helps figure out the arch name.  This is important
670
 
        for producing predictable distro names (and profile names) from differing import sources
671
 
        """
672
 
        result = {}
673
 
        # FIXME : this is called only once, should not be a walk
674
 
        if self.get_pkgdir():
675
 
            os.path.walk(self.get_pkgdir(), self.arch_walker, result)
676
 
        if result.pop("amd64",False):
677
 
            result["x86_64"] = 1
678
 
        if result.pop("i686",False):
679
 
            result["i386"] = 1
680
 
        return result.keys()
681
 
 
682
 
    def match_kernelarch_file(self, filename):
683
 
        """
684
 
        Is the given filename a kernel filename?
685
 
        """
686
 
        if not filename.endswith("deb"):
687
 
            return False
688
 
        if filename.startswith("linux-headers-"):
689
 
            return True
690
 
        return False
691
 
 
692
 
    def scan_pkg_filename(self, file):
693
 
        """
694
 
        Determine what the distro is based on the release package filename.
695
 
        """
696
 
        # FIXME: all of these dist_names should probably be put in a function
697
 
        # which would be called in place of looking in codes.py.  Right now
698
 
        # you have to update both codes.py and this to add a new release
699
 
        if self.breed == "debian":
700
 
            dist_names = ['etch','lenny',]
701
 
        elif self.breed == "ubuntu":
702
 
            dist_names = ['dapper','hardy','intrepid','jaunty','karmic','lynx','maverick','natty',]
703
 
        else:
704
 
            return None
705
 
 
706
 
        if os.path.basename(file) in dist_names:
707
 
            release_file = os.path.join(file,'Release')
708
 
            self.logger.info("Found %s release file: %s" % (self.breed,release_file))
709
 
 
710
 
            f = open(release_file,'r')
711
 
            lines = f.readlines()
712
 
            f.close()
713
 
 
714
 
            for line in lines:
715
 
                if line.lower().startswith('version: '):
716
 
                    version = line.split(':')[1].strip()
717
 
                    values = version.split('.')
718
 
                    if len(values) == 1:
719
 
                        # I don't think you'd ever hit this currently with debian or ubuntu,
720
 
                        # just including it for safety reasons
721
 
                        return (os.path.basename(file), values[0], "0", "0")
722
 
                    elif len(values) == 2:
723
 
                        return (os.path.basename(file), values[0], values[1], "0")
724
 
                    elif len(values) > 2:
725
 
                        return (os.path.basename(file), values[0], values[1], values[2])
726
 
        return None
727
 
 
728
 
    def get_datestamp(self):
729
 
        """
730
 
        Not used for debian/ubuntu... should probably be removed? - jcammarata
731
 
        """
732
 
        pass
733
 
 
734
 
    def set_variance(self, flavor, major, minor, arch):
735
 
        """
736
 
        Set distro specific versioning.
737
 
        """
738
 
        # I don't think this is required anymore, as the scan_pkg_filename() function
739
 
        # above does everything we need it to - jcammarata
740
 
        #
741
 
        #if self.breed == "debian":
742
 
        #    dist_names = { '4.0' : "etch" , '5.0' : "lenny" }
743
 
        #    dist_vers = "%s.%s" % ( major , minor )
744
 
        #    os_version = dist_names[dist_vers]
745
 
        #
746
 
        #    return os_version , "/var/lib/cobbler/kickstarts/sample.seed"
747
 
        #elif self.breed == "ubuntu":
748
 
        #    # Release names taken from wikipedia
749
 
        #    dist_names = { '6.4'  :"dapper", 
750
 
        #                   '8.4'  :"hardy", 
751
 
        #                   '8.10' :"intrepid", 
752
 
        #                   '9.4'  :"jaunty",
753
 
        #                   '9.10' :"karmic",
754
 
        #                   '10.4' :"lynx",
755
 
        #                   '10.10':"maverick",
756
 
        #                   '11.4' :"natty",
757
 
        #                 }
758
 
        #    dist_vers = "%s.%s" % ( major , minor )
759
 
        #    if not dist_names.has_key( dist_vers ):
760
 
        #        dist_names['4ubuntu2.0'] = "IntrepidIbex"
761
 
        #    os_version = dist_names[dist_vers]
762
 
        # 
763
 
        #    return os_version , "/var/lib/cobbler/kickstarts/sample.seed"
764
 
        #else:
765
 
        #    return None
766
 
        pass
767
 
 
768
 
    def process_repos(self, main_importer, distro):
769
 
        # Create a disabled repository for the new distro, and the security updates
770
 
        #
771
 
        # NOTE : We cannot use ks_meta nor os_version because they get fixed at a later stage
772
 
 
773
 
        # Obtain repo mirror from APT if available
774
 
        mirror = False
775
 
        if apt_available:
776
 
            # Example returned URL: http://us.archive.ubuntu.com/ubuntu
777
 
            mirror = self.get_repo_mirror_from_apt()
778
 
            if mirror:
779
 
                mirror = mirror + "/dists"
780
 
        if not mirror:
781
 
            mirror = "http://archive.ubuntu.com/ubuntu/dists/"
782
 
 
783
 
        repo = item_repo.Repo(main_importer.config)
784
 
        repo.set_breed( "apt" )
785
 
        repo.set_arch( distro.arch )
786
 
        repo.set_keep_updated( False )
787
 
        repo.yumopts["--ignore-release-gpg"] = None
788
 
        repo.yumopts["--verbose"] = None
789
 
        repo.set_name( distro.name )
790
 
        repo.set_os_version( distro.os_version )
791
 
 
792
 
        if distro.breed == "ubuntu":
793
 
            repo.set_mirror( "%s/%s" % (mirror, distro.os_version) )
794
 
        else:
795
 
            # NOTE : The location of the mirror should come from timezone
796
 
            repo.set_mirror( "http://ftp.%s.debian.org/debian/dists/%s" % ( 'us' , distro.os_version ) )
797
 
 
798
 
        security_repo = item_repo.Repo(main_importer.config)
799
 
        security_repo.set_breed( "apt" )
800
 
        security_repo.set_arch( distro.arch )
801
 
        security_repo.set_keep_updated( False )
802
 
        security_repo.yumopts["--ignore-release-gpg"] = None
803
 
        security_repo.yumopts["--verbose"] = None
804
 
        security_repo.set_name( distro.name + "-security" )
805
 
        security_repo.set_os_version( distro.os_version )
806
 
        # There are no official mirrors for security updates
807
 
        if distro.breed == "ubuntu":
808
 
            security_repo.set_mirror( "%s/%s-security" % (mirror, distro.os_version) )
809
 
        else:
810
 
            security_repo.set_mirror( "http://security.debian.org/debian-security/dists/%s/updates" % distro.os_version )
811
 
 
812
 
        self.logger.info("Added repos for %s" % distro.name)
813
 
        repos  = main_importer.config.repos()
814
 
        repos.add(repo,save=True)
815
 
        repos.add(security_repo,save=True)
816
 
 
817
 
# ==========================================================================
818
 
 
819
 
def get_import_manager(config,logger):
820
 
    return ImportDebianUbuntuManager(config,logger)