summaryrefslogtreecommitdiffstats
path: root/pyanaconda
diff options
context:
space:
mode:
Diffstat (limited to 'pyanaconda')
-rw-r--r--pyanaconda/iutil.py104
-rw-r--r--pyanaconda/packaging/__init__.py15
-rw-r--r--pyanaconda/packaging/yumpayload.py54
-rw-r--r--pyanaconda/ui/gui/spokes/source.py61
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())