This file is indexed.

/usr/share/pyshared/arcom/service.py is in nordugrid-arc-python 1.1.1-1.

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
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
# namespace URIs of the storage services
ahash_uri = 'http://www.nordugrid.org/schemas/ahash'
librarian_uri = 'http://www.nordugrid.org/schemas/librarian'
bartender_uri = 'http://www.nordugrid.org/schemas/bartender'
shepherd_uri = 'http://www.nordugrid.org/schemas/shepherd'
gateway_uri = 'http://www.nordugrid.org/schemas/gateway'
delegation_uri = 'http://www.nordugrid.org/schemas/delegation'
rbyteio_uri = 'http://schemas.ggf.org/byteio/2005/10/random-access'

wsrf_rp_uri = 'http://docs.oasis-open.org/wsrf/rp-2'


# service type names
ahash_servicetype = 'org.nordugrid.storage.ahash'
librarian_servicetype = 'org.nordugrid.storage.librarian'
bartender_servicetype = 'org.nordugrid.storage.bartender'
shepherd_servicetype = 'org.nordugrid.storage.shepherd'

# URI for the simple transfer mechanism of ByteIO
byteio_simple_uri = 'http://schemas.ggf.org/byteio/2005/10/transfer-mechanisms/simple'
# True and False values used in the XML representation
true = '1'
false = '0'
# the defaults for TrustManager
default_checking_interval = 600
default_ahash_id = '3'

import arc
import inspect
import time
import sys
import threading
import random
from arcom import get_child_nodes
from arcom.security import AuthRequest, parse_ssl_config
from arcom.logger import Logger
log = Logger(arc.Logger(arc.Logger_getRootLogger(), 'Storage.Service'))

class ServiceState:
    def __init__(self, running = True):
        self.running = running

