Package backend :: Package server :: Package handlers :: Package xmlrpc :: Module up2date
[hide private]
[frames] | no frames]

Source Code for Module backend.server.handlers.xmlrpc.up2date

  1  # 
  2  # Copyright (c) 2008--2016 Red Hat, Inc. 
  3  # 
  4  # This software is licensed to you under the GNU General Public License, 
  5  # version 2 (GPLv2). There is NO WARRANTY for this software, express or 
  6  # implied, including the implied warranties of MERCHANTABILITY or FITNESS 
  7  # FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2 
  8  # along with this software; if not, see 
  9  # http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. 
 10  # 
 11  # Red Hat trademarks are not licensed under GPLv2. No permission is 
 12  # granted to use or replicate Red Hat trademarks that are incorporated 
 13  # in this software or its documentation. 
 14  # 
 15  # Implements the up2date.* fucntions for XMLRPC 
 16  # 
 17   
 18  # system module import 
 19  import time 
 20  import string 
 21   
 22  from spacewalk.server.rhnServer import server_lib 
 23  from spacewalk.common.usix import ListType, TupleType, StringType 
 24  from spacewalk.common import rhnFlags 
 25  from spacewalk.common.rhnLog import log_debug, log_error 
 26  from spacewalk.common.rhnConfig import CFG 
 27  from spacewalk.common.rhnException import rhnFault 
 28  from spacewalk.common.rhnTB import add_to_seclist 
 29  from spacewalk.common.rhnTranslate import _ 
 30  from spacewalk.server.rhnLib import computeSignature 
 31  from spacewalk.server.rhnHandler import rhnHandler 
 32  from spacewalk.server import rhnChannel, rhnDependency, rhnCapability 
 33  from spacewalk.server.rhnServer import server_route 
 34   
 35  import re 
 36  NONSUBSCRIBABLE_CHANNELS = re.compile("(rhn-proxy|rhn-satellite)") 
 37   
 38   
