* Allowing RPMs to be served in a yum repo over http server in the
installation.
| ... | ... |
@@ -13,7 +13,8 @@ |
| 13 | 13 |
"elfutils-libelf", "sqlite-autoconf", "nspr", "nss", "popt", "lua", "rpm", |
| 14 | 14 |
"gptfdisk", "tar", "gzip", "openssl", "python2", "python2-libs", "python-requests", |
| 15 | 15 |
"pcre", "glib", "parted", "libsigc++", "XML-Parser", "glibmm", "dparted", |
| 16 |
- "libgsystem", "ostree","device-mapper","device-mapper-libs","libsepol","libselinux"] |
|
| 16 |
+ "libgsystem", "ostree","device-mapper","device-mapper-libs","libsepol","libselinux", |
|
| 17 |
+ "db", "libsolv", "hawkey", "python-hawkey"] |
|
| 17 | 18 |
} |
| 18 | 19 |
|
| 19 | 20 |
|
| ... | ... |
@@ -16,7 +16,9 @@ import fnmatch |
| 16 | 16 |
import signal |
| 17 | 17 |
import sys |
| 18 | 18 |
import glob |
| 19 |
+import urllib |
|
| 19 | 20 |
import modules.commons |
| 21 |
+import xml.etree.ElementTree as ET |
|
| 20 | 22 |
from jsonwrapper import JsonWrapper |
| 21 | 23 |
from progressbar import ProgressBar |
| 22 | 24 |
from window import Window |
| ... | ... |
@@ -52,7 +54,6 @@ class Installer(object): |
| 52 | 52 |
else: |
| 53 | 53 |
self.output = None |
| 54 | 54 |
|
| 55 |
- self.install_factor = 3 |
|
| 56 | 55 |
if self.iso_installer: |
| 57 | 56 |
#initializing windows |
| 58 | 57 |
self.maxy = maxy |
| ... | ... |
@@ -105,7 +106,7 @@ class Installer(object): |
| 105 | 105 |
continue |
| 106 | 106 |
if self.iso_installer: |
| 107 | 107 |
self.progress_bar.update_message('Installing {0}...'.format(rpm['package']))
|
| 108 |
- return_value = self.install_package(rpm['package']) |
|
| 108 |
+ return_value = self.install_package(rpm['filename']) |
|
| 109 | 109 |
if return_value != 0: |
| 110 | 110 |
self.exit_gracefully(None, None) |
| 111 | 111 |
if self.iso_installer: |
| ... | ... |
@@ -135,14 +136,80 @@ class Installer(object): |
| 135 | 135 |
|
| 136 | 136 |
return ActionResult(True, None) |
| 137 | 137 |
|
| 138 |
+ def download_file(self, url, directory): |
|
| 139 |
+ # TODO: Add errors handling |
|
| 140 |
+ urlopener = urllib.URLopener() |
|
| 141 |
+ urlopener.retrieve(url, os.path.join(directory, os.path.basename(url))) |
|
| 142 |
+ |
|
| 143 |
+ def download_rpms(self): |
|
| 144 |
+ repodata_dir = os.path.join(self.photon_root, 'RPMS/repodata') |
|
| 145 |
+ process = subprocess.Popen(['mkdir', '-p', repodata_dir], stdout=self.output) |
|
| 146 |
+ retval = process.wait() |
|
| 147 |
+ |
|
| 148 |
+ import hawkey |
|
| 149 |
+ self.install_factor = 1 |
|
| 150 |
+ # Load the repo data |
|
| 151 |
+ sack = hawkey.Sack() |
|
| 152 |
+ |
|
| 153 |
+ repomd_filename = "repomd.xml" |
|
| 154 |
+ repomd_url = os.path.join(self.rpm_path, "repodata/repomd.xml") |
|
| 155 |
+ |
|
| 156 |
+ self.download_file(repomd_url, repodata_dir) |
|
| 157 |
+ |
|
| 158 |
+ # parse to the xml to get the primary and files list |
|
| 159 |
+ tree = ET.parse(os.path.join(repodata_dir, repomd_filename)) |
|
| 160 |
+ # TODO: Get the namespace dynamically from the xml file |
|
| 161 |
+ ns = {'ns': 'http://linux.duke.edu/metadata/repo'}
|
|
| 162 |
+ |
|
| 163 |
+ primary_location = tree.find("./ns:data[@type='primary']/ns:location", ns).get("href");
|
|
| 164 |
+ filelists_location = tree.find("./ns:data[@type='filelists']/ns:location", ns).get("href");
|
|
| 165 |
+ primary_filename = os.path.basename(primary_location); |
|
| 166 |
+ filelists_filename = os.path.basename(filelists_location); |
|
| 167 |
+ |
|
| 168 |
+ self.download_file(os.path.join(self.rpm_path, primary_location), repodata_dir) |
|
| 169 |
+ self.download_file(os.path.join(self.rpm_path, filelists_location), repodata_dir) |
|
| 170 |
+ |
|
| 171 |
+ repo = hawkey.Repo("installrepo")
|
|
| 172 |
+ repo.repomd_fn = os.path.join(repodata_dir, repomd_filename) |
|
| 173 |
+ repo.primary_fn = os.path.join(repodata_dir, primary_filename) |
|
| 174 |
+ repo.filelists_fn = os.path.join(repodata_dir, filelists_filename) |
|
| 175 |
+ |
|
| 176 |
+ sack.load_yum_repo(repo, load_filelists=True) |
|
| 177 |
+ |
|
| 178 |
+ progressbar_num_items = 0 |
|
| 179 |
+ self.rpms_tobeinstalled = [] |
|
| 180 |
+ selected_packages = self.install_config['packages'] |
|
| 181 |
+ for package in selected_packages: |
|
| 182 |
+ # Locate the package |
|
| 183 |
+ q = hawkey.Query(sack).filter(name=package) |
|
| 184 |
+ if (len(q) > 0): |
|
| 185 |
+ progressbar_num_items += q[0].size + q[0].size * self.install_factor |
|
| 186 |
+ self.rpms_tobeinstalled.append({'package': package, 'size': q[0].size, 'location': q[0].location, 'filename': os.path.basename(q[0].location)})
|
|
| 187 |
+ else: |
|
| 188 |
+ print >> sys.stderr, "Package %s not found in the repo" % package |
|
| 189 |
+ #self.exit_gracefully(None, None) |
|
| 190 |
+ |
|
| 191 |
+ self.progress_bar.update_num_items(progressbar_num_items) |
|
| 192 |
+ |
|
| 193 |
+ # Download the rpms |
|
| 194 |
+ for rpm in self.rpms_tobeinstalled: |
|
| 195 |
+ message = 'Downloading {0}...'.format(rpm['filename'])
|
|
| 196 |
+ self.progress_bar.update_message(message) |
|
| 197 |
+ self.download_file(os.path.join(self.rpm_path, rpm['location']), os.path.join(self.photon_root, "RPMS")) |
|
| 198 |
+ self.progress_bar.increment(rpm['size']) |
|
| 199 |
+ |
|
| 200 |
+ # update the rpms path |
|
| 201 |
+ self.rpm_path = os.path.join(self.photon_root, "RPMS") |
|
| 202 |
+ |
|
| 138 | 203 |
def copy_rpms(self): |
| 139 | 204 |
# prepare the RPMs list |
| 205 |
+ self.install_factor = 3 |
|
| 140 | 206 |
rpms = [] |
| 141 | 207 |
for root, dirs, files in os.walk(self.rpm_path): |
| 142 | 208 |
for name in files: |
| 143 | 209 |
file = os.path.join(root, name) |
| 144 | 210 |
size = os.path.getsize(file) |
| 145 |
- rpms.append({'name': name, 'path': file, 'size': size})
|
|
| 211 |
+ rpms.append({'filename': name, 'path': file, 'size': size})
|
|
| 146 | 212 |
|
| 147 | 213 |
progressbar_num_items = 0 |
| 148 | 214 |
self.rpms_tobeinstalled = [] |
| ... | ... |
@@ -150,20 +217,20 @@ class Installer(object): |
| 150 | 150 |
for package in selected_packages: |
| 151 | 151 |
pattern = package + '-[0-9]*.rpm' |
| 152 | 152 |
for rpm in rpms: |
| 153 |
- if fnmatch.fnmatch(rpm['name'], pattern): |
|
| 153 |
+ if fnmatch.fnmatch(rpm['filename'], pattern): |
|
| 154 | 154 |
rpm['package'] = package |
| 155 | 155 |
self.rpms_tobeinstalled.append(rpm) |
| 156 | 156 |
progressbar_num_items += rpm['size'] + rpm['size'] * self.install_factor |
| 157 | 157 |
break |
| 158 | 158 |
|
| 159 |
- process = subprocess.Popen(['mkdir', '-p', self.photon_root + '/RPMS'], stdout=self.output) |
|
| 160 |
- retval = process.wait() |
|
| 161 |
- |
|
| 162 | 159 |
if self.iso_installer: |
| 163 | 160 |
self.progress_bar.update_num_items(progressbar_num_items) |
| 164 | 161 |
|
| 165 | 162 |
# Copy the rpms |
| 166 | 163 |
for rpm in self.rpms_tobeinstalled: |
| 164 |
+ if self.iso_installer: |
|
| 165 |
+ message = 'Copying {0}...'.format(rpm['filename'])
|
|
| 166 |
+ self.progress_bar.update_message(message) |
|
| 167 | 167 |
shutil.copy(rpm['path'], self.photon_root + '/RPMS/') |
| 168 | 168 |
if self.iso_installer: |
| 169 | 169 |
self.progress_bar.increment(rpm['size']) |
| ... | ... |
@@ -177,7 +244,14 @@ class Installer(object): |
| 177 | 177 |
process = subprocess.Popen(['cp', '-r', "../installer", self.photon_root], stdout=self.output) |
| 178 | 178 |
retval = process.wait() |
| 179 | 179 |
|
| 180 |
- self.copy_rpms() |
|
| 180 |
+ # Create the rpms directory |
|
| 181 |
+ process = subprocess.Popen(['mkdir', '-p', self.photon_root + '/RPMS'], stdout=self.output) |
|
| 182 |
+ retval = process.wait() |
|
| 183 |
+ |
|
| 184 |
+ if self.rpm_path.startswith("http://"):
|
|
| 185 |
+ self.download_rpms() |
|
| 186 |
+ else: |
|
| 187 |
+ self.copy_rpms() |
|
| 181 | 188 |
|
| 182 | 189 |
def initialize_system(self): |
| 183 | 190 |
#Setup the disk |
| ... | ... |
@@ -25,8 +25,8 @@ from license import License |
| 25 | 25 |
|
| 26 | 26 |
class IsoInstaller(object): |
| 27 | 27 |
|
| 28 |
- def get_config(self, path, cd_path): |
|
| 29 |
- if path.startswith("http"):
|
|
| 28 |
+ def get_config(self, path): |
|
| 29 |
+ if path.startswith("http://"):
|
|
| 30 | 30 |
# Do 3 trials to get the kick start |
| 31 | 31 |
# TODO: make sure the installer run after network is up |
| 32 | 32 |
for x in range(0,3): |
| ... | ... |
@@ -48,10 +48,15 @@ class IsoInstaller(object): |
| 48 | 48 |
raise Exception(err_msg) |
| 49 | 49 |
else: |
| 50 | 50 |
if path.startswith("cdrom:/"):
|
| 51 |
- path = os.path.join(cd_path, path.replace("cdrom:/", "", 1))
|
|
| 51 |
+ self.mount_RPMS_cd() |
|
| 52 |
+ path = os.path.join(self.cd_path, path.replace("cdrom:/", "", 1))
|
|
| 52 | 53 |
return (JsonWrapper(path)).read(); |
| 53 | 54 |
|
| 54 | 55 |
def mount_RPMS_cd(self): |
| 56 |
+ # check if the cd is already mounted |
|
| 57 |
+ if self.cd_path: |
|
| 58 |
+ return |
|
| 59 |
+ |
|
| 55 | 60 |
# Mount the cd to get the RPMS |
| 56 | 61 |
process = subprocess.Popen(['mkdir', '-p', '/mnt/cdrom']) |
| 57 | 62 |
retval = process.wait() |
| ... | ... |
@@ -61,7 +66,8 @@ class IsoInstaller(object): |
| 61 | 61 |
process = subprocess.Popen(['mount', '/dev/cdrom', '/mnt/cdrom']) |
| 62 | 62 |
retval = process.wait() |
| 63 | 63 |
if retval == 0: |
| 64 |
- return "/mnt/cdrom" |
|
| 64 |
+ self.cd_path = "/mnt/cdrom" |
|
| 65 |
+ return |
|
| 65 | 66 |
print "Failed to mount the cd, retry in a second" |
| 66 | 67 |
time.sleep(1) |
| 67 | 68 |
print "Failed to mount the cd, exiting the installer, check the logs for more details" |
| ... | ... |
@@ -83,32 +89,40 @@ class IsoInstaller(object): |
| 83 | 83 |
|
| 84 | 84 |
curses.curs_set(0) |
| 85 | 85 |
|
| 86 |
- self.install_config = {'iso_system': False}
|
|
| 86 |
+ self.cd_path = None; |
|
| 87 | 87 |
|
| 88 |
- # Mount the cd for the RPM, tools, and may be the ks |
|
| 89 |
- cd_path = self.mount_RPMS_cd() |
|
| 88 |
+ self.install_config = {'iso_system': False}
|
|
| 90 | 89 |
|
| 91 |
- # check the kickstart params |
|
| 92 |
- ks_config = None |
|
| 93 | 90 |
kernel_params = subprocess.check_output(['cat', '/proc/cmdline']) |
| 91 |
+ |
|
| 92 |
+ # check the kickstart param |
|
| 93 |
+ ks_config = None |
|
| 94 | 94 |
m = re.match(r".*ks=(\S+)\s*.*\s*", kernel_params) |
| 95 | 95 |
if m != None: |
| 96 |
- ks_config = self.get_config(m.group(1), cd_path) |
|
| 97 |
- |
|
| 98 |
- license_agreement = License(self.maxy, self.maxx) |
|
| 99 |
- select_disk = SelectDisk(self.maxy, self.maxx, self.install_config) |
|
| 100 |
- package_selector = PackageSelector(self.maxy, self.maxx, self.install_config, options_file) |
|
| 101 |
- hostname_reader = WindowStringReader(self.maxy, self.maxx, 10, 70, False, 'Choose the hostname for your system', |
|
| 102 |
- 'Hostname:', |
|
| 103 |
- 2, self.install_config) |
|
| 104 |
- root_password_reader = WindowStringReader(self.maxy, self.maxx, 10, 70, True, 'Set up root password', |
|
| 105 |
- 'Root password:', |
|
| 106 |
- 2, self.install_config) |
|
| 107 |
- installer = Installer(self.install_config, self.maxy, self.maxx, True, rpm_path=os.path.join(cd_path, "RPMS"), log_path="/var/log", ks_config=ks_config) |
|
| 96 |
+ ks_config = self.get_config(m.group(1)) |
|
| 97 |
+ |
|
| 98 |
+ # check for the repo param |
|
| 99 |
+ m = re.match(r".*repo=(\S+)\s*.*\s*", kernel_params) |
|
| 100 |
+ if m != None: |
|
| 101 |
+ rpm_path = m.group(1) |
|
| 102 |
+ else: |
|
| 103 |
+ # the rpms should be in the cd |
|
| 104 |
+ self.mount_RPMS_cd() |
|
| 105 |
+ rpm_path=os.path.join(self.cd_path, "RPMS") |
|
| 108 | 106 |
|
| 109 | 107 |
# This represents the installer screen, the bool indicated if I can go back to this window or not |
| 110 | 108 |
items = [] |
| 111 | 109 |
if not ks_config: |
| 110 |
+ license_agreement = License(self.maxy, self.maxx) |
|
| 111 |
+ select_disk = SelectDisk(self.maxy, self.maxx, self.install_config) |
|
| 112 |
+ package_selector = PackageSelector(self.maxy, self.maxx, self.install_config, options_file) |
|
| 113 |
+ hostname_reader = WindowStringReader(self.maxy, self.maxx, 10, 70, False, 'Choose the hostname for your system', |
|
| 114 |
+ 'Hostname:', |
|
| 115 |
+ 2, self.install_config) |
|
| 116 |
+ root_password_reader = WindowStringReader(self.maxy, self.maxx, 10, 70, True, 'Set up root password', |
|
| 117 |
+ 'Root password:', |
|
| 118 |
+ 2, self.install_config) |
|
| 119 |
+ |
|
| 112 | 120 |
items = items + [ |
| 113 | 121 |
(license_agreement.display, False), |
| 114 | 122 |
(select_disk.display, True), |
| ... | ... |
@@ -116,6 +130,7 @@ class IsoInstaller(object): |
| 116 | 116 |
(hostname_reader.get_user_string, True), |
| 117 | 117 |
(root_password_reader.get_user_string, True), |
| 118 | 118 |
] |
| 119 |
+ installer = Installer(self.install_config, self.maxy, self.maxx, True, rpm_path=rpm_path, log_path="/var/log", ks_config=ks_config) |
|
| 119 | 120 |
items = items + [(installer.install, False)] |
| 120 | 121 |
|
| 121 | 122 |
index = 0 |
| ... | ... |
@@ -27,7 +27,7 @@ fi |
| 27 | 27 |
[ ${EUID} -eq 0 ] || fail "${PRGNAME}: Need to be root user: FAILURE"
|
| 28 | 28 |
|
| 29 | 29 |
RPMPKG="" |
| 30 |
-RPMPKG=$(find ${RPMROOT} -name "$1-[0-9]*.rpm" -print)
|
|
| 30 |
+RPMPKG=$(find ${RPMROOT} -name "$1" -print)
|
|
| 31 | 31 |
# TODO: sometimes we catch several items into RPMPKG. |
| 32 | 32 |
# In case we have several releases in rpm cache. Need to handle that. |
| 33 | 33 |
[ -z $RPMPKG ] && fail "installation error: rpm package not found\n" |
| ... | ... |
@@ -8,9 +8,9 @@ enabled = True |
| 8 | 8 |
def execute(name, ks_config, config, root): |
| 9 | 9 |
|
| 10 | 10 |
if ks_config: |
| 11 |
- package_list_micro = JsonWrapper("packages_micro.json").read()
|
|
| 12 |
- package_list_minimal = JsonWrapper("packages_minimal.json").read()
|
|
| 13 |
- package_list_full = JsonWrapper("packages_full.json").read()
|
|
| 11 |
+ package_list_micro = JsonWrapper("data/packages_micro.json").read()
|
|
| 12 |
+ package_list_minimal = JsonWrapper("data/packages_minimal.json").read()
|
|
| 13 |
+ package_list_full = JsonWrapper("data/packages_full.json").read()
|
|
| 14 | 14 |
|
| 15 | 15 |
if ks_config['type'] == 'micro': |
| 16 | 16 |
packages = package_list_micro["packages"] |