/usr/share/rhn/up2date_client/config.py is in rhn-client-tools 1.8.26-4.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 | # This file is a portion of the Red Hat Update Agent
# Copyright (c) 1999--2012 Red Hat, Inc. Distributed under GPL
#
# Authors:
# Cristian Gafton <gafton@redhat.com>
# Adrian Likins <alikins@redhat.com>
#
# $Id$
"""
This module includes the Config and Up2date Config classes use by the
up2date agent to hold config info.
"""
import os
import sys
from urlparse import urlsplit, urlunsplit
from rhn.connections import idn_ascii_to_pune, idn_pune_to_unicode
import gettext
t = gettext.translation('rhn-client-tools', fallback=True)
_ = t.ugettext
# XXX: This could be moved in a more "static" location if it is too
# much of an eye sore
Defaults = {
'enableProxy' : ("Use a HTTP Proxy",
0),
'serverURL' : ("Remote server URL",
"https://your.server.url.here/XMLRPC"),
'debug' : ("Whether or not debugging is enabled",
0),
'systemIdPath' : ("Location of system id",
"/etc/sysconfig/rhn/systemid"),
'versionOverride' : ("Override the automatically determined "\
"system version",
""),
'httpProxy' : ("HTTP proxy in host:port format, e.g. "\
"squid.example.com:3128",
""),
'proxyUser' : ("The username for an authenticated proxy",
""),
'proxyPassword' : ("The password to use for an authenticated proxy",
""),
'enableProxyAuth' : ("To use an authenticated proxy or not",
0),
'networkRetries' : ("Number of attempts to make at network "\
"connections before giving up",
1),
'sslCACert' : ("The CA cert used to verify the ssl server",
"/usr/share/rhn/RHN-ORG-TRUSTED-SSL-CERT"),
'noReboot' : ("Disable the reboot action",
0),
'disallowConfChanges': ("Config options that can not be overwritten by a config update action",
['sslCACert','serverURL','disallowConfChanges',
'noReboot']),
}
FileOptions = ['systemIdPath', 'sslCACert', 'tmpDir', ]
# a peristent configuration storage class
class ConfigFile:
"class for handling persistent config options for the client"
def __init__(self, filename = None):
self.dict = {}
self.fileName = filename
if self.fileName:
self.load()
def load(self, filename = None):
if filename:
self.fileName = filename
if self.fileName == None:
return
if not os.access(self.fileName, os.R_OK):
# print "warning: can't access %s" % self.fileName
return
f = open(self.fileName, "r")
multiline = ''
for line in f.readlines():
# strip comments
if line.find('#') == 0:
continue
line = multiline + line.strip()
if not line:
continue
# if line ends in '\', append the next line before parsing
if line[-1] == '\\':
multiline = line[:-1].strip()
continue
else:
multiline = ''
split = line.split('=', 1)
if len(split) != 2:
# not in 'a = b' format. we should log this
# or maybe error.
continue
key = split[0].strip()
value = unicode(split[1].strip(), 'utf-8')
# decode a comment line
comment = None
pos = key.find("[comment]")
if pos != -1:
key = key[:pos]
comment = value
value = None
# figure out if we need to parse the value further
if value:
# possibly split value into a list
values = value.split(";")
if key in ['proxyUser', 'proxyPassword']:
value = str(value)
elif len(values) == 1:
try:
value = int(value)
except ValueError:
pass
elif values[0] == "":
value = []
else:
# there could be whitespace between the values on
# one line, let's strip it out
value = [val.strip() for val in values[:-1]]
# now insert the (comment, value) in the dictionary
newval = (comment, value)
if self.dict.has_key(key): # do we need to update
newval = self.dict[key]
if comment is not None: # override comment
newval = (comment, newval[1])
if value is not None: # override value
newval = (newval[0], value)
self.dict[key] = newval
f.close()
def save(self):
if self.fileName == None:
return
# this really shouldn't happen, since it means that the
# /etc/sysconfig/rhn directory doesn't exist, which is way broken
# and note the attempted fix breaks useage of this by the applet
# since it reuses this code to create its config file, and therefore
# tries to makedirs() the users home dir again (with a specific perms)
# and fails (see #130391)
if not os.access(self.fileName, os.R_OK):
if not os.access(os.path.dirname(self.fileName), os.R_OK):
print _("%s was not found" % os.path.dirname(self.fileName))
return
f = open(self.fileName+'.new', "w")
os.chmod(self.fileName, 0600)
f.write("# Automatically generated Red Hat Update Agent "\
"config file, do not edit.\n")
f.write("# Format: 1.0\n")
f.write("")
for key in self.dict.keys():
(comment, value) = self.dict[key]
f.write((u"%s[comment]=%s\n" % (key, comment)).encode('utf-8'))
if type(value) != type([]):
value = [ value ]
if key in FileOptions:
value = map(os.path.abspath, value)
f.write((u"%s=%s\n" % (key, ';'.join(map(str, value)))).encode('utf-8'))
f.write("\n")
f.close()
os.rename(self.fileName+'.new', self.fileName)
# dictionary interface
def has_key(self, name):
return self.dict.has_key(name)
def keys(self):
return self.dict.keys()
def values(self):
return map(lambda a: a[1], self.dict.values())
def update(self, dict):
self.dict.update(dict)
# we return None when we reference an invalid key instead of
# raising an exception
def __getitem__(self, name):
if self.dict.has_key(name):
return self.dict[name][1]
return None
def __setitem__(self, name, value):
if self.dict.has_key(name):
val = self.dict[name]
else:
val = (None, None)
self.dict[name] = (val[0], value)
# we might need to expose the comments...
def info(self, name):
if self.dict.has_key(name):
return self.dict[name][0]
return ""
# a superclass for the ConfigFile that also handles runtime-only
# config values
class Config:
def __init__(self, filename = None):
self.stored = ConfigFile()
self.stored.update(Defaults)
if filename:
self.stored.load(filename)
self.runtime = {}
# classic dictionary interface: we prefer values from the runtime
# dictionary over the ones from the stored config
def has_key(self, name):
if self.runtime.has_key(name):
return True
if self.stored.has_key(name):
return True
return False
def keys(self):
ret = self.runtime.keys()
for k in self.stored.keys():
if k not in ret:
ret.append(k)
return ret
def values(self):
ret = []
for k in self.keys():
ret.append(self.__getitem__(k))
return ret
def items(self):
ret = []
for k in self.keys():
ret.append((k, self.__getitem__(k)))
return ret
def __len__(self):
return len(self.keys())
def __setitem__(self, name, value):
self.runtime[name] = value
# we return None when nothing is found instead of raising and exception
def __getitem__(self, name):
if self.runtime.has_key(name):
return self.runtime[name]
if self.stored.has_key(name):
return self.stored[name]
return None
# These function expose access to the peristent storage for
# updates and saves
def info(self, name): # retrieve comments
return self.stored.info(name)
def save(self):
self.stored.save()
def load(self, filename):
self.stored.load(filename)
# make sure the runtime cache is not polluted
for k in self.stored.keys():
if not self.runtime.has_key(k):
continue
# allow this one to pass through
del self.runtime[k]
# save straight in the persistent storage
def set(self, name, value):
self.stored[name] = value
# clean up the runtime cache
if self.runtime.has_key(name):
del self.runtime[name]
def getProxySetting():
""" returns proxy string in format hostname:port
hostname is converted to Pune encoding if needed
"""
cfg = initUp2dateConfig()
proxy = None
proxyHost = cfg["httpProxy"]
if proxyHost:
if proxyHost[:7] == "http://":
proxyHost = proxyHost[7:]
parts = proxyHost.split(':')
parts[0] = idn_ascii_to_pune(parts[0])
proxy = ':'.join(parts)
return proxy
def convert_url_to_pune(url):
""" returns url where hostname is converted to Pune encoding """
s = urlsplit(url)
return urlunsplit((s[0], idn_ascii_to_pune(s[1]), s[2], s[3], s[4])).encode('utf-8')
def convert_url_from_pune(url):
""" returns url where hostname is converted from Pune encoding. Returns unicode string. """
s = urlsplit(url)
return unicode(urlunsplit((s[0], idn_pune_to_unicode(s[1]), s[2], s[3], s[4])))
def getServerlURL():
""" return list of serverURL from config
Note: in config may be one value or more values, but this
function always return list
"""
cfg = initUp2dateConfig()
# serverURL may be a list in the config file, so by default, grab the
# first element.
if type(cfg['serverURL']) == type([]):
return map(convert_url_to_pune, cfg['serverURL'])
else:
return [convert_url_to_pune(cfg['serverURL'])]
def setServerURL(serverURL):
""" Set serverURL in config """
cfg = initUp2dateConfig()
cfg.set('serverURL', serverURL)
def initUp2dateConfig(cfg_file = "/etc/sysconfig/rhn/up2date"):
"""This function is the right way to get at the up2date config."""
global cfg
try:
cfg
except NameError:
cfg = None
if cfg == None:
cfg = Config(cfg_file)
cfg["isatty"] = False
if sys.stdout.isatty():
cfg["isatty"] = True
return cfg
|