diff options
Diffstat (limited to 'pyanaconda')
| -rw-r--r-- | pyanaconda/iutil.py | 104 | ||||
| -rw-r--r-- | pyanaconda/packaging/__init__.py | 15 | ||||
| -rw-r--r-- | pyanaconda/packaging/yumpayload.py | 54 | ||||
| -rw-r--r-- | pyanaconda/ui/gui/spokes/source.py | 61 |
4 files changed, 187 insertions, 47 deletions
diff --git a/pyanaconda/iutil.py b/pyanaconda/iutil.py index 398ef7789..122894695 100644 --- a/pyanaconda/iutil.py +++ b/pyanaconda/iutil.py @@ -28,6 +28,7 @@ import os.path import errno import subprocess import threading +import re from flags import flags from constants import * @@ -1081,3 +1082,106 @@ def dracut_eject(device): except Exception, e: log.error("Error writing dracut shutdown eject hook for %s: %s" % (device, e)) +class ProxyStringError(Exception): + pass + +class ProxyString(object): + """ Handle a proxy url + """ + def __init__(self, url=None, protocol="http://", host=None, port="3128", + username=None, password=None): + """ Initialize with either url + ([protocol://][username[:password]@]host[:port]) or pass host and + optionally: + + protocol http, https, ftp + host hostname without protocol + port port number (defaults to 3128) + username username + password password + + The str() of the object is the full proxy url + + ProxyString.url is the full url including username:password@ + ProxyString.noauth_url is the url without username:password@ + """ + self.url = url + self.protocol = protocol + self.host = host + self.port = str(port) + self.username = username + self.password = password + self.proxy_auth = "" + self.noauth_url = None + + if url: + self.parse_url() + elif not host: + raise ProxyStringError("No host url") + else: + self.parse_components() + + def parse_url(self): + """ Parse the proxy url into its component pieces + """ + # NOTE: If this changes, update tests/regex/proxy.py + # + # proxy=[protocol://][username[:password]@]host[:port][path] + # groups + # 1 = protocol + # 2 = username:password@ + # 3 = username + # 4 = password + # 5 = hostname + # 6 = port + # 7 = extra + pattern = re.compile("([A-Za-z]+://)?(([A-Za-z0-9]+)(:[^:@]+)?@)?([^:/]+)(:[0-9]+)?(/.*)?") + m = pattern.match(self.url) + if not m: + raise ProxyStringError("malformed url, cannot parse it.") + + # If no protocol was given default to http. + if m.group(1): + self.protocol = m.group(1) + else: + self.protocol = "http://" + + if m.group(3): + self.username = m.group(3) + + if m.group(4): + # Skip the leading colon + self.password = m.group(4)[1:] + + if m.group(5): + self.host = m.group(5) + if m.group(6): + # Skip the leading colon + self.port = m.group(6)[1:] + else: + raise ProxyStringError("url has no host component") + + self.parse_components() + + def parse_components(self): + """ Parse the components of a proxy url into url and noauth_url + """ + if self.username or self.password: + self.proxy_auth = "%s:%s@" % (self.username or "", + self.password or "") + + self.url = self.protocol + self.proxy_auth + self.host + ":" + self.port + self.noauth_url = self.protocol + self.host + ":" + self.port + + @property + def dict(self): + """ return a dict of all the elements of the proxy string + url, noauth_url, protocol, host, port, username, password + """ + components = ["url", "noauth_url", "protocol", "host", "port", + "username", "password"] + return dict([(k, getattr(self, k)) for k in components]) + + def __str__(self): + return self.url + diff --git a/pyanaconda/packaging/__init__.py b/pyanaconda/packaging/__init__.py index 8b56268a8..ca23f53a1 100644 --- a/pyanaconda/packaging/__init__.py +++ b/pyanaconda/packaging/__init__.py @@ -43,6 +43,7 @@ from pyanaconda.constants import * from pyanaconda.flags import flags from pyanaconda import iutil +from pyanaconda.iutil import ProxyString, ProxyStringError from pykickstart.parser import Group @@ -118,8 +119,9 @@ def get_mount_device(mountpoint): class Payload(object): """ Payload is an abstract class for OS install delivery methods. """ def __init__(self, data): + """ data is a kickstart.AnacondaKSHandler class + """ self.data = data - self.proxy = None self._kernelVersionList = [] def setup(self, storage): @@ -378,9 +380,14 @@ class Payload(object): version)) proxies = {} - if self.proxy: - proxies = {"http": self.proxy, - "https": self.proxy} + if self.data.method.proxy: + try: + proxy = ProxyString(self.data.method.proxy) + proxies = {"http": proxy.url, + "https": proxy.url} + except ProxyStringError as e: + log.info("Failed to parse proxy for _getReleaseVersion %s: %s" \ + % (self.data.method.proxy, e)) treeinfo = self._getTreeInfo(url, not flags.noverifyssl, proxies) if treeinfo: diff --git a/pyanaconda/packaging/yumpayload.py b/pyanaconda/packaging/yumpayload.py index 1482125f0..9ab8d3240 100644 --- a/pyanaconda/packaging/yumpayload.py +++ b/pyanaconda/packaging/yumpayload.py @@ -61,6 +61,7 @@ from pyanaconda.constants import * from pyanaconda.flags import flags from pyanaconda import iutil +from pyanaconda.iutil import ProxyString, ProxyStringError from pyanaconda import isys from pyanaconda.network import hasActiveNetDev @@ -100,7 +101,6 @@ class YumPayload(PackagePayload): PackagePayload.__init__(self, data) self.install_device = None - self.proxy = None # global proxy self._root_dir = "/tmp/yum.root" self._repos_dir = "/etc/yum.repos.d,/etc/anaconda.repos.d,/tmp/updates/anaconda.repos.d,/tmp/product/anaconda.repos.d" self._yum = None @@ -142,8 +142,7 @@ class YumPayload(PackagePayload): self._resetYum(root=root) - def setup(self, storage, proxy=None): - self.proxy = proxy + def setup(self, storage): self._writeYumConfig() self._setup = True @@ -201,9 +200,17 @@ reposdir=%s if flags.noverifyssl: buf += "sslverify=0\n" - if self.proxy: - # FIXME: include proxy_username, proxy_password - buf += "proxy=%s\n" % proxy + if self.data.method.proxy: + try: + proxy = ProxyString(self.data.method.proxy) + buf += "proxy=%s\n" % (proxy.noauth_url,) + if proxy.username: + buf += "proxy_username=%s\n" % (proxy.username,) + if proxy.password: + buf += "proxy_password=%s\n" % (proxy.password,) + except ProxyStringError as e: + log.error("Failed to parse proxy for _writeYumConfig %s: %s" \ + % (self.data.method.proxy, e)) open("/tmp/anaconda-yum.conf", "w").write(buf) @@ -250,10 +257,19 @@ reposdir=%s # kickstart repo modifiers if ks_repo: if ks_repo.noverifyssl: - f.write("verifyssl=0\n") + f.write("sslverify=0\n") if ks_repo.proxy: - f.write("proxy=%s\n" % ks_repo.proxy) + try: + proxy = ProxyString(ks_repo.proxy) + f.write("proxy=%s\n" % (proxy.noauth_url,)) + if proxy.username: + f.write("proxy_username=%s\n" % (proxy.username,)) + if proxy_password: + f.write("proxy_password=%s\n" % (proxy.password,)) + except ProxyStringError as e: + log.error("Failed to parse proxy for _writeInstallConfig %s: %s" \ + % (self.data.method.proxy, e)) if ks_repo.cost: f.write("cost=%d\n" % ks_repo.cost) @@ -485,7 +501,6 @@ reposdir=%s method = self.data.method sslverify = True url = None - proxy = None if method.method == "harddrive": if method.biospart: @@ -527,7 +542,6 @@ reposdir=%s elif method.method == "url": url = method.url sslverify = not (method.noverifyssl or flags.noverifyssl) - proxy = method.proxy or self.proxy elif method.method == "cdrom" or not method.method: # cdrom or no method specified -- check for media device = opticalInstallMedia(storage.devicetree) @@ -545,7 +559,7 @@ reposdir=%s self._yumCacheDirHack() try: self._addYumRepo(BASE_REPO_NAME, url, - proxy=proxy, sslverify=sslverify) + proxyurl=method.proxy, sslverify=sslverify) except MetadataError as e: log.error("base repo (%s/%s) not valid -- removing it" % (method.method, url)) @@ -565,13 +579,13 @@ reposdir=%s if self._repoNeedsNetwork(repo) and not hasActiveNetDev(): raise NoNetworkError - proxy = repo.proxy or self.proxy + proxy = repo.proxy or self.data.method.proxy sslverify = not (flags.noverifyssl or repo.noverifyssl) # this repo is already in ksdata, so we only add it to yum here self._addYumRepo(repo.name, url, repo.mirrorlist, cost=repo.cost, exclude=repo.excludepkgs, includepkgs=repo.includepkgs, - proxy=proxy, sslverify=sslverify) + proxyurl=proxy, sslverify=sslverify) # TODO: enable addons via treeinfo @@ -599,7 +613,7 @@ reposdir=%s except RepoMDError: log.error("failed to get groups for repo %s" % yumrepo.id) - def _addYumRepo(self, name, baseurl, mirrorlist=None, **kwargs): + def _addYumRepo(self, name, baseurl, mirrorlist=None, proxyurl=None, **kwargs): """ Add a yum repo to the YumBase instance. """ from yum.Errors import RepoError @@ -607,6 +621,18 @@ reposdir=%s if name in self._yum.repos.repos: self._yum.repos.delete(name) + if proxyurl: + try: + proxy = ProxyString(proxyurl) + kwargs["proxy"] = proxy.noauth_url + if proxy.username: + kwargs["proxy_username"] = proxy.username + if proxy.password: + kwargs["proxy_password"] = proxy.password + except ProxyStringError as e: + log.error("Failed to parse proxy for _addYumRepo %s: %s" \ + % (proxyurl, e)) + log.debug("adding yum repo %s with baseurl %s and mirrorlist %s" % (name, baseurl, mirrorlist)) with _yum_lock: diff --git a/pyanaconda/ui/gui/spokes/source.py b/pyanaconda/ui/gui/spokes/source.py index 9a87c033d..7752439aa 100644 --- a/pyanaconda/ui/gui/spokes/source.py +++ b/pyanaconda/ui/gui/spokes/source.py @@ -24,6 +24,9 @@ import gettext _ = lambda x: gettext.ldgettext("anaconda", x) N_ = lambda x: x +import logging +log = logging.getLogger("anaconda") + import os.path from gi.repository import AnacondaWidgets, GLib, Gtk @@ -33,6 +36,7 @@ from pyanaconda.ui.gui import UIObject, communication from pyanaconda.ui.gui.spokes import NormalSpoke from pyanaconda.ui.gui.categories.software import SoftwareCategory from pyanaconda.ui.gui.utils import enlightbox, gdk_threaded +from pyanaconda.iutil import ProxyString, ProxyStringError __all__ = ["SourceSpoke"] @@ -57,15 +61,23 @@ class ProxyDialog(UIObject): self.window.destroy() return - proxy = self._proxyURLEntry.get_text() + url = self._proxyURLEntry.get_text() + if self._authCheck.get_active(): + username = self._proxyPasswordEntry.get_text() + password = self._proxyPasswordEntry.get_text() + else: + username = None + password = None - if self._authCheck.get_active() and self._proxyUsernameEntry.get_text(): - if self._proxyPasswordEntry.get_text(): - proxy = self._proxyUsernameEntry.get_text() + ":" + self._proxyPasswordEntry.get_text() + "@" + proxy - else: - proxy = self._proxyUsernameEntry.get_text() + "@" + proxy + try: + proxy = ProxyString(url=url, username=username, password=password) + self.data.method.proxy = proxy.url + except ProxyStringError as e: + log.error("Failed to parse proxy for ProxyDialog Add - %s:%s@%s: %s" \ + % (username, password, url, e)) + # TODO - tell the user they entered an invalid proxy and let them retry + self.data.method.proxy = "" - self.data.method.proxy = proxy self.window.destroy() def on_proxy_enable_toggled(self, button, *args): @@ -95,28 +107,19 @@ class ProxyDialog(UIObject): self.on_proxy_auth_toggled(self._authCheck) return - # proxy=[protocol://][username[:password]@]host[:port][path] - pattern = re.compile("([A-Za-z]+://)?(([A-Za-z0-9]+)(:[^:@]+)?@)?([^:/]+)(:[0-9]+)?(/.*)?") - m = pattern.match(self.data.method.proxy) - - if m and m.group(3): - self._proxyUsernameEntry.set_text(m.group(3)) - if m and m.group(4): - # Skip the leading colon. - self._proxyPasswordEntry.set_text(m.group(4)[1:]) - if m and m.group(5): - # If both a host and port was found, just paste them - # together using the colon at the beginning of the port - # match as a separator. Otherwise, just use the host. - if m.group(6): - proxy = m.group(5) + m.group(6) - else: - proxy = m.group(5) - - self._proxyURLEntry.set_text(proxy) + try: + proxy = ProxyString(self.data.method.proxy) + if proxy.username: + self._proxyUsernameEntry.set_text(proxy.username) + if proxy.password: + self._proxyPasswordEntry.set_text(proxy.password) + self._proxyURLEntry.set_text(proxy.noauth_url) + except ProxyStringError as e: + log.error("Failed to parse proxy for ProxyDialog.refresh %s: %s" % (self.data.method.proxy, e)) + return - self._proxyCheck.set_active(self.data.method.proxy != "") - self._authCheck.set_active("@" in self.data.method.proxy) + self._proxyCheck.set_active(True) + self._authCheck.set_active(bool(proxy.username or proxy.password)) self.on_proxy_enable_toggled(self._proxyCheck) self.on_proxy_auth_toggled(self._authCheck) @@ -816,5 +819,5 @@ class SourceSpoke(NormalSpoke): # Only allow the proxy button to be clicked if a proxy makes sense for # the currently selected protocol. - proxyButton.set_sensitive(self._http_active()) + proxyButton.set_sensitive(self._http_active() or self._mirror_active()) nfsOptsBox.set_visible(self._nfs_active()) |