class Service:
    
    def __init__(self, request_config, cfg = None, start_service = True):
        self._trust_manager = []
        self.ssl_config = {}
        self._force_trust = False
        self.state = ServiceState(start_service)
        if cfg:
            self.ssl_config = parse_ssl_config(cfg)
            trust_manager_node = cfg.Get('TrustManager')
            fromFile = str(trust_manager_node.Attribute('FromFile'))
            if fromFile:
                try:
                    xml_string = file(fromFile).read()
                    trust_manager_node = arc.XMLNode(xml_string)
                except:
                    log.msg()
                    pass
            self._force_trust = str(trust_manager_node.Attribute('Force')) not in ['no', 'No', 'NO']
            entries = get_child_nodes(trust_manager_node)
            for entry in entries:
                name = entry.Name()
                if name in ['DN', 'CA']:
                    self._trust_manager.append({'type': name, 'DNs': [str(entry)]})
                if name in ['DNsFromAHash']:
                    try:
                        checking_interval = int(str(entry.Attribute('CheckingInterval')))
                    except:
                        checking_interval = None
                    if not checking_interval:
                        checking_interval = default_checking_interval
                    ahash_id = str(entry.Attribute('ID'))
                    if not ahash_id:
                        ahash_id = default_ahash_id
                    ahashes = get_child_nodes(entry)
                    ahash_urls = []
                    for ahash in ahashes:
                        if ahash.Name() == 'AHashURL':
                            ahash_urls.append(str(ahash))
                    data = {'type': name, 'DNs' : [], 'URLs' : ahash_urls,
                        'checking_interval' : checking_interval, 'ahash_id' : ahash_id}
                    self._trust_manager.append(data)
                    threading.Thread(target = self._get_dns_from_ahash, args = [data]).start()
        if not hasattr(self,'service_name'):
            self.service_name = 'Python Service With No Name'
        #if self._trust_manager:
        #    print self.service_name, "TrustManager:", self._force_trust and 'force' or 'don\'t force', self._trust_manager
        log.msg(arc.INFO, "Starting:", self.service_name)
        self.request_config = request_config
        self.ns = arc.NS(dict([(request_type['namespace_prefix'], request_type['namespace_uri'])
            for request_type in self.request_config]))
        
    def __del__(self):
        try:
            self.state.running = False
        except:
            pass
        log.msg(arc.INFO, "Stopping:", self.service_name)
    
    def _get_dns_from_ahash(self, data):
        try:
            from storage.client import AHashClient
        except:
            log.msg()
        # first just wait a few seconds
        time.sleep(10)
        while True:
            try:
                #print "Start getting a list of DNs from an AHash"
                ahash_url = random.choice(data['URLs'])
                #print "Chosen AHash:", ahash_url
                ahash = AHashClient(ahash_url, ssl_config = self.ssl_config)
                results = ahash.get([data['ahash_id']])[data['ahash_id']]
                data['DNs'] = [DN for (_, DN) in results.keys()]
                #print "data", data
                #print "Done, waiting for %d seconds" % data['checking_interval']
                time.sleep(data['checking_interval'])
            except:
                log.msg()
                time.sleep(1)
    
    def _is_trusted(self, DN, CA):
        if not self._trust_manager:
            return True
        #print '_is_trusted called with', DN, CA
        trusted = False
        for entry in self._trust_manager:
            if entry['type'] == 'DN':
                if DN in entry['DNs']:
                    #print DN, 'is listed as trusted'
                    trusted = True
            if entry['type'] == 'CA':
                if CA in entry['DNs']:
                    #print DN, 'has a CA which is listed as trusted'
                    trusted = True
            if entry['type'] == 'DNsFromAHash':
                if DN in entry['DNs']:
                    #print DN, 'is listed as trusted in these AHashes:', ', '.join(entry['URLs'])
                    trusted = True
        return trusted
        
    def _get_trusted_dns(self):
        dns = []
        for entry in self._trust_manager:
            if entry['type'] in ['DN' or 'DNsFromAHash']:
                dns.extend(entry['DNs'])
        return dns
    
    def _new_soap_payload(self):
        return arc.PayloadSOAP(self.ns)
    
    def _call_request(self, request_name, inmsg):
        inpayload = inmsg.Payload()
        auth = AuthRequest(inmsg)
        inpayload.auth = auth
        if self._force_trust and not self._is_trusted(*auth.get_identity_and_ca()):
            raise Exception, 'client is not trusted'
        return getattr(self,request_name)(inpayload)
    
    def GetLocalInformation(self):
        ns = arc.NS({'':'http://schemas.ogf.org/glue/2008/05/spec_2.0_d41_r01'})
        info = arc.XMLNode(ns,'Domains')
        service_node = info.NewChild('AdminDomain').NewChild('Services').NewChild('Service')
        endpoint_node = service_node.NewChild('Endpoint')
        endpoint_node.NewChild('HealthState').Set('ok')
        if self.state.running:
            serving_state = 'production'
        else:
            serving_state = 'closed'
        endpoint_node.NewChild('ServingState').Set(serving_state)
        try:
            self.GetAdditionalLocalInformation(service_node)
        except:
            pass
        return info
    
    def process(self, inmsg, outmsg):
        """ Method to process incoming message and create outgoing one. """
        # gets the payload from the incoming message
        inpayload = inmsg.Payload()
        try:
            # the first child of the payload should be the name of the request
            request_node = inpayload.Child()
            # get the namespace of the request node
            request_namespace = request_node.Namespace()
            matched_request_types = [request_type for request_type in self.request_config if request_type['namespace_uri'] == request_namespace]
            if len(matched_request_types) == 0:
                # check if it is a LIDI request:
                if request_namespace == wsrf_rp_uri:
                    outpayload = arc.PayloadSOAP(arc.NS({'wsrf-rp':wsrf_rp_uri}))
                    outpayload.NewChild('wsrf-rp:GetResourcePropertyDocumentResponse').NewChild(self.GetLocalInformation())
                    outmsg.Payload(outpayload)
                    return arc.MCC_Status(arc.STATUS_OK)
                raise Exception, 'wrong namespace. expected: %s' % ', '.join([request_type['namespace_uri'] for request_type in self.request_config])
            current_request_type = matched_request_types[0]
            # get the name of the request without the namespace prefix
            request_name = request_node.Name()
            if request_name not in current_request_type['request_names']:
                # if the name of the request is not in the list of supported request names
                raise Exception, 'wrong request (%s)' % request_name
            log.msg(arc.VERBOSE,'%(sn)s.%(rn)s called' % {'sn':self.service_name, 'rn':request_name})
            if not self.state.running:
                outpayload = arc.PayloadSOAP(self.ns, True)
                fault = outpayload.Fault()
                fault.Reason('%s service is inactive (not initialized yet or shutting down)' % self.service_name) 
                outmsg.Payload(outpayload)
                return arc.MCC_Status(arc.STATUS_OK)
            # if the request name is in the supported names,
            # then this class should have a method with this name
            # the 'getattr' method returns this method
            # which then we could call with the incoming payload
            # and which will return the response payload
            log.msg(arc.DEBUG, inpayload.GetXML())
            outpayload = self._call_request(request_name, inmsg)
            # sets the payload of the outgoing message
            outmsg.Payload(outpayload)
            # return with the STATUS_OK status
            return arc.MCC_Status(arc.STATUS_OK)
        except:
            # if there is any exception, print it
            msg = log.msg()
            outpayload = arc.PayloadSOAP(self.ns, True)
            fault = outpayload.Fault()
            fault.Reason('%s service raised a %s' % (self.service_name, msg))
            outmsg.Payload(outpayload)
            return arc.MCC_Status(arc.STATUS_OK)

