diff options
author | Brian C. Lane <bcl@redhat.com> | 2012-06-29 12:15:33 -0700 |
---|---|---|
committer | Brian C. Lane <bcl@redhat.com> | 2012-07-09 09:34:26 -0700 |
commit | ed019a5e3aad1ef8f59a765a1d4c0005ff665910 (patch) | |
tree | 97dd616b0cf31ee92f92309cc153063f315770ad /pyanaconda | |
parent | 35babd1dee70c5aa2f57311e00163c6128bcb740 (diff) | |
download | anaconda-ed019a5e3aad1ef8f59a765a1d4c0005ff665910.tar.gz anaconda-ed019a5e3aad1ef8f59a765a1d4c0005ff665910.tar.xz anaconda-ed019a5e3aad1ef8f59a765a1d4c0005ff665910.zip |
update proxy support
cmdline proxy strings use the standard form:
[protocol://][username[:password]@]host[:port]
proxy url strings are stored in the ksdata, either in method.proxy for
the global proxy or per repo in repo.proxy
ProxyString handles parsing the proxy url and returning it in various
forms useful for urlgrabber, yum and the UI.
--proxyAuth has been removed. It has no meaning with noloader.
Also fix a typo with sslverify in the repo configuration file.
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()) |