35
35
import version
36
36
from version import *
37
37
from constants import *
38
+ from diskutil import getRemovableDeviceList
38
39
39
40
MY_PRODUCT_BRAND = PRODUCT_BRAND or PLATFORM_NAME
40
41
@@ -106,6 +107,7 @@ def getPrepSequence(ans, interactive):
106
107
Task (util .getUUID , As (ans ), ['installation-uuid' ]),
107
108
Task (util .getUUID , As (ans ), ['control-domain-uuid' ]),
108
109
Task (util .randomLabelStr , As (ans ), ['disk-label-suffix' ]),
110
+ Task (diskutil .create_raid , A (ans , 'raid' ), []),
109
111
Task (partitionTargetDisk , A (ans , 'primary-disk' , 'installation-to-overwrite' , 'preserve-first-partition' ,'sr-on-primary' , 'target-platform' ),
110
112
['target-boot-mode' , 'primary-partnum' , 'backup-partnum' , 'storage-partnum' , 'boot-partnum' , 'logs-partnum' , 'swap-partnum' ]),
111
113
]
@@ -158,7 +160,7 @@ def getPrepSequence(ans, interactive):
158
160
159
161
def getMainRepoSequence (ans , repos ):
160
162
seq = []
161
- seq .append (Task (repository .installFromRepos , lambda a : [repos ] + [a .get ('mounts' )], [],
163
+ seq .append (Task (repository .installFromRepos , lambda a : [repos ] + [a .get ('mounts' ), a . get ( 'kernel-alt' ) ], [],
162
164
progress_scale = 100 ,
163
165
pass_progress_callback = True ,
164
166
progress_text = "Installing %s..." % (", " .join ([repo .name () for repo in repos ]))))
@@ -180,6 +182,7 @@ def getRepoSequence(ans, repos):
180
182
181
183
def getFinalisationSequence (ans ):
182
184
seq = [
185
+ Task (importYumAndRpmGpgKeys , A (ans , 'mounts' ), []),
183
186
Task (writeResolvConf , A (ans , 'mounts' , 'manual-hostname' , 'manual-nameservers' ), []),
184
187
Task (writeMachineID , A (ans , 'mounts' ), []),
185
188
Task (writeKeyboardConfiguration , A (ans , 'mounts' , 'keymap' ), []),
@@ -201,6 +204,7 @@ def getFinalisationSequence(ans):
201
204
'boot-partnum' , 'primary-partnum' , 'target-boot-mode' , 'branding' ,
202
205
'disk-label-suffix' , 'bootloader-location' , 'write-boot-entry' , 'install-type' ,
203
206
'serial-console' , 'boot-serial' , 'host-config' , 'fcoe-interfaces' ), []),
207
+ Task (postInstallAltKernel , A (ans , 'mounts' , 'kernel-alt' ), []),
204
208
Task (touchSshAuthorizedKeys , A (ans , 'mounts' ), []),
205
209
Task (setRootPassword , A (ans , 'mounts' , 'root-password' ), [], args_sensitive = True ),
206
210
Task (setTimeZone , A (ans , 'mounts' , 'timezone' ), []),
@@ -299,6 +303,50 @@ def progressCallback(x):
299
303
doCleanup (answers ['cleanup' ])
300
304
del answers ['cleanup' ]
301
305
306
+ def determineRepositories (answers , answers_pristine , main_repositories , update_repositories ):
307
+ def add_repos (main_repositories , update_repositories , repos , repo_gpgcheck , gpgcheck ):
308
+ """Add repositories to the appropriate list, ensuring no duplicates,
309
+ that the main repository is at the beginning, and that the order of the
310
+ rest is maintained."""
311
+
312
+ for repo in repos :
313
+ if isinstance (repo , repository .UpdateYumRepository ):
314
+ repo_list = update_repositories
315
+ else :
316
+ repo_list = main_repositories
317
+
318
+ if repo not in repo_list :
319
+ if repo .identifier () == MAIN_REPOSITORY_NAME :
320
+ repo_list .insert (0 , repo )
321
+ else :
322
+ repo_list .append (repo )
323
+
324
+ if repo_list is main_repositories : # i.e., if repo is a "main repository"
325
+ repo .setRepoGpgCheck (repo_gpgcheck )
326
+ repo .setGpgCheck (gpgcheck )
327
+
328
+ default_repo_gpgcheck = answers .get ('repo-gpgcheck' , True )
329
+ default_gpgcheck = answers .get ('gpgcheck' , True )
330
+ # A list of sources coming from the answerfile
331
+ if 'sources' in answers_pristine :
332
+ for i in answers_pristine ['sources' ]:
333
+ repos = repository .repositoriesFromDefinition (i ['media' ], i ['address' ])
334
+ repo_gpgcheck = default_repo_gpgcheck if i ['repo_gpgcheck' ] is None else i ['repo_gpgcheck' ]
335
+ gpgcheck = default_gpgcheck if i ['gpgcheck' ] is None else i ['gpgcheck' ]
336
+ add_repos (main_repositories , update_repositories , repos , repo_gpgcheck , gpgcheck )
337
+
338
+ # A single source coming from an interactive install
339
+ if 'source-media' in answers_pristine and 'source-address' in answers_pristine :
340
+ repos = repository .repositoriesFromDefinition (answers_pristine ['source-media' ], answers_pristine ['source-address' ])
341
+ add_repos (main_repositories , update_repositories , repos , default_repo_gpgcheck , default_gpgcheck )
342
+
343
+ for media , address in answers_pristine ['extra-repos' ]:
344
+ repos = repository .repositoriesFromDefinition (media , address )
345
+ add_repos (main_repositories , update_repositories , repos , default_repo_gpgcheck , default_gpgcheck )
346
+
347
+ if not main_repositories or main_repositories [0 ].identifier () != MAIN_REPOSITORY_NAME :
348
+ raise RuntimeError ("No main repository found" )
349
+
302
350
def performInstallation (answers , ui_package , interactive ):
303
351
logger .log ("INPUT ANSWERS DICTIONARY:" )
304
352
prettyLogAnswers (answers )
@@ -367,9 +415,17 @@ def performInstallation(answers, ui_package, interactive):
367
415
assert answers ['net-admin-interface' ].startswith ("eth" )
368
416
answers ['net-admin-bridge' ] = "xenbr%s" % answers ['net-admin-interface' ][3 :]
369
417
418
+ # A list needs to be used rather than a set since the order of updates is
419
+ # important. However, since the same repository might exist in multiple
420
+ # locations or the same location might be listed multiple times, care is
421
+ # needed to ensure that there are no duplicates.
422
+ main_repositories = []
423
+ update_repositories = []
424
+ answers_pristine = answers .copy ()
425
+ determineRepositories (answers , answers_pristine , main_repositories , update_repositories )
426
+
370
427
# perform installation:
371
428
prep_seq = getPrepSequence (answers , interactive )
372
- answers_pristine = answers .copy ()
373
429
executeSequence (prep_seq , "Preparing for installation..." , answers , ui_package , False )
374
430
375
431
# install from main repositories:
@@ -383,48 +439,6 @@ def handleRepos(repos, ans):
383
439
384
440
answers ['installed-repos' ] = {}
385
441
386
- # A list needs to be used rather than a set since the order of updates is
387
- # important. However, since the same repository might exist in multiple
388
- # locations or the same location might be listed multiple times, care is
389
- # needed to ensure that there are no duplicates.
390
- main_repositories = []
391
- update_repositories = []
392
-
393
- def add_repos (main_repositories , update_repositories , repos ):
394
- """Add repositories to the appropriate list, ensuring no duplicates,
395
- that the main repository is at the beginning, and that the order of the
396
- rest is maintained."""
397
-
398
- for repo in repos :
399
- if isinstance (repo , repository .UpdateYumRepository ):
400
- repo_list = update_repositories
401
- else :
402
- repo_list = main_repositories
403
-
404
- if repo not in repo_list :
405
- if repo .identifier () == MAIN_REPOSITORY_NAME :
406
- repo_list .insert (0 , repo )
407
- else :
408
- repo_list .append (repo )
409
-
410
- # A list of sources coming from the answerfile
411
- if 'sources' in answers_pristine :
412
- for i in answers_pristine ['sources' ]:
413
- repos = repository .repositoriesFromDefinition (i ['media' ], i ['address' ])
414
- add_repos (main_repositories , update_repositories , repos )
415
-
416
- # A single source coming from an interactive install
417
- if 'source-media' in answers_pristine and 'source-address' in answers_pristine :
418
- repos = repository .repositoriesFromDefinition (answers_pristine ['source-media' ], answers_pristine ['source-address' ])
419
- add_repos (main_repositories , update_repositories , repos )
420
-
421
- for media , address in answers_pristine ['extra-repos' ]:
422
- repos = repository .repositoriesFromDefinition (media , address )
423
- add_repos (main_repositories , update_repositories , repos )
424
-
425
- if not main_repositories or main_repositories [0 ].identifier () != MAIN_REPOSITORY_NAME :
426
- raise RuntimeError ("No main repository found" )
427
-
428
442
handleMainRepos (main_repositories , answers )
429
443
if update_repositories :
430
444
handleRepos (update_repositories , answers )
@@ -435,7 +449,18 @@ def add_repos(main_repositories, update_repositories, repos):
435
449
if r .accessor ().canEject ():
436
450
r .accessor ().eject ()
437
451
438
- if interactive and constants .HAS_SUPPLEMENTAL_PACKS :
452
+ # XCP-ng: so, very unfortunately we don't remember with precision why this was added and
453
+ # no commit message or comment can help us here.
454
+ # It may be related to the fact that the "all_repositories" above doesn't contain
455
+ # the installation CD-ROM or USB stick in the case of a netinstall.
456
+ # Question: why it is needed at all since there's no repository on the netinstall
457
+ # installation media?
458
+ if answers .get ('netinstall' ):
459
+ for device in getRemovableDeviceList ():
460
+ util .runCmd2 (['eject' , device ])
461
+
462
+ if interactive and (constants .HAS_SUPPLEMENTAL_PACKS or
463
+ "driver-repos" in answers ):
439
464
# Add supp packs in a loop
440
465
while True :
441
466
media_ans = dict (answers_pristine )
@@ -1130,7 +1155,11 @@ def installBootLoader(mounts, disk, boot_partnum, primary_partnum, target_boot_m
1130
1155
setEfiBootEntry (mounts , disk , boot_partnum , install_type , branding )
1131
1156
else :
1132
1157
if location == constants .BOOT_LOCATION_MBR :
1133
- installGrub2 (mounts , disk , False )
1158
+ if diskutil .is_raid (disk ):
1159
+ for member in diskutil .getDeviceSlaves (disk ):
1160
+ installGrub2 (mounts , member , False )
1161
+ else :
1162
+ installGrub2 (mounts , disk , False )
1134
1163
else :
1135
1164
installGrub2 (mounts , root_partition , True )
1136
1165
@@ -1505,15 +1534,15 @@ def configureNetworking(mounts, admin_iface, admin_bridge, admin_config, hn_conf
1505
1534
print ("NETMASK='%s'" % admin_config .netmask , file = mc )
1506
1535
if admin_config .gateway :
1507
1536
print ("GATEWAY='%s'" % admin_config .gateway , file = mc )
1508
- if manual_nameservers :
1509
- print ("DNS='%s'" % (',' .join (nameservers ),), file = mc )
1510
- if domain :
1511
- print ("DOMAIN='%s'" % domain , file = mc )
1512
1537
print ("MODEV6='%s'" % netinterface .NetInterface .getModeStr (admin_config .modev6 ), file = mc )
1513
1538
if admin_config .modev6 == netinterface .NetInterface .Static :
1514
1539
print ("IPv6='%s'" % admin_config .ipv6addr , file = mc )
1515
1540
if admin_config .ipv6_gateway :
1516
1541
print ("IPv6_GATEWAY='%s'" % admin_config .ipv6_gateway , file = mc )
1542
+ if manual_nameservers :
1543
+ print ("DNS='%s'" % (',' .join (nameservers ),), file = mc )
1544
+ if domain :
1545
+ print ("DOMAIN='%s'" % domain , file = mc )
1517
1546
if admin_config .vlan :
1518
1547
print ("VLAN='%d'" % admin_config .vlan , file = mc )
1519
1548
mc .close ()
@@ -1556,12 +1585,18 @@ def configureNetworking(mounts, admin_iface, admin_bridge, admin_config, hn_conf
1556
1585
# now we need to write /etc/sysconfig/network
1557
1586
nfd = open ("%s/etc/sysconfig/network" % mounts ["root" ], "w" )
1558
1587
nfd .write ("NETWORKING=yes\n " )
1559
- if admin_config .modev6 :
1588
+ ipv6 = admin_config .modev6 is not None
1589
+ if ipv6 :
1560
1590
nfd .write ("NETWORKING_IPV6=yes\n " )
1561
1591
util .runCmd2 (['chroot' , mounts ['root' ], 'systemctl' , 'enable' , 'ip6tables' ])
1562
1592
else :
1563
1593
nfd .write ("NETWORKING_IPV6=no\n " )
1564
1594
netutil .disable_ipv6_module (mounts ["root" ])
1595
+
1596
+ with open ("%s/etc/sysctl.d/91-net-ipv6.conf" % mounts ["root" ], "w" ) as ipv6_conf :
1597
+ for i in ['all' , 'default' ]:
1598
+ ipv6_conf .write ('net.ipv6.conf.%s.disable_ipv6=%d\n ' % (i , int (not ipv6 )))
1599
+
1565
1600
nfd .write ("IPV6_AUTOCONF=no\n " )
1566
1601
nfd .write ('NTPSERVERARGS="iburst prefer"\n ' )
1567
1602
nfd .close ()
@@ -1654,6 +1689,57 @@ def touchSshAuthorizedKeys(mounts):
1654
1689
fh = open ("%s/root/.ssh/authorized_keys" % mounts ['root' ], 'a' )
1655
1690
fh .close ()
1656
1691
1692
+ def importYumAndRpmGpgKeys (mounts ):
1693
+ # Python script that uses yum functions to import the GPG key for our repositories
1694
+ import_yum_keys = """#!/bin/env python
1695
+ from __future__ import print_function
1696
+ from yum import YumBase
1697
+
1698
+ def retTrue(*args, **kwargs):
1699
+ return True
1700
+
1701
+ base = YumBase()
1702
+ for repo in base.repos.repos.itervalues():
1703
+ if repo.id.startswith('xcp-ng'):
1704
+ print("*** Importing GPG key for repository %s - %s" % (repo.id, repo.name))
1705
+ base.getKeyForRepo(repo, callback=retTrue)
1706
+ """
1707
+ internal_tmp_filepath = '/tmp/import_yum_keys.py'
1708
+ external_tmp_filepath = mounts ['root' ] + internal_tmp_filepath
1709
+ with open (external_tmp_filepath , 'w' ) as f :
1710
+ f .write (import_yum_keys )
1711
+ # bind mount /dev, necessary for NSS initialization without which RPM won't work
1712
+ util .bindMount ('/dev' , "%s/dev" % mounts ['root' ])
1713
+ try :
1714
+ util .runCmd2 (['chroot' , mounts ['root' ], 'python' , internal_tmp_filepath ])
1715
+ util .runCmd2 (['chroot' , mounts ['root' ], 'rpm' , '--import' , '/etc/pki/rpm-gpg/RPM-GPG-KEY-xcpng' ])
1716
+ finally :
1717
+ util .umount ("%s/dev" % mounts ['root' ])
1718
+ os .unlink (external_tmp_filepath )
1719
+
1720
+ def postInstallAltKernel (mounts , kernel_alt ):
1721
+ """ Install our alternate kernel. Must be called after the bootloader installation. """
1722
+ if not kernel_alt :
1723
+ logger .log ('kernel-alt not installed' )
1724
+ return
1725
+
1726
+ util .bindMount ("/proc" , "%s/proc" % mounts ['root' ])
1727
+ util .bindMount ("/sys" , "%s/sys" % mounts ['root' ])
1728
+ util .bindMount ("/dev" , "%s/dev" % mounts ['root' ])
1729
+
1730
+ try :
1731
+ rc , out = util .runCmd2 (['chroot' , mounts ['root' ], 'rpm' , '-q' , 'kernel-alt' , '--qf' , '%{version}' ],
1732
+ with_stdout = True )
1733
+ version = out
1734
+ # Generate the initrd as it was disabled during initial installation
1735
+ util .runCmd2 (['chroot' , mounts ['root' ], 'dracut' , '-f' , '/boot/initrd-%s.img' % version , version ])
1736
+
1737
+ # Update grub
1738
+ util .runCmd2 (['chroot' , mounts ['root' ], '/opt/xensource/bin/updategrub.py' , 'add' , 'kernel-alt' , version ])
1739
+ finally :
1740
+ util .umount ("%s/dev" % mounts ['root' ])
1741
+ util .umount ("%s/sys" % mounts ['root' ])
1742
+ util .umount ("%s/proc" % mounts ['root' ])
1657
1743
1658
1744
################################################################################
1659
1745
# OTHER HELPERS
0 commit comments