Package up2date_client :: Module config
[hide private]
[frames] | no frames]

Source Code for Module up2date_client.config

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