def parse_node(node, names, single = False, string = True):
    """ Call node_to_data() for each child of the given node.
    
    parse_node(node, names, single = False, string = True)
    
    node is the XMLNode whose children we want to convert
    names is a list of tag names which will be returned in the specified order
    single indicates that we need only one value beside the key, do not put it into a list
    string indicates that we need the string data of the nodes, not the nodes itself.
    
    Example:
    
        xml = XMLNode('''
            <statRequestList>
                <statRequestElement>
                    <requestID>0</requestID>
                    <LN>/</LN>
                </statRequestElement>
                <statRequestElement>
                    <requestID>1</requestID>
                    <LN>/testfile</LN>
                </statRequestElement>
            </statRequestList>
        ''')
      
    parse_node(xml, ['requestID','LN']) returns:
        
        {'0': ['/'], '1': ['/testfile']}


    parse_node(xml, ['requestID','LN'], single = True) returns:
        
        {'0': '/', '1': '/testfile'}


    parse_node(xml, ['LN','requestID'], True) returns:
        
        {'/': '0', '/testfile': '1'}


    parse_node(xml, ['requestID','LN','LN']) returns:
        
        {'0': ['/', '/'], '1': ['/testfile', '/testfile']}


    """
    return dict([
        node_to_data(n, names, single, string)
            for n in get_child_nodes(node)
    ])

def parse_to_dict(node, names):
    """ Convert the children of the node to a dictionary of dictionaries.
    
    parse_to_dict(node, names)
    
    node is the XMLNode whose children we want to convert
    names is a list of tag names, for each child only these names will be included in the dictionary
    
    Example:
    
        <statResponseList>
            <statResponseElement>
                <requestID>123</requestID>
                <referenceID>abdad</referenceID>
                <state>alive</state>
                <size>871432</size>
            </statResponseElement>
            <statResponseElement>
                <requestID>456</requestID>
                <referenceID>fefeg</referenceID>
                <state>alive</state>
                <size>945</size>
            </statResponseElement>
        </statResponseList>
        
    parse_to_dict(xml, ['requestID', 'state', 'size']) returns:

        {'123': {'size': '871432', 'state': 'alive'},
         '456': {'size': '945', 'state': 'alive'}}


    parse_to_dict(xml, ['referenceID','requestID', 'state', 'size']) returns:
    
        {'abdad': {'requestID': '123', 'size': '871432', 'state': 'alive'},
         'fefeg': {'requestID': '456', 'size': '945', 'state': 'alive'}}
    """
    return dict([(str(n.Get(names[0])), dict([(name, str(n.Get(name))) for name in names[1:]]))
        for n in get_child_nodes(node)])

