File mgr-osad-git-0.9b8771e.obscpio of Package mgr-osad.23570
07070100000000000041FD000000000000000000000001624467C000000000000000000000000000000000000000000000000900000000mgr-osad07070100000001000081B4000000000000000000000001624467C0000046AC000000000000000000000000000000000000001100000000mgr-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.
07070100000002000081B4000000000000000000000001624467C000000026000000000000000000000000000000000000001200000000mgr-osad/Makefileinclude ../../../rel-eng/Makefile.git
07070100000003000081B4000000000000000000000001624467C0000007A7000000000000000000000000000000000000001700000000mgr-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
07070100000004000081B4000000000000000000000001624467C000000703000000000000000000000000000000000000001700000000mgr-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
07070100000005000081B4000000000000000000000001624467C000000367000000000000000000000000000000000000001900000000mgr-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 = devel/galaxy/manager/4.2/docker/containers/suma-4.2
DOCKER_REGISTRY = registry.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
07070100000006000081FD000000000000000000000001624467C0000005C9000000000000000000000000000000000000001700000000mgr-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)
07070100000007000041FD000000000000000000000001624467C000000000000000000000000000000000000000000000001300000000mgr-osad/logrotate07070100000008000081B4000000000000000000000001624467C0000000CD000000000000000000000000000000000000001C00000000mgr-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
07070100000009000081B4000000000000000000000001624467C000000175000000000000000000000000000000000000002200000000mgr-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
}
0707010000000A000081B4000000000000000000000001624467C000000072000000000000000000000000000000000000001800000000mgr-osad/logrotate/osad/var/log/osad {
weekly
rotate 5
copytruncate
compress
notifempty
missingok
size 10M
}
0707010000000B000081B4000000000000000000000001624467C00000003C000000000000000000000000000000000000001C00000000mgr-osad/mgr-osad-rpmlintrcaddFilter("suse-filelist-forbidden-sysconfig .*/sysconfig")
0707010000000C000081B4000000000000000000000001624467C000003C4D000000000000000000000000000000000000001A00000000mgr-osad/mgr-osad.changes-------------------------------------------------------------------
Wed Mar 30 16:22:04 CEST 2022 - jmassaguerpla@suse.de
- version 4.2.8-1
* Fix the condition for preventing building python 2 subpackage
for SLE15
-------------------------------------------------------------------
Wed Feb 02 13:45:19 CET 2022 - jmassaguerpla@suse.de
- version 4.2.7-1
* Do not build python 2 package for SLE15SP4 and higher
* require python macros for building
-------------------------------------------------------------------
Fri Jul 16 14:05:16 CEST 2021 - jgonzalez@suse.com
- version 4.2.6-1
- Adapt the tests to the new images
-------------------------------------------------------------------
Tue May 11 12:46:33 CEST 2021 - jgonzalez@suse.com
- version 4.2.5-1
- Change the log file permissions as expected by logrotate (bsc#1177884)
-------------------------------------------------------------------
Wed May 05 15:54:53 CEST 2021 - jgonzalez@suse.com
- version 4.2.4-1
- change deprecated path /var/run into /run for systemd (bsc#1185178)
-------------------------------------------------------------------
Thu Feb 25 12:13:37 CET 2021 - jgonzalez@suse.com
- version 4.2.3-1
- adapt to new SSL implementation of rhnlib (bsc#1181807)
-------------------------------------------------------------------
Thu Dec 03 13:35:30 CET 2020 - jgonzalez@suse.com
- version 4.2.2-1
- Python fixes
- Removal of RHEL5
-------------------------------------------------------------------
Fri Sep 18 11:13:51 CEST 2020 - jgonzalez@suse.com
- version 4.2.1-1
- Update package version to 4.2.0
-------------------------------------------------------------------
Thu Jul 23 17:58:28 CEST 2020 - jgonzalez@suse.com
- version 4.1.3-1
- move uyuni-base-common dependency from mgr-osad to mgr-osa-dispatcher
(bsc#1174405)
-------------------------------------------------------------------
Wed Jan 22 12:09:22 CET 2020 - jgonzalez@suse.com
- version 4.1.2-1
- take care that osad is not disabled nor deactivated during update
(bsc#1157700, bsc#1158697)
- separate osa-dispatcher and jabberd so it can be disabled independently
-------------------------------------------------------------------
Wed Nov 27 16:55:56 CET 2019 - jgonzalez@suse.com
- version 4.1.1-1
- replace spacewalk-usix with uyuni-common-libs
- Bump version to 4.1.0 (bsc#1154940)
- Obsolete all old python2-osa* packages to avoid conflicts (bsc#1152290)
- move /usr/share/rhn/config-defaults to uyuni-base-common
- Require uyuni-base-common for /etc/rhn (for osa-dispatcher)
-------------------------------------------------------------------
Wed Jul 31 17:28:01 CEST 2019 - jgonzalez@suse.com
- version 4.0.9-1
- Ensure bytes type when using hashlib to avoid traceback (bsc#1138822)
- Fix obsolete for old osad packages, to allow installing mgr-osad
even by using osad at yum/zyppper install (bsc#1139453)
-------------------------------------------------------------------
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
-------------------------------------------------------------------
0707010000000D000081B4000000000000000000000001624467C000005826000000000000000000000000000000000000001700000000mgr-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}}
%global __python /usr/bin/python2
%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} && 0%{?sle_version} < 150000)
%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.2.8
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 >= 4.2.2
Requires: python2-uyuni-common-libs
%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 >= 4.2.2
Requires: python3-uyuni-common-libs
BuildRequires: python3-devel
BuildRequires: python3-rpm-macros
%description -n python3-%{name}
Python 3 specific files for %{name}
%endif
%if 0%{?build_py2}
%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
%endif
%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}
BuildRequires: uyuni-base-common
Requires(pre): uyuni-base-common
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.
%if 0%{?build_py2}
%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 || 0%{?rhel}
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.
%endif
%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} >= 8
sed -i 's@^#!/usr/bin/python$@#!/usr/bin/python3 -s@' invocation.py
%endif
%build
%if 0%{?build_py2}
make -f Makefile.osad all PYTHONPATH=%{python_sitelib}
%endif
%if 0%{?build_py3}
make -f Makefile.osad all PYTHONPATH=%{python3_sitelib}
%endif
%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}
%if 0%{?build_py2}
make -f Makefile.osad install PREFIX=$RPM_BUILD_ROOT ROOT=%{rhnroot} INITDIR=%{_initrddir} \
PYTHONPATH=%{python_sitelib} PYTHONVERSION=%{python_version}
%endif
%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\b|#!/usr/bin/python3|' $RPM_BUILD_ROOT/usr/sbin/osad-%{python3_version}
sed -i 's|#!/usr/bin/python\b|#!/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
mkdir -p %{buildroot}%{_var}/log/rhn
touch %{buildroot}%{_var}/log/osad
touch %{buildroot}%{_var}/log/rhn/osa-dispatcher.log
%if 0%{?suse_version}
%if 0%{?build_py2}
%py_compile -O %{buildroot}/%{python_sitelib}
%endif
%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 -e /var/lib/systemd/migrated/enable-osad && /usr/bin/systemctl enable osad.service >/dev/null 2>&1
rm -f /var/lib/systemd/migrated/enable-osad 2> /dev/null
test -e /var/lib/systemd/migrated/activate-osad && /usr/bin/systemctl start osad.service >/dev/null 2>&1
rm -f /var/lib/systemd/migrated/activate-osad 2> /dev/null
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
%pre
%if 0%{?suse_version} >= 1210
%service_add_pre osad.service
%endif
if [ -x /usr/bin/systemctl ]; then
(
[ -d /var/lib/systemd/migrated ] || mkdir -p /var/lib/systemd/migrated || :
/usr/bin/systemctl is-enabled osad.service >/dev/null 2>&1 && touch /var/lib/systemd/migrated/enable-osad
/usr/bin/systemctl is-active osad.service >/dev/null 2>&1 && touch /var/lib/systemd/migrated/activate-osad
) ||:
fi
%if 0%{?suse_version} >= 1210
%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},%{apache_group}) %{_var}/log/rhn/osa-dispatcher.log
%if 0%{?suse_version}
%{_sbindir}/rcosa-dispatcher
%dir %{rhnroot}
%dir %{_sysconfdir}/rhn/tns_admin
%attr(770,root,%{apache_group}) %dir %{_var}/log/rhn
%endif
%if 0%{?build_py2}
%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*
%endif
%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
%if 0%{?build_py2}
%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*
%endif
%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
0707010000000E000041FD000000000000000000000001624467C000000000000000000000000000000000000000000000002000000000mgr-osad/osa-dispatcher-selinux0707010000000F000081B4000000000000000000000001624467C0000002F4000000000000000000000000000000000000003E00000000mgr-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
07070100000010000081B4000000000000000000000001624467C000000161000000000000000000000000000000000000003200000000mgr-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)
/run/osa-dispatcher\.pid gen_context(system_u:object_r:osa_dispatcher_var_run_t,s0)
07070100000011000081B4000000000000000000000001624467C000000021000000000000000000000000000000000000003200000000mgr-osad/osa-dispatcher-selinux/osa-dispatcher.if## This file is empty (for now).
07070100000012000081B4000000000000000000000001624467C000000BF4000000000000000000000000000000000000003200000000mgr-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;
07070100000013000081B4000000000000000000000001624467C000000023000000000000000000000000000000000000003B00000000mgr-osad/osa-dispatcher-selinux/osa-dispatcher.te.fedora17auth_read_passwd(osa_dispatcher_t)
07070100000014000081B4000000000000000000000001624467C00000009B000000000000000000000000000000000000003B00000000mgr-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)
07070100000015000081B4000000000000000000000001624467C0000001A3000000000000000000000000000000000000002000000000mgr-osad/osa-dispatcher.service[Unit]
Description=OSA Dispatcher daemon
After=syslog.target network.target jabberd.service
BindsTo=jabberd.service
Requires=spacewalk-wait-for-jabberd.service
[Service]
Type=forking
EnvironmentFile=-/etc/sysconfig/osa-dispatcher
PIDFile=/run/osa-dispatcher.pid
ExecStart=/usr/sbin/osa-dispatcher --pid-file /run/osa-dispatcher.pid
ExecStartPre=/bin/rm -f /run/osa-dispatcher.pid
[Install]
WantedBy=multi-user.target
07070100000016000041FD000000000000000000000001624467C000000000000000000000000000000000000000000000001300000000mgr-osad/osad-conf07070100000017000081B4000000000000000000000001624467C0000001AD000000000000000000000000000000000000001C00000000mgr-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)
07070100000018000081B4000000000000000000000001624467C000000023000000000000000000000000000000000000001800000000mgr-osad/osad-conf/osadosad.ping(1)=1
osad.rhn_check(1)=1
07070100000019000081B4000000000000000000000001624467C000000028000000000000000000000000000000000000002200000000mgr-osad/osad-conf/osad-auth.conf# Automatically generated. Do not edit!
0707010000001A000081B4000000000000000000000001624467C0000006F9000000000000000000000000000000000000001D00000000mgr-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
0707010000001B000081B4000000000000000000000001624467C0000000FE000000000000000000000000000000000000001600000000mgr-osad/osad.service[Unit]
Description=OSAD daemon
After=syslog.target network.target
[Service]
Type=forking
KillMode=process
EnvironmentFile=-/etc/sysconfig/osad
PIDFile=/run/osad.pid
ExecStart=/usr/sbin/osad --pid-file /run/osad.pid
[Install]
WantedBy=multi-user.target
0707010000001C000081FD000000000000000000000001624467C000000711000000000000000000000000000000000000001300000000mgr-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
0707010000001D000081FD000000000000000000000001624467C00000062F000000000000000000000000000000000000001800000000mgr-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
0707010000001E000081B4000000000000000000000001624467C000001396000000000000000000000000000000000000001200000000mgr-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=
0707010000001F000041FD000000000000000000000001624467C000000000000000000000000000000000000000000000001200000000mgr-osad/rhn-conf07070100000020000081B4000000000000000000000001624467C0000000DC000000000000000000000000000000000000001B00000000mgr-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
07070100000021000081B4000000000000000000000001624467C000000164000000000000000000000000000000000000002A00000000mgr-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
07070100000022000041FD000000000000000000000001624467C000000000000000000000000000000000000000000000000D00000000mgr-osad/src07070100000023000081B4000000000000000000000001624467C00000010E000000000000000000000000000000000000001600000000mgr-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
07070100000024000081B4000000000000000000000001624467C000000266000000000000000000000000000000000000001900000000mgr-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.
#
07070100000025000081B4000000000000000000000001624467C000001E80000000000000000000000000000000000000002200000000mgr-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
07070100000026000081B4000000000000000000000001624467C00000CB1E000000000000000000000000000000000000001B00000000mgr-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 uyuni.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.SSLError):
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")
sslsock = SSLSocket(self._sock, trusted_certs=self.trusted_certs)
# Explicitly perform the SSL handshake
try:
sslsock.init_ssl(server_name=self._host)
sslsock.do_handshake()
except (SSL.SSL.SSLError, SSL.CertificateError) as e:
# Error in the SSL handshake - most likely mismatching CA cert
log_error("Traceback caught: ", e)
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 = sslsock._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 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.SSLError:
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.SSLError):
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
07070100000027000081B4000000000000000000000001624467C000003EB8000000000000000000000000000000000000001F00000000mgr-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)
07070100000028000081B4000000000000000000000001624467C000004234000000000000000000000000000000000000001500000000mgr-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 uyuni.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)
07070100000029000081B4000000000000000000000001624467C00000280F000000000000000000000000000000000000001C00000000mgr-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
0707010000002A000081B4000000000000000000000001624467C000000FE0000000000000000000000000000000000000001C00000000mgr-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()
0707010000002B000081B4000000000000000000000001624467C000000A24000000000000000000000000000000000000001800000000mgr-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)
0707010000002C000041FD000000000000000000000001624467C000000000000000000000000000000000000000000000001300000000mgr-osad/sysconfig0707010000002D000081B4000000000000000000000001624467C0000000C6000000000000000000000000000000000000001C00000000mgr-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
0707010000002E000081B4000000000000000000000001624467C00000003F000000000000000000000000000000000000002200000000mgr-osad/sysconfig/osa-dispatcher
TNS_ADMIN=/etc/rhn/tns_admin/osa-dispatcher
export TNS_ADMIN
0707010000002F000041FD000000000000000000000001624467C000000000000000000000000000000000000000000000000E00000000mgr-osad/test07070100000030000081B4000000000000000000000001624467C0000009BC000000000000000000000000000000000000001F00000000mgr-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)
07070100000031000081B4000000000000000000000001624467C00000043F000000000000000000000000000000000000002300000000mgr-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)
07070100000032000081B4000000000000000000000001624467C000000CB5000000000000000000000000000000000000001A00000000mgr-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)
07070100000033000041FD000000000000000000000001624467C000000000000000000000000000000000000000000000002200000000mgr-osad/tns-admin-osa-dispatcher07070100000034000081B4000000000000000000000001624467C0000000E5000000000000000000000000000000000000002B00000000mgr-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
07070100000035000081B4000000000000000000000001624467C000000053000000000000000000000000000000000000002D00000000mgr-osad/tns-admin-osa-dispatcher/sqlnet.ora
log_directory_client = /var/log/rhn/oracle/osa-dispatcher
diag_adr_enabled = off
07070100000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000B00000000TRAILER!!!