39 -class Up2date(rhnHandler):
40 41 """ xml-rpc Server Functions that we will provide for the outside world. 42 """ 43
44 - def __init__(self):
45 """ Up2date Class Constructor 46 47 o Initializes inherited class. 48 o Appends the functions available to the outside world in the 49 rhnHandler list. 50 """ 51 rhnHandler.__init__(self) 52 # Function list inherited from rhnHandler 53 # This action garners control of what is available to the client. 54 55 # --- Clients v2+ --- 56 # (getting headers, source and packages done with GETs now). 57 self.functions.append('login') 58 self.functions.append('listChannels') 59 self.functions.append('subscribeChannels') 60 self.functions.append('unsubscribeChannels') 61 self.functions.append('history') 62 self.functions.append('solvedep') 63 self.functions.append('solveDependencies') 64 self.functions.append('solveDependencies_arch') 65 self.functions.append('solveDependencies_with_limits')
66
67 - def auth_system(self, action, system_id):
68 # Stuff the action in the headers: 69 transport = rhnFlags.get('outputTransportOptions') 70 transport['X-RHN-Action'] = action 71 return rhnHandler.auth_system(self, system_id)
72
73 - def login(self, system_id, extra_data={}):
74 """ Clients v2+ 75 Log in routine. 76 Return a dictionary of session token/channel information. 77 Also sets this information in the headers. 78 """ 79 log_debug(5, system_id) 80 # Authenticate the system certificate. We need the user record 81 # to generate the tokens 82 self.load_user = 1 83 server = self.auth_system('login', system_id) 84 # log the entry 85 log_debug(1, self.server_id) 86 # Update the capabilities list 87 rhnCapability.update_client_capabilities(self.server_id) 88 # Fetch the channels this client is subscribed to 89 channels = rhnChannel.getSubscribedChannels(self.server_id) 90 91 rhnServerTime = str(time.time()) 92 expireOffset = str(CFG.CLIENT_AUTH_TIMEOUT) 93 signature = computeSignature(CFG.SECRET_KEY, 94 self.server_id, 95 self.user, 96 rhnServerTime, 97 expireOffset) 98 99 loginDict = { 100 'X-RHN-Server-Id': self.server_id, 101 'X-RHN-Auth-User-Id': self.user, 102 'X-RHN-Auth': signature, 103 'X-RHN-Auth-Server-Time': rhnServerTime, 104 'X-RHN-Auth-Expire-Offset': expireOffset, 105 # List of lists [[label,last_mod],...]: 106 'X-RHN-Auth-Channels': channels 107 } 108 109 # Duplicate these values in the headers so that the proxy can 110 # intercept and cache them without parseing the xmlrpc. 111 transport = rhnFlags.get('outputTransportOptions') 112 for k, v in loginDict.items(): 113 # Special case for channels 114 if string.lower(k) == string.lower('X-RHN-Auth-Channels'): 115 # Concatenate the channel information column-separated 116 transport[k] = [string.join(x, ':') for x in v] 117 else: 118 transport[k] = v 119 log_debug(5, "loginDict", loginDict, transport) 120 121 # store route in DB (schema for RHN 3.1+ only!) 122 server_route.store_client_route(self.server_id) 123 124 return loginDict
125
126 - def listChannels(self, system_id):
127 """ Clients v2+ """ 128 log_debug(5, system_id) 129 # Authenticate the system certificate 130 self.auth_system('listChannels', system_id) 131 # log the entry 132 log_debug(1, self.server_id) 133 channelList = rhnChannel.channels_for_server(self.server_id) 134 return channelList
135
136 - def subscribeChannels(self, system_id, channelNames, username, passwd):
137 """ Clients v2+ """ 138 add_to_seclist(passwd) 139 log_debug(5, system_id, channelNames, username, passwd) 140 # Authenticate the system certificate 141 self.auth_system('subscribeChannel', system_id) 142 # log the entry 143 log_debug(1, self.server_id, channelNames) 144 server_lib.snapshot_server(self.server_id, 'Base Channel Updated') 145 for channelName in channelNames: 146 if NONSUBSCRIBABLE_CHANNELS.search(channelName): 147 raise rhnFault(73, explain=False) 148 else: 149 rhnChannel.subscribe_channel(self.server_id, channelName, 150 username, passwd) 151 return 0
152
153 - def unsubscribeChannels(self, system_id, channelNames, username, passwd):
154 """ Clients v2+ """ 155 add_to_seclist(passwd) 156 log_debug(3) 157 # Authenticate the system certificate 158 self.auth_system('unsubscribeChannel', system_id) 159 # log the entry 160 log_debug(1, self.server_id, channelNames) 161 for channelName in channelNames: 162 rhnChannel.unsubscribe_channel(self.server_id, channelName, 163 username, passwd) 164 return 0
165
166 - def solvedep(self, system_id, deps):
167 """ Clients v1- 168 Solve dependencies for a given dependency problem list. 169 IN: a dependency problem list: [name, name, name, ...] 170 RET: a package list: [[n,v,r,e],[n,v,r,e],...] That solves the 171 dependencies. 172 """ 173 log_debug(4, system_id) 174 return self.__solveDep(system_id, deps, action="solvedep", 175 clientVersion=1)
176
177 - def solveDependencies(self, system_id, deps):
178 """ Clients v2+ 179 Solve dependencies for a given dependency problem list (newer version) 180 IN: a dependency problem list: [name, name, name, ...] 181 RET: a hash {name: [[n, v, r, e], [n, v, r, e], ...], ...} 182 """ 183 log_debug(4, system_id) 184 return self.__solveDep(system_id, deps, action="solvedep", 185 clientVersion=2)
186
187 - def solveDependencies_arch(self, system_id, deps):
188 """ Does the same thing as solve_dependencies, but also returns the architecture label with the 189 package info. 190 IN: a dependency problem list: [name, name, name, ...] 191 RET: a hash {name: [[n, v, r, e, a], [n, v, r, e, a], ...], ...} 192 """ 193 log_debug(4, system_id) 194 return self.__solveDep_arch(system_id, deps, action="solvedep", 195 clientVersion=2)
196
197 - def solveDependencies_with_limits(self, system_id, deps, all=0, limit_operator=None, limit=None):
198 """ This version of solve_dependencies allows the caller to get all of the packages that solve a 199 dependency and limit the packages that are returned to those that match the criteria defined 200 by limit_operator and limit. This version of the function also returns the architecture label 201 of the package[s] that get returned. 202 203 limit_operator can be any of: '<', '<=', '==', '>=', or '>'. 204 limit is a a string of the format [epoch:]name-version-release 205 deps is a list of filenames that the packages that are returned must provide. 206 version is the version of the client that is calling the function. 207 """ 208 log_debug(4, system_id) 209 return self.__solveDep_with_limits(system_id, deps, action="solvedep", 210 clientVersion=2, all=all, limit_operator=limit_operator, limit=limit)
211
212 - def history(self, system_id, summary, body=""):
213 """ Clients v2+ 214 Add a history log for a performed action 215 """ 216 log_debug(5, system_id, summary, body) 217 # Authenticate the system certificate 218 server = self.auth_system('history', system_id) 219 # log the entry 220 log_debug(1, self.server_id) 221 # XXX: Probably this should be a non fatal error... 222 server.add_history(summary, body) 223 server.save_history() 224 return 0
225 226 # --- PRIVATE METHODS --- 227
228 - def __solveDep_prepare(self, system_id, deps, action, clientVersion):
229 """ Response for clients: 230 version 1: list 231 version 2: hash 232 """ 233 log_debug(7, system_id, deps, action, clientVersion) 234 faultString = _("Invalid value %s (%s)") 235 if type(deps) not in (ListType, TupleType): 236 log_error("Invalid argument type", type(deps)) 237 raise rhnFault(30, faultString % (deps, type(deps))) 238 for dep in deps: 239 if type(dep) is not StringType: 240 log_error("Invalid dependency member", type(dep)) 241 raise rhnFault(30, faultString % (dep, type(dep))) 242 # Ignore empty strings 243 deps = list(filter(len, deps)) 244 # anything left to do? 245 if not deps: 246 return [] 247 # Authenticate the system certificate 248 server = self.auth_system(action, system_id) 249 log_debug(1, self.server_id, action, "items: %d" % len(deps)) 250 return deps
251
252 - def __solveDep(self, system_id, deps, action, clientVersion):
253 """ Response for clients: 254 version 1: list 255 version 2: hash 256 """ 257 log_debug(5, system_id, deps, action, clientVersion) 258 result = self.__solveDep_prepare(system_id, deps, action, clientVersion) 259 if result: 260 # Solve dependencies 261 result = rhnDependency.solve_dependencies(self.server_id, 262 result, clientVersion) 263 return result
264
265 - def __solveDep_arch(self, system_id, deps, action, clientVersion):
266 """ Response for clients: 267 version 1: list 268 version 2: hash 269 """ 270 log_debug(5, system_id, deps, action, clientVersion) 271 result = self.__solveDep_prepare(system_id, deps, action, clientVersion) 272 if result: 273 # Solve dependencies 274 result = rhnDependency.solve_dependencies_arch(self.server_id, 275 result, clientVersion) 276 return result
277
278 - def __solveDep_with_limits(self, system_id, deps, action, clientVersion, all=0, limit_operator=None, limit=None):
279 """ Response for clients: 280 version 1: list 281 version 2: hash 282 """ 283 log_debug(5, system_id, deps, action, clientVersion) 284 result = self.__solveDep_prepare(system_id, deps, action, clientVersion) 285 if result: 286 # Solve dependencies 287 result = rhnDependency.solve_dependencies_with_limits(self.server_id, 288 deps, clientVersion, all, limit_operator, limit) 289 return result
290 291
292 -class Servers(rhnHandler):
293 294 """ A class to handle the site selection... """ 295
296 - def __init__(self):
297 """Servers Class Constructor. """ 298 rhnHandler.__init__(self) 299 self.functions.append('get') 300 self.functions.append('list')
301
302 - def get(self, *junk):
303 """ Older funtion that can be a noop. """ 304 return []
305
306 - def list(self, systemid=None):
307 """ Returns a list of available servers the client can connect to. """ 308 servers_list = [ 309 { 310 'server': 'xmlrpc.rhn.redhat.com', 311 'handler': '/XMLRPC', 312 'description': 'XML-RPC Server', 313 'location': 'United States', 314 }, 315 ] 316 return servers_list
317