def create_response(method_name, tag_names, elements, payload, single = False):
    """ Creates an XMLNode payload from a dictionary of tag names and list of values.
    
    create_response(method_name, tag_names, elements, payload, single = False)
    
    method_name is the name of the method which will be used as a prefix in the name of the 'Response' tag
    tag_names is a list of names which will be used in the specified order as tag names
    elements is a dictionary where the key will be tagged as the first tag name,
        and the value is a list whose items will be tagged in the order of the tag_names list
    payload is an XMLNode, the response will be added to that
    single indicates if there is only one value per key
    
    Example:
    
        elements = {'123': ['alive', '871432'], '456': ['alive', '945']}
        tag_names = ['requestID', 'state', 'size']
        method_name = 'stat'
        payload = arc.PayloadSOAP(arc.NS())

    after create_response(method_name, tag_names, elements, payload, single = False) payload will contain:
    
        <statResponse>
            <statResponseList>
                <statResponseElement>
                    <requestID>123</requestID>
                    <state>alive</state>
                    <size>871432</size>
                </statResponseElement>
                <statResponseElement>
                    <requestID>456</requestID>
                    <state>alive</state>
                    <size>945</size>
                </statResponseElement>
            </statResponseList>
        </statResponse>

    The method_name used to prefix the 'Response' the 'ResponseList' and 'ResponseElement' node names.
    We could say
        method_name = 'ns:stat'
        tag_names = ['ns:requestID', 'ns:state', 'ns:size']
    if we want namespace prefixes.
    """
    # first create an XMLTree, then add it to the payload XMLNode
    from arcom.xmltree import XMLTree
    if single:
        # if there is only a single value for each key
        tree = XMLTree(from_tree =
            (method_name + 'ResponseList', [
                (method_name + 'ResponseElement', [
                    (tag_names[0], key),
                    (tag_names[1], value)
                ]) for key, value in elements.items()
            ])
        )
    else:
        # if there is more values for a key
        tree = XMLTree(from_tree =
            (method_name + 'ResponseList', [
                (method_name + 'ResponseElement', [
                    (tag_names[0], key) # tag the key with the first item in tag_names
                ] + [ # for each item in the values list pick the next name from tag_names
                    (tag_names[i + 1], values[i]) for i in range(len(values))
                ]) for key, values in elements.items()
            ])
        )
    # create a <method_name>Response child node in the payload
    response_node = payload.NewChild(method_name + 'Response')
    # add the XMLTree to this newly created node
    tree.add_to_node(response_node)
    # return the payload XMLNode
    return payload

def node_to_data(node, names, single = False, string = True):
    """ Get some children of an XMLNode and return them in a list in the specified order using the first one as a key.
    
    node_to_data(node, names, single = False, string = True)
    
    node is an XMLNode which has some children
    names is a list of strings, the names of the children we want to extract, the first name always will be a key
    single is a boolean indicating if we want only a single value thus do not put it in a list
    string is a boolean indicating if we want the string values of the nodes or the nodes itself
    
    Example:
    
        node:
            <changeRequest>
                <changeID>0</changeID>
                <ID>123</ID>
                <section>states</section>
                <property>neededReplicas</property>
                <value>3</value>
                <somethingElse>not interesting</somethingElse>
                <changeType>set</changeType>
            </changeRequest>
            
        names: ['changeID', 'ID', 'changeType', 'section', 'property', 'value']
        
        here changeID will be the key, and all the other names will be in a list in the specified order
        
        so it returns ('0', ['123', 'set', 'states', 'neededReplicas', '3'])
        
            ('somethingElse' is not returned)
    
    Example:
    
        node:
            <getRequest>
                <GUID>11</GUID>
                <requestID>99</requestID>
            </getRequest>
            
        names: ['requestID', 'GUID']
        single: True
        
        here requestID will be the key, and GUID is the single value which won't be in a list
        
        so it returns ('99', '11')
        
            (instead of '99', ['11'])
    """
    if string:
        # if we need the strings
        # for each name get the string data of the child with that name,
        data = [str(node.Get(name)) for name in names]
    else:
        # for each name get the child node itself
        data = [node.Get(name) for name in names]
    if single:
        # return the first item as a key and the second item as a single value
        return data[0], data[1]
    else:
        # return the first item as a key, and all the rest items as a list
        return data[0], data[1:]

def get_data_node(node):
    return node.Get('Body').Child().Child()