Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
SUSE:SLE-15-SP1:GA
mgr-osad.12967
mgr-osad-git-0.707735a.obscpio
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File mgr-osad-git-0.707735a.obscpio of Package mgr-osad.12967
07070100000000000041FD0000000000000000000000015DA8415F00000000000000000000000000000000000000000000000900000000mgr-osad07070100000001000081B40000000000000000000000015DA8415F000046AC000000000000000000000000000000000000001100000000mgr-osad/LICENSE GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. <one line to give the program's name and a brief idea of what it does.> Copyright (C) <year> <name of author> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. <signature of Ty Coon>, 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. 07070100000002000081B40000000000000000000000015DA8415F00000026000000000000000000000000000000000000001200000000mgr-osad/Makefileinclude ../../../rel-eng/Makefile.git 07070100000003000081B40000000000000000000000015DA8415F000007A7000000000000000000000000000000000000001700000000mgr-osad/Makefile.defs# Common pathnames and programs for the Spacewalk project # # if not defined, definit as a noop TOP ?= . # global defines which control this build and where we deploy files ROOT ?= /usr/share/rhn export ROOT PREFIX ?= export PREFIX # Compilation stuff CC = gcc PYTHON_INCLUDE = -I/usr/include/python$(PythonVersion) CFLAGS = -Wall -O2 -fomit-frame-pointer $(PYTHON_INCLUDE) -fPIC SOFLAGS = -shared -fPIC # Installation stuff INSTALL = /usr/bin/install -c --verbose INSTALL_BIN = $(INSTALL) -m 755 INSTALL_DATA = $(INSTALL) -m 644 INSTALL_DIR = $(INSTALL) -m 755 -d # This is for the subdir part PYFILES = $(addsuffix .py,$(FILES)) # what do we need to install and where INSTALL_FILES += $(PYFILES) INSTALL_DEST ?= $(PYTHONPATH)/$(SUBDIR) DIRS += $(addprefix $(PREFIX), \ $(sort $(EXTRA_DIRS)) $(INSTALL_DEST)) all :: $(INSTALL_FILES) $(INSTALL_LINKS) install :: all $(DIRS) $(INSTALL_FILES) $(INSTALL_LINKS) @$(foreach f,$(INSTALL_FILES), \ $(INSTALL_DATA) $(f) $(PREFIX)$(INSTALL_DEST)/$(f) ; ) @$(foreach f,$(INSTALL_LINKS), \ ln -s `cat $(f)` $(PREFIX)$(INSTALL_DEST)/$(f) ; ) $(DIRS): $(INSTALL_DIR) $@ clean :: @rm -fv *~ *.pyc *.pyo .??*~ @rm -fv .\#* @rm -fv core # useful macro descend-subdirs = @$(foreach d,$(SUBDIRS), $(MAKE) -C $(d) $@ || exit 1; ) # subdirs are treated at the end all install clean:: $(SUBDIRS) $(descend-subdirs) # extra toy targets # Python checker support PYTHONPATH = $(TOP) PYCHECKER = pychecker PYCHECKEROPTS = --maxreturns 10 --maxbranches 15 DBCHECKER = db-checker.py DBCHECKEROPTS = DB = user/pass@instance pychecker :: $(PYFILES) @PYTHONPATH=$(PYTHONPATH) $(PYCHECKER) $(PYCHECKEROPTS) $(PYFILES) || : $(descend-subdirs) db-checker :: $(PYFILES) @PYTHONPATH=$(PYTHONPATH) $(TOP)/$(DBCHECKER) $(DBCHECKEROPTS) $(PYFILES) || : $(descend-subdirs) graphviz :: @PYTHONPATH=$(PYTHONPATH) $(PYCHECKER) -Z $(PYCHECKEROPTS) $(PYFILES) || exit 0 07070100000004000081B40000000000000000000000015DA8415F00000703000000000000000000000000000000000000001700000000mgr-osad/Makefile.osad# Makefile for the backend directory # PKGNAME = osad VERSION = $(shell echo `awk '{ print $$1 }' version`) RELEASE = $(shell echo `awk '{ print $$2 }' version`) CODE_DIRS = src CONF_DIRS = rhn-conf osad-conf logrotate sysconfig tns-admin-osa-dispatcher # We look for config files in "well known" locations (rhn-conf, # httpd-conf, logrotate) EXTRA_DIRS = /var/log/rhn /var/log/rhn/oracle /var/log/rhn/oracle/osa-dispatcher $(BINDIR) $(SBINDIR) $(INITDIR) BINDIR = /usr/bin SBINDIR = /usr/sbin INITDIR = /etc/rc.d/init.d PROGS = osad osa-dispatcher all :: all-code all-conf %-code : Makefile @$(foreach d,$(CODE_DIRS), $(MAKE) -C $(d) $* || exit 1; ) %-conf : Makefile @$(foreach d,$(CONF_DIRS), $(MAKE) -C $(d) $* || exit 1; ) # now include some Macros include Makefile.defs install :: install-code install-conf install-bins install-rcs install-bins : $(addsuffix .inst, $(PROGS)) install-rcs : $(addsuffix .inst.rc, $(PROGS)) %.inst : %.new $(PREFIX)$(SBINDIR) $(INSTALL_BIN) $*.new $(PREFIX)$(SBINDIR)/$*-$(PYTHONVERSION) rm -f $*.new %.new : invocation.py sed -e 's|@@ROOT@@|$(ROOT)|g' < $^ > $@ %.inst.rc : %.new.rc $(PREFIX)$(INITDIR) $(INSTALL_BIN) $*.new.rc $(PREFIX)$(INITDIR)/$* %.new.rc : prog.init sed -e 's|@@PROG@@|$*|g' < $^ > $@ clean :: clean-code clean-conf rm -f *.new *.rcnew archive: _archive _archive: @rm -rf ${PKGNAME}-%{VERSION}.tar.gz @rm -rf /tmp/${PKGNAME}-$(VERSION) /tmp/${PKGNAME} @dir=$$PWD; cd /tmp; cp -a $$dir ${PKGNAME} @mv /tmp/${PKGNAME} /tmp/${PKGNAME}-$(VERSION) @dir=$$PWD; cd /tmp; tar cvzf $$dir/${PKGNAME}-$(VERSION).tar.gz ${PKGNAME}-$(VERSION) @rm -rf /tmp/${PKGNAME}-$(VERSION) @echo "The archive is in ${PKGNAME}-$(VERSION).tar.gz" srpm: archive rpmbuild -ts ${PKGNAME}-$(VERSION).tar.gz 07070100000005000081B40000000000000000000000015DA8415F00000344000000000000000000000000000000000000001900000000mgr-osad/Makefile.pythonTHIS_MAKEFILE := $(realpath $(lastword $(MAKEFILE_LIST))) CURRENT_DIR := $(dir $(THIS_MAKEFILE)) include $(CURRENT_DIR)../../../rel-eng/Makefile.python # Docker tests variables DOCKER_CONTAINER_BASE = uyuni-master DOCKER_REGISTRY = registry.mgr.suse.de DOCKER_RUN_EXPORT = "PYTHONPATH=$PYTHONPATH" DOCKER_VOLUMES = -v "$(CURDIR)/../../../:/manager" __pylint :: $(call update_pip_env) pylint --rcfile=pylintrc $(shell find -name '*.py') > reports/pylint.log || true docker_pylint :: docker run --rm -e $(DOCKER_RUN_EXPORT) $(DOCKER_VOLUMES) $(DOCKER_REGISTRY)/$(DOCKER_CONTAINER_BASE)-pgsql /bin/sh -c "cd /manager/client/tools/mgr-osad; make -f Makefile.python __pylint" docker_shell :: docker run -t -i --rm -e $(DOCKER_RUN_EXPORT) $(DOCKER_VOLUMES) $(DOCKER_REGISTRY)/$(DOCKER_CONTAINER_BASE)-pgsql /bin/bash 07070100000006000081FD0000000000000000000000015DA8415F000005C9000000000000000000000000000000000000001700000000mgr-osad/invocation.py#!/usr/bin/python # # Copyright (c) 2008--2016 Red Hat, Inc. # # This software is licensed to you under the GNU General Public License, # version 2 (GPLv2). There is NO WARRANTY for this software, express or # implied, including the implied warranties of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2 # along with this software; if not, see # http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. # # Red Hat trademarks are not licensed under GPLv2. No permission is # granted to use or replicate Red Hat trademarks that are incorporated # in this software or its documentation. # import os import sys _path = "@@ROOT@@" if _path not in sys.path: sys.path.append(_path) mod_name = os.path.basename(sys.argv[0]) mod_name = mod_name.replace('-', '_') try: mod = __import__("osad." + mod_name) except ImportError: e = sys.exc_info()[1] sys.stderr.write("Unable to load module %s\n" % mod_name) sys.stderr.write(str(e) + "\n") sys.exit(1) mod = getattr(mod, mod_name) if __name__ == '__main__': try: sys.exit(mod.main() or 0) except KeyboardInterrupt: e = sys.exc_info()[1] sys.stderr.write("\nUser interrupted process.\n") sys.exit(0) except SystemExit: e = sys.exc_info()[1] sys.exit(e.code) except Exception: e = sys.exc_info()[1] sys.stderr.write("\nERROR: unhandled exception occurred: (%s).\n" % e) sys.exit(-1) 07070100000007000041FD0000000000000000000000015DA8415F00000000000000000000000000000000000000000000001300000000mgr-osad/logrotate07070100000008000081B40000000000000000000000015DA8415F000000CD000000000000000000000000000000000000001C00000000mgr-osad/logrotate/Makefile# Makefile for installation of the logrotation configuration files # # what is the backend top dir TOP = .. INSTALL_FILES = $(wildcard osa*) INSTALL_DEST = /etc/logrotate.d include $(TOP)/Makefile.defs 07070100000009000081B40000000000000000000000015DA8415F00000175000000000000000000000000000000000000002200000000mgr-osad/logrotate/osa-dispatcher# logrotation file for Red Hat Satellite's osa-dispatcher /var/log/rhn/osa-dispatcher.log { weekly rotate 5 copytruncate compress notifempty missingok size 10M su wwwrun www } /var/log/rhn/oracle/osa-dispatcher/sqlnet.ora { weekly rotate 5 copytruncate compress notifempty missingok su root www size 10M } 0707010000000A000081B40000000000000000000000015DA8415F00000072000000000000000000000000000000000000001800000000mgr-osad/logrotate/osad/var/log/osad { weekly rotate 5 copytruncate compress notifempty missingok size 10M } 0707010000000B000081B40000000000000000000000015DA8415F0000003C000000000000000000000000000000000000001C00000000mgr-osad/mgr-osad-rpmlintrcaddFilter("suse-filelist-forbidden-sysconfig .*/sysconfig") 0707010000000C000081B40000000000000000000000015DA8415F0000332B000000000000000000000000000000000000001A00000000mgr-osad/mgr-osad.changes------------------------------------------------------------------- Thu Oct 17 12:10:30 CEST 2019 - jgonzalez@suse.com - version 4.0.10-1 - Obsolete all old python2-osa* packages to avoid conflicts (bsc#1152290) ------------------------------------------------------------------- Tue Jul 30 14:40:28 CEST 2019 - jgonzalez@suse.com - version 4.0.9-1 - Fix obsolete for old osad packages, to allow installing mgr-osad even by using osad at yum/zyppper install (bsc#1139453) - Ensure bytes type when using hashlib to avoid traceback (bsc#1138822) ------------------------------------------------------------------- Wed May 15 20:07:58 CEST 2019 - jgonzalez@suse.com - version 4.0.8-1 - Obsolete newer versions of osad ------------------------------------------------------------------- Wed May 15 14:59:49 CEST 2019 - jgonzalez@suse.com - version 4.0.7-1 - SPEC cleanup - Fix wrong bugzilla entry at changelog ------------------------------------------------------------------- Mon Apr 22 12:01:44 CEST 2019 - jgonzalez@suse.com - version 4.0.6-1 - add makefile and pylint configuration ------------------------------------------------------------------- Thu Jan 31 09:40:02 CET 2019 - jgonzalez@suse.com - version 4.0.5-1 - Final fixes to make osa-dispatcher compatible with python3 ------------------------------------------------------------------- Wed Jan 16 12:14:14 CET 2019 - jgonzalez@suse.com - version 4.0.4-1 - Require correct python version for osa-dispatcher ------------------------------------------------------------------- Fri Oct 26 09:55:23 CEST 2018 - jgonzalez@suse.com - version 4.0.3-1 - Change dependencies for subpackages to python2-mgr-osa-* python3-mgr-osa-* and mgr-osa-* (bsc#1104034) ------------------------------------------------------------------- Fri Aug 10 17:04:37 CEST 2018 - jgonzalez@suse.com - version 4.0.2-1 - Fix SPEC issue for subpackage mgr-osa-dispatcher-selinux (bsc#1104034) ------------------------------------------------------------------- Fri Aug 10 16:02:12 CEST 2018 - jgonzalez@suse.com - version 4.0.1-1 - Bump version to 4.0.0 (bsc#1104034) - Rename package to mgr-osad to allow version 4.0.0 (bsc#1104034) - Fix copyright for the package specfile (bsc#1103696) ------------------------------------------------------------------- Thu Mar 29 01:21:06 CEST 2018 - jgonzalez@suse.com - version 5.11.102.2-1 - use full package name python-jabberpy as dependency (bsc#1087299) ------------------------------------------------------------------- Mon Mar 26 08:30:09 CEST 2018 - jgonzalez@suse.com - version 5.11.102.1-1 - Sync with upstream (bsc#1083294) - Remove osad files when packaging only for python3 - Run osa-dispatcher on python3 when possible ------------------------------------------------------------------- Mon Mar 05 08:35:34 CET 2018 - jgonzalez@suse.com - version 5.11.100.2-1 - remove clean section from spec (bsc#1083294) ------------------------------------------------------------------- Fri Feb 23 10:36:23 CET 2018 - jgonzalez@suse.com - version 5.11.100.1-1 - remove unused python-xml requirement (bsc#1082211) ------------------------------------------------------------------- Wed Jan 17 11:06:04 CET 2018 - jgonzalez@suse.com - version 5.11.98.2-1 - Fix update mechanism when updating the updateservice (bsc#1073619) ------------------------------------------------------------------- Fri Nov 10 16:19:00 CET 2017 - mc@suse.de - version 5.11.98.1-1 - add missing directory to filelist ------------------------------------------------------------------- Thu Oct 26 16:42:22 CEST 2017 - mc@suse.de - version 5.11.97.1-1 - splitinto python2/python3 specific packages - Fixed TypeError for force flag in setup_config that could happen when jabberd restart was needed. (bsc#1064393) ------------------------------------------------------------------- Tue Aug 08 09:32:23 CEST 2017 - fkobzik@suse.de - version 5.11.80.3-1 - reduce maximal size of osad log before rotating - perform osad restart in posttrans (bsc#1039913) ------------------------------------------------------------------- Tue May 23 07:57:05 CEST 2017 - mc@suse.de - version 5.11.80.2-1 - require rhnlib version with i18n module (bsc#1038483) ------------------------------------------------------------------- Tue Mar 07 14:38:36 CET 2017 - mc@suse.de - version 5.11.80.1-1 - Updated links to github in spec files - fix TypeError: descriptor 'with_traceback' - remove running rhn_check on osad start - require spacewalk-usix indead of spacewalk-backend-usix - fix osa_dispatcher so it can successfully register with jabberd ------------------------------------------------------------------- Tue Feb 07 17:49:37 CET 2017 - michele.bologna@suse.com - version 5.11.77.1-1 - Align with upstream versioning ------------------------------------------------------------------- Wed Jan 11 15:14:52 CET 2017 - michele.bologna@suse.com - version 5.11.76.1-1 - Initial submission for Manager-3.1 ------------------------------------------------------------------- Fri Dec 16 16:01:48 CET 2016 - michele.bologna@suse.com - version 5.11.64.3-1 - fix logfile option for osa-dispatcher (bsc#980752) ------------------------------------------------------------------- Mon Mar 21 16:39:52 CET 2016 - mc@suse.de - version 5.11.64.2-1 - fix file permissions (bsc#970550) ------------------------------------------------------------------- Wed Mar 02 12:02:31 CET 2016 - mc@suse.de - version 5.11.64.1-1 - Add possibility for OSAD to work in failover mode ------------------------------------------------------------------- Wed Feb 10 08:28:15 CET 2016 - mc@suse.de - version 5.11.63.2-1 - set osa-dispatcher notify_threshold to 100 as default ------------------------------------------------------------------- Mon Nov 30 10:57:19 CET 2015 - mc@suse.de - version 5.11.63.1-1 - fix TypeError: unbound method set_jabber_connection() ------------------------------------------------------------------- Wed Oct 07 15:33:35 CEST 2015 - mc@suse.de - version 5.11.62.1-1 - Bump version ------------------------------------------------------------------- Wed Sep 23 15:02:44 CEST 2015 - mc@suse.de - version 5.11.33.10-1 - osad: re-send subscription stanzas after a while (bsc#933738) ------------------------------------------------------------------- Mon Jun 22 16:04:29 CEST 2015 - jrenner@suse.de - version 5.11.33.9-1 - fix duplicate jabber ids (bsc#869888, bsc#931685) - improve error logging ------------------------------------------------------------------- Tue Mar 31 14:32:18 CEST 2015 - mc@suse.de - version 5.11.33.8-1 - Apply needed SElinux fix for RHEL7 and make use of systemd unit files - introduce notify_threshold for osa-dispatcher (bsc#915581) - really check for action type reboot ------------------------------------------------------------------- Tue Feb 03 13:14:54 CET 2015 - mc@suse.de - version 5.11.33.7-1 - Getting rid of Tabs and trailing spaces ------------------------------------------------------------------- Thu Dec 04 13:16:34 CET 2014 - mc@suse.de - version 5.11.33.6-1 - removed PyXML dependency for RHEL systems - fix osad through unauthenticated proxy case ------------------------------------------------------------------- Fri Nov 07 13:06:40 CET 2014 - mc@suse.de - version 5.11.33.5-1 - enable and install osad during first installation (bsc#901958) ------------------------------------------------------------------- Wed Sep 3 01:41:37 CEST 2014 - ro@suse.de - sanitize release line in specfile ------------------------------------------------------------------- Mon Sep 01 17:04:21 CEST 2014 - mc@suse.de - version 5.11.33.4-1 - osad: fix traceback if http proxy is not configured - osad: support communication over proxy ------------------------------------------------------------------- Tue Jun 17 10:57:46 CEST 2014 - jrenner@suse.de - version 5.11.33.3-1 - Call python using the -s option ------------------------------------------------------------------- Thu Apr 10 17:21:11 CEST 2014 - mc@suse.de - version 5.11.33.2-1 ------------------------------------------------------------------- Thu Apr 10 17:20:09 CEST 2014 - mc@suse.de - fix release in specfile for SLE12 (bnc#872970) ------------------------------------------------------------------- Fri Feb 07 12:53:56 CET 2014 - mc@suse.de - version 5.11.33.1-1 - create rc links on SUSE distributions - make reboot_in_progress a public function (bnc#859541) ------------------------------------------------------------------- Mon Jan 13 09:35:06 CET 2014 - mc@suse.de - version 5.11.32.2-1 - do not notify osad of a server which reboot is in progress (FATE#312591) ------------------------------------------------------------------- Mon Dec 09 16:10:08 CET 2013 - mc@suse.de - version 5.11.32.1-1 - switch to 2.1 ------------------------------------------------------------------- Thu Nov 28 16:21:13 CET 2013 - mc@suse.de - version 5.10.41.10-1 - remove extraneous 'except' - catch jabberd connection errors ------------------------------------------------------------------- Fri Sep 27 10:01:57 CEST 2013 - mc@suse.de - version 5.10.41.9-1 - require python-xml on SLE11 (bnc#838509) ------------------------------------------------------------------- Fri Feb 08 11:17:14 CET 2013 - mc@suse.de - version 5.10.41.8-1 - always commit the update ------------------------------------------------------------------- Thu Nov 22 15:42:02 CET 2012 - jrenner@suse.de - version 5.10.41.7-1 - osad requires config.getServerURL() ------------------------------------------------------------------- Mon Oct 15 12:20:56 CEST 2012 - mc@suse.de - version 5.10.41.6-1 - recompile python files only on SUSE ------------------------------------------------------------------- Fri Sep 28 16:35:57 CEST 2012 - mc@suse.de - version 5.10.41.5-1 - Set owner/group of config-defaults dir consistently (bnc#776377) - recompile python files (bnc#776356) ------------------------------------------------------------------- Mon May 14 10:56:20 CEST 2012 - mc@suse.de - version 5.10.41.4-1 - no use of /var/lock/subsys/ anymore ------------------------------------------------------------------- Fri Apr 27 16:55:29 CEST 2012 - mc@suse.de - version 5.10.41.3-1 - rotate osa-dispatcher logfiles at 10M ------------------------------------------------------------------- Fri Apr 20 15:41:28 CEST 2012 - mc@suse.de - version 5.10.41.2-1 - prevent 'notifying clients' starvation - Make osa-dispatcher use the hostname in the rhn.conf if present ------------------------------------------------------------------- Thu Mar 22 16:14:48 CET 2012 - mc@suse.de - osa-dispatcher: rotate logfiles as user www (bnc#681984) CVE-2011-1550 ------------------------------------------------------------------- Wed Mar 21 17:14:46 CET 2012 - mc@suse.de - version 5.10.41.1-1 - Bumping package version ------------------------------------------------------------------- Fri Feb 3 15:44:17 CET 2012 - ug@suse.de - changed permissions of /etc/rhn ------------------------------------------------------------------- Tue Sep 13 11:47:54 CEST 2011 - mc@suse.de - enable and start osad during installation (FATE#312379) ------------------------------------------------------------------- Fri Aug 26 13:03:20 CEST 2011 - mc@suse.de - start osa-dispatcher after oracle DB ------------------------------------------------------------------- Thu Aug 11 15:11:07 CEST 2011 - iartarisi@suse.cz - fix some imports after moving modules out of spacewalk.common ------------------------------------------------------------------- Mon Jul 4 17:18:58 CEST 2011 - mc@suse.de - require python-hashlib for SLE10 ------------------------------------------------------------------- Wed Jun 15 14:35:25 CEST 2011 - mc@suse.de - ensure presence subscription works with standard jabberd setup.(bnc#695946) ------------------------------------------------------------------- Mon Feb 7 15:31:07 CET 2011 - mc@suse.de - add rc links (bnc#669894) ------------------------------------------------------------------- Wed Feb 2 17:27:07 CET 2011 - mc@suse.de - fix build on RH4 ------------------------------------------------------------------- Sun Jan 30 15:27:23 CET 2011 - mc@suse.de - backport upstrem fixes ------------------------------------------------------------------- Sat Jan 22 12:38:52 CET 2011 - mc@suse.de - fix macros ------------------------------------------------------------------- Thu Sep 16 08:28:50 CEST 2010 - mantel@suse.de - fix missing prog.init.SUSE ------------------------------------------------------------------- Wed Sep 15 13:11:04 CEST 2010 - mantel@suse.de - cleanup specfile: remove excessive *init.SUSE Source statement ------------------------------------------------------------------- Wed Sep 15 12:13:40 CEST 2010 - mantel@suse.de - fix post-build-checks ------------------------------------------------------------------- Tue Sep 14 17:31:29 CEST 2010 - mantel@suse.de - Initial release of osad ------------------------------------------------------------------- 0707010000000D000081B40000000000000000000000015DA8415F00005471000000000000000000000000000000000000001700000000mgr-osad/mgr-osad.spec# # spec file for package mgr-osad # # Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany. # Copyright (c) 2008-2018 Red Hat, Inc. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed # upon. The license for this file, and modifications and additions to the # file, is the same license as for the pristine package itself (unless the # license for the pristine package is not an Open Source License, in which # case the license is the MIT License). An "Open Source License" is a # license that conforms to the Open Source Definition (Version 1.9) # published by the Open Source Initiative. # Please submit bugfixes or comments via https://bugs.opensuse.org/ # # Old name and version+1 before switching to mgr-osad %define oldname osad %define oldversion 5.11.103 %global rhnroot /usr/share/rhn %global rhnconf /etc/sysconfig/rhn %global client_caps_dir /etc/sysconfig/rhn/clientCaps.d %{!?fedora: %global sbinpath /sbin}%{?fedora: %global sbinpath %{_sbindir}} %if 0%{?suse_version} %global apache_group www %global apache_user wwwrun %global include_selinux_package 0 %else %global apache_group apache %global apache_user apache %global include_selinux_package 1 %endif %if 0%{?fedora} || 0%{?suse_version} > 1320 || 0%{?rhel} >= 8 %global build_py3 1 %global default_py3 1 %endif %if ( 0%{?fedora} && 0%{?fedora} < 28 ) || ( 0%{?rhel} && 0%{?rhel} < 8 ) || 0%{?suse_version} %global build_py2 1 %endif %define pythonX %{?default_py3: python3}%{!?default_py3: python2} Name: mgr-osad Summary: Open Source Architecture Daemon License: GPL-2.0-only Group: System Environment/Daemons Version: 4.0.10 Provides: %{oldname} = %{oldversion} Obsoletes: %{oldname} < %{oldversion} Release: 1%{?dist} Url: https://github.com/uyuni-project/uyuni Source0: https://github.com/spacewalkproject/spacewalk/archive/%{name}-%{version}.tar.gz Source1: %{name}-rpmlintrc BuildRoot: %{_tmppath}/%{name}-%{version}-build %if 0%{?fedora} || 0%{?rhel} || 0%{?suse_version} >= 1210 BuildArch: noarch %endif %if 0%{?fedora} > 26 BuildRequires: perl-interpreter %else BuildRequires: perl %endif Requires: %{pythonX}-%{name} = %{version}-%{release} Conflicts: mgr-osa-dispatcher < %{version}-%{release} Conflicts: mgr-osa-dispatcher > %{version}-%{release} %if 0%{?suse_version} >= 1210 BuildRequires: systemd %{?systemd_requires} %endif %if 0%{?suse_version} # provides chkconfig on SUSE Requires(post): aaa_base Requires(preun): aaa_base # to make chkconfig test work during build BuildRequires: sysconfig BuildRequires: syslog %if 0%{?suse_version} < 1210 Requires: %fillup_prereq Requires: %insserv_prereq %endif %else %if 0%{?fedora} || 0%{?rhel} >= 7 Requires(post): chkconfig Requires(preun): chkconfig Requires(post): systemd-sysv Requires(preun): systemd-sysv Requires(post): systemd-units Requires(preun): systemd-units BuildRequires: systemd-units %else Requires(post): chkconfig Requires(preun): chkconfig # This is for /sbin/service Requires(preun): initscripts %endif %endif %description OSAD agent receives commands over jabber protocol from Spacewalk Server and commands are instantly executed. This package effectively replaces the behavior of rhnsd/rhn_check that only poll the Spacewalk Server from time to time. %if 0%{?build_py2} %package -n python2-%{name} Summary: Open Source Architecture Daemon Group: System Environment/Daemons Provides: python-%{name} = %{oldversion} Obsoletes: python-%{name} < %{oldversion} Provides: python2-%{oldname} = %{oldversion} Obsoletes: python2-%{oldname} < %{oldversion} Requires: %{name} = %{version}-%{release} Requires: python Requires: python-jabberpy Requires: python2-mgr-osa-common = %{version} Requires: python2-rhn-client-tools >= 2.8.4 Requires: rhnlib >= 2.8.3 Requires: spacewalk-usix %if 0%{?rhel} && 0%{?rhel} <= 5 Requires: python-hashlib %endif BuildRequires: python-devel %description -n python2-%{name} Python 2 specific files for %{name} %endif %if 0%{?build_py3} %package -n python3-%{name} Summary: Open Source Architecture Daemon Group: System Environment/Daemons Provides: python3-%{oldname} = %{oldversion} Obsoletes: python3-%{oldname} < %{oldversion} Requires: %{name} = %{version}-%{release} Requires: python3 Requires: python3-jabberpy Requires: python3-mgr-osa-common = %{version} Requires: python3-rhn-client-tools >= 2.8.4 Requires: python3-rhnlib >= 2.8.3 Requires: python3-spacewalk-usix BuildRequires: python3-devel %description -n python3-%{name} Python 3 specific files for %{name} %endif %package -n python2-mgr-osa-common Summary: OSA common files Group: System Environment/Daemons Requires: python-jabberpy Conflicts: %{name} < %{version}-%{release} Conflicts: %{name} > %{version}-%{release} Obsoletes: osa-common < %{oldversion} Provides: osa-common = %{oldversion} Obsoletes: python2-osa-common < %{oldversion} Provides: python2-osa-common = %{oldversion} %description -n python2-mgr-osa-common Python 2 common files needed by mgr-osad and mgr-osa-dispatcher %if 0%{?build_py3} %package -n python3-mgr-osa-common Summary: OSA common files Group: System Environment/Daemons Requires: python3-jabberpy Conflicts: %{name} < %{version}-%{release} Conflicts: %{name} > %{version}-%{release} Obsoletes: osa-common < %{oldversion} Provides: osa-common = %{oldversion} Obsoletes: python3-osa-common < %{oldversion} Provides: python3-osa-common = %{oldversion} %description -n python3-mgr-osa-common Python 3 common files needed by mgr-osad and mgr-osa-dispatcher %endif %package -n mgr-osa-dispatcher Summary: OSA dispatcher Group: System Environment/Daemons Obsoletes: osa-dispatcher < %{oldversion} Provides: osa-dispatcher = %{oldversion} Requires: lsof Requires: %{pythonX}-mgr-osa-dispatcher = %{version}-%{release} Requires: spacewalk-backend-server >= 1.2.32 Conflicts: %{name} < %{version}-%{release} Conflicts: %{name} > %{version}-%{release} %if 0%{?suse_version} >= 1210 %{?systemd_requires} %endif %if 0%{?suse_version} # provides chkconfig on SUSE Requires(post): aaa_base Requires(preun): aaa_base %else Requires(post): chkconfig Requires(preun): chkconfig # This is for /sbin/service Requires(preun): initscripts %endif %description -n mgr-osa-dispatcher OSA dispatcher is supposed to run on the Spacewalk server. It gets information from the Spacewalk server that some command needs to be execute on the client; that message is transported via jabber protocol to OSAD agent on the clients. %package -n python2-mgr-osa-dispatcher Summary: OSA dispatcher Group: System Environment/Daemons Obsoletes: python2-osa-dispatcher < %{oldversion} Provides: python2-osa-dispatcher = %{oldversion} %if 0%{?fedora} >= 28 BuildRequires: python2-devel Requires: python2 %else BuildRequires: python-devel Requires: python %endif Requires: python-jabberpy Requires: python2-mgr-osa-common = %{version}-%{release} %description -n python2-mgr-osa-dispatcher Python 2 specific files for osa-dispatcher. %if 0%{?build_py3} %package -n python3-mgr-osa-dispatcher Summary: OSA dispatcher Group: System Environment/Daemons Obsoletes: python3-osa-dispatcher < %{oldversion} Provides: python3-osa-dispatcher = %{oldversion} BuildRequires: python3-devel Requires: python3 Requires: python3-jabberpy Requires: python3-mgr-osa-common = %{version}-%{release} %description -n python3-mgr-osa-dispatcher Python 3 specific files for osa-dispatcher. %endif %if 0%{?include_selinux_package} %package -n mgr-osa-dispatcher-selinux %global selinux_variants mls strict targeted %global selinux_policyver %(sed -e 's,.*selinux-policy-\\([^/]*\\)/.*,\\1,' /usr/share/selinux/devel/policyhelp 2> /dev/null) %global POLICYCOREUTILSVER 1.33.12-1 %global moduletype apps %global modulename osa-dispatcher Summary: SELinux policy module supporting osa-dispatcher Group: System Environment/Base Obsoletes: osa-dispatcher-selinux < %{oldversion} Provides: osa-dispatcher-selinux = %{oldversion} BuildRequires: checkpolicy BuildRequires: hardlink BuildRequires: policycoreutils >= %{POLICYCOREUTILSVER} BuildRequires: selinux-policy-devel Requires: spacewalk-selinux %if "%{selinux_policyver}" != "" Requires: selinux-policy >= %{selinux_policyver} %endif %if 0%{?rhel} == 5 Requires: selinux-policy >= 2.4.6-114 %endif Requires(post): /usr/sbin/semodule, %{sbinpath}/restorecon, /usr/sbin/selinuxenabled, /usr/sbin/semanage Requires(postun): /usr/sbin/semodule, %{sbinpath}/restorecon, /usr/sbin/semanage, spacewalk-selinux Requires: mgr-osa-dispatcher %description -n mgr-osa-dispatcher-selinux SELinux policy module supporting osa-dispatcher. %endif %prep %setup -q %if 0%{?suse_version} cp prog.init.SUSE prog.init %endif %if 0%{?fedora} || (0%{?rhel} && 0%{?rhel} > 5) sed -i 's@^#!/usr/bin/python$@#!/usr/bin/python -s@' invocation.py %endif %build make -f Makefile.osad all PYTHONPATH=%{python_sitelib} %if 0%{?include_selinux_package} %{__perl} -i -pe 'BEGIN { $VER = join ".", grep /^\d+$/, split /\./, "%{version}.%{release}"; } s!\@\@VERSION\@\@!$VER!g;' osa-dispatcher-selinux/%{modulename}.te %if 0%{?fedora} || 0%{?rhel} >= 7 cat osa-dispatcher-selinux/%{modulename}.te.fedora17 >> osa-dispatcher-selinux/%{modulename}.te %endif %if 0%{?fedora} >= 26 cat osa-dispatcher-selinux/%{modulename}.te.fedora26 >> osa-dispatcher-selinux/%{modulename}.te %endif for selinuxvariant in %{selinux_variants} do make -C osa-dispatcher-selinux NAME=${selinuxvariant} -f /usr/share/selinux/devel/Makefile mv osa-dispatcher-selinux/%{modulename}.pp osa-dispatcher-selinux/%{modulename}.pp.${selinuxvariant} make -C osa-dispatcher-selinux NAME=${selinuxvariant} -f /usr/share/selinux/devel/Makefile clean done %endif %install install -d $RPM_BUILD_ROOT%{rhnroot} make -f Makefile.osad install PREFIX=$RPM_BUILD_ROOT ROOT=%{rhnroot} INITDIR=%{_initrddir} \ PYTHONPATH=%{python_sitelib} PYTHONVERSION=%{python_version} %if 0%{?build_py3} make -f Makefile.osad install PREFIX=$RPM_BUILD_ROOT ROOT=%{rhnroot} INITDIR=%{_initrddir} \ PYTHONPATH=%{python3_sitelib} PYTHONVERSION=%{python3_version} sed -i 's|#!/usr/bin/python|#!/usr/bin/python3|' $RPM_BUILD_ROOT/usr/sbin/osad-%{python3_version} sed -i 's|#!/usr/bin/python|#!/usr/bin/python3|' $RPM_BUILD_ROOT/usr/sbin/osa-dispatcher-%{python3_version} %endif %define default_suffix %{?default_py3:-%{python3_version}}%{!?default_py3:-%{python_version}} ln -s osad%{default_suffix} $RPM_BUILD_ROOT/usr/sbin/osad # osa-dispatcher is python2 even on Fedora ln -s osa-dispatcher%{default_suffix} $RPM_BUILD_ROOT/usr/sbin/osa-dispatcher mkdir -p %{buildroot}%{_var}/log/rhn touch %{buildroot}%{_var}/log/osad touch %{buildroot}%{_var}/log/rhn/osa-dispatcher.log %if 0%{?fedora} || 0%{?rhel} > 6 sed -i 's/#LOGROTATE-3.8#//' $RPM_BUILD_ROOT%{_sysconfdir}/logrotate.d/osa-dispatcher %endif %if 0%{?fedora} || 0%{?suse_version} >= 1210 || 0%{?rhel} >= 7 rm $RPM_BUILD_ROOT/%{_initrddir}/osad rm $RPM_BUILD_ROOT/%{_initrddir}/osa-dispatcher mkdir -p $RPM_BUILD_ROOT/%{_unitdir} install -m 0644 osad.service $RPM_BUILD_ROOT/%{_unitdir}/ install -m 0644 osa-dispatcher.service $RPM_BUILD_ROOT/%{_unitdir}/ %endif %if 0%{?include_selinux_package} for selinuxvariant in %{selinux_variants} do install -d %{buildroot}%{_datadir}/selinux/${selinuxvariant} install -p -m 644 osa-dispatcher-selinux/%{modulename}.pp.${selinuxvariant} \ %{buildroot}%{_datadir}/selinux/${selinuxvariant}/%{modulename}.pp done # Install SELinux interfaces install -d %{buildroot}%{_datadir}/selinux/devel/include/%{moduletype} install -p -m 644 osa-dispatcher-selinux/%{modulename}.if \ %{buildroot}%{_datadir}/selinux/devel/include/%{moduletype}/%{modulename}.if # Hardlink identical policy module packages together /usr/sbin/hardlink -cv %{buildroot}%{_datadir}/selinux # Install osa-dispatcher-selinux-enable which will be called in %%post install -d %{buildroot}%{_sbindir} install -p -m 755 osa-dispatcher-selinux/osa-dispatcher-selinux-enable %{buildroot}%{_sbindir}/osa-dispatcher-selinux-enable %endif %if ! 0%{?build_py2} rm -rf $RPM_BUILD_ROOT/%{python_sitelib}/osad/osad* rm -f $RPM_BUILD_ROOT/usr/sbin/osad-%{python_version} %endif mkdir -p %{buildroot}%{_var}/log/rhn touch %{buildroot}%{_var}/log/osad touch %{buildroot}%{_var}/log/rhn/osa-dispatcher.log %if 0%{?suse_version} %py_compile -O %{buildroot}/%{python_sitelib} %if 0%{?build_py3} %py3_compile -O %{buildroot}/%{python3_sitelib} %endif %endif %if 0%{?suse_version} # add rclinks %if 0%{?suse_version} < 1210 ln -sf ../../etc/init.d/osad %{buildroot}%{_sbindir}/rcosad ln -sf ../../etc/init.d/osa-dispatcher %{buildroot}%{_sbindir}/rcosa-dispatcher %else ln -s %{_sbindir}/service %{buildroot}%{_sbindir}/rcosad ln -s %{_sbindir}/service %{buildroot}%{_sbindir}/rcosa-dispatcher %endif %endif %{!?systemd_post: %global systemd_post() if [ $1 -eq 1 ] ; then /usr/bin/systemctl enable %%{?*} >/dev/null 2>&1 || : ; fi; } %{!?systemd_preun: %global systemd_preun() if [ $1 -eq 0 ] ; then /usr/bin/systemctl --no-reload disable %%{?*} > /dev/null 2>&1 || : ; /usr/bin/systemctl stop %%{?*} >/dev/null 2>&1 || : ; fi; } %{!?systemd_postun_with_restart: %global systemd_postun_with_restart() /usr/bin/systemctl daemon-reload >/dev/null 2>&1 || : ; if [ $1 -ge 1 ] ; then /usr/bin/systemctl try-restart %%{?*} >/dev/null 2>&1 || : ; fi; } %post ARG=$1 %if 0%{?suse_version} >= 1210 %service_add_post osad.service if [ $ARG -eq 1 ] ; then # executed only in case of install /usr/bin/systemctl enable osad.service >/dev/null 2>&1 /usr/bin/systemctl start osad.service ||: fi %else if [ -f %{_sysconfdir}/init.d/osad ]; then /sbin/chkconfig --add osad ||: fi if [ -f %{_unitdir}/osad.service ]; then %systemd_post osad.service if [ "$1" = "2" ]; then # upgrade from old init.d if [ -L /etc/rc2.d/S97osad ]; then /usr/bin/systemctl enable osad.service >/dev/null 2>&1 fi rm -f /etc/rc?.d/[SK]??osad fi fi # Fix the /var/log/osad permission BZ 836984 if [ -f %{_var}/log/osad ]; then /bin/chmod 600 %{_var}/log/osad fi if [ $ARG -eq 1 ] ; then # executed only in case of install /sbin/service osad start ||: fi %endif %preun %if 0%{?suse_version} >= 1210 %service_del_preun osad.service %else if [ $1 = 0 ]; then %if 0%{?fedora} || 0%{?rhel} >= 7 %systemd_preun osad.service %else /sbin/service osad stop > /dev/null 2>&1 /sbin/chkconfig --del osad %endif fi %endif %postun %if 0%{?fedora} || 0%{?rhel} >= 7 %systemd_postun osad.service %else %if 0%{?suse_version} >= 1210 %service_del_postun -n osad.service %endif %endif %posttrans if [ -x /usr/bin/systemctl ]; then ( test "$YAST_IS_RUNNING" = instsys && exit 0 test -f /etc/sysconfig/services -a \ -z "$DISABLE_RESTART_ON_UPDATE" && . /etc/sysconfig/services test "$DISABLE_RESTART_ON_UPDATE" = yes -o \ "$DISABLE_RESTART_ON_UPDATE" = 1 && exit 0 /usr/bin/systemctl try-restart osad.service ) || : fi %if 0%{?suse_version} >= 1210 %pre %service_add_pre osad.service %pre -n mgr-osa-dispatcher %service_add_pre osa-dispatcher.service %postun -n mgr-osa-dispatcher %service_del_postun osa-dispatcher.service %endif %post -n mgr-osa-dispatcher %if 0%{?suse_version} >= 1210 %service_add_post osa-dispatcher.service %else if [ -f %{_sysconfdir}/init.d/osa-dispatcher ]; then /sbin/chkconfig --add osa-dispatcher ||: fi if [ -f %{_unitdir}/osa-dispatcher.service ]; then %systemd_post osa-dispatcher.service if [ "$1" = "2" ]; then # upgrade from old init.d if [ -L /etc/rc2.d/S86osa-dispatcher ]; then /usr/bin/systemctl enable osa-dispatcher.service >/dev/null 2>&1 fi rm -f /etc/rc?.d/[SK]??osa-dispatcher fi fi %endif %preun -n mgr-osa-dispatcher %if 0%{?suse_version} >= 1210 %service_del_preun osa-dispatcher.service %else if [ $1 = 0 ]; then %if 0%{?fedora} || 0%{?rhel} >= 7 %systemd_preun osa-dispatcher.service %else /sbin/service osa-dispatcher stop > /dev/null 2>&1 /sbin/chkconfig --del osa-dispatcher %endif fi %endif %if 0%{?include_selinux_package} %post -n mgr-osa-dispatcher-selinux if /usr/sbin/selinuxenabled ; then %{_sbindir}/osa-dispatcher-selinux-enable fi %posttrans -n mgr-osa-dispatcher-selinux #this may be safely remove when BZ 505066 is fixed if /usr/sbin/selinuxenabled ; then rpm -ql osa-dispatcher | xargs -n 1 /sbin/restorecon -rvi {} /sbin/restorecon -vvi /var/log/rhn/osa-dispatcher.log fi %postun -n mgr-osa-dispatcher-selinux # Clean up after package removal if [ $1 -eq 0 ]; then for selinuxvariant in %{selinux_variants} do /usr/sbin/semanage module -s ${selinuxvariant} -l > /dev/null 2>&1 \ && /usr/sbin/semodule -s ${selinuxvariant} -r %{modulename} || : done fi rpm -ql osa-dispatcher | xargs -n 1 /sbin/restorecon -rvi {} /sbin/restorecon -vvi /var/log/rhn/osa-dispatcher.log %endif %files %defattr(-,root,root) %{_sbindir}/osad %config(noreplace) %{_sysconfdir}/sysconfig/rhn/osad.conf %config(noreplace) %attr(600,root,root) %{_sysconfdir}/sysconfig/rhn/osad-auth.conf %config(noreplace) %{client_caps_dir}/* %if 0%{?fedora} || 0%{?suse_version} >= 1210 || 0%{?rhel} >= 7 %{_unitdir}/osad.service %else %attr(755,root,root) %{_initrddir}/osad %endif %doc LICENSE %config(noreplace) %attr(644,root,root) %{_sysconfdir}/logrotate.d/osad %ghost %attr(600,root,root) %{_var}/log/osad %if 0%{?suse_version} %{_sbindir}/rcosad # provide directories not owned by any package during build %dir %{_sysconfdir}/sysconfig/rhn %dir %{_sysconfdir}/sysconfig/rhn/clientCaps.d %endif %if 0%{?build_py2} %files -n python2-%{name} %defattr(-,root,root) %attr(755,root,root) %{_sbindir}/osad-%{python_version} %dir %{python_sitelib}/osad %{python_sitelib}/osad/osad.py* %{python_sitelib}/osad/osad_client.py* %{python_sitelib}/osad/osad_config.py* %endif %if 0%{?build_py3} %files -n python3-%{name} %defattr(-,root,root) %attr(755,root,root) %{_sbindir}/osad-%{python3_version} %dir %{python3_sitelib}/osad %{python3_sitelib}/osad/osad.py* %{python3_sitelib}/osad/osad_client.py* %{python3_sitelib}/osad/osad_config.py* %dir %{python3_sitelib}/osad/__pycache__ %{python3_sitelib}/osad/__pycache__/osad.* %{python3_sitelib}/osad/__pycache__/osad_client.* %{python3_sitelib}/osad/__pycache__/osad_config.* %endif %files -n mgr-osa-dispatcher %defattr(0644,root,root,0755) %{_sbindir}/osa-dispatcher %config(noreplace) %{_sysconfdir}/sysconfig/osa-dispatcher %config(noreplace) %{_sysconfdir}/logrotate.d/osa-dispatcher %{rhnroot}/config-defaults/rhn_osa-dispatcher.conf %dir %{_sysconfdir}/rhn/tns_admin %dir %{_sysconfdir}/rhn/tns_admin/osa-dispatcher %config(noreplace) %{_sysconfdir}/rhn/tns_admin/osa-dispatcher/sqlnet.ora %if 0%{?fedora} || 0%{?suse_version} >= 1210 || 0%{?rhel} >= 7 %{_unitdir}/osa-dispatcher.service %else %attr(755,root,root) %{_initrddir}/osa-dispatcher %endif %attr(770,root,%{apache_group}) %dir %{_var}/log/rhn/oracle %attr(770,root,root) %dir %{_var}/log/rhn/oracle/osa-dispatcher %doc LICENSE %ghost %attr(640,%{apache_user},root) %{_var}/log/rhn/osa-dispatcher.log %if 0%{?suse_version} %{_sbindir}/rcosa-dispatcher %attr(750, root, %{apache_group}) %dir %{_sysconfdir}/rhn %dir %{rhnroot} %attr(755,root,%{apache_group}) %dir %{rhnroot}/config-defaults %dir %{_sysconfdir}/rhn/tns_admin %attr(770,root,%{apache_group}) %dir %{_var}/log/rhn %endif %files -n python2-mgr-osa-dispatcher %defattr(-,root,root) %attr(755,root,root) %{_sbindir}/osa-dispatcher-%{python_version} %dir %{python_sitelib}/osad %{python_sitelib}/osad/osa_dispatcher.py* %{python_sitelib}/osad/dispatcher_client.py* %if 0%{?build_py3} %files -n python3-mgr-osa-dispatcher %defattr(-,root,root) %attr(755,root,root) %{_sbindir}/osa-dispatcher-%{python3_version} %dir %{python3_sitelib}/osad %{python3_sitelib}/osad/osa_dispatcher.py* %{python3_sitelib}/osad/dispatcher_client.py* %{python3_sitelib}/osad/__pycache__/osa_dispatcher.* %{python3_sitelib}/osad/__pycache__/dispatcher_client.* %endif %files -n python2-mgr-osa-common %defattr(-,root,root) %{python_sitelib}/osad/__init__.py* %{python_sitelib}/osad/jabber_lib.py* %{python_sitelib}/osad/rhn_log.py* %if 0%{?build_py3} %files -n python3-mgr-osa-common %defattr(-,root,root) %{python3_sitelib}/osad/__init__.py* %{python3_sitelib}/osad/jabber_lib.py* %{python3_sitelib}/osad/rhn_log.py* %{python3_sitelib}/osad/__pycache__/__init__.* %{python3_sitelib}/osad/__pycache__/jabber_lib.* %{python3_sitelib}/osad/__pycache__/rhn_log.* %endif %if 0%{?include_selinux_package} %files -n mgr-osa-dispatcher-selinux %defattr(-,root,root) %doc osa-dispatcher-selinux/%{modulename}.fc %doc osa-dispatcher-selinux/%{modulename}.if %doc osa-dispatcher-selinux/%{modulename}.te %{_datadir}/selinux/*/%{modulename}.pp %{_datadir}/selinux/devel/include/%{moduletype}/%{modulename}.if %doc LICENSE %attr(0755,root,root) %{_sbindir}/osa-dispatcher-selinux-enable %endif %changelog 0707010000000E000041FD0000000000000000000000015DA8415F00000000000000000000000000000000000000000000002000000000mgr-osad/osa-dispatcher-selinux0707010000000F000081B40000000000000000000000015DA8415F000002F4000000000000000000000000000000000000003E00000000mgr-osad/osa-dispatcher-selinux/osa-dispatcher-selinux-enable#!/bin/bash # make sure osa_dispatcher_upstream_notif_server_port_t has been removed /usr/sbin/semanage port -ln \ | awk -F'[ ,]+' '/osa_dispatcher_upstream_notif_server_port_t +tcp / {for (n=3;n<=NF;n++) {print $n}}' \ | while read port ; do /usr/sbin/semanage port -d -t osa_dispatcher_upstream_notif_server_port_t -p tcp $port || : done # Install SELinux policy modules for selinuxvariant in mls strict targeted do /usr/sbin/semanage module -l -S ${selinuxvariant} > /dev/null 2>&1 \ && /usr/sbin/semodule -s ${selinuxvariant} -i \ /usr/share/selinux/${selinuxvariant}/osa-dispatcher.pp || : done rpm -ql osa-dispatcher | xargs -n 1 /sbin/restorecon -rvi {} /sbin/restorecon -vvi /var/log/rhn/osa-dispatcher.log 07070100000010000081B40000000000000000000000015DA8415F00000164000000000000000000000000000000000000003200000000mgr-osad/osa-dispatcher-selinux/osa-dispatcher.fc/usr/sbin/osa-dispatcher(-\d.\d)? gen_context(system_u:object_r:osa_dispatcher_exec_t,s0) /var/log/rhn/osa-dispatcher\.log gen_context(system_u:object_r:osa_dispatcher_log_t,s0) /var/log/rhn/oracle/osa-dispatcher gen_context(system_u:object_r:osa_dispatcher_log_t,s0) /var/run/osa-dispatcher\.pid gen_context(system_u:object_r:osa_dispatcher_var_run_t,s0) 07070100000011000081B40000000000000000000000015DA8415F00000021000000000000000000000000000000000000003200000000mgr-osad/osa-dispatcher-selinux/osa-dispatcher.if## This file is empty (for now). 07070100000012000081B40000000000000000000000015DA8415F00000BF4000000000000000000000000000000000000003200000000mgr-osad/osa-dispatcher-selinux/osa-dispatcher.tepolicy_module(osa-dispatcher,@@VERSION@@) require { type var_log_t; type spacewalk_log_t; type httpd_sys_content_t; type jabber_client_port_t; type inaddr_any_node_t; type postgresql_port_t; } type osa_dispatcher_t; type osa_dispatcher_exec_t; init_daemon_domain(osa_dispatcher_t,osa_dispatcher_exec_t) allow init_t osa_dispatcher_exec_t:lnk_file read; allow osa_dispatcher_t osa_dispatcher_exec_t:lnk_file { getattr read }; type osa_dispatcher_log_t; logging_log_file(osa_dispatcher_log_t) type osa_dispatcher_var_run_t; files_pid_file(osa_dispatcher_var_run_t) files_pid_filetrans(osa_dispatcher_t,osa_dispatcher_var_run_t,file) create_files_pattern(osa_dispatcher_t,var_run_t,osa_dispatcher_var_run_t) write_files_pattern(osa_dispatcher_t,var_run_t,osa_dispatcher_var_run_t) files_read_etc_files(osa_dispatcher_t) libs_use_ld_so(osa_dispatcher_t) libs_use_shared_libs(osa_dispatcher_t) miscfiles_read_localization(osa_dispatcher_t) corecmd_exec_bin(osa_dispatcher_t) kernel_read_system_state(osa_dispatcher_t) files_read_usr_files(osa_dispatcher_t) dev_read_urand(osa_dispatcher_t) files_search_var(osa_dispatcher_t) allow osa_dispatcher_t var_log_t:dir search_dir_perms; allow osa_dispatcher_t spacewalk_log_t:dir search_dir_perms; # We cannot use logging_log_filetrans here because /var/log/rhn has # type spacewalk_log_t. filetrans_pattern(osa_dispatcher_t,spacewalk_log_t,osa_dispatcher_log_t,{ file dir }) manage_files_pattern(osa_dispatcher_t,osa_dispatcher_log_t,osa_dispatcher_log_t) init_rw_utmp(osa_dispatcher_t) read_files_pattern(osa_dispatcher_t,httpd_sys_content_t,httpd_sys_content_t) allow osa_dispatcher_t self:fifo_file rw_fifo_file_perms; gen_require(` type lo_node_t; ') allow osa_dispatcher_t lo_node_t:udp_socket node_bind; corenet_udp_bind_all_nodes(osa_dispatcher_t) corenet_udp_bind_generic_node(osa_dispatcher_t) sysnet_dns_name_resolve(osa_dispatcher_t) allow osa_dispatcher_t jabber_client_port_t:tcp_socket name_connect; allow osa_dispatcher_t postgresql_port_t:tcp_socket name_connect; corenet_all_recvfrom_unlabeled(osa_dispatcher_t) corenet_all_recvfrom_netlabel(osa_dispatcher_t) allow osa_dispatcher_t self:process { setpgid setsched getsched }; allow osa_dispatcher_t self:capability { sys_nice chown fowner sys_tty_config }; allow osa_dispatcher_t inaddr_any_node_t:tcp_socket node_bind; allow osa_dispatcher_t osa_dispatcher_t:tcp_socket listen; files_list_tmp(osa_dispatcher_t) optional_policy(` tunable_policy(`allow_ypbind',` nis_use_ypbind_uncond(osa_dispatcher_t) ') ') optional_policy(` gen_require(` type oracle_port_t; ') allow osa_dispatcher_t oracle_port_t:tcp_socket name_connect; ') postgresql_stream_connect(osa_dispatcher_t) kernel_read_kernel_sysctls(osa_dispatcher_t) dev_list_sysfs(osa_dispatcher_t) dev_read_sysfs(osa_dispatcher_t) require { class netlink_route_socket { write getattr read bind create nlmsg_read }; } allow osa_dispatcher_t self:netlink_route_socket { write getattr read bind create nlmsg_read }; allow osa_dispatcher_t self:process execmem; 07070100000013000081B40000000000000000000000015DA8415F00000023000000000000000000000000000000000000003B00000000mgr-osad/osa-dispatcher-selinux/osa-dispatcher.te.fedora17auth_read_passwd(osa_dispatcher_t) 07070100000014000081B40000000000000000000000015DA8415F0000009B000000000000000000000000000000000000003B00000000mgr-osad/osa-dispatcher-selinux/osa-dispatcher.te.fedora26sssd_read_public_files(osa_dispatcher_t) sssd_run_stream_connect(osa_dispatcher_t) sssd_search_lib(osa_dispatcher_t) sssd_stream_connect(osa_dispatcher_t) 07070100000015000081B40000000000000000000000015DA8415F0000016B000000000000000000000000000000000000002000000000mgr-osad/osa-dispatcher.service[Unit] Description=OSA Dispatcher daemon After=syslog.target network.target jabberd.service [Service] Type=forking EnvironmentFile=-/etc/sysconfig/osa-dispatcher PIDFile=/var/run/osa-dispatcher.pid ExecStart=/usr/sbin/osa-dispatcher --pid-file /var/run/osa-dispatcher.pid ExecStartPre=/bin/rm -f /var/run/osa-dispatcher.pid [Install] WantedBy=multi-user.target 07070100000016000041FD0000000000000000000000015DA8415F00000000000000000000000000000000000000000000001300000000mgr-osad/osad-conf07070100000017000081B40000000000000000000000015DA8415F000001AD000000000000000000000000000000000000001C00000000mgr-osad/osad-conf/Makefile# Makefile for installation of the RHN server configuration files # # what is the backend top dir TOP = .. INSTALL_FILES = $(wildcard *.conf) INSTALL_DEST = /etc/sysconfig/rhn CAPS = osad CAPS_DIR = /etc/sysconfig/rhn/clientCaps.d EXTRA_DIRS = $(CAPS_DIR) include $(TOP)/Makefile.defs install :: install-caps install-caps :: $(CAPS) $(PREFIX)$(CAPS_DIR) $(INSTALL_DATA) $(CAPS) $(PREFIX)$(CAPS_DIR) 07070100000018000081B40000000000000000000000015DA8415F00000023000000000000000000000000000000000000001800000000mgr-osad/osad-conf/osadosad.ping(1)=1 osad.rhn_check(1)=1 07070100000019000081B40000000000000000000000015DA8415F00000028000000000000000000000000000000000000002200000000mgr-osad/osad-conf/osad-auth.conf# Automatically generated. Do not edit! 0707010000001A000081B40000000000000000000000015DA8415F000006F9000000000000000000000000000000000000001D00000000mgr-osad/osad-conf/osad.conf[osad] # don't change this systemid = /etc/sysconfig/rhn/systemid # increase for debugging output debug_level = 0 # don't change this... used in substitutions below. # if you get rid of the '%(server_handler)s' bits below, # the *MUST* be replaced with this value... server_handler = /XMLRPC # Protocol to talk upstream proto = https # to use a server other than what up2date is configured to use, # do something along the lines of: # server_url = https://some.example.com%(server_handler)s # server_url = http://another.example.net:8080%(server_handler)s # server_url = https://yet.another.example.org:8081/XMLRPC server_url = %(proto)s://%(server_name)s%(server_handler)s # the following fields are inherited from up2date's configuration, # but are overridable in this file # enableProxy = 1 # enableProxyAuth = 1 # httpProxy = some.proxy.example.com:3030 # proxyUser = proxy_user_name # proxyPassword = proxy_password # Use a different certificate from what up2date is using # This should point to the satellite certificate for # server_name osa_ssl_cert = logfile = /var/log/osad max_time_drift = 120 run_rhn_check = 1 # Default command to run when asked by the dispatcher rhn_check_command = /usr/sbin/rhn_check # By default we only use the first jabber server. # Turn the enable_failover option to 1 if you want the connections # to try Satellite's jabberd if Proxy's is not available. enable_failover = 0 # Enable kernel keepalive timer on the osad client side socket # in case the satellite/proxy side socket is closed without osad realising it # After 'tcp_keepalive_timeout' seconds the kernel will probe the connection # After 'tcp_keepalive_count' unsuccessful probes, the kernel will close the connection tcp_keepalive_timeout = 1800 tcp_keepalive_count = 3 0707010000001B000081B40000000000000000000000015DA8415F00000106000000000000000000000000000000000000001600000000mgr-osad/osad.service[Unit] Description=OSAD daemon After=syslog.target network.target [Service] Type=forking KillMode=process EnvironmentFile=-/etc/sysconfig/osad PIDFile=/var/run/osad.pid ExecStart=/usr/sbin/osad --pid-file /var/run/osad.pid [Install] WantedBy=multi-user.target 0707010000001C000081FD0000000000000000000000015DA8415F00000711000000000000000000000000000000000000001300000000mgr-osad/prog.init#!/bin/sh # # @@PROG@@ This shell script starts the @@PROG@@ daemon # # chkconfig: - 86 04 # description: @@PROG@@ is a daemon used by the Spacewalk # ### BEGIN INIT INFO # Provides: @@PROG@@ # Required-Start: $local_fs $network # Required-Stop: $local_fs $network # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: This shell script starts the @@PROG@@ daemon # Description: @@PROG@@ is a daemon used by the Spacewalk ### END INIT INFO # Source function library. . /etc/rc.d/init.d/functions # Source networking configuration. . /etc/sysconfig/network # Source prog-specific configuration if [ -f /etc/sysconfig/@@PROG@@ ]; then . /etc/sysconfig/@@PROG@@ fi # Check that networking is up. [ "${NETWORKING}" = "no" ] && exit 0 RETVAL=0 prog="@@PROG@@" script="/usr/sbin/@@PROG@@" [ -f $script ] || exit 0 start() { # Start daemon echo -n "Starting $prog: " if [ "$prog" == "osa-dispatcher" ]; then /usr/sbin/spacewalk-startup-helper wait-for-jabberd fi daemon $script --pid-file /var/run/$prog.pid RETVAL=$? echo [ $RETVAL -eq 0 ] && touch /var/lock/subsys/$prog return $RETVAL } stop() { # Stop daemon echo -n "Shutting down $prog: " killproc $prog RETVAL=$? echo [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/$prog return $RETVAL } # See how we were called. case "$1" in start) start ;; stop) stop ;; restart|reload) stop start ;; status) status "$script" RETVAL=$? ;; condrestart) if status "$script" >/dev/null; then stop start fi ;; *) echo $"Usage: $0 {start|stop|restart|reload|status|condrestart}" exit 1 esac exit $RETVAL 0707010000001D000081FD0000000000000000000000015DA8415F0000062F000000000000000000000000000000000000001800000000mgr-osad/prog.init.SUSE#!/bin/sh # # @@PROG@@ This shell script starts the @@PROG@@ daemon # # chkconfig: - 81 04 # description: @@PROG@@ is a daemon used by the Spacewalk # ### BEGIN INIT INFO # Provides: @@PROG@@ # Required-Start: $syslog $local_fs $network $remote_fs # Required-Stop: $syslog $local_fs $network $remote_fs # Should-Start: oracle-xe oracle jabberd postgresql # Should-Stop: oracle-xe oracle jabberd postgresql # Default-Start: 3 5 # Default-Stop: 0 1 6 # Short-Description: This shell script starts the @@PROG@@ daemon # Description: @@PROG@@ is a daemon used by the Spacewalk ### END INIT INFO # Source function library. . /etc/rc.status prog="@@PROG@@" script="/usr/sbin/@@PROG@@" PIDFILE="/var/run/@@PROG@@.pid" [ -f $script ] || exit 0 start() { # Start daemon echo -n "Starting $prog: " startproc -p $PIDFILE $script --pid-file="$PIDFILE" rc_status -v } stop() { # Stop daemon echo -n "Shutting down $prog: " killproc -p $PIDFILE $script rc_status -v } # See how we were called. case "$1" in start) start ;; stop) stop ;; restart|reload) stop start ;; status) echo -n "Checking for service $prog: " checkproc -p $PIDFILE $script rc_status -v ;; condrestart|try-restart) $0 status if test $? = 0; then $0 restart else rc_reset fi rc_status ;; *) echo $"Usage: $0 {start|stop|restart|reload|status|condrestart}" exit 1 esac rc_exit 0707010000001E000081B40000000000000000000000015DA8415F00001396000000000000000000000000000000000000001200000000mgr-osad/pylintrc# mgr-osad package pylint configuration [MASTER] # Profiled execution. profile=no # Pickle collected data for later comparisons. persistent=no [MESSAGES CONTROL] # Disable the message(s) with the given id(s). disable=I0011, C0302, C0111, R0801, R0902, R0903, R0904, R0912, R0913, R0914, R0915, R0921, R0922, W0142, W0403, W0603, C1001, W0121, useless-else-on-loop, bad-whitespace, unpacking-non-sequence, superfluous-parens, cyclic-import, redefined-variable-type, no-else-return, # Uyuni disabled E0203, E0611, E1101, E1102 # list of disabled messages: #I0011: 62: Locally disabling R0201 #C0302: 1: Too many lines in module (2425) #C0111: 1: Missing docstring #R0902: 19:RequestedChannels: Too many instance attributes (9/7) #R0903: Too few public methods #R0904: 26:Transport: Too many public methods (22/20) #R0912:171:set_slots_from_cert: Too many branches (59/20) #R0913:101:GETServer.__init__: Too many arguments (11/10) #R0914:171:set_slots_from_cert: Too many local variables (38/20) #R0915:171:set_slots_from_cert: Too many statements (169/50) #W0142:228:MPM_Package.write: Used * or ** magic #W0403: 28: Relative import 'rhnLog', should be 'backend.common.rhnLog' #W0603: 72:initLOG: Using the global statement # for pylint-1.0 we also disable #C1001: 46, 0: Old-style class defined. (old-style-class) #W0121: 33,16: Use raise ErrorClass(args) instead of raise ErrorClass, args. (old-raise-syntax) #W:243, 8: Else clause on loop without a break statement (useless-else-on-loop) # pylint-1.1 checks #C:334, 0: No space allowed after bracket (bad-whitespace) #W:162, 8: Attempting to unpack a non-sequence defined at line 6 of (unpacking-non-sequence) #C: 37, 0: Unnecessary parens after 'not' keyword (superfluous-parens) #C:301, 0: Unnecessary parens after 'if' keyword (superfluous-parens) [REPORTS] # Set the output format. Available formats are text, parseable, colorized, msvs # (visual studio) and html output-format=parseable # Include message's id in output include-ids=yes # Tells whether to display a full report or only the messages reports=yes # Template used to display messages. This is a python new-style format string # used to format the message information. See doc for all details msg-template="{path}:{line}: [{msg_id}({symbol}), {obj}] {msg}" [VARIABLES] # A regular expression matching names used for dummy variables (i.e. not used). dummy-variables-rgx=_|dummy [BASIC] # Regular expression which should only match correct module names #module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ module-rgx=([a-zA-Z_][a-zA-Z0-9_]+)$ # Regular expression which should only match correct module level names const-rgx=(([a-zA-Z_][a-zA-Z0-9_]*)|(__.*__))$ # Regular expression which should only match correct class names class-rgx=[a-zA-Z_][a-zA-Z0-9_]+$ # Regular expression which should only match correct function names function-rgx=[a-z_][a-zA-Z0-9_]{,42}$ # Regular expression which should only match correct method names method-rgx=[a-z_][a-zA-Z0-9_]{,42}$ # Regular expression which should only match correct instance attribute names attr-rgx=[a-z_][a-zA-Z0-9_]{,30}$ # Regular expression which should only match correct argument names argument-rgx=[a-z_][a-zA-Z0-9_]{,30}$ # Regular expression which should only match correct variable names variable-rgx=[a-z_][a-zA-Z0-9_]{,30}$ # Regular expression which should only match correct list comprehension / # generator expression variable names inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ # Regular expression which should only match correct class sttribute names class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,42}|(__.*__))$ # Good variable names which should always be accepted, separated by a comma good-names=i,j,k,ex,Run,_ # Bad variable names which should always be refused, separated by a comma bad-names=foo,bar,baz,toto,tutu,tata # List of builtins function names that should not be used, separated by a comma bad-functions=apply,input [DESIGN] # Maximum number of arguments for function / method max-args=10 # Maximum number of locals for function / method body max-locals=20 # Maximum number of return / yield for function / method body max-returns=6 # Maximum number of branch for function / method body max-branchs=20 # Maximum number of statements in function / method body max-statements=50 # Maximum number of parents for a class (see R0901). max-parents=7 # Maximum number of attributes for a class (see R0902). max-attributes=7 # Minimum number of public methods for a class (see R0903). min-public-methods=1 # Maximum number of public methods for a class (see R0904). max-public-methods=20 [CLASSES] [FORMAT] # Maximum number of characters on a single line. max-line-length=120 # Maximum number of lines in a module max-module-lines=1000 # String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 # tab). indent-string=' ' [MISCELLANEOUS] # List of note tags to take in consideration, separated by a comma. notes= 0707010000001F000041FD0000000000000000000000015DA8415F00000000000000000000000000000000000000000000001200000000mgr-osad/rhn-conf07070100000020000081B40000000000000000000000015DA8415F000000DC000000000000000000000000000000000000001B00000000mgr-osad/rhn-conf/Makefile# Makefile for installation of the RHN server configuration files # # what is the backend top dir TOP = .. INSTALL_FILES = $(wildcard *.conf) INSTALL_DEST = /usr/share/rhn/config-defaults include $(TOP)/Makefile.defs 07070100000021000081B40000000000000000000000015DA8415F00000164000000000000000000000000000000000000002A00000000mgr-osad/rhn-conf/rhn_osa-dispatcher.conf# Default log file log_file = /var/log/rhn/osa-dispatcher.log # SSL cert osa_ssl_cert = /usr/share/rhn/RHNS-OSA-CERT # Jabber server to connect to jabber_server = jabberserver.example.org:5234 poll_interval = 5 # number of systems that can run actions until # osad-dispatcher stops notifying more clients. # default: 100 notify_threshold = 100 07070100000022000041FD0000000000000000000000015DA8415F00000000000000000000000000000000000000000000000D00000000mgr-osad/src07070100000023000081B40000000000000000000000015DA8415F0000010E000000000000000000000000000000000000001600000000mgr-osad/src/Makefile# Makefile for spacewalk backend # # what is the backend top dir TOP = .. # Specific stuff SUBDIR = osad FILES = __init__ dispatcher_client jabber_lib osa_dispatcher \ osad_client osad osad_config rhn_log include $(TOP)/Makefile.defs 07070100000024000081B40000000000000000000000015DA8415F00000266000000000000000000000000000000000000001900000000mgr-osad/src/__init__.py# # Copyright (c) 2008--2013 Red Hat, Inc. # # This software is licensed to you under the GNU General Public License, # version 2 (GPLv2). There is NO WARRANTY for this software, express or # implied, including the implied warranties of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2 # along with this software; if not, see # http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. # # Red Hat trademarks are not licensed under GPLv2. No permission is # granted to use or replicate Red Hat trademarks that are incorporated # in this software or its documentation. # 07070100000025000081B40000000000000000000000015DA8415F00001E80000000000000000000000000000000000000002200000000mgr-osad/src/dispatcher_client.py# # Copyright (c) 2008--2016 Red Hat, Inc. # # This software is licensed to you under the GNU General Public License, # version 2 (GPLv2). There is NO WARRANTY for this software, express or # implied, including the implied warranties of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2 # along with this software; if not, see # http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. # # Red Hat trademarks are not licensed under GPLv2. No permission is # granted to use or replicate Red Hat trademarks that are incorporated # in this software or its documentation. # import time import sys from spacewalk.common.rhnLog import log_debug from spacewalk.server import rhnSQL try: # python 2 import jabber_lib except ImportError: # python 3 from osad import jabber_lib class Client(jabber_lib.JabberClient): def __init__(self, *args, **kwargs): jabber_lib.JabberClient.__init__(self, *args, **kwargs) self.username = None self.resource = None #self.DEBUG = jabber_lib.my_debug def start(self, username, password, resource): # XXX find a better name for this function log_debug(2) self.auth(username, password, resource) log_debug(3, "Authenticated") self.username = username self.resource = resource self.jid = "%s@%s/%s" % (self.username, self._host, self.resource) self.username = username self.resource = resource def _add_jid_resource(self, jid, resource): if not isinstance(jid, jabber_lib.jabber.JID) or jid.resource: return jid return jabber_lib.jabber.JID(str(jid) + '/' + resource) def _fix_jid(self, jid): return self._add_jid_resource(jid, 'osad') def _check_signature(self, stanza, actions=None): # Do we have this client in the table? jid = stanza.getFrom() if jid is None: log_debug(3, 'no from') return None jid = str(self._fix_jid(jid)) # Look for a <x> child that has our namespace xes = stanza.getTags('x') for x in xes: if x.getNamespace() != jabber_lib.NS_RHN_SIGNED: continue break else: #for log_debug(1, "No signature node found in stanza") return None # We now have our signature node x_client_id = x.getAttr('client-id') row = lookup_client_by_name(x_client_id) if not row: log_debug(3, 'no client found', x_client_id) if self.debug_level > 5: raise Exception(1) return None shared_key = row['shared_key'] timestamp = x.getAttr('timestap') serial = x.getAttr('serial') action = x.getAttr('action') if actions and action not in actions: log_debug(1, "action %s not allowed" % action) return None attrs = { 'client-id' : x_client_id, 'timestamp' : x.getAttr('timestamp'), 'serial' : x.getAttr('serial'), 'action' : x.getAttr('action'), 'jid' : jid, } signing_comps = ['client-id', 'timestamp', 'serial', 'action', 'jid'] args = [shared_key, self.jid] for sc in signing_comps: args.append(attrs[sc]) log_debug(4, "Signature args", args) signature = jabber_lib.sign(*args) x_signature = x.getAttr('signature') if signature != x_signature: log_debug(1, "Signatures do not match", signature, x_signature) if self.debug_level > 5: raise Exception(1) return None # Happy joy return x def _create_signature(self, jid, action): row = lookup_client_by_jid(jid) if not row: log_debug(3, 'no client found for jid', jid) if self.debug_level > 5: raise Exception(1) return None full_jid = row['jabber_id'] shared_key = row['shared_key'] attrs = { 'timestamp' : int(time.time()), 'serial' : self.get_unique_id(), 'action' : action, 'jid' : self.jid, } signing_comps = ['timestamp', 'serial', 'action', 'jid'] args = [shared_key, full_jid] for sc in signing_comps: args.append(attrs[sc]) log_debug(4, "Signature args", args) attrs['signature'] = jabber_lib.sign(*args) x = jabber_lib.jabber.xmlstream.Node('x') x.setNamespace(jabber_lib.NS_RHN_SIGNED) for k, v in attrs.items(): x.putAttr(k, v) return x def _message_callback(self, client, stanza): log_debug(4) assert stanza.getName() == 'message' # Actions we know how to react to actions = [ jabber_lib.NS_RHN_MESSAGE_RESPONSE_CHECKIN, jabber_lib.NS_RHN_MESSAGE_RESPONSE_PING, ] sig = self._check_signature_from_message(stanza, actions) if not sig: return self.update_client_message_received(stanza.getFrom()) action = sig.getAttr('action') if action == jabber_lib.NS_RHN_MESSAGE_RESPONSE_PING: log_debug(1, 'Ping response') # XXX return def ping_clients(self, clients): for client in clients: jid = client['jabber_id'] if jid is None: continue self.send_message(jid, jabber_lib.NS_RHN_MESSAGE_REQUEST_PING) def set_jid_available(self, jid): jabber_lib.JabberClient.set_jid_available(self, jid) self._set_state(jid, self._get_push_state_id('online')) def set_jid_unavailable(self, jid): jabber_lib.JabberClient.set_jid_unavailable(self, jid) self._set_state(jid, self._get_push_state_id('offline')) _query_set_state = rhnSQL.Statement(""" update rhnPushClient set state_id = :state_id, last_ping_time = NULL, next_action_time = NULL where jabber_id = :jid """) def _set_state(self, jid, state_id): h = rhnSQL.prepare(self._query_set_state) h.execute(state_id=state_id, jid=str(jid)) rhnSQL.commit() def _get_push_state_id(self, state): t = rhnSQL.Table('rhnPushClientState', 'label') row = t[state] assert row is not None return row['id'] _query_update_client_message_received = rhnSQL.Statement(""" update rhnPushClient set state_id = :state_id, last_message_time = current_timestamp, last_ping_time = NULL, next_action_time = NULL where jabber_id = :jid """) def update_client_message_received(self, jid): jid = str(jid) state_id = self._get_push_state_id('online') h = rhnSQL.prepare(self._query_update_client_message_received) ret = h.execute(jid=jid, state_id=state_id) rhnSQL.commit() class InvalidClientError(Exception): pass def lookup_client_by_name(client_name): client_name = str(client_name) t = rhnSQL.Table('rhnPushClient', 'name') row = t[client_name] if row is None: raise InvalidClientError(client_name) return row def lookup_client_by_jid(jid): if not isinstance(jid, jabber_lib.jabber.JID): jid = jabber_lib.jabber.JID(jid) if not jid.getResource(): # add the resource so we can find the guy in our table jid.setResource('osad') jid = str(jid) t = rhnSQL.Table('rhnPushClient', 'jabber_id') row = t[jid] if row is None: raise InvalidClientError(jid) return row 07070100000026000081B40000000000000000000000015DA8415F0000CFB8000000000000000000000000000000000000001B00000000mgr-osad/src/jabber_lib.py# # Copyright (c) 2008--2017 Red Hat, Inc. # # This software is licensed to you under the GNU General Public License, # version 2 (GPLv2). There is NO WARRANTY for this software, express or # implied, including the implied warranties of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2 # along with this software; if not, see # http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. # # Red Hat trademarks are not licensed under GPLv2. No permission is # granted to use or replicate Red Hat trademarks that are incorporated # in this software or its documentation. # import os import hashlib import sys import time import select import socket import random import fnmatch from optparse import OptionParser, Option import traceback from rhn import SSL try: # python 2 from rhn_log import log_debug, log_error except ImportError: # python 3 from osad.rhn_log import log_debug, log_error from spacewalk.common.usix import raise_with_tb from rhn.i18n import bstr import warnings try: warnings.filterwarnings("ignore", category=DeprecationWarning) import jabber finally: warnings.resetwarnings() NS_RHN = "http://jabber.rhn.redhat.com/jabber" NS_RHN_SIGNED = "%s/signed" % NS_RHN NS_RHN_PRESENCE_SUBSCRIBE = "%s/presence/subscribe" % NS_RHN NS_RHN_PRESENCE_SUBSCRIBED = "%s/presence/subscribed" % NS_RHN NS_RHN_PRESENCE_UNSUBSCRIBE = "%s/presence/unsubscribe" % NS_RHN NS_RHN_MESSAGE_REQUEST_CHECKIN = "%s/message/request/checkin" % NS_RHN NS_RHN_MESSAGE_RESPONSE_CHECKIN = "%s/message/response/checkin" % NS_RHN NS_RHN_MESSAGE_REQUEST_PING = "%s/message/request/ping" % NS_RHN NS_RHN_MESSAGE_RESPONSE_PING = "%s/message/response/ping" % NS_RHN NS_STARTTLS = 'urn:ietf:params:xml:ns:xmpp-tls' NS_STANZAS = "urn:ietf:params:xml:ns:xmpp-stanzas" # The class that starts everything class Runner(object): option_parser = OptionParser option = Option client_factory = None # How often will we try to reconnect. We want this randomized, so not all # clients hit the server at the same time _min_sleep = 60 _max_sleep = 90 def __init__(self): self.options_table = [ self.option("-v", "--verbose", action="count", help="Increase verbosity"), self.option('-N', "--nodetach", action="store_true", help="Suppress backgrounding and detachment of the process"), self.option('--pid-file', action="store", help="Write to this PID file"), self.option('--logfile', action="store", help="Write log information to this file"), ] self.ssl_cert = None self.debug_level = 0 self._jabber_servers = [] self._connected_jabber_server = None self._username = None self._password = None self._resource = None self._in_background = 0 self._use_proxy = 0 def process_cli_options(self): "Process command line options" self._parser = self.option_parser(option_list=self.options_table) self.options, self.args = self._parser.parse_args() def main(self): """Method that starts up everything - processes command line options - big loop to reconnect if necessary - read config - setup config - setup jabber connection - process requests """ self.process_cli_options() force_setup = 0 no_fork = None while 1: # First time around? if no_fork is None: # Yes, we may be forking no_fork=0 else: # Been here before, no need to fork anymore no_fork=1 try: config = self.read_config() if force_setup: log_debug(2,"###Forcing setup") self.setup_config(config, 1) force_setup = 0 else: self.setup_config(config) c = self.setup_connection(no_fork=no_fork) self.fix_connection(c) self.process_forever(c) except KeyboardInterrupt: try: c.disconnect() except: pass sys.exit(0) except SystemExit: raise except RestartRequested: e = sys.exc_info()[1] log_error("Restart requested", e) if not self.is_in_background(): self.push_to_background() continue except NeedRestart: e = sys.exc_info()[1] log_debug(3, "Need Restart") force_setup = 1 continue except JabberConnectionError: time_to_sleep = random.randint(self._min_sleep, self._max_sleep) log_debug(0, "Unable to connect to jabber servers, sleeping" " %s seconds" % time_to_sleep) if not self.is_in_background(): self.push_to_background() try: time.sleep(time_to_sleep) except KeyboardInterrupt: sys.exit(0) except InvalidCertError: e = sys.exc_info()[1] log_error("Invalid Cert Error:") raise except: # Print traceback log_error("Error caught:") log_error(extract_traceback()) time_to_sleep = random.randint(self._min_sleep, self._max_sleep) log_debug(3, "Sleeping", time_to_sleep, "seconds") if not self.is_in_background(): self.push_to_background() try: time.sleep(time_to_sleep) except KeyboardInterrupt: sys.exit(0) def fix_connection(self, client): "After setting up the connection, do whatever else is necessary" return client def preprocess_once(self, client): return client def process_forever(self, client): """Big loop to process requests """ log_debug(1) self.preprocess_once(client) while 1: try: self.process_once(client) # random sleep so we don't kill CPU performance, bz 222988 time_to_sleep = random.randint(6, 10) time.sleep(time_to_sleep) except KeyboardInterrupt: # CTRL+C client.disconnect() sys.exit(0) except: # XXX to be refined later raise def process_once(self, client): "To be overridden in a client class" raise NotImplementedError def setup_config(self, config): pass def read_config(self): return {} def is_in_background(self): return self._in_background def push_to_background(self): if not self.options.nodetach: # Detach and push to the background push_to_background() self._in_background = 1 pid_file = self.options.pid_file if pid_file: try: os.unlink(pid_file) except OSError: e = sys.exc_info()[1] if e.errno != 2: raise try: # Make sure we don't create the file world-writable (#162619) fd = os.open(pid_file, os.O_WRONLY| os.O_APPEND | os.O_CREAT, int("0644", 8)) os.write(fd, bstr("%d" % os.getpid())) os.write(fd, bstr("\n")) os.close(fd) except OSError: pass def check_cert(self, cert): return check_cert(cert) def print_message(self, js, e): log_debug(1, e) log_debug(1, "Could not connect to jabber server", js) def setup_connection(self, no_fork=0): """ - initializes a Jabber connection (by instantiating a Jabber client) - if necessary, pushes to background - authentication and resource binding (by calling start()) Possible causes for this function to return None: - jabber server is not started - jabber server is started but did not initialize SSL just yet This function will kill the process with exit code 1 if the SSL handshake failed (an indication of a mismatching CA cert). We do this so starting the program as a daemon to fail if this happens. Of course, if the server is down and the CA cert is bad, then the daemon will start but will silently fail afterwards; the error log should have a traceback though. """ for js in self._jabber_servers: log_debug(3, "Connecting to", js) try: c = self._get_jabber_client(js) log_debug(1, "Connected to jabber server", js) self._connected_jabber_server = js break except SSLHandshakeError: # Error doing the handshake - this is a permanent error sys.exit(1) except socket.error: e = sys.exc_info()[1] self.print_message(js, "socket error") log_error(extract_traceback()) continue except JabberError: e = sys.exc_info()[1] self.print_message(js, "JabberError") log_error(extract_traceback()) continue except SSLError: e = sys.exc_info()[1] self.print_message(js, "SSLError") log_error(extract_traceback()) continue else: # Ran out of Jabber servers to try # Could not connect to any servers log_debug(1, "Could not connect to any jabber server") # Make sure we push to background at this point, we don't want the # service to block at startup if not no_fork: self.push_to_background() raise JabberConnectionError # If we got to this point, we have a connection set up if not no_fork: self.push_to_background() # Autentication and resource binding c.start(username=self._username, password=self._password, resource=self._resource) # Register callbacks c.custom_handler.register_callback(c._presence_callback, 'presence') c.custom_handler.register_callback(c._message_callback, 'message') c.custom_handler.register_callback(self._error_callback, 'error') return c def _get_jabber_client(self, jabber_server): """Returns a connected Jabber client, or raises an exception if it was unable to connect""" log_debug(3) arr = jabber_server.split(':', 1) jabber_server = arr[0] cf = self.read_config() jabberpy_proxy_dict = None if self._use_proxy and 'proxy_url' in cf: jabberpy_proxy_dict = {'host': cf['proxy_url'].split(':')[0], 'port': int(cf['proxy_url'].split(':')[1])} if cf['enable_proxy_auth']: jabberpy_proxy_dict['user'] = cf['proxy_user']; jabberpy_proxy_dict['password'] = cf['proxy_password']; if len(arr) == 2: jabber_port = int(arr[1]) log_debug(2, "Connecting to", jabber_server, jabber_port) c = self.client_factory(jabber_server, jabber_port, proxy=jabberpy_proxy_dict) else: log_debug(2, "Connecting to", jabber_server) c = self.client_factory(jabber_server, proxy=jabberpy_proxy_dict) c.debug_level = self.debug_level c.add_trusted_cert(self.ssl_cert) c.connect() return c def _error_callback(self, client, stanza): """Logs error stanza messages for diagnostic purposes""" log_error("Received an error stanza: ", stanza) for kid in stanza.kids: if kid.getName() == "conflict": log_error("Received an conflict. Restarting with new credentials.") raise NeedRestart class InvalidCertError(SSL.SSL.Error): def __str__(self): return " ".join(self.args) __repr__ = __str__ def check_cert(cert_path): if cert_path is None: raise InvalidCertError("Cannot pass None as a certificate path") try: c = open(cert_path) cert = c.read() c.close() except IOError: raise_with_tb(InvalidCertError("Unable to read file", cert_path), sys.exc_info()[2]) try: x509 = SSL.crypto.load_certificate(SSL.crypto.FILETYPE_PEM, cert) except SSL.crypto.Error: raise_with_tb(InvalidCertError("Unable to open certificate", cert_path), sys.exc_info()[2]) log_debug(4, "Loading cert", x509.get_subject()) if x509.has_expired(): raise InvalidCertError("Expired certificate", cert_path) def sign(secret_key, *values): h = hashlib.new('sha1', bstr(secret_key)).hexdigest() for v in values: h = hashlib.new('sha1', bstr("%s%s" % (h, v))).hexdigest() return h # getAttr is braindead, rewrite it class JabberProtocolNode(jabber.Protocol): def getAttr(self, key): return self.attrs.get(key, None) class JabberIqNode(jabber.Iq, JabberProtocolNode): getAttr = JabberProtocolNode.getAttr class JabberMessageNode(jabber.Message, JabberProtocolNode): getAttr = JabberProtocolNode.getAttr class JabberPresenceNode(jabber.Presence, JabberProtocolNode): getAttr = JabberProtocolNode.getAttr class Handlers: def __init__(self): log_debug(3) self._handlers = {} def dispatch(self, client, stanza): log_debug(5, stanza) self.cleanup_expired_callbacks() callbacks = self._get_callbacks(stanza) if not callbacks: log_debug(4, "Unhandled stanza", stanza) return for callback in callbacks: log_debug(6, "Calling callback", callback, stanza) callback(client, stanza) def _get_callbacks(self, stanza): log_debug(5, stanza) stanza_name = stanza.getName() if stanza_name not in self._handlers: return [] stanza_id = stanza.getID() stanza_ns = stanza.getNamespace() result = {} (h_idns, h_id, h_ns, l_def) = self._handlers[stanza_name] if stanza_id is not None and stanza_ns: cbs = h_idns.get((stanza_id, stanza_ns), []) self._get_callbacks_from_list(cbs, result) if stanza_id is not None: cbs = h_id.get(stanza_id, []) self._get_callbacks_from_list(cbs, result) if stanza_ns: cbs = h_ns.get(stanza_ns, []) self._get_callbacks_from_list(cbs, result) self._get_callbacks_from_list(l_def, result) return list(result.keys()) def _get_callbacks_from_list(self, l, result_hash): for ent in l: (callback, expiry, usage_count) = ent[:3] if usage_count is None or usage_count >= 1: result_hash[callback] = None if usage_count is None: # We're done here continue usage_count = usage_count - 1 if usage_count <= 0: # Expired l.remove(ent) continue # Update the usage count ent[2] = usage_count - 1 def register_callback(self, callback, stanza_name, stanza_id=None, stanza_ns=None, timeout=None, usage_count=None): log_debug(3, callback, stanza_name, stanza_id, stanza_ns, timeout, usage_count) if timeout: expiry = time.time() + timeout else: expiry = None callback_entry = [callback, expiry, usage_count] h_idns, h_id, h_ns, l_def = self._get_from_hash(self._handlers, stanza_name, default_value=({}, {}, {}, [])) # h_id is for all the callbacks we should call for a particular stanza # id; h_ns is for namespaces if stanza_id is not None and stanza_ns: l = self._get_from_hash(h_idns, (stanza_id, stanza_ns), []) l.append(callback_entry) return if stanza_id is not None: l = self._get_from_hash(h_id, stanza_id, []) l.append(callback_entry) return if stanza_ns: l = self._get_from_hash(h_ns, stanza_ns, []) l.append(callback_entry) return # Default callback l_def.append(callback_entry) def _get_from_hash(self, h, key, default_value): if key in h: val = h[key] else: val = h[key] = default_value return val def cleanup_expired_callbacks(self): log_debug(5) now = time.time() for stanza_name, vals in self._handlers.items(): h_idns, h_id, h_ns, l_def = vals for h in (h_idns, h_id, h_ns): self._expire_callbacks_hash(h, now) self._expire_callbacks_list(l_def, now) def _expire_callbacks_hash(self, h, now): log_debug(6, now) for key, vals in h.items(): self._expire_callbacks_list(vals, now) def _expire_callbacks_list(self, vals, now): log_debug(7, vals, now) for val in vals: (callback, expiry, usage_count) = val if not expiry: continue if now <= expiry: # Fresh continue # Callback is stale vals.remove(val) def my_debug(*args): print("Debugging:", args) class RestartRequested(Exception): pass class JabberError(Exception): pass class NeedRestart(Exception): pass class TimeoutError(JabberError): pass class SSLError(Exception): "Raised when a lower-level SSL error is caught" pass class SSLHandshakeError(SSLError): "Raised when the SSL handshake failed" pass class SSLDisabledError(SSLError): "Raised if the server does not support SSL" pass class JabberConnectionError(Exception): "Raised when we were unable to make a jabber connection" pass class JabberQualifiedError(JabberError): def __init__(self, errcode, err, *args): self.errcode = errcode self.err = err JabberError.__init__(self, *args) def __repr__(self): return "<%s instance at %s; errcode=%s; err=%s>" % ( self.__class__.__name__, id(self), self.errcode, self.err) __str__ = __repr__ class JabberClient(jabber.Client, object): _seq = 0 BLOCK_SIZE = jabber.xmlstream.BLOCK_SIZE def __init__(self, *args, **kwargs): log_debug(1) jabber.Client.__init__(self, *args, **kwargs) self.jid = None # Lots of magic to add the nodes into a queue self._incoming_node_queue = [] self.debug_level = 0 self.trusted_certs = [] self.registerProtocol('unknown', JabberProtocolNode) self.registerProtocol('iq', JabberIqNode) self.registerProtocol('message', JabberMessageNode) self.registerProtocol('presence', JabberPresenceNode) self.registerProtocol('error', JabberProtocolNode) self.registerHandler('iq', self._expectedIqHandler, system=True) self.registerHandler('iq', self._IqRegisterResult, 'result', jabber.NS_REGISTER, system=True) h = Handlers() self.custom_handler = h self.registerHandler('presence', h.dispatch) self.registerHandler('iq', h.dispatch) self.registerHandler('message', h.dispatch) self.registerHandler('error', h.dispatch) self._non_ssl_sock = None self._roster = Roster() self._uniq_client_string = generate_random_string(6) def add_trusted_cert(self, trusted_cert): check_cert(trusted_cert) self.trusted_certs.append(trusted_cert) def connect(self): log_debug(2) if not self.trusted_certs: raise SSLVerifyError("No trusted certs added") # Use our own dispatcher - we need to be able to read one stanza at # the time self.dispatch = self._auth_dispatch log_debug(5, "Attempting to connect") for retry in range(0,3): try: jabber.Client.connect(self) except socket.error: e = sys.exc_info()[1] log_error("Error connecting to jabber server: %s. " "See https://access.redhat.com/solutions/327903 for more information. " % e) raise socket.error(e) log_debug(5, "Connected") # From the XMPP Core Internet Draft: # server advertises <features><starttls /></features> # client sends back <starttls /> # server responds with <proceed /> # Wait for a stanza stanza = self.get_one_stanza() log_debug(5, "Expecting features stanza, got:", stanza) if stanza.getName() != 'features': log_debug(1, "Server did not return a <features /> stanza," " reconnecting") self.disconnect() time.sleep(1) else: break else: log_error("Not able to reconnect - " "See https://access.redhat.com/solutions/45332 for possible solutions.\n") raise SSLDisabledError starttls_node = stanza.getTag('starttls') log_debug(5, "starttls node", starttls_node) if starttls_node is None: log_error("Server does not support TLS - <starttls /> " "not in <features /> stanza") self.disconnect() raise SSLDisabledError # Initiate the TLS stream self.write("<starttls xmlns='%s' />" % NS_STARTTLS) stanza = self.get_one_stanza() log_debug(5, "Expecting proceed stanza, got:", stanza) if stanza.getName() != 'proceed': log_error("Server broke TLS negotiation - <proceed /> not sent") self.disconnect() raise SSLDisabledError log_debug(4, "Preparing for TLS handshake") ssl = SSLSocket(self._sock, trusted_certs=self.trusted_certs) ssl.ssl_verify_callback = self.ssl_verify_callback ssl.init_ssl() # Explicitly perform the SSL handshake try: ssl.do_handshake() self.verify_peer(ssl) except SSL.SSL.Error: # Error in the SSL handshake - most likely mismatching CA cert log_error("Traceback caught:") log_error(extract_traceback()) raise_with_tb(SSLHandshakeError(), sys.exc_info()[2]) # Re-init the parsers jabber.xmlstream.Stream.connect(self) # Now replace the socket with the ssl object's connection self._non_ssl_sock = self._sock self._sock = ssl._connection # jabber.py has copies of _read, _write, _reader - those have to # be re-initialized as well self._setupComms() # Send the header again self.send(self._header_string()) # Read the server's open stream tag self.process() stanza = self.get_one_stanza() if stanza.getName() != 'features': self.disconnect() raise Exception("Server did not pass any features?") # Now replace the dispatcher self.dispatch = self._orig_dispatch log_debug(5, "connect returning") def disconnect(self): try: jabber.Client.disconnect(self) except SSL.SSL.Error: pass def _setupComms(self): # We pretty much only support TCP connections self._read = self._sock.recv if hasattr(self._sock, 'sendall'): self._write = self._sock.sendall else: self._write = Sendall(self._sock).sendall self._reader = self._sock def ssl_verify_callback(self, conn, cert, errnum, depth, ok): log_debug(4, "Called", errnum, depth, ok) if not ok: log_error("SSL certificate verification failed") self.write("</stream:stream>") conn.close() self._sock.close() return ok return ok def verify_peer(self, ssl): cert = ssl.get_peer_certificate() if cert is None: raise SSLVerifyError("Unable to retrieve peer cert") subject = cert.get_subject() if not hasattr(subject, 'CN'): raise SSLVerifyError("Certificate has no Common Name") common_name = subject.CN # Add a trailing . since foo.example.com. is equal to foo.example.com # This also catches non-FQDNs if common_name[-1] != '.': common_name = common_name + '.' hdot = self._host if hdot[-1] != '.': hdot = hdot + '.' if common_name != hdot and not fnmatch.fnmatchcase(hdot, common_name): raise SSLVerifyError("Mismatch: peer name: %s; common name: %s" % (self._host, common_name)) def retrieve_roster(self): """Request the roster. Will register the roster callback, but the call will wait for the roster to be properly populated""" # Register the roster callback self.custom_handler.register_callback(self._roster_callback, 'iq') iq_node_id = 'iq-request-%s' % self.get_unique_id() iq_node = JabberIqNode(type="get") iq_node.setQuery(jabber.NS_ROSTER) iq_node.setID(iq_node_id) self.send(iq_node) stanza = None # Wait for an IQ stanza with the same ID as the one we sent while 1: stanza = self.get_one_stanza() node_id = stanza.getAttr('id') if node_id == iq_node_id: # This is the response break # We now have the roster populated # All entries of type "from" and ask="subscribe" should be answered to for k, v in self._roster.get_subscribed_from().items(): if 'ask' in v and v['ask'] == 'subscribe': self.send_presence(k, type="subscribed") else: # Ask for a subscription self.send_presence(k, type="subscribe") def _roster_callback(self, client, stanza): log_debug(3, "Updating the roster", stanza) # Extract the <query> node qnode = stanza.getTag('query') if qnode is None or qnode.getNamespace() != jabber.NS_ROSTER: # No query log_debug(5, "Query node not found, skipping") return # This gets called any time a roster event is received node_type = stanza.getAttr('type') if node_type not in ('result', 'set'): log_debug(5, "Not a result or a set, skipping") return # Now extract the <item> nodes for node in qnode.getTags('item'): self._roster.add_item(node) def cancel_subscription(self, jids): if not jids: return qnode = JabberProtocolNode("query") qnode.setNamespace(jabber.NS_ROSTER) for jid in jids: attrs = { 'jid' : jid, 'subscription' : 'remove', } inode = JabberProtocolNode("item", attrs=attrs) qnode.insertNode(inode) node = JabberIqNode(type="set") remove_iq_id = "remove-%s" % self.get_unique_id() node.setID(remove_iq_id) node.insertNode(qnode) self.send(node) def get_one_stanza(self, timeout=None): """Returns one stanza (or None if timeout is set)""" if timeout: start = time.time() while not self._incoming_node_queue: if timeout: now = time.time() if now >= start + timeout: # Timed out log_debug(4, "timed out", now, start, timeout) return None tm = start + timeout - now else: tm = None # No nodes in the queue, read some data self.process(timeout=tm) # Now we have nodes in the queue node = self._incoming_node_queue[0] del self._incoming_node_queue[0] return node def _build_stanza(self, stanza): """Builds one stanza according to the handlers we have registered via registerHandler or registerProtocol""" name = stanza.getName() if name not in self.handlers: name = 'unknown' # XXX This is weird - why is jabbberpy using type which is a type? stanza = self.handlers[name][type](node=stanza) return stanza def _orig_dispatch(self, stanza): log_debug(6, stanza) if self.debug_level > 5: # Even more verbosity sys.stderr.write("<-- ") sys.stderr.write(str(stanza)) sys.stderr.write("\n\n") # Even though Client.dispatch does build a stanza properly, we have to # do it ourselves too since dispatch doesn't return the modified # stanza, so it was always of type Node (i.e. the top-level class) stanza = self._build_stanza(stanza) jabber.Client.dispatch(self, stanza) self._incoming_node_queue.append(stanza) def _auth_dispatch(self, stanza): log_debug(6, stanza) if self.debug_level > 5: # Even more verbosity sys.stderr.write("<-- ") sys.stderr.write(str(stanza)) sys.stderr.write("\n\n") # Create the stanza of the proper type stanza = self._build_stanza(stanza) self._incoming_node_queue.append(stanza) def auth(self, username, password, resource, register=1): """Try to authenticate the username with the specified password If the authentication fails, try to register the user. If that fails as well, then JabberQualifiedError is raised """ log_debug(2, username, password, resource, register) auth_iq_id = "auth-get-%s" % self.get_unique_id() auth_get_iq = jabber.Iq(type='get') auth_get_iq.setID(auth_iq_id) q = auth_get_iq.setQuery(jabber.NS_AUTH) q.insertTag('username').insertData(username) self.send(auth_get_iq) log_debug(4, "Sending auth request", auth_get_iq) try: auth_response = self.waitForResponse(auth_iq_id, timeout=60) except JabberQualifiedError: e = sys.exc_info()[1] if not register: raise if e.errcode == '401': # Need to register the user if possible log_debug(4, "Need to register") self.register(username, password) return self.auth(username, password, resource, register=0) raise log_debug(4, "Auth response", auth_response) auth_ret_query = auth_response.getTag('query') auth_set_id = "auth-set-%s" % self.get_unique_id() auth_set_iq = jabber.Iq(type="set") auth_set_iq.setID(auth_set_id) q = auth_set_iq.setQuery(jabber.NS_AUTH) q.insertTag('username').insertData(username) q.insertTag('resource').insertData(resource) if auth_ret_query.getTag('token'): token = auth_ret_query.getTag('token').getData() seq = auth_ret_query.getTag('sequence').getData() h = hashlib.new('sha1', hashlib.new('sha1', password).hexdigest() + token).hexdigest() for i in range(int(seq)): h = hashlib.new('sha1', h).hexdigest() q.insertTag('hash').insertData(h) elif auth_ret_query.getTag('digest'): digest = q.insertTag('digest') digest.insertData(hashlib.new('sha1', bstr(self.getIncomingID() + password)).hexdigest() ) else: q.insertTag('password').insertData(password) log_debug(4, "Sending auth info", auth_set_iq) try: self.SendAndWaitForResponse(auth_set_iq) except JabberQualifiedError: e = sys.exc_info()[1] if e.errcode == '401': # Need to reserve the user if possible log_debug(4, "Need to register") return self.register(username, password) raise log_debug(4, "Authenticated") return True def send(self, stanza): if self.debug_level > 5: sys.stderr.write("--> ") sys.stderr.write(str(stanza)) sys.stderr.write("\n\n") return jabber.Client.send(self, stanza) def subscribe_to_presence(self, jids): """Subscribe to these nodes' presence The subscription in jabber works like this: Contact 1 State Contact 1 State Contact 2 Contact 2 ----------+-------------------+------------------+---------- subscribe -> [ none + ask ] [ from ] <- subscribed [ to ] [ from + ask ] <- subscribe subscribed -> [ both ] [ both ] ----------+-------------------+------------------+---------- Enclosed in square brackets is the state when the communication took place. """ subscribed_to = self._roster.get_subscribed_to() log_debug(4, "Subscribed to", subscribed_to) subscribed_both = self._roster.get_subscribed_both() log_debug(4, "Subscribed both", subscribed_both) subscribed_none = self._roster.get_subscribed_none() log_debug(4, "Subscribed none", subscribed_none) subscribed_from = self._roster.get_subscribed_from() log_debug(4, "Subscribed from", subscribed_from) for full_jid in jids: jid = self._strip_resource(full_jid) jid = str(jid) if jid in subscribed_both: log_debug(4, "Already subscribed to the presence of node", jid) continue # If to or from subscription for this node, we still send the # subscription request, but we shouldn't drop the subscription, so # we take the jid out of the respective hash if jid in subscribed_to: log_debug(4, "Subscribed to") continue if jid in subscribed_none: ent = subscribed_none[jid] if 'ask' in ent and ent['ask'] == 'subscribe': log_debug(4, "Subscribed none + ask=subscribe") # We already asked for a subscription continue if jid in subscribed_from: ent = subscribed_from[jid] if 'ask' in ent and ent['ask'] == 'subscribe': log_debug(4, "Subscribed from + ask=subscribe") # We already asked for a subscription continue # Make sure we update the roster ourselves, to avoid sending # presence subscriptions twice # At this point we should only have 2 cases left: either from or # none. if jid in self._roster._subscribed_from: subscription = "from" hashd = self._roster._subscribed_from else: subscription = "none" hashd = self._roster._subscribed_none hashd[jid] = { 'jid' : jid, 'subscription' : subscription, 'ask' : 'subscribe', } # subscribe this node to the jid's presence log_debug(4, jid) stripped_jid = self._strip_resource(jid) presence_node = JabberPresenceNode(to=stripped_jid, type="subscribe") presence_node.setID("presence-%s" % self.get_unique_id()) sig = self._create_signature(jid, NS_RHN_PRESENCE_SUBSCRIBE) if sig: presence_node.insertNode(sig) log_debug(5, "Sending presence subscription request", presence_node) self.send(presence_node) # XXX Here we should clean up everybody that is no longer online, but # this is more difficult def send_presence(self, jid=None, type=None, xid=None): log_debug(3, jid, type) if jid is None: node = JabberPresenceNode() else: node = JabberPresenceNode(to=jid) if type: node.setType(type) if xid: node.setID(xid) self.send(node) def fileno(self): return self._reader.fileno() def read(self): received = '' while 1: rfds, wfds, exfds = select.select([self.fileno()], [], [], 0) if not rfds: # No input break buff = self._read(self.BLOCK_SIZE) if not buff: break received = received + buff if not received: # EOF reached self.disconnected(self) return received def process_loop_hook(self): pass def process(self, timeout=None): log_debug(3, timeout) self._incoming_node_queue = [] fileno = self.fileno() # Wait for a node or until we hit the timeout start = time.time() while 1: now = time.time() if timeout: if now >= start + timeout: # Timed out return 0 tm = start + timeout - now else: tm = None self.process_loop_hook() # tm is the number of seconds we have to wait (or None) log_debug(5, "before select(); timeout", tm) rfds, wfds, exfds = select.select([fileno], [], [], tm) log_debug(5, "select() returned") if not rfds: # Timed out return 0 # Try to read as much data as possible if hasattr(self._sock, 'pending'): # This is on the SSL case - select() will use the native # socket's file descriptor. SSL may decode more data than we # are willing to read - so just read what's available log_debug(5, "Reading %s bytes from ssl socket" % self.BLOCK_SIZE) try: data = self._read(self.BLOCK_SIZE) except SSL.SSL.SysCallError: e = sys.exc_info()[1] log_debug(5, "Closing socket") self._non_ssl_sock.close() raise_with_tb(SSLError("OpenSSL error; will retry", str(e)), sys.exc_info()[2]) log_debug(5, "Read %s bytes" % len(data)) if not data: raise JabberError("Premature EOF") self._parser.Parse(data) pending = self._sock.pending() if pending: # More bytes to read from the SSL socket data = self._read(pending) self._parser.Parse(data) else: # Normal socket - select will figure out correctly if the read # will block data = self._read(self.BLOCK_SIZE) if not data: raise JabberError("Premature EOF") self._parser.Parse(data) # We may not have read enough data to be able to produce a node if not self._incoming_node_queue: # Go back and read some more if timeout: # Trying to wait some more before giving up in this call continue # No reason to block again, return into the higher-level # select() return 0 return len(self._incoming_node_queue) return 0 def register(self, username, password): log_debug(2, username, password) self.requestRegInfo() d = self.getRegInfo() if 'username' in d: self.setRegInfo('username', username) if 'password' in d: self.setRegInfo('password', password) try: self.sendRegInfo() except JabberQualifiedError: e = sys.exc_info()[1] if e.errcode == '409': # Need to register the user if possible log_error("Invalid password") self.disconnect() sys.exit(0) raise return True def _waitForResponse(self, ID, timeout=jabber.timeout): log_debug(5, ID, timeout) # jabberpy's function waits when it shouldn't so have to rebuild it ID = jabber.ustr(ID) self.lastErr = '' self.lastErrCode = 0 if timeout is not None: abort_time = time.time() + timeout self.DEBUG("waiting with timeout:%s for %s" % (timeout, ID), jabber.DBG_NODE_IQ) else: self.DEBUG("waiting for %s" % ID, jabber.DBG_NODE_IQ) while 1: if timeout is None: tmout = None else: tmout = abort_time - time.time() if tmout <= 0: # Timed out break log_debug(5, "before get_one_stanza") stanza = self.get_one_stanza(tmout) log_debug(5, "after get_one_stanza") if not stanza: # get_one_stanza should only return None for a timeout assert timeout is not None break error_code = stanza.getErrorCode() if error_code: # Error self.lastErr = stanza.getError() self.lastErrCode = error_code return None # Is it the proper stanza ID? tid = jabber.ustr(stanza.getID()) if ID == tid: # This is the node return stanza # Keep looking for stanzas until we time out (if a timeout was # passed) # Timed out self.lastErr = "Timeout" return None def waitForResponse(self, ID, timeout=jabber.timeout): result = self._waitForResponse(ID, timeout=timeout) if result is not None: return result if self.lastErr == 'Timeout': raise TimeoutError() if self.lastErrCode: raise JabberQualifiedError(self.lastErrCode, self.lastErr) raise JabberError("Unknown error", self.lastErr) def get_unique_id(self): seq = self._seq JabberClient._seq = seq + 1 return "%s-%s" % (self._uniq_client_string, seq) def disconnectHandler(self, conn): pass # Need to add the version tothe XML stream def _header_string(self): self.DEBUG("jabber_lib.JabberClient.header: sending initial header", jabber.DBG_INIT) templ = "<?xml version='1.0' encoding='UTF-8'?><stream:stream %s>" attrs = { 'to' : self._host, 'xmlns' : self._namespace, 'xmlns:stream' : "http://etherx.jabber.org/streams", 'version' : '1.0', } if self._outgoingID: attrs['id'] = self._outgoingID # XXX Add more custom attributes here addition = [] for k, v in attrs.items(): addition.append("%s='%s'" % (k, v)) addition = " ".join(addition) return templ % addition def header(self): header = self._header_string() self.send(header) self.process(jabber.timeout) def _fix_jid(self, jid): return jid def _presence_callback(self, client, stanza): """ If the roster is enabled, presence stanzas with type="subscribed" should never be received - the server will initiate a roster push instead """ jid = stanza.getFrom() presence_type = stanza.getType() log_debug(3, self.jid, jid, presence_type) stanza_id = stanza.getID() assert(stanza.getName() == 'presence') # We may not get the full JID here if presence_type is None or presence_type == 'subscribed': log_debug(4, "Node is available", jid, presence_type) self.set_jid_available(jid) # Now subscribe this node to the other node's presence, just in # case self.subscribe_to_presence([jid]) return if presence_type in ('unsubscribed', 'unavailable'): log_debug(4, "Node is unavailable", jid, presence_type) self.set_jid_unavailable(jid) return if presence_type == 'subscribe': # XXX misa 20051111: don't check signatures for presence anymore, # the fact they expire makes them unreliable #sig = self._check_signature(stanza) #if not sig: # print("KKKKKK", stanza) # log_debug(1, "Invalid signature", jid) # return log_debug(4, "Subscription request approved", jid) self.send_presence(jid, type="subscribed", xid=stanza_id) # Now subscribe this node to the other node's presence self.subscribe_to_presence([jid]) return if presence_type == 'probe': log_debug(4, "Presence probe", jid) self.send(JabberPresenceNode(to=jid)) def _check_signature(self, stanza, actions=None): return 1 def _strip_resource(self, jid): return strip_resource(jid) def _create_signature(self, jid, action): return None def send_message(self, jid, action): node = JabberMessageNode(to=jid, type='normal') sig = self._create_signature(jid, action) if sig: node.insertNode(sig) self.send(node) def jid_available(self, jid): return self._roster.jid_available(jid) def set_jid_available(self, jid): return self._roster.set_available(jid) def set_jid_unavailable(self, jid): return self._roster.set_unavailable(jid) def match_stanza_tags(self, stanza, tag_name, namespace=None): """Get the matching (child) tags of this stanza, possibly with the specified namespace""" tags = stanza.getTags(tag_name) if not tags: return [] if namespace is None: # Nothing more to look for return tags return [x for x in tags if x.getNamespace() == namespace] def _check_signature_from_message(self, stanza, actions): log_debug(4, stanza) assert stanza.getName() == 'message' message_from = stanza.getFrom() message_type = stanza.getType() if message_type == 'error': log_debug(1, 'Received error from %s: %s' % (message_from, stanza)) return None if message_type != 'normal': log_debug(1, 'Unsupported message type %s ignored' % message_type) return None x_delayed_nodes = self.match_stanza_tags(stanza, 'x', namespace=jabber.NS_DELAY) if x_delayed_nodes: log_debug(1, 'Ignoring delayed stanza') return None sig = self._check_signature(stanza, actions=actions) if not sig: if self.debug_level > 5: raise Exception(1) log_debug(1, "Mismatching signatures") return None return sig class SSLSocket(SSL.SSLSocket): pass class SSLVerifyError(SSL.SSL.Error): pass def generate_random_string(length=20): if not length: return '' random_bytes = 16 length = int(length) s = hashlib.new('sha1') s.update(bstr("%.8f" % time.time())) s.update(bstr("%s" % os.getpid())) devrandom = open('/dev/urandom', "rb") result = [] cur_length = 0 while 1: s.update(bstr(devrandom.read(random_bytes))) buf = s.hexdigest() result.append(buf) cur_length = cur_length + len(buf) if cur_length >= length: break devrandom.close() return ''.join(result)[:length].lower() def push_to_background(): log_debug(3, "Pushing process into background") # Push this process into background pid = os.fork() if pid > 0: # Terminate parent process os._exit(0) # Child process becomes a process group leader (and detaches from # terminal) os.setpgrp() # Change working directory os.chdir('/') # Set umask #7/7/05 wregglej 162619 set the umask to 0 so the remote scripts can run os.umask(0) #redirect stdin, stdout, and stderr. for f in sys.stdout, sys.stderr: f.flush() #files we want stdin,stdout and stderr to point to. si = open("/dev/null", 'r') so = open("/dev/null", 'ab+') se = open("/dev/null", 'ab+', 0) os.dup2(si.fileno(), sys.stdin.fileno()) os.dup2(so.fileno(), sys.stdout.fileno()) os.dup2(se.fileno(), sys.stderr.fileno()) # close file descriptors # from subprocess import MAXFD #for i in range(3, MAXFD): # try: # os.close(i) # except: # pass class Roster: def __init__(self): self._subscribed_to = {} self._subscribed_from = {} self._subscribed_both = {} self._subscribed_none = {} self._available_nodes = {} def add_item(self, item): subscr = item.getAttr('subscription') jid = item.getAttr('jid') jid = strip_resource(jid) jid = str(jid) entry = { 'jid' : jid, 'subscription' : subscr, } ask = item.getAttr('ask') if ask: entry['ask'] = ask actions = ['to', 'from', 'both', 'none'] if subscr in actions: for a in actions: d = getattr(self, '_subscribed_' + a) if subscr == a: # Set it d[jid] = entry elif jid in d: # Remove it del d[jid] def get_subscribed_from(self): return self._subscribed_from.copy() def get_subscribed_to(self): return self._subscribed_to.copy() def get_subscribed_both(self): return self._subscribed_both.copy() def get_subscribed_none(self): return self._subscribed_none.copy() def get_subscribed_to_jids(self): ret = self._subscribed_to.copy() ret.update(self._subscribed_both) return ret def get_subscribed_from_jids(self): ret = self._subscribed_from.copy() ret.update(self._subscribed_both) return ret def get_available_nodes(self): return self._available_nodes.copy() def set_available(self, jid): jid = str(jid) self._available_nodes[jid] = 1 def set_unavailable(self, jid): jid = str(jid) if jid in self._available_nodes: del self._available_nodes[jid] def jid_available(self, jid): return jid in self._available_nodes def clear(self): self._subscribed_to.clear() self._subscribed_from.clear() self._subscribed_both.clear() self._subscribed_none.clear() def __repr__(self): return "Roster:\n\tto: %s\n\tfrom: %s\n\tboth: %s\n\tnone: %s" % ( self._subscribed_to.keys(), self._subscribed_from.keys(), self._subscribed_both.keys(), self._subscribed_none.keys(), ) def strip_resource(jid): # One doesn't subscribe to a specific resource if not isinstance(jid, jabber.JID): jid = jabber.JID(jid) return jid.getStripped() def extract_traceback(): return traceback.format_exc(None) class Sendall: """This class exists here because python 1.5.2 does not support a sendall() method for sockets""" def __init__(self, sock): self.sock = sock def sendall(self, data, flags=0): to_send = len(data) if not to_send: # No data return 0 bytes_sent = 0 while 1: ret = self.sock.send(data[bytes_sent:], flags) if bytes_sent + ret == to_send: # We're done break bytes_sent = bytes_sent + ret return to_send 07070100000027000081B40000000000000000000000015DA8415F00003EB8000000000000000000000000000000000000001F00000000mgr-osad/src/osa_dispatcher.py# # Copyright (c) 2008--2017 Red Hat, Inc. # # This software is licensed to you under the GNU General Public License, # version 2 (GPLv2). There is NO WARRANTY for this software, express or # implied, including the implied warranties of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2 # along with this software; if not, see # http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. # # Red Hat trademarks are not licensed under GPLv2. No permission is # granted to use or replicate Red Hat trademarks that are incorporated # in this software or its documentation. # import sys import select import socket import string try: # python 3 import socketserver except ImportError: # python 2 import SocketServer from random import choice from rhn.connections import idn_ascii_to_puny from spacewalk.common.rhnLog import initLOG, log_debug, log_error from spacewalk.common.rhnConfig import initCFG, CFG from spacewalk.server import rhnSQL try: # python 3 from osad import jabber_lib, dispatcher_client except ImportError: # python 2 import jabber_lib, dispatcher_client # Override the log functions jabber_lib.log_debug = log_debug jabber_lib.log_error = log_error def main(): return Runner().main() class Runner(jabber_lib.Runner): client_factory = dispatcher_client.Client # We want the dispatcher to check in quite often in case the jabberd # connection drops _min_sleep = 10 _max_sleep = 10 def __init__(self): jabber_lib.Runner.__init__(self) initCFG("osa-dispatcher") self._notifier = Notifier() self._poll_interval = None self._next_poll_interval = None # Cache states self._state_ids = {} def read_config(self): ret = { 'jabber_server' : CFG.jabber_server, } return ret _query_get_dispatcher_password = """ select id, password from rhnPushDispatcher where jabber_id like :jabber_id """ _update_dispatcher_password = """ update rhnPushDispatcher set password = :password_in where id = :id_in """ def get_dispatcher_password(self, username): h = rhnSQL.prepare(self._query_get_dispatcher_password) h.execute(jabber_id = username + "%") ret = h.fetchall_dict() if ret and len(ret) == 1: if ret[0]['password']: return ret[0]['password'] else: # Upgrade Spacewalk 1.5 -> 1.6: the dispatcher row exists, # we just need to generate and save the password. self._password = self.create_dispatcher_password(32) u = rhnSQL.prepare(self._update_dispatcher_password) u.execute(password_in = self._password, id_in = ret[0]['id']) return self._password else: return None def create_dispatcher_password(self, length): chars = string.ascii_letters + string.digits return "".join(choice(chars) for x in range(length)) def setup_config(self, config, force=0): # Figure out the log level debug_level = self.options.verbose if debug_level is None: debug_level = CFG.debug self.debug_level = debug_level logfile = self.options.logfile if logfile is None or logfile == '': logfile = CFG.log_file initLOG(level=debug_level, log_file=logfile) # Get the ssl cert ssl_cert = CFG.osa_ssl_cert try: self.check_cert(ssl_cert) except jabber_lib.InvalidCertError: e = sys.exc_info()[1] log_error("Invalid SSL certificate:", e) return 1 self.ssl_cert = ssl_cert rhnSQL.initDB() self._username = 'rhn-dispatcher-sat' self._password = self.get_dispatcher_password(self._username) if not self._password: self._password = self.create_dispatcher_password(32) self._resource = 'superclient' js = config.get('jabber_server') self._jabber_servers = [ idn_ascii_to_puny(js) ] def fix_connection(self, c): "After setting up the connection, do whatever else is necessary" self._notifier.set_jabber_connection(c) self._poll_interval = CFG.poll_interval self._next_poll_interval = self._poll_interval if self._jabber_servers and self._jabber_servers[0]: hostname = self._jabber_servers[0] else: hostname = socket.gethostname() self._register_dispatcher(c.jid, hostname) c.retrieve_roster() log_debug(4, "Subscribed to", c._roster.get_subscribed_to()) log_debug(4, "Subscribed from", c._roster.get_subscribed_from()) log_debug(4, "Subscribed both", c._roster.get_subscribed_both()) client_jids = self._get_client_jids() client_jids = [x[0] for x in client_jids] # self-healing no longer works correctly since we blow away jabberd's # db on restart. Instead try to resubscribe jabberd to active jids manually. c.subscribe_to_presence(client_jids) # Unsubscribe the dispatcher from any client jid that no longer exists self.cleanup_roster(c, client_jids) c.send_presence() return c def cleanup_roster(self, client, active_jids): roster = client._roster active_stripped_jids = {} for jid in active_jids: stripped_jid = jabber_lib.strip_resource(jid) stripped_jid = str(stripped_jid) active_stripped_jids[stripped_jid] = None roster_jids = roster.get_subscribed_to() roster_jids.update(roster.get_subscribed_from()) roster_jids.update(roster.get_subscribed_both()) to_remove = [] for jid in roster_jids.keys(): stripped_jid = jabber_lib.strip_resource(jid) stripped_jid = str(stripped_jid) if stripped_jid not in active_stripped_jids: to_remove.append(stripped_jid) client.cancel_subscription(to_remove) def process_once(self, client): log_debug(3) # First, clean up the nodes that have been pinged and have not # responded client.retrieve_roster() self.reap_pinged_clients() need_pinging = self._fetch_clients_to_be_pinged() log_debug(4, "Clients to be pinged:", need_pinging) if need_pinging: client.ping_clients(need_pinging) npi = self._next_poll_interval rfds, wfds, efds = select.select([client], [client], [], npi) # Reset the next poll interval npi = self._next_poll_interval = self._poll_interval if client in rfds: log_debug(5, "before process") client.process(timeout=None) log_debug(5, "after process") if wfds: # Timeout log_debug(5,"Notifying jabber nodes") self._notifier.notify_jabber_nodes() else: log_debug(5,"Not notifying jabber nodes") _query_reap_pinged_clients = rhnSQL.Statement(""" update rhnPushClient set state_id = :offline_id where state_id = :online_id and last_ping_time is not null and current_timestamp > next_action_time """) def reap_pinged_clients(self): # Get the online and offline ids online_id = self._get_push_state_id('online') offline_id = self._get_push_state_id('offline') h = rhnSQL.prepare(self._query_reap_pinged_clients) ret = h.execute(online_id=online_id, offline_id=offline_id) if ret: # We have changed something rhnSQL.commit() _query_fetch_clients_to_be_pinged = rhnSQL.Statement(""" select id, name, shared_key, jabber_id from rhnPushClient where state_id = :online_id and last_ping_time is not null and next_action_time is null and jabber_id is not null """) _query_update_clients_to_be_pinged = rhnSQL.Statement(""" update rhnPushClient set next_action_time = current_timestamp + numtodsinterval(:delta, 'second') where id = :client_id """) def _fetch_clients_to_be_pinged(self): online_id = self._get_push_state_id('online') h = rhnSQL.prepare(self._query_fetch_clients_to_be_pinged) h.execute(online_id=online_id) clients = h.fetchall_dict() or [] rhnSQL.commit() if not clients: # Nothing to do return # XXX Need config option delta = 20 client_ids = [x['id'] for x in clients] deltas = [ delta ] * len(client_ids) h = rhnSQL.prepare(self._query_update_clients_to_be_pinged) h.executemany(client_id=client_ids, delta=deltas) rhnSQL.commit() return clients def _get_push_state_id(self, state): if state in self._state_ids: return self._state_ids[state] t = rhnSQL.Table('rhnPushClientState', 'label') row = t[state] assert row is not None self._state_ids[state] = row['id'] return row['id'] _query_update_register_dispatcher = rhnSQL.Statement(""" update rhnPushDispatcher set last_checkin = current_timestamp, hostname = :hostname_in where jabber_id = :jabber_id_in """) _query_insert_register_dispatcher = rhnSQL.Statement(""" insert into rhnPushDispatcher (id, jabber_id, last_checkin, hostname, password) values (sequence_nextval('rhn_pushdispatch_id_seq'), :jabber_id_in, current_timestamp, :hostname_in, :password_in) """) def _register_dispatcher(self, jabber_id, hostname): h = rhnSQL.prepare(self._query_update_register_dispatcher) rowcount = h.execute(jabber_id_in=jabber_id, hostname_in=hostname, password_in=self._password) if not rowcount: h = rhnSQL.prepare(self._query_insert_register_dispatcher) h.execute(jabber_id_in=jabber_id, hostname_in=hostname, password_in=self._password) rhnSQL.commit() _query_get_client_jids = rhnSQL.Statement(""" select jabber_id, TO_CHAR(modified, 'YYYY-MM-DD HH24:MI:SS') modified from rhnPushClient where jabber_id is not null """) def _get_client_jids(self): h = rhnSQL.prepare(self._query_get_client_jids) h.execute() ret = [] while 1: row = h.fetchone_dict() if not row: break # Save the modified time too - we don't want to mark as offline # clients that just checked in ret.append((row['jabber_id'], row['modified'])) return ret class Notifier: def __init__(self): self._next_poll_interval = None self._notify_threshold = CFG.get('notify_threshold') def get_next_poll_interval(self): return self._next_poll_interval def set_jabber_connection(self, jabber_connection): self.jabber_connection = jabber_connection def get_running_clients(self): log_debug(3) # only with contact_method = default. SSH Push has its own value h = rhnSQL.prepare(self._query_get_running_clients) h.execute() row = h.fetchone_dict() or {} return int(row.get("clients", 0)) def notify_jabber_nodes(self): log_debug(3) running_clients = self.get_running_clients() free_slots = 0 if self._notify_threshold: free_slots = self._notify_threshold - running_clients log_debug(4, "notify_threshold: %s running_clients: %s free_slots: %s" % (self._notify_threshold, running_clients, free_slots)) h = rhnSQL.prepare(self._query_get_pending_clients) h.execute() self._next_poll_interval = None notified = [] while 1: if self._notify_threshold and free_slots <= 0: # End of loop log_debug(4, "max running clients reached; stop notifying") break row = h.fetchone_dict() if not row: # End of loop break delta = row['delta'] if delta > 0: # Set the next poll interval to something large if it was not # previously set before; this way min() will pick up this # delta, but we don't have to special-case the first delta we # find npi = self._next_poll_interval or 86400 self._next_poll_interval = min(delta, npi) log_debug(4, "Next poll interval", delta) continue jabber_id = row['jabber_id'] if jabber_id is None: # Not even online continue server_id = row['server_id'] if server_id and reboot_in_progress(server_id): # don't call when a reboot is in progress continue if not self.jabber_connection.jid_available(jabber_id): log_debug(4, "Node %s not available for notifications" % jabber_id) # iterate further, in case there are other clients that # CAN be notified. continue log_debug(4, "Notifying", jabber_id, row['server_id']) self.jabber_connection.send_message(jabber_id, jabber_lib.NS_RHN_MESSAGE_REQUEST_CHECKIN) if jabber_id not in notified: free_slots -= 1 notified.append(jabber_id) rhnSQL.commit() # We need to drive this query by rhnPushClient since it's substantially # smaller than rhnAction # order by status, earliest_action, server_id to get # "Queued" first with earliest_action first. If multiple clients have the # same values, finally order by server_id to get a defined order # important for notify_threshold _query_get_pending_clients = rhnSQL.Statement(""" select a.id, sa.server_id, pc.jabber_id, date_diff_in_days(current_timestamp, earliest_action) * 86400 delta from rhnServerAction sa, rhnAction a, rhnPushClient pc where pc.server_id = sa.server_id and sa.action_id = a.id and sa.status in (0, 1) -- Queued or picked up and not exists ( -- This is like saying 'this action has no -- prerequisite or has a prerequisite that has completed -- (status = 2) select 1 from rhnServerAction sap where sap.server_id = sa.server_id and sap.action_id = a.prerequisite and sap.status != 2 ) order by sa.status, earliest_action, sa.server_id """) _query_get_running_clients = rhnSQL.Statement(""" select count(distinct sa.server_id) clients from rhnServerAction sa join rhnServer s ON sa.server_id = s.id join suseServerContactMethod sscm ON sscm.id = s.contact_method_id where sscm.label = 'default' and sa.status = 1 -- picked up """) def reboot_in_progress(server_id): """check for a reboot action for this server in status Picked Up""" h = rhnSQL.prepare(""" select 1 from rhnServerAction sa join rhnAction a on sa.action_id = a.id join rhnActionType at on a.action_type = at.id where sa.server_id = :server_id and at.label = 'reboot.reboot' and sa.status = 1 -- Picked Up """) h.execute(server_id = server_id) ret = h.fetchone_dict() or None if ret: return True return False if __name__ == '__main__': sys.exit(main() or 0) 07070100000028000081B40000000000000000000000015DA8415F00004238000000000000000000000000000000000000001500000000mgr-osad/src/osad.py# # Copyright (c) 2008--2017 Red Hat, Inc. # # This software is licensed to you under the GNU General Public License, # version 2 (GPLv2). There is NO WARRANTY for this software, express or # implied, including the implied warranties of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2 # along with this software; if not, see # http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. # # Red Hat trademarks are not licensed under GPLv2. No permission is # granted to use or replicate Red Hat trademarks that are incorporated # in this software or its documentation. # import re import sys import time from spacewalk.common.usix import ListType from rhn import rpclib import random import socket from up2date_client.config import initUp2dateConfig from up2date_client import config try: # python 3 PY3 = sys.version_info.major >= 3 except AttributeError: # python 2 PY3 = False if PY3: import urllib.parse as urlparse from osad.rhn_log import set_debug_level, log_debug, die, set_logfile from osad import jabber_lib, osad_config, osad_client else: import urlparse from rhn_log import set_debug_level, log_debug, die, set_logfile import jabber_lib import osad_config import osad_client def main(): return Runner().main() class Runner(jabber_lib.Runner): client_factory = osad_client.Client # How often will we try to reconnect. We want this randomized, so not all # clients hit the server at the same time _min_sleep = 60 _max_sleep = 120 def __init__(self): jabber_lib.Runner.__init__(self) self._up2date_config = None self._config = None self._xmlrpc_server = None self._systemid_file = None self._time_drift = 0 self.options_table.extend([ self.option('--cfg', action="store", help="Use this configuration file for defaults"), self.option('--jabber-server', action="store", help="Primary jabber server to connect to"), ]) self._config_options = {} # Counter for the number of config setups we had self._config_setup_counter = 0 # How often to re-setup the config (i.e. make xmlrpc requests to get # the config from the server) self._config_setup_interval = random.randint(50, 100) self._use_proxy = 1 def setup_config(self, config, force=0): # We don't want to slam the server with lots of XMLRPC requests at the # same time, especially if jabberd goes down - in that case all # clients are slamming the server at the same time try: if (self._config_setup_counter % self._config_setup_interval == 0) or \ force: # This will catch the first pass too self._setup_config(config, force) else: log_debug(4, "Skipping config setup; counter=%s; interval=%s" % (self._config_setup_counter, self._config_setup_interval)) except: self._config_setup_counter = 0 raise # Update the counter for the next time self._config_setup_counter = self._config_setup_counter + 1 def _setup_config(self, config, force=0): logfile = self.options.logfile if logfile is None or logfile == '': logfile = config['logfile'] debug_level = self.options.verbose if debug_level is None: dl = config['debug_level'] if dl is not None: debug_level = int(dl) else: dl = 0 set_logfile(logfile) self.debug_level = debug_level set_debug_level(debug_level) self._tcp_keepalive_timeout = config['tcp_keepalive_timeout'] self._tcp_keepalive_count = config['tcp_keepalive_count'] log_debug(3, "Updating configuration") client_ssl_cert = config['ssl_ca_cert'] osa_ssl_cert = config['osa_ssl_cert'] or client_ssl_cert if osa_ssl_cert is None: die("No SSL cert supplied") self.ssl_cert = osa_ssl_cert auth_info = self.read_auth_info(force) self._username = auth_info['username'] self._password = auth_info['password'] self._resource = auth_info['resource'] server_url = config.get('server_url') self._jabber_servers = [] if self.options.jabber_server: self._jabber_servers.append(self.options.jabber_server) if type(server_url) == type([]): for su in server_url: a_su = self._parse_url(su)[1] self._jabber_servers.append(a_su) else: upstream_jabber_server = self._parse_url(server_url)[1] if upstream_jabber_server not in self._jabber_servers: self._jabber_servers.append(upstream_jabber_server) if 'enable_failover' not in config or config['enable_failover'] != '1': self._jabber_servers = [self._jabber_servers[0]] # Load the config self._config_options.clear() self._config_options.update(config) # No reason to expose these at the Client level - but if we have to, # uncommment some of the values below self._config_options.update({ # 'jabber-servers' : self._jabber_servers, # 'dispatchers' : self._dispatchers, # 'client_name' : self._client_name, # 'shared_key' : self._shared_key, }) def _parse_url(self, url, scheme="http"): sch, netloc, path, params, query, fragment = urlparse.urlparse(url) if not netloc: # No schema - trying to patch it up ourselves? url = scheme + "://" + url sch, netloc, path, params, query, fragment = urlparse.urlparse(url) return sch, netloc, path, params, query, fragment def fix_connection(self, c): "After setting up the connection, do whatever else is necessary" # Setup XMLRPC server xmlrpc_params = self.build_rpclib_params(self._config_options) # Looking for a server we connected to jabberd on server_urls = self._config_options['server_url'] for url in server_urls: if self._connected_jabber_server in url: xmlrpc_params['uri'] = url break server = rpclib.Server(**xmlrpc_params) self._xmlrpc_server = server client_ssl_cert = self._config_options['ssl_ca_cert'] osa_ssl_cert = self._config_options['osa_ssl_cert'] or client_ssl_cert if osa_ssl_cert: server.add_trusted_cert(osa_ssl_cert) server.registration.welcome_message() server_capabilities = get_server_capability(server) if 'registration.register_osad' not in server_capabilities: raise Exception("Server does not support OSAD registration") self._systemid_file = self._config_options['systemid'] self._systemid = open(self._systemid_file).read() current_timestamp = int(time.time()) ret = server.registration.register_osad(self._systemid, {'client-timestamp': current_timestamp}) #Bugzilla: 142067 #If the server doesn't have push support. 'ret' won't have anything in it. if len(ret.keys()) < 1: raise jabber_lib.JabberConnectionError js = ret.get('jabber-server') if js not in self._jabber_servers: self._jabber_servers.append(js) server_timestamp = ret.get('server-timestamp') # Compute the time drift between the client and the server self._time_drift = server_timestamp - current_timestamp log_debug(2, "Time drift", self._time_drift) self._dispatchers = ret.get('dispatchers') self._client_name = ret.get('client-name') self._shared_key = ret.get('shared-key') log_debug(2, "Client name", self._client_name) log_debug(2, "Shared key", self._shared_key) c.set_config_options(self._config_options) c.client_id = self._client_name c.shared_key = self._shared_key c.time_drift = self._time_drift c._sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1) c._sock.setsockopt(socket.SOL_TCP, socket.TCP_KEEPIDLE, self._tcp_keepalive_timeout) c._sock.setsockopt(socket.SOL_TCP, socket.TCP_KEEPCNT, self._tcp_keepalive_count) # Update the jabber ID systemid = open(self._systemid_file).read() args = { 'jabber-id' : str(c.jid), } ret = self._xmlrpc_server.registration.register_osad_jid(systemid, args) c.set_dispatchers(self._dispatchers) c.subscribe_to_presence(self._dispatchers) # Signal presence to the jabber server c.send_presence() return c def preprocess_once(self, client): # BZ 1410781 # If the system just started following a reboot event, # we need to run rhn_check in order to let the server # know the reboot is complete, otherwise it won't send # any further events to us. # # not needed for SUSE systems - we have update-status-service # to do this. # #super(Runner, self).preprocess_once(client) #client.run_rhn_check_async() return client def process_once(self, client): # Re-read the systemid file. If it's changed from the # previous version re-setup the config. This will create a new # key on the satellite server tied to this new system id. # This change prevents having to restart osad after a system # re-registration. systemid = open(self._systemid_file).read() if systemid != self._systemid: log_debug(4, "System re-registration detected. systemid file has changed.") config = self.read_config() raise jabber_lib.NeedRestart # make sure that dispatchers are not stuck in state [none + ask] or [from + ask] # for too long. This can happen, for example, if a "subscribe" presence stanza # gets lost - in that case re-send it client.unstick_contacts(self._dispatchers) # if rhn_check is running or the last one failed, check more often if (client._rhn_check_process is None) and (client._rhn_check_fail_count < 1): client.process(timeout=180) else: client.process(timeout=5) def read_config(self): ret = {} # Read from the global config first config_file = self.options.cfg self._config = osad_config.init('osad', config_file=config_file) config_keys = ['debug_level', 'osa_ssl_cert', 'logfile', 'run_rhn_check', 'rhn_check_command', 'enable_failover'] for key in config_keys: ret[key] = osad_config.get(key) try: server_url = osad_config.get('server_url') except osad_config.InterpolationError: e = sys.exc_info()[1] server_url = config.getServerlURL() else: if not server_url: server_url = config.getServerlURL() else: def convert_url(s): s = s.strip() if hasattr(config, 'convert_url_to_puny'): s = config.convert_url_to_puny(s) elif hasattr(config, 'convert_url_to_pune'): s = config.convert_url_to_pune(s) return s server_url = [convert_url(i) for i in server_url.split(';')] # Remove empty URLs for url in server_url: if not url: server_url.remove(url) # Real unusual case if there is no server URL both in up2date and osad config files if not server_url: die("Missing server URL in config file") ret['server_url'] = server_url #8/23/05 wregglej 165775 added the run_rhn_check option. run_rhn_check = osad_config.get('run_rhn_check') if run_rhn_check is None: log_debug(3, "Forcing run_rhn_check") run_rhn_check = 1 ret['run_rhn_check'] = int(run_rhn_check) ret['tcp_keepalive_timeout'] = int(osad_config.get('tcp_keepalive_timeout', defval=1800)) ret['tcp_keepalive_count'] = int(osad_config.get('tcp_keepalive_count', defval=3)) systemid = osad_config.get('systemid') if systemid is None: systemid = self.get_up2date_config()['systemIdPath'] ret['systemid'] = systemid enable_proxy = self._config.get_option('enableProxy') if enable_proxy is None: enable_proxy = self.get_up2date_config()['enableProxy'] if enable_proxy: ret['enable_proxy'] = 1 ret['proxy_url'] = self._config.get_option('httpProxy') if ret['proxy_url'] is None: ret['proxy_url'] = str(config.getProxySetting()) ret['enable_proxy_auth'] = 0 enable_proxy_auth = self._config.get_option('enableProxyAuth') if enable_proxy_auth is None: enable_proxy_auth = self.get_up2date_config()['enableProxyAuth'] if enable_proxy_auth: ret['enable_proxy_auth'] = 1 proxy_user = self._config.get_option('proxyUser') if proxy_user is None: proxy_user = self.get_up2date_config()['proxyUser'] ret['proxy_user'] = proxy_user proxy_password = self._config.get_option('proxyPassword') if proxy_password is None: proxy_password = self.get_up2date_config()['proxyPassword'] ret['proxy_password'] = proxy_password if not server_url: die("Unable to retrieve server URL") # SSL cert for Jabber's TLS, it can potentially be different than the # client's osa_ssl_cert = self._config.get_option('osa_ssl_cert') # The up2date ssl cert - we get it from up2daate's config file client_ca_cert = self.get_up2date_config()['sslCACert'] if isinstance(client_ca_cert, ListType): if client_ca_cert: client_ca_cert = client_ca_cert[0] else: client_ca_cert = None if osa_ssl_cert is None: # No setting, use up2date's osa_ssl_cert = client_ca_cert if client_ca_cert is not None: ret['ssl_ca_cert'] = client_ca_cert if osa_ssl_cert is not None: ret['osa_ssl_cert'] = osa_ssl_cert return ret def get_up2date_config(self): if self._up2date_config is None: self._up2date_config = initUp2dateConfig() return self._up2date_config def build_rpclib_params(self, config): ret = {} kmap = { 'server_url' : 'uri', 'proxy_user' : 'username', 'proxy_password' : 'password', 'proxy_url' : 'proxy', } for k, v in kmap.items(): if k in config: val = config[k] if val is not None: ret[v] = val return ret def read_auth_info(self, force): # generate some defaults resource = 'osad' username = 'osad-%s' % jabber_lib.generate_random_string(10) password = jabber_lib.generate_random_string(20) # Get the path to the auth info file - may be None auth_info_file = self._config.get_option('auth_file') auth_info = osad_config.get_auth_info(auth_info_file, 'osad-auth', force, username=username, password=password, resource=resource) return auth_info def get_server_capability(s): headers = s.get_response_headers() if headers is None: # No request done yet return {} if PY3: cap_headers = ["X-RHN-Server-Capability: %s" % val for val in headers.get_all("X-RHN-Server-Capability")] else: cap_headers = headers.getallmatchingheaders("X-RHN-Server-Capability") if not cap_headers: return {} regexp = re.compile( r"^(?P<name>[^(]*)\((?P<version>[^)]*)\)\s*=\s*(?P<value>.*)$") vals = {} for h in cap_headers: arr = h.split(':', 1) assert len(arr) == 2 val = arr[1].strip() if not val: continue mo = regexp.match(val) if not mo: # XXX Just ignoring it, for now continue vdict = mo.groupdict() for k, v in vdict.items(): vdict[k] = v.strip() vals[vdict['name']] = vdict return vals if __name__ == '__main__': sys.exit(main() or 0) 07070100000029000081B40000000000000000000000015DA8415F0000280F000000000000000000000000000000000000001C00000000mgr-osad/src/osad_client.py# # Copyright (c) 2008--2016 Red Hat, Inc. # # This software is licensed to you under the GNU General Public License, # version 2 (GPLv2). There is NO WARRANTY for this software, express or # implied, including the implied warranties of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2 # along with this software; if not, see # http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. # # Red Hat trademarks are not licensed under GPLv2. No permission is # granted to use or replicate Red Hat trademarks that are incorporated # in this software or its documentation. # import os import time import sys from subprocess import Popen try: # python 3 PY3 = sys.version_info.major >= 3 except AttributeError: # python 2 PY3 = False if PY3: from osad.rhn_log import log_debug from osad import jabber_lib else: from rhn_log import log_debug import jabber_lib class Client(jabber_lib.JabberClient): RHN_CHECK_CMD = '/usr/sbin/rhn_check' def __init__(self, *args, **kwargs): jabber_lib.JabberClient.__init__(self, *args, **kwargs) self.username = None self.resource = None self.client_id = None self.shared_key = None self.debug_level = 0 self.time_drift = 0 self._dispatchers = [] self._config = {} self._rhn_check_process = None self._rhn_check_fail_count = 0 self._stuck_subscription_timestamp = time.time() def set_config_options(self, config): self._config = config def set_debug_level(self, debug_level): self.debug_level = debug_level def set_dispatchers(self, dispatchers): self._dispatchers = dispatchers def start(self, username, password, resource): log_debug(3, username, password, resource) # XXX find a better name for this function self.auth(username, password, resource) self.username = username self.resource = resource self.jid = "%s@%s/%s" % (self.username, self._host, self.resource) # Retrieve roster self.retrieve_roster() def _create_signature(self, jid, action): log_debug(4, jid, action) attrs = { 'client-id' : self.client_id, 'timestamp' : int(time.time()), 'serial' : self.get_unique_id(), 'action' : action, 'jid' : self.jid, } signing_comps = ['client-id', 'timestamp', 'serial', 'action', 'jid'] args = [self.shared_key, jid] for sc in signing_comps: args.append(attrs[sc]) log_debug(4, "Signature args", args) attrs['signature'] = jabber_lib.sign(*args) x = jabber_lib.jabber.xmlstream.Node('x') x.setNamespace(jabber_lib.NS_RHN_SIGNED) for k, v in attrs.items(): x.putAttr(k, v) return x def _lookup_dispatcher(self, jid): # presence may not send a resource in the JID if not isinstance(jid, jabber_lib.jabber.JID) or jid.resource: return str(jid) jid = str(jid) jid_len = len(jid) for d in self._dispatchers: if d[:jid_len] != jid: continue assert len(d) > jid_len if d[jid_len] == '/': # This is it return d return None def _fix_jid(self, jid): return self._lookup_dispatcher(jid) def _check_signature(self, stanza, actions=None): # Do we have this client in the table? jid = stanza.getFrom() if jid is None: log_debug(3, 'no from') return None # Look for a <x> child that has our namespace xes = stanza.getTags('x') for x in xes: if x.getNamespace() != jabber_lib.NS_RHN_SIGNED: continue break else: #for log_debug(1, "No signature node found in stanza") return None timestamp = x.getAttr('timestamp') try: timestamp = int(timestamp) except ValueError: log_debug(1, "Invalid message timestamp", timestamp) return None now = time.time() current_drift = timestamp - now # Allow for a 120 seconds drift max_drift = 120 abs_drift = abs(current_drift - self.time_drift) if abs_drift > max_drift: log_debug(1, "Dropping message, drift is too big", abs_drift) action = x.getAttr('action') if actions and action not in actions: log_debug(1, "action %s not allowed" % action) return None # We need the fully qualified JID here too full_jid = x.getAttr('jid') if not full_jid: log_debug(3, "Full JID not found in signature stanza") return None attrs = { 'timestamp' : x.getAttr('timestamp'), 'serial' : x.getAttr('serial'), 'action' : x.getAttr('action'), 'jid' : full_jid, } signing_comps = ['timestamp', 'serial', 'action', 'jid'] args = [self.shared_key, self.jid] for sc in signing_comps: args.append(attrs[sc]) log_debug(4, "Signature args", args) signature = jabber_lib.sign(*args) x_signature = x.getAttr('signature') if signature != x_signature: log_debug(1, "Signatures do not match", signature, x_signature) return None # Happy joy return x def _message_callback(self, client, stanza): log_debug(4) assert stanza.getName() == 'message' # Actions we know how to react to actions = [ jabber_lib.NS_RHN_MESSAGE_REQUEST_CHECKIN, jabber_lib.NS_RHN_MESSAGE_REQUEST_PING, ] sig = self._check_signature_from_message(stanza, actions) if not sig: return action = sig.getAttr('action') if action == jabber_lib.NS_RHN_MESSAGE_REQUEST_PING: log_debug(1, 'Ping request') self.send_message(stanza.getFrom(), jabber_lib.NS_RHN_MESSAGE_RESPONSE_PING) return # Send confirmation self.send_message(stanza.getFrom(), jabber_lib.NS_RHN_MESSAGE_RESPONSE_CHECKIN) # Checkin run_check = self._config.get('run_rhn_check') log_debug(3, "run_rhn_check:", run_check) if not self._config.get('run_rhn_check'): log_debug(0, "Pretend that command just ran") else: self.run_rhn_check_async() def process_loop_hook(self): # if rhn_check process exists, check it last # status if self._rhn_check_process is not None: retcode = self._rhn_check_process.poll() if retcode is not None: log_debug(3, "rhn_check exited with status %d" % retcode) if retcode != 0: self._rhn_check_fail_count += 1 else: self._rhn_check_fail_count = 0 self._rhn_check_process = None else: log_debug(3, "rhn_check is still running...") else: # rhn_check is not running but last one failed # we force a check even if the server does not # contact us. The idea is to exhaust the number of # times we can pick up the action until the server fails # it. if self._rhn_check_fail_count > 0: log_debug(3, "rhn_check failed last time, " \ "force retry (fail count %d)" % self._rhn_check_fail_count) self.run_rhn_check_async() def run_rhn_check_async(self): """Runs rhn_check and keeps a handle that it is monitored during the event loop """ command = self._config.get('rhn_check_command') # rhn_check now checks for multiple instances, # lets use that directly if command is None: args = [self.RHN_CHECK_CMD] else: # XXX should find a better way to get the list of args args = command.split() # if rhn_check process already exists if self._rhn_check_process is not None: retcode = self._rhn_check_process.poll() if retcode is None: log_debug(3, "rhn_check is still running, not running again...") return if self._rhn_check_fail_count > 0: log_debug(3, "rhn_check failed last time (fail count %d)" % self._rhn_check_fail_count) log_debug(3, "About to execute:", args) oldumask = os.umask(int("0077", 8)) os.umask(oldumask | int("0022", 8)) self._rhn_check_process = Popen(args) os.umask(oldumask) log_debug(0, "executed %s with pid %d" % (args[0], self._rhn_check_process.pid)) def unstick_contacts(self, jids): """If we are waiting for 'subscribed' presence stanzas for too long, ask again""" if time.time() - self._stuck_subscription_timestamp > 60: for jid in jids: stripped_jid = self._strip_resource(jid) if self.needs_unsticking(stripped_jid): presence_node = jabber_lib.JabberPresenceNode(to=stripped_jid, type="subscribe") presence_node.setID("presence-%s" % self.get_unique_id()) log_debug(4, "Re-sending presence subscription request", presence_node) self.send(presence_node) self._stuck_subscription_timestamp = time.time() def needs_unsticking(self, jid): """Returns True if jid is in state [none + ask] or [from + ask]""" contact = None subscribed_none = self._roster.get_subscribed_none() if jid in subscribed_none: contact = subscribed_none[jid] subscribed_from = self._roster.get_subscribed_from() if jid in subscribed_from: contact = subscribed_from[jid] if contact is not None: return 'ask' in contact and contact['ask'] == 'subscribe' return False 0707010000002A000081B40000000000000000000000015DA8415F00000FE0000000000000000000000000000000000000001C00000000mgr-osad/src/osad_config.py# # Copyright (c) 2008--2016 Red Hat, Inc. # # This software is licensed to you under the GNU General Public License, # version 2 (GPLv2). There is NO WARRANTY for this software, express or # implied, including the implied warranties of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2 # along with this software; if not, see # http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. # # Red Hat trademarks are not licensed under GPLv2. No permission is # granted to use or replicate Red Hat trademarks that are incorporated # in this software or its documentation. # import os import sys try: # python 3 import configparser as ConfigParser except ImportError: # python 2 import ConfigParser InterpolationError = ConfigParser.InterpolationError class ClientConfigParser(ConfigParser.ConfigParser): _instance = None _global_config_file = "/etc/sysconfig/rhn/osad.conf" def __init__(self, section, defaults=None): """defaults is either None, or a dictionary of default values which can be overridden""" ConfigParser.ConfigParser.__init__(self, defaults) self.section = section self.overrides = {} def read_config_files(self, overrides={}): self.overrides.clear() self.overrides.update(overrides) try: self.read(self._get_config_files()) except ConfigParser.MissingSectionHeaderError: e = sys.exc_info()[1] print("Config error: line %s, file %s: %s" % (e.lineno, e.filename, e)) sys.exit(1) def _get_config_files(self): return [ self._global_config_file, ] def get_option(self, option, defval=None): try: return self.get(self.section, option, vars=self.overrides) except (ConfigParser.NoOptionError, ConfigParser.NoSectionError): e = sys.exc_info()[1] pass defaults = self.defaults() if option in defaults: return defaults[option] return defval def has_key(self, option): return self.has_option(self.section, option) def keys(self): return self.options(self.section) def __getitem__(self, item): return self.get_option(item) class UserPassConfigParser(ClientConfigParser): _global_config_file = "/etc/sysconfig/rhn/osad-auth.conf" def init(section, defaults=None, config_file=None, **overrides): cp = ClientConfigParser._instance = ClientConfigParser(section, defaults) # Allow for the config file to be changed, if necessary if config_file is not None: cp._global_config_file = config_file cp.read_config_files(overrides) return cp def get(var, defval=None): return _get_config().get_option(var, defval=defval) def _get_config(): if ClientConfigParser._instance is None: raise ValueError("Configuration not initialized") return ClientConfigParser._instance def instance(): return _get_config() def keys(): return _get_config().keys() def get_auth_info(auth_file, section, force, **defaults): _modified = 0 c = UserPassConfigParser(section) if auth_file is not None: c._global_config_file = auth_file c.read_config_files() if not c.has_section(section): _modified = 1 c.add_section(section) for k, v in defaults.items(): if not c.has_option(section, k) or force: c.set(section, k, v) _modified = 1 if _modified: fd = os.open(c._global_config_file, os.O_CREAT | os.O_TRUNC | os.O_WRONLY, int("0600", 8)) f = os.fdopen(fd, "w") f.write("# Automatically generated. Do not edit!\n\n") c.write(f) f.close() return c def main(): init('osad') print("server_url: %s" % get("server_url")) auth_file = "/tmp/osad-auth.conf" section = "osad-auth" c = get_auth_info(auth_file, section, username="aaa", password="bbb") print(c.keys()) if __name__ == '__main__': main() 0707010000002B000081B40000000000000000000000015DA8415F00000A24000000000000000000000000000000000000001800000000mgr-osad/src/rhn_log.py# # Copyright (c) 2008--2016 Red Hat, Inc. # # This software is licensed to you under the GNU General Public License, # version 2 (GPLv2). There is NO WARRANTY for this software, express or # implied, including the implied warranties of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2 # along with this software; if not, see # http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. # # Red Hat trademarks are not licensed under GPLv2. No permission is # granted to use or replicate Red Hat trademarks that are incorporated # in this software or its documentation. # import os import sys import time import traceback from rhn.i18n import bstr class Logger: debug_level = 1 logfile = "/var/log/osad" def set_logfile( self, logfile ): Logger.logfile = logfile def log_debug(self, debug_level, *args): if debug_level <= self.debug_level: info_out = ( time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time())), self.get_caller(), " ".join([str(x) for x in args]) ) outstring = "%s %s: %s\n" % info_out sys.stdout.write( outstring ) if not Logger.logfile is None: try: fd = os.open(Logger.logfile, os.O_APPEND | os.O_RDWR | os.O_CREAT, int("0600", 8)) os.write(fd, bstr(outstring)) os.close(fd) except IOError: raise def set_debug_level(self, debug_level): Logger.debug_level = debug_level def get_caller(self, caller_offset=4): tbStack = traceback.extract_stack() callid = len(tbStack) - caller_offset module = tbStack[callid] module_file = os.path.basename(module[0]) module_file = module_file.split('.', 1)[0] return "%s.%s" % (module_file, module[2]) def log_error(self, *args): self.log_debug(0, *args) line = [str(x) for x in args] sys.stderr.write(" ".join(line)) sys.stderr.write("\n") def die(self, error_code, *args): self.log_error(args) sys.exit(error_code) def set_logfile(*args): return Logger().set_logfile(*args) def set_debug_level(*args): return Logger().set_debug_level(*args) def get_debug_level(): return Logger().debug_level def log_debug(*args): return Logger().log_debug(*args) def log_error(*args): return Logger().log_error(*args) def die(error_code, *args): Logger().log_error(*args) sys.exit(error_code) 0707010000002C000041FD0000000000000000000000015DA8415F00000000000000000000000000000000000000000000001300000000mgr-osad/sysconfig0707010000002D000081B40000000000000000000000015DA8415F000000C6000000000000000000000000000000000000001C00000000mgr-osad/sysconfig/Makefile# Makefile for installation of the RHN server configuration files # what is the backend top dir TOP = .. INSTALL_FILES = osa-dispatcher INSTALL_DEST = /etc/sysconfig include $(TOP)/Makefile.defs 0707010000002E000081B40000000000000000000000015DA8415F0000003F000000000000000000000000000000000000002200000000mgr-osad/sysconfig/osa-dispatcher TNS_ADMIN=/etc/rhn/tns_admin/osa-dispatcher export TNS_ADMIN 0707010000002F000041FD0000000000000000000000015DA8415F00000000000000000000000000000000000000000000000E00000000mgr-osad/test07070100000030000081B40000000000000000000000015DA8415F000009BC000000000000000000000000000000000000001F00000000mgr-osad/test/simple-client.py# # Copyright (c) 2008--2016 Red Hat, Inc. # # This software is licensed to you under the GNU General Public License, # version 2 (GPLv2). There is NO WARRANTY for this software, express or # implied, including the implied warranties of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2 # along with this software; if not, see # http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. # # Red Hat trademarks are not licensed under GPLv2. No permission is # granted to use or replicate Red Hat trademarks that are incorporated # in this software or its documentation. # import sys import jabber_lib import test_lib class SimpleClientClient(test_lib.SimpleClient): pass class SimpleClientRunner(test_lib.SimpleRunner): client_factory = SimpleClientClient _resource = 'client' def __init__(self, *args, **kwargs): test_lib.SimpleRunner.__init__(self, *args, **kwargs) self.options_table.extend([ self.option('--dispatcher', action="store", help="Dispatcher"), self.option('--exit', action="store_true", help="Exit after registering"), ]) def setup_config(self, config): test_lib.SimpleRunner.setup_config(self, config) self.dispatcher = self.options.dispatcher self._should_exit = self.options.exit if not self.dispatcher: print("Missing dispatcher") sys.exit(0) def fix_connection(self, client): # First, retrieve the roster client.retrieve_roster() # If not subscribed already, subscribe to the dispatcher dest = str(jabber_lib.strip_resource(self.dispatcher)) client.subscribe_to_presence([dest]) client._roster._subscribed_to[dest] = { 'jid' : dest, 'subscription' : "to", } client.send_presence() def process_once(self, client): ret = test_lib.SimpleRunner.process_once(self, client) if not self._should_exit: return ret # Wait for a presence subscription request djid = str(jabber_lib.strip_resource(self.dispatcher)) if djid in client._roster.get_subscribed_both(): client.disconnect() sys.exit(0) return ret def main(): d = SimpleClientRunner('username1', 'password1', "client") d.main() if __name__ == '__main__': sys.exit(main() or 0) 07070100000031000081B40000000000000000000000015DA8415F0000043F000000000000000000000000000000000000002300000000mgr-osad/test/simple-dispatcher.py# # Copyright (c) 2008--2013 Red Hat, Inc. # # This software is licensed to you under the GNU General Public License, # version 2 (GPLv2). There is NO WARRANTY for this software, express or # implied, including the implied warranties of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2 # along with this software; if not, see # http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. # # Red Hat trademarks are not licensed under GPLv2. No permission is # granted to use or replicate Red Hat trademarks that are incorporated # in this software or its documentation. # import sys import test_lib class SimpleDispatcherClient(test_lib.SimpleClient): pass class SimpleDispatcherRunner(test_lib.SimpleRunner): client_factory = SimpleDispatcherClient _resource = 'DISPATCHER' def fix_connection(self, client): client.retrieve_roster() client.send_presence() def main(): d = SimpleDispatcherRunner('username1', 'password1', "DISPATCHER") d.main() if __name__ == '__main__': sys.exit(main() or 0) 07070100000032000081B40000000000000000000000015DA8415F00000CB5000000000000000000000000000000000000001A00000000mgr-osad/test/test_lib.py# # Copyright (c) 2008--2016 Red Hat, Inc. # # This software is licensed to you under the GNU General Public License, # version 2 (GPLv2). There is NO WARRANTY for this software, express or # implied, including the implied warranties of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2 # along with this software; if not, see # http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. # # Red Hat trademarks are not licensed under GPLv2. No permission is # granted to use or replicate Red Hat trademarks that are incorporated # in this software or its documentation. # import sys import jabber_lib import time import rhn_log class SimpleClient(jabber_lib.JabberClient): def start(self, username, password, resource): t0 = time.time() self.auth(username, password, resource) t1 = time.time() print("TIMING: auth: %.3f" % (t1 - t0)) self.username = username self.resource = resource self.jid = "%s@%s/%s" % (self.username, self._host, self.resource) rhn_log.log_debug(0, "Authenticated", self.jid) def _message_callback(self, client, stanza): pass class SimpleRunner(jabber_lib.Runner): def __init__(self, username, password, resource): jabber_lib.Runner.__init__(self) self._username = username self._password = password self._resource = resource self.log_file = '/tmp/simple-dispatcher.log' self.options_table.extend([ self.option('--jabberd', action="append", help="Use this jabber server"), self.option('--trusted-cert', action="store", help="Use this trusted CA cert"), self.option('--username', action="store", help="Username"), self.option('--password', action="store", help="Password"), self.option('--resource', action="store", help="Resource"), ]) def set_log_file(self, log_file): self.log_file = log_file def set_trusted_cert(self, trusted_cert): self.ssl_cert = trusted_cert def read_config(self): return { 'logfile' : self.log_file, } def setup_config(self, config): self.options.nodetach = 1 self.debug_level = self.options.verbose rhn_log.set_logfile(config.get('logfile') or "/dev/null") self._username = self.options.username self._password = self.options.password if not self._username: print("Missing username") sys.exit(0) if not self._password: print("Missing password") sys.exit(0) if self.options.resource: self._resource = self.options.resource if not self.options.jabberd: print("Missing jabber servers") sys.exit(0) if not self.options.trusted_cert: print("Missing trusted cert") sys.exit(0) self.ssl_cert = self.options.trusted_cert self._jabber_servers.extend(self.options.jabberd) def process_once(self, client): client.process(timeout=None) 07070100000033000041FD0000000000000000000000015DA8415F00000000000000000000000000000000000000000000002200000000mgr-osad/tns-admin-osa-dispatcher07070100000034000081B40000000000000000000000015DA8415F000000E5000000000000000000000000000000000000002B00000000mgr-osad/tns-admin-osa-dispatcher/Makefile# Makefile for installation of the RHN server configuration files # what is the backend top dir TOP = .. INSTALL_FILES = sqlnet.ora INSTALL_LINKS = INSTALL_DEST = /etc/rhn/tns_admin/osa-dispatcher include $(TOP)/Makefile.defs 07070100000035000081B40000000000000000000000015DA8415F00000053000000000000000000000000000000000000002D00000000mgr-osad/tns-admin-osa-dispatcher/sqlnet.ora log_directory_client = /var/log/rhn/oracle/osa-dispatcher diag_adr_enabled = off 07070100000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000B00000000TRAILER!!!
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor