1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 import sys
19 import re
20 from xml.sax import make_parser, SAXParseException, ContentHandler, \
21 ErrorHandler
22
23 from spacewalk.common import usix
24 from spacewalk.common import rhnFlags
25 from spacewalk.common.rhnLog import log_debug
26 from spacewalk.common.rhnConfig import CFG
27 from spacewalk.common.rhnTB import Traceback
28 from spacewalk.server.importlib import importLib, backendLib
29
30 RHEL234_REGEX = re.compile("rhel-[^-]*-[aew]s-(4|3|2.1)")
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45 -class ParseException(Exception):
46
47 """general parser exception (generated at this level).
48 """
49 pass
50
53
55 Exception.__init__(self)
56 self.container = container
57
60
61 - def __init__(self, stream_version, parser_version, *args):
62 ParseException.__init__(self, *args)
63 self.stream_version = stream_version
64 self.parser_version = parser_version
65
72
73 """exception wrapper for a critical, but possibly recoverable, XML parser
74 error.
75 """
76 pass
77
80
81 """exception wrapper for a critical XML parser error.
82 """
83 pass
84
89
90 - def __init__(self, name, attributes=None, subelements=None):
98
101
103 return "[<Node element: name=%s>]" % self.name
104
108
109 """ Base class we use as a SAX parsing handler
110
111 We expect the meaningful data to be on the third level.
112 The root element defines what the export contains, while the collection
113 element defines what this collection contains
114 """
115 rootElement = None
116 __stream = None
117 container_dispatch = {}
118
131
133
134 self.__parser.setContentHandler(self)
135 self.__parser.setErrorHandler(self)
136
137 @staticmethod
140
141
143 log_debug(6)
144 if stream is not None:
145 self.setStream(stream)
146 try:
147 self.__parser.parse(self.__stream)
148 except (KeyboardInterrupt, SystemExit):
149 raise
150 except Exception:
151 Traceback(ostream=sys.stderr, with_locals=1)
152 if stream is not None:
153 stream.close()
154 sys.exit(1)
155
160
162
163
164 self.__parser = None
165
167
168 if self.__container:
169 try:
170 self.__container.batch = []
171 except (KeyboardInterrupt, SystemExit):
172 raise
173 except Exception:
174 e = sys.exc_info()[1]
175 log_debug(-1, 'ERROR (odd) upon container.batch=[] cleanup: %s' % e)
176 raise
177
178
186
195
198
199
202
203
204
205
206
224
228
241
242
243
244
245 - def error(self, exception):
246 """Handle a recoverable error.
247 """
248 log_debug(-1, "ERROR (RECOVERABLE): parse error encountered - line: %s, col: %s, msg: %s"
249 % (exception.getLineNumber(), exception.getColumnNumber(), exception._msg))
250 raise RecoverableParseException(exception._msg, exception, exception._locator)
251
253 """Handle a non-recoverable error.
254 """
255 log_debug(-1, "ERROR (FATAL): parse error encountered - line: %s, col: %s, msg: %s"
256 % (exception.getLineNumber(), exception.getColumnNumber(), exception._msg))
257 raise FatalParseException(exception._msg, exception, exception._locator)
258
260 """Handle a warning.
261 """
262 log_debug(-1, "ERROR (WARNING): parse error encountered - line: %s, col: %s, msg: %s"
263 % (exception.getLineNumber(), exception.getColumnNumber(), exception._msg))
264
265
268
273 rootElement = 'rhn-satellite'
274
275 version = "3.0"
276
277
278
279
280
281
282
283
284
300
359
362 if isinstance(obj, usix.StringType):
363 return 1
364 if isinstance(obj, usix.UnicodeType):
365 return 1
366 return 0
367
370
371 if isinstance(data, usix.StringType):
372 return data
373 elif isinstance(data, usix.UnicodeType):
374 return data.encode('UTF8')
375 return str(data)
376
379
380 ret = {}
381 for k, v in d.items():
382 if isinstance(k, usix.UnicodeType):
383 k = k.encode('UTF8')
384 if isinstance(v, usix.UnicodeType):
385 v = v.encode('UTF8')
386 ret[k] = v
387 return ret
388
389
390 __itemDispatcher = {}
395
404
412
417 addItem(ServerArchItem)
423 addItem(PackageArchItem)
429 addItem(ChannelArchItem)
435 addItem(CPUArchItem)
441 addItem(ServerPackageArchCompatItem)
447 addItem(ServerChannelArchCompatItem)
453 addItem(ChannelPackageArchCompatItem)
459 addItem(ServerGroupServerArchCompatItem)
463 item_name = 'rhn-channel-family'
464 item_class = importLib.ChannelFamily
465 tagMap = {
466 'id': 'channel-family-id',
467
468
469 'rhn-channel-family-name': 'name',
470 'rhn-channel-family-product-url': 'product_url',
471 'channel-labels': 'channels',
472 }
473 addItem(ChannelFamilyItem)
477 item_name = 'rhn-channel'
478 item_class = importLib.Channel
479 tagMap = {
480 'channel-id': 'string_channel_id',
481 'org-id': 'org_id',
482 'rhn-channel-parent-channel': 'parent_channel',
483 'rhn-channel-families': 'families',
484 'channel-arch': 'channel_arch',
485 'rhn-channel-basedir': 'basedir',
486 'rhn-channel-name': 'name',
487 'rhn-channel-summary': 'summary',
488 'rhn-channel-description': 'description',
489 'rhn-channel-last-modified': 'last_modified',
490 'rhn-dists': 'dists',
491 'rhn-release': 'release',
492 'channel-errata': 'errata',
493 'kickstartable-trees': 'kickstartable_trees',
494 'rhn-channel-errata': 'errata_timestamps',
495 'source-packages': 'source_packages',
496 'rhn-channel-gpg-key-url': 'gpg_key_url',
497 'rhn-channel-product-name': 'product_name',
498 'rhn-channel-product-version': 'product_version',
499 'rhn-channel-product-beta': 'product_beta',
500 'rhn-channel-receiving-updates': 'receiving_updates',
501 'rhn-channel-checksum-type': 'checksum_type',
502 'rhn-channel-comps-last-modified': 'comps_last_modified',
503 'rhn-channel-modules-last-modified': 'modules_last_modified',
504 'sharing': 'channel_access',
505 'rhn-channel-trusted-orgs': 'trust_list',
506 }
507
509
510
511
512 checksum_type_really_null = False
513 for element in elements:
514 if (not _is_string(element)
515 and element.name == 'rhn-channel-checksum-type'):
516 for subelement in element.subelements:
517 if (not _is_string(subelement)
518 and subelement.name == 'rhn-null'):
519 checksum_type_really_null = True
520
521 BaseItem.populateFromElements(self, obj, elements)
522
523 if obj['checksum_type'] == 'sha':
524 obj['checksum_type'] = 'sha1'
525 if not obj['checksum_type'] and not checksum_type_really_null:
526 obj['checksum_type'] = 'sha1'
527
528
529
530 if not obj['channel_access']:
531 obj['channel_access'] = 'private'
532
533
534
535 if (RHEL234_REGEX.match(obj['label'])
536 or (obj['parent_channel']
537 and RHEL234_REGEX.match(obj['parent_channel']))):
538 obj['checksum_type'] = None
539
540 addItem(ChannelItem)
549 addItem(ChannelTrustItem)
558 addItem(OrgTrustItem)
562 item_name = 'rhn-org'
563 item_class = importLib.Org
564 tagMap = {
565 'id': 'id',
566 'name': 'name',
567 'rhn-org-trusts': 'org_trust_ids',
568 }
569 addItem(OrgItem)
573
574 - def populate(self, attributes, elements):
575 item = BaseItem.populate(self, attributes, elements)
576 item['checksums'] = {}
577 if 'md5sum' in item:
578
579 item['checksums']['md5'] = item['md5sum']
580 del(item['md5sum'])
581 if 'checksum_list' in item and item['checksum_list']:
582 for csum in item['checksum_list']:
583 item['checksums'][csum['type']] = csum['value']
584 del(item['checksum_list'])
585 for ctype in CFG.CHECKSUM_PRIORITY_LIST:
586 if ctype in item['checksums']:
587 item['checksum_type'] = ctype
588 item['checksum'] = item['checksums'][ctype]
589 break
590 return item
591 addItem(BaseChecksummedItem)
595 item_name = 'rhn-package-short'
596 item_class = importLib.IncompletePackage
597 tagMap = {
598 'id': 'package_id',
599 'package-size': 'package_size',
600 'last-modified': 'last_modified',
601 'package-arch': 'arch',
602 'org-id': 'org_id',
603 'checksums': 'checksum_list',
604 }
605 addItem(IncompletePackageItem)
615 addItem(ChecksumItem)
619 item_name = 'rhn-package'
620 item_class = importLib.Package
621 tagMap = {
622
623 'package-group': 'package_group',
624 'rpm-version': 'rpm_version',
625 'payload-size': 'payload_size',
626 'build-host': 'build_host',
627 'build-time': 'build_time',
628 'source-rpm': 'source_rpm',
629 'payload-format': 'payload_format',
630
631 'rhn-package-summary': 'summary',
632 'rhn-package-description': 'description',
633 'rhn-package-vendor': 'vendor',
634 'rhn-package-copyright': 'license',
635 'rhn-package-header-sig': 'header_sig',
636
637 'rhn-package-package-group': 'package_group',
638 'rhn-package-rpm-version': 'rpm_version',
639 'rhn-package-payload-size': 'payload_size',
640 'rhn-package-header-start': 'header_start',
641 'rhn-package-header-end': 'header_end',
642 'rhn-package-build-host': 'build_host',
643 'rhn-package-build-time': 'build_time',
644 'rhn-package-source-rpm': 'source_rpm',
645 'rhn-package-payload-format': 'payload_format',
646 'rhn-package-cookie': 'cookie',
647
648 'rhn-package-files': 'files',
649 'rhn-package-requires': 'requires',
650 'rhn-package-provides': 'provides',
651 'rhn-package-conflicts': 'conflicts',
652 'rhn-package-obsoletes': 'obsoletes',
653 'rhn-package-recommends': 'recommends',
654 'rhn-package-suggests': 'suggests',
655 'rhn-package-supplements': 'supplements',
656 'rhn-package-enhances': 'enhances',
657 'rhn-package-changelog': 'changelog',
658 }
659 tagMap.update(IncompletePackageItem.tagMap)
660
661 - def populate(self, attributes, elements):
662 item = IncompletePackageItem.populate(self, attributes, elements)
663
664
665 have_filedigests = len([1 for i in item['requires'] if i['name'] == 'rpmlib(FileDigests)'])
666 if not have_filedigests:
667 item['checksum_type'] = 'md5'
668 item['checksum'] = item['checksums']['md5']
669 return item
670 addItem(PackageItem)
680 addItem(IncompleteSourcePackageItem)
684 item_name = 'rhn-source-package'
685 item_class = importLib.SourcePackage
686 tagMap = {
687 'id': 'package_id',
688 'source-rpm': 'source_rpm',
689 'package-group': 'package_group',
690 'rpm-version': 'rpm_version',
691 'payload-size': 'payload_size',
692 'build-host': 'build_host',
693 'build-time': 'build_time',
694 'package-size': 'package_size',
695 'last-modified': 'last_modified',
696 }
697 addItem(SourcePackageItem)
701 item_name = 'rhn-package-changelog-entry'
702 item_class = importLib.ChangeLog
703 tagMap = {
704 'rhn-package-changelog-entry-name': 'name',
705 'rhn-package-changelog-entry-text': 'text',
706 'rhn-package-changelog-entry-time': 'time',
707 }
708 addItem(ChangelogItem)
712
713 """virtual class - common settings for dependency items"""
714 item_class = importLib.Dependency
715 tagMap = {
716 'sense': 'flags',
717 }
718
722 addItem(ProvidesItem)
727 addItem(RequiresItem)
731 item_name = 'rhn-package-conflicts-entry'
732 addItem(ConflictsItem)
736 item_name = 'rhn-package-obsoletes-entry'
737 addItem(ObsoletesItem)
741 item_name = 'rhn-package-recommends-entry'
742 addItem(RecommendsItem)
747 addItem(SuggestsItem)
751 item_name = 'rhn-package-supplements-entry'
752 addItem(SupplementsItem)
757 addItem(EnhancesItem)
758
759
760 -class FileItem(BaseChecksummedItem):
773 addItem(FileItem)
782 addItem(DistItem)
792 addItem(ChannelErratumItem)
801 addItem(ReleaseItem)
805 item_name = 'rhn-erratum-bug'
806 item_class = importLib.Bug
807 tagMap = {
808 'rhn-erratum-bug-id': 'bug_id',
809 'rhn-erratum-bug-summary': 'summary',
810 'rhn-erratum-bug-href': 'href',
811 }
812 addItem(BugItem)
820 addItem(KeywordItem)
824 item_name = 'rhn-erratum'
825 item_class = importLib.Erratum
826 tagMap = {
827 'id': 'erratum_id',
828 'org-id': 'org_id',
829 'rhn-erratum-advisory-name': 'advisory_name',
830 'rhn-erratum-advisory-rel': 'advisory_rel',
831 'rhn-erratum-advisory-type': 'advisory_type',
832 'rhn-erratum-product': 'product',
833 'rhn-erratum-description': 'description',
834 'rhn-erratum-synopsis': 'synopsis',
835 'rhn-erratum-topic': 'topic',
836 'rhn-erratum-solution': 'solution',
837 'rhn-erratum-issue-date': 'issue_date',
838 'rhn-erratum-update-date': 'update_date',
839 'rhn-erratum-notes': 'notes',
840 'rhn-erratum-org-id': 'org_id',
841 'rhn-erratum-refers-to': 'refers_to',
842 'rhn-erratum-channels': 'channels',
843 'rhn-erratum-keywords': 'keywords',
844 'rhn-erratum-checksums': 'checksums',
845 'rhn-erratum-bugs': 'bugs',
846 'rhn-erratum-cve': 'cve',
847 'rhn-erratum-last-modified': 'last_modified',
848 'rhn-erratum-files': 'files',
849 'rhn-erratum-errata-from': 'errata_from',
850 'rhn-erratum-severity': 'severity_id',
851 'cve-names': 'cve',
852 }
853 addItem(ErratumItem)
859 addItem(ErrorItem)
863 item_name = 'rhn-erratum-file'
864 item_class = importLib.ErrataFile
865 tagMap = {
866 'type': 'file_type',
867 'channels': 'channel_list',
868
869 'package': 'package',
870 'source-package': 'source-package',
871 'checksum-type': 'checksum_type',
872 }
873 addItem(ErrataFileItem)
879 addItem(ProductNamesItem)
883 item_name = 'rhn-kickstartable-tree'
884 item_class = importLib.KickstartableTree
885 tagMap = {
886 'rhn-kickstart-files': 'files',
887 'base-path': 'base_path',
888 'boot-image': 'boot_image',
889 'kstree-type-label': 'kstree_type_label',
890 'install-type-label': 'install_type_label',
891 'kstree-type-name': 'kstree_type_name',
892 'install-type-name': 'install_type_name',
893 'last-modified': 'last_modified',
894 }
895 addItem(KickstartableTreeItem)
899 item_name = 'rhn-kickstart-file'
900 item_class = importLib.KickstartFile
901 tagMap = {
902 'relative-path': 'relative_path',
903 'file-size': 'file_size',
904 'last-modified': 'last_modified',
905 'checksums': 'checksum_list',
906 }
907 addItem(KickstartFileItem)
915 container_name = None
916
918
919 self.tagStack = []
920
921
922 self.objStack = []
923
924 self.batch = []
925
927
928 batch = self.batch
929
930 self.__init__()
931
932 self.batch = batch
933
935
936 if not self.tagStack and element != self.container_name:
937
938
939 raise Exception('This object should not have been used')
940 self.tagStack.append(Node(element, attrs))
941 self.objStack.append([])
942
944 log_debug(6, data)
945 if data == '':
946
947 return
948
949 lastObj = self.objStack[-1]
950 if lastObj and _is_string(lastObj[-1]):
951 lastObj[-1] = '%s%s' % (lastObj[-1], data)
952 else:
953 lastObj.append(data)
954
956
957 tagobj = self.tagStack[-1]
958
959 del self.tagStack[-1]
960
961 name = tagobj.name
962 if name != element:
963 raise ParseException(
964 "incorrect XML data: closing tag %s, opening tag %s" % (
965 element, name))
966
967 for obj in self.objStack[-1]:
968 tagobj.addSubelement(obj)
969
970
971 del self.objStack[-1]
972
973 if not self.objStack:
974
975 self.endContainerCallback()
976 raise _EndContainerEvent(tagobj)
977
978
979
980 self.objStack[-1].append(tagobj)
981 if len(self.tagStack) == 1:
982
983 self.endItemCallback()
984
986 return self.objStack[-1][-1]
987
989 del self.objStack[-1][-1]
990
1012
1015
1016 - def postprocessItem(self, item):
1019
1022
1023
1024 if objtype is None:
1025
1026 return _stringify(subelements)
1027
1028 if not subelements:
1029
1030 if isinstance(objtype, usix.ListType):
1031
1032 return []
1033
1034 return None
1035
1036
1037
1038 _s = []
1039 _strings_only = 1
1040 for subel in subelements:
1041 if _is_string(subel) and not subel.strip():
1042
1043 continue
1044 _s.append(subel)
1045 if not _is_string(subel):
1046 _strings_only = 0
1047
1048 if _strings_only:
1049
1050 subelements = [''.join(subelements)]
1051 else:
1052
1053 subelements = _s
1054
1055 if not isinstance(objtype, usix.ListType):
1056 if len(subelements) > 1:
1057 raise Exception("Expected a scalar, got back a list")
1058 subelement = subelements[0]
1059
1060 if isinstance(subelement, Node):
1061 if subelement.name == 'rhn-null':
1062 return None
1063 raise Exception("Expected a scalar, got back an element '%s'" % subelement.name)
1064
1065 if objtype is usix.StringType:
1066 return _stringify(subelement)
1067
1068 if objtype is usix.IntType:
1069 if subelement == '':
1070
1071 return None
1072 return int(subelement)
1073
1074 if objtype is importLib.DateType:
1075 return _normalizeDateType(subelement)
1076 raise Exception("Unhandled type %s for subelement %s" % (objtype,
1077 subelement))
1078
1079
1080 expectedType = objtype[0]
1081 if expectedType is usix.StringType:
1082
1083 return list(map(_stringify, subelements))
1084
1085 if expectedType is usix.IntType:
1086
1087 return list(map(int, subelements))
1088
1089 if expectedType is importLib.DateType:
1090 return list(map(_normalizeDateType, subelements))
1091
1092
1093 result = []
1094 for subelement in subelements:
1095 item = _createItem(subelement)
1096 if item is None:
1097
1098 continue
1099 if not isinstance(item, expectedType):
1100 raise Exception("Expected type %s, got back %s %s" % (expectedType,
1101 type(item), item))
1102 result.append(item)
1103
1104 return result
1105
1108
1109 if (objtype is None) or (objtype is usix.StringType):
1110
1111 return attribute
1112 elif objtype is usix.IntType:
1113 if attribute == '' or attribute == 'None':
1114
1115 return None
1116 else:
1117 return int(attribute)
1118 elif objtype is importLib.DateType:
1119 return _normalizeDateType(attribute)
1120 elif isinstance(objtype, usix.ListType):
1121
1122 return attribute.split()
1123 else:
1124 raise Exception("Unhandled attribute data type %s" % objtype)
1125
1128 try:
1129 value = int(value)
1130 except ValueError:
1131
1132 return value
1133
1134 return backendLib.localtime(value)
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150 -class ChannelFamilyContainer(ContainerHandler):
1152
1156
1168
1171
1172 """Inherits from IncompletePackageContainer, since we need to postprocess the
1173 channel information
1174 """
1175 container_name = 'rhn-packages'
1176
1180
1184
1188
1192
1196
1200
1204
1208
1212
1215 container_name = 'rhn-server-group-server-arch-compatibility-map'
1216
1220
1224
1228