File uyuni-common-libs-git-0.610c547.obscpio of Package uyuni-common-libs.28934
07070100000000000041FD00000000000000000000000164462CA600000000000000000000000000000000000000000000001200000000uyuni-common-libs07070100000001000081B400000000000000000000000164462CA6000046AC000000000000000000000000000000000000001A00000000uyuni-common-libs/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.
07070100000002000081B400000000000000000000000164462CA600000280000000000000000000000000000000000000002700000000uyuni-common-libs/Makefile.common-libs# Makefile for the common libs directory
#
SPACEWALK_FILES = __init__
CODE_DIRS = common
PYLINT_DIRS = common
CONF_DIRS =
# We look for config files in "well known" locations (rhn-conf,
# httpd-conf, logrotate)
EXTRA_DIRS =
all :: all-code all-conf
%-code : Makefile.common-libs
@$(foreach d,$(CODE_DIRS), $(MAKE) -C $(d) $* || exit 1; )
%-conf : Makefile.common-libs
@$(foreach d,$(CONF_DIRS), $(MAKE) -C $(d) $* || exit 1; )
# now include some Macros
include Makefile.defs
install :: install-code install-conf
clean :: clean-code clean-conf
test ::
mkdir -p $(CURDIR)/reports
cd ..; $(PYTHON_BIN) -m pytest test/unit/uyuni/
07070100000003000081B400000000000000000000000164462CA6000006F6000000000000000000000000000000000000002000000000uyuni-common-libs/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
ifeq ("$(PYTHON_BIN)", "")
PYTHON_BIN = "python"
endif
SPACEWALK_ROOT ?= $(shell $(PYTHON_BIN) -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())")/uyuni
export SPACEWALK_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))
SPACEWALK_PYFILES = $(addsuffix .py,$(SPACEWALK_FILES))
SPACEWALK_DEST ?= $(SPACEWALK_ROOT)/$(SUBDIR)
# what do we need to install and where
INSTALL_FILES += $(PYFILES)
INSTALL_DEST ?= $(ROOT)/$(SUBDIR)
SPACEWALK_INSTALL_FILES += $(SPACEWALK_PYFILES)
DIRS += $(addprefix $(PREFIX), \
$(sort $(EXTRA_DIRS)) $(INSTALL_DEST) $(SPACEWALK_ROOT) $(SPACEWALK_DEST))
all :: $(INSTALL_FILES)
install :: all $(DIRS) $(INSTALL_FILES) $(SPACEWALK_INSTALL_FILES)
@$(foreach f,$(INSTALL_FILES), \
$(INSTALL_DATA) $(f) $(PREFIX)$(INSTALL_DEST)/$(f) ; )
@$(foreach f,$(SPACEWALK_INSTALL_FILES), \
$(INSTALL_DATA) $(f) $(PREFIX)$(SPACEWALK_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)
07070100000004000081B400000000000000000000000164462CA6000001A4000000000000000000000000000000000000001E00000000uyuni-common-libs/__init__.py#
# Copyright (c) 2019 SUSE LLC
#
# 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.
#
07070100000005000041FD00000000000000000000000164462CA600000000000000000000000000000000000000000000001900000000uyuni-common-libs/common07070100000006000081B400000000000000000000000164462CA600000308000000000000000000000000000000000000002200000000uyuni-common-libs/common/Makefile# Makefile for spacewalk backend
#
# what is the backend top dir
TOP = ..
# Specific stuff
SUBDIR = common
SPACEWALK_FILES = __init__ \
checksum \
cli \
context_managers \
fileutils \
notificationUtils \
rhnLib \
rhn_deb \
rhn_mpm \
rhn_pkg \
rhn_rpm \
timezone_utils \
usix
SCRIPTS =
# check if we can build man pages
DOCBOOK = $(wildcard /usr/bin/docbook2man)
SGMLS = $(wildcard *.sgml)
MANS = $(patsubst %.sgml,%.8,$(SGMLS))
MANDIR ?= /usr/man
EXTRA_DIRS =
include $(TOP)/Makefile.defs
# install scripts
ifneq ($(DOCBOOK),)
# install man pages
all :: $(MANS)
install :: $(MANS) $(PREFIX)/$(MANDIR)
$(INSTALL_DATA) $(MANS) $(PREFIX)/$(MANDIR)/man8
endif
%.8 : %.sgml
$(DOCBOOK) $<
clean ::
@rm -fv $(MANS) manpage.*
07070100000007000081B400000000000000000000000164462CA6000001D3000000000000000000000000000000000000002500000000uyuni-common-libs/common/__init__.py#
# Copyright (c) 2019 SUSE LLC
#
# 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.
#
# Initialization file for the common module
#
07070100000008000081B400000000000000000000000164462CA600000BA6000000000000000000000000000000000000002500000000uyuni-common-libs/common/checksum.py#
# Copyright (c) 2009--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
try:
import hashlib
import inspect
hashlib_has_usedforsecurity = 'usedforsecurity' in inspect.getargspec(hashlib.new)[0]
except ImportError:
import md5
import sha
# pylint: disable=F0401
# pylint can't find Crypto.Hash here, but it is present on older systems.
from Crypto.Hash import SHA256 as sha256
hashlib_has_usedforsecurity = False
class hashlib(object):
@staticmethod
def new(checksum):
if checksum == 'md5':
return md5.new()
elif checksum == 'sha1':
return sha.new()
elif checksum == 'sha256':
return sha256.new()
else:
raise ValueError("Incompatible checksum type")
def getHashlibInstance(hash_type, used_for_security):
"""Get an instance of a hashlib object.
"""
if hashlib_has_usedforsecurity:
return hashlib.new(hash_type, usedforsecurity=used_for_security)
else:
return hashlib.new(hash_type)
def getFileChecksum(hashtype, filename=None, fd=None, file_obj=None, buffer_size=None, used_for_security=False):
""" Compute a file's checksum
Used by rotateFile()
"""
# python's md5 lib sucks
# there's no way to directly import a file.
if buffer_size is None:
buffer_size = 65536
if hashtype == 'sha':
hashtype = 'sha1'
if filename is None and fd is None and file_obj is None:
raise ValueError("no file specified")
if file_obj:
f = file_obj
elif fd is not None:
f = os.fdopen(os.dup(fd), "rb")
else:
f = open(filename, "rb")
# Rewind it
f.seek(0, 0)
m = getHashlibInstance(hashtype, used_for_security)
while 1:
try:
buf = f.read(buffer_size)
except: # pylint: disable=W0702,W0703
# No need to know exact root cause of the exception.
# Will produce checksum other than expected for such case.
break
if not buf:
break
m.update(buf)
# cleanup time
if file_obj is not None:
file_obj.seek(0, 0)
else:
f.close()
return m.hexdigest()
def getStringChecksum(hashtype, s):
""" compute checksum of an arbitrary string """
h = getHashlibInstance(hashtype, False)
h.update(s)
return h.hexdigest()
07070100000009000081B400000000000000000000000164462CA6000009B3000000000000000000000000000000000000002000000000uyuni-common-libs/common/cli.py#
# Copyright (c) 2012--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 getpass
import io
try:
# python 2
import xmlrpclib
except ImportError:
# python3
import xmlrpc.client as xmlrpclib # pylint: disable=F0401
def getUsernamePassword(cmdlineUsername, cmdlinePassword):
"""
Returns a username and password (either by returning the ones passed as
args, or the user's input
"""
if cmdlineUsername and cmdlinePassword:
return cmdlineUsername, cmdlinePassword
username = cmdlineUsername
password = cmdlinePassword
# Read the username, if not already specified
tty = io.TextIOWrapper(open("/dev/tty", "r+b", buffering=0))
while not username:
tty.write("SUSE Manager username: ")
try:
username = tty.readline()
except KeyboardInterrupt:
tty.write("\n")
sys.exit(0)
if username is None:
# EOF
tty.write("\n")
sys.exit(0)
username = username.strip()
if username:
break
# Now read the password
while not password:
try:
password = getpass.getpass("SUSE Manager password: ")
except KeyboardInterrupt:
tty.write("\n")
sys.exit(0)
tty.close()
return username, password
def xmlrpc_login(client, username, password, verbose=0):
"""
Authenticate Session call
"""
if verbose:
print("...logging in to server...")
try:
sessionkey = client.auth.login(username, password)
except xmlrpclib.Fault:
e = sys.exc_info()[1]
sys.stderr.write("Error: %s\n" % e.faultString)
sys.exit(-1)
return sessionkey
def xmlrpc_logout(client, session_key, verbose=0):
"""
End Authentication call
"""
if verbose:
print("...logging out of server...")
client.auth.logout(session_key)
0707010000000A000081B400000000000000000000000164462CA60000041F000000000000000000000000000000000000002D00000000uyuni-common-libs/common/context_managers.py"""Collection of context managers for Uyuni."""
from contextlib import contextmanager
from spacewalk.common.rhnConfig import CFG, initCFG
@contextmanager
def cfg_component(component=None, root=None, filename=None):
"""Context manager for rhnConfig.
:param comp: The configuration component to use in this context
:param root: Root directory location of configuration files, optional
:param filename: Configuration file, optional
There is a common pattern when using rhnConfig that consists of the following steps:
1. save current component: old = CFG.getComponent()
2. set CFG to another component: initCFG('my_component')
3. Read / Set configuration values
4. set CFG back to the previous component
This pattern can now be expressed using the ``with`` statement:
with cfg_component('my_component') as CFG:
print(CFG.my_value)
"""
previous = CFG.getComponent()
initCFG(component=component, root=root, filename=filename)
try:
yield CFG
finally:
initCFG(previous)
0707010000000B000081B400000000000000000000000164462CA60000440B000000000000000000000000000000000000002600000000uyuni-common-libs/common/fileutils.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 codecs
import os
import sys
import bz2
import gzip
import pwd
import grp
import shutil
import subprocess
import select
import stat
import tempfile
import io
from uyuni.common.checksum import getFileChecksum
from uyuni.common.rhnLib import isSUSE
from uyuni.common.usix import ListType, TupleType, MaxInt
try:
import lzma
HAS_LZMA = True
except ImportError:
HAS_LZMA = False
def cleanupAbsPath(path):
""" take ~taw/../some/path/$MOUNT_POINT/blah and make it sensible.
Path returned is absolute.
NOTE: python 2.2 fixes a number of bugs with this and eliminates
the need for os.path.expanduser
"""
if path is None:
return None
return os.path.abspath(
os.path.expanduser(
os.path.expandvars(path)))
def cleanupNormPath(path, dotYN=0):
""" take ~taw/../some/path/$MOUNT_POINT/blah and make it sensible.
Returned path may be relative.
NOTE: python 2.2 fixes a number of bugs with this and eliminates
the need for os.path.expanduser
"""
if path is None:
return None
path = os.path.normpath(
os.path.expanduser(
os.path.expandvars(path)))
if dotYN and not (path and path[0] == '/'):
dirs = path.split('/')
if dirs[:1] not in (['.'], ['..']):
dirs = ['.'] + dirs
path = '/'.join(dirs)
return path
def rotateFile(filepath, depth=5, suffix='.', verbosity=0):
""" backup/rotate a file
depth (-1==no limit) refers to num. of backups (rotations) to keep.
Behavior:
(1)
x.txt (current)
x.txt.1 (old)
x.txt.2 (older)
x.txt.3 (oldest)
(2)
all file stats preserved. Doesn't blow away original file.
(3)
if x.txt and x.txt.1 are identical (size or checksum), None is
returned
"""
# check argument sanity (should really be down outside of this function)
if not filepath or not isinstance(filepath, type('')):
raise ValueError("filepath '%s' is not a valid arguement" % filepath)
if not isinstance(depth, type(0)) or depth < -1 \
or depth > MaxInt - 1 or depth == 0:
raise ValueError("depth must fall within range "
"[-1, 1...%s]" % (MaxInt - 1))
# force verbosity to be a numeric value
verbosity = verbosity or 0
if not isinstance(verbosity, type(0)) or verbosity < -1 \
or verbosity > MaxInt - 1:
raise ValueError('invalid verbosity value: %s' % (verbosity))
filepath = cleanupAbsPath(filepath)
if not os.path.isfile(filepath):
raise ValueError("filepath '%s' does not lead to a file" % filepath)
pathNSuffix = filepath + suffix
pathNSuffix1 = pathNSuffix + '1'
if verbosity > 1:
sys.stderr.write("Working dir: %s\n"
% os.path.dirname(pathNSuffix))
# is there anything to do? (existence, then size, then checksum)
checksum_type = 'sha1'
if os.path.exists(pathNSuffix1) and os.path.isfile(pathNSuffix1) \
and os.stat(filepath)[6] == os.stat(pathNSuffix1)[6] \
and getFileChecksum(checksum_type, filepath) == \
getFileChecksum(checksum_type, pathNSuffix1):
# nothing to do
if verbosity:
sys.stderr.write("File '%s' is identical to its rotation. "
"Nothing to do.\n" % os.path.basename(filepath))
return None
# find last in series (of rotations):
last = 0
while os.path.exists('%s%d' % (pathNSuffix, last + 1)):
last = last + 1
# percolate renames:
for i in range(last, 0, -1):
os.rename('%s%d' % (pathNSuffix, i), '%s%d' % (pathNSuffix, i + 1))
if verbosity > 1:
filename = os.path.basename(pathNSuffix)
sys.stderr.write("Moving file: %s%d --> %s%d\n" % (filename, i,
filename, i + 1))
# blow away excess rotations:
if depth != -1:
last = last + 1
for i in range(depth + 1, last + 1):
path = '%s%d' % (pathNSuffix, i)
os.unlink(path)
if verbosity:
sys.stderr.write("Rotated out: '%s'\n" % (
os.path.basename(path)))
# do the actual rotation
shutil.copy2(filepath, pathNSuffix1)
if os.path.exists(pathNSuffix1) and verbosity:
sys.stderr.write("Backup made: '%s' --> '%s'\n"
% (os.path.basename(filepath),
os.path.basename(pathNSuffix1)))
# return the full filepath of the backed up file
return pathNSuffix1
def rhn_popen(cmd, progressCallback=None, bufferSize=16384, outputLog=None):
""" popen-like function, that accepts execvp-style arguments too (i.e. an
array of params, thus making shell escaping unnecessary)
cmd can be either a string (like "ls -l /dev"), or an array of
arguments ["ls", "-l", "/dev"]
Returns the command's error code, a stream with stdout's contents
and a stream with stderr's contents
progressCallback --> progress bar twiddler
outputLog --> optional log file file object write method
"""
cmd_is_list = isinstance(cmd, (ListType, TupleType))
if cmd_is_list:
cmd = list(map(str, cmd))
# pylint: disable=E1101
c = subprocess.Popen(cmd, bufsize=0, stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
close_fds=True, shell=(not cmd_is_list))
# We don't write to the child process
c.stdin.close()
# Create two temporary streams to hold the info from stdout and stderr
child_out = tempfile.TemporaryFile(prefix='/tmp/my-popen-', mode='r+b')
child_err = tempfile.TemporaryFile(prefix='/tmp/my-popen-', mode='r+b')
# Map the input file descriptor with the temporary (output) one
fd_mappings = [(c.stdout, child_out), (c.stderr, child_err)]
exitcode = None
count = 1
while 1:
# Is the child process done?
status = c.poll()
if status is not None:
if status >= 0:
# Save the exit code, we still have to read from the pipes
exitcode = status
else:
# Some signal sent to this process
if outputLog is not None:
outputLog("rhn_popen: Signal %s received\n" % (-status))
exitcode = status
break
fd_set = [x[0] for x in fd_mappings]
readfds = select.select(fd_set, [], [])[0]
for in_fd, out_fd in fd_mappings:
if in_fd in readfds:
# There was activity on this file descriptor
output = os.read(in_fd.fileno(), bufferSize)
if output:
# show progress
if progressCallback:
count = count + len(output)
progressCallback(count)
if outputLog is not None:
outputLog(output)
# write to the output buffer(s)
out_fd.write(output)
out_fd.flush()
if exitcode is not None:
# Child process is done
break
for f_in, f_out in fd_mappings:
f_in.close()
f_out.seek(0, 0)
return exitcode, child_out, child_err
def makedirs(path, mode=int('0755', 8), user=None, group=None):
"""Creates all required directories on a path and changes its owner and group
:param path: path to create
:type path: str
:param mode: mode for the created directories
:type mode: int
:param user: desired owner
:type user: str
:param group: desired group
:type group:str
:returns: None
"""
dirs_to_create = []
dirname = path
uid, gid = getUidGid(user, group)
if uid is None:
raise OSError("*** ERROR: user %s doesn't exist. Cannot create path." % user)
if gid is None:
raise OSError("*** ERROR: group %s doesn't exist. Cannot create path." % group)
while 1:
if os.path.isdir(dirname):
# We're done with this step
break
# We have to create this directory
dirs_to_create.append(dirname)
dirname, last = os.path.split(dirname)
if not last:
# We reached the top directory
break
# Now create the directories
while dirs_to_create:
dirname = dirs_to_create.pop()
try:
os.mkdir(dirname, mode)
except OSError:
e = sys.exc_info()[1]
if e.errno != 17: # File exists
raise
# Ignore the error
try:
os.chown(dirname, uid, gid)
except OSError:
# Changing permissions failed; ignore the error
sys.stderr.write("Changing owner for %s failed\n" % dirname)
def createPath(path, user=None, group=None, chmod=int('0755', 8)):
"""advanced makedirs
Will create the path if necessary.
Will chmod, and chown that path properly.
Defaults for user/group to the apache user
Uses the above makedirs() function.
"""
if isSUSE():
if user is None:
user = 'wwwrun'
if group is None:
group = 'www'
else:
if user is None:
user = 'apache'
if group is None:
group = 'apache'
path = cleanupAbsPath(path)
if not os.path.exists(path):
makedirs(path, mode=chmod, user=user, group=group)
elif not os.path.isdir(path):
raise ValueError("ERROR: createPath('%s'): path doesn't lead to a directory" % str(path))
else:
os.chmod(path, chmod)
uid, gid = getUidGid(user, group)
try:
os.chown(path, uid, gid)
except OSError:
# Changing permissions failed; ignore the error
sys.stderr.write("Changing owner for %s failed\n" % path)
def setPermsPath(path, user=None, group='root', chmod=int('0750', 8)):
"""chown user.group and set permissions to chmod"""
if isSUSE() and user is None:
user = 'wwwrun'
elif user is None:
user = 'apache'
if not os.path.exists(path):
raise OSError("*** ERROR: Path doesn't exist (can't set permissions): %s" % path)
# If non-root, don't bother to change owners
if os.getuid() != 0:
return
gc = GecosCache()
uid = gc.getuid(user)
if uid is None:
raise OSError("*** ERROR: user '%s' doesn't exist. Cannot set permissions properly." % user)
gid = gc.getgid(group)
if gid is None:
raise OSError("*** ERROR: group '%s' doesn't exist. Cannot set permissions properly." % group)
uid_, gid_ = os.stat(path)[4:6]
if uid_ != uid or gid_ != gid:
os.chown(path, uid, gid)
os.chmod(path, chmod)
class GecosCache:
"Cache getpwnam() and getgrnam() calls"
__shared_data = {}
def __init__(self):
self.__dict__ = self.__shared_data
if not list(self.__shared_data.keys()):
# Not initialized
self._users = {}
self._groups = {}
def getuid(self, name):
"Return the UID of the user by name"
if name in self._users:
return self._users[name]
try:
uid = pwd.getpwnam(name)[2]
except KeyError:
return None
self._users[name] = uid
return uid
def getgid(self, name):
"Return the GID of the group by name"
if name in self._groups:
return self._groups[name]
try:
gid = grp.getgrnam(name)[2]
except KeyError:
return None
self._groups[name] = gid
return gid
def reset(self):
self.__shared_data.clear()
self.__init__()
def getUidGid(user=None, group=None):
"""Returns uid and gid of given user name and group name
:param user: The name of the user
:type user: str
:param group: The name of the group
:type group: str
:returns: a tuple with the uid and the gid
:rtype: tuple
"""
gc = GecosCache()
if user:
uid = gc.getuid(user)
else:
uid = os.getuid()
if group:
gid = gc.getgid(group)
else:
gid = os.getgid()
return uid, gid
# Duplicated in client/tools/rhncfg/config_common/file_utils.py to remove dependency
# requirement. If making changes make them there too.
FILETYPE2CHAR = {
'file': '-',
'directory': 'd',
'symlink': 'l',
'chardev': 'c',
'blockdev': 'b',
}
# Duplicated in client/tools/rhncfg/config_common/file_utils.py to remove dependency
# requirement. If making changes make them there too.
def _ifelse(cond, thenval, elseval):
if cond:
return thenval
else:
return elseval
# Duplicated in client/tools/rhncfg/config_common/file_utils.py to remove dependency
# requirement. If making changes make them there too.
def ostr_to_sym(octstr, ftype):
""" Convert filemode in octets (like '644') to string like "ls -l" ("-rwxrw-rw-")
ftype is one of: file, directory, symlink, chardev, blockdev.
"""
mode = int(str(octstr), 8)
symstr = FILETYPE2CHAR.get(ftype, '?')
symstr += _ifelse(mode & stat.S_IRUSR, 'r', '-')
symstr += _ifelse(mode & stat.S_IWUSR, 'w', '-')
symstr += _ifelse(mode & stat.S_IXUSR,
_ifelse(mode & stat.S_ISUID, 's', 'x'),
_ifelse(mode & stat.S_ISUID, 'S', '-'))
symstr += _ifelse(mode & stat.S_IRGRP, 'r', '-')
symstr += _ifelse(mode & stat.S_IWGRP, 'w', '-')
symstr += _ifelse(mode & stat.S_IXGRP,
_ifelse(mode & stat.S_ISGID, 's', 'x'),
_ifelse(mode & stat.S_ISGID, 'S', '-'))
symstr += _ifelse(mode & stat.S_IROTH, 'r', '-')
symstr += _ifelse(mode & stat.S_IWOTH, 'w', '-')
symstr += _ifelse(mode & stat.S_IXOTH,
_ifelse(mode & stat.S_ISVTX, 't', 'x'),
_ifelse(mode & stat.S_ISVTX, 'T', '-'))
return symstr
# Duplicated in client/tools/rhncfg/config_common/file_utils.py to remove dependency
# requirement. If making changes make them there too.
def f_date(dbiDate):
return "%04d-%02d-%02d %02d:%02d:%02d" % (dbiDate.year, dbiDate.month,
dbiDate.day, dbiDate.hour, dbiDate.minute, dbiDate.second)
class payload:
""" this class implements simple file like object usable for reading payload
from rpm, mpm, etc.
it skips first 'skip' bytes of header
"""
def __init__(self, filename, skip=0):
self.fileobj = open(filename, 'r')
self.skip = skip
self.seek(0)
def seek(self, offset, whence=0):
if whence == 0:
offset += self.skip
return self.fileobj.seek(offset, whence)
def tell(self):
return self.fileobj.tell() - self.skip
@staticmethod
def truncate(size=-1):
# pylint: disable=W0613
raise AttributeError("'Payload' object do not implement this method")
@staticmethod
def write(_s):
raise AttributeError("'Payload' object do not implement this method")
@staticmethod
def writelines(_seq):
raise AttributeError("'Payload' object do not implement this method")
def __getattr__(self, x):
return getattr(self.fileobj, x)
def decompress_open(filename):
file_obj = None
if filename.endswith('.gz'):
file_obj = gzip.open(filename, 'rb')
elif filename.endswith('.bz2'):
file_obj = bz2.BZ2File(filename, 'rb')
elif filename.endswith('.xz'):
if HAS_LZMA:
file_obj = lzma.LZMAFile(filename, 'rb')
else:
file_obj = subprocess.Popen(["xz", "-d", "-k", filename],
stdout=subprocess.PIPE,
stderr=subprocess.DEVNULL).stdout
elif filename.endswith('.zck'):
file_obj = subprocess.Popen(["unzck", "-c", filename],
stdout=subprocess.PIPE,
stderr=subprocess.DEVNULL).stdout
elif filename.endswith('.zst'):
file_obj = subprocess.Popen(["zstd", "-d", "-c", filename],
stdout=subprocess.PIPE,
stderr=subprocess.DEVNULL).stdout
else:
file_obj = codecs.open(filename, 'r', encoding="utf8")
if filename.endswith(('.gz', '.bz2', '.xz', '.zck')):
return io.TextIOWrapper(file_obj, encoding="utf8")
return file_obj
0707010000000C000081B400000000000000000000000164462CA60000054A000000000000000000000000000000000000002E00000000uyuni-common-libs/common/notificationUtils.pyfrom spacewalk.common.rhnConfig import initCFG, CFG
from spacewalk.common.rhnLog import log_debug
from spacewalk.server import rhnSQL
import json
try:
import xmlrpc.client as xmlrpc_client
except ImportError:
import xmlrpclib as xmlrpc_client
# see TaskoXmlRpcHandler.java for available methods
TASKOMATIC_XMLRPC_URL = 'http://localhost:2829/RPC2'
def getNotificationsTypeDisabled():
"""Return list of types which are disabled"""
disabledTypes = []
comp = CFG.getComponent()
initCFG("java")
if CFG.notifications_type_disabled:
disabledTypes = CFG.notifications_type_disabled.split(",")
initCFG(comp)
return disabledTypes
class CreateBootstrapRepoFailed:
def __init__(self, ident, detail=""):
self.identifier = ident
self.details = detail
self.type = "CreateBootstrapRepoFailed"
def store(self):
if self.type in getNotificationsTypeDisabled():
return
return self._create_bootstrap_repo_failed_notification()
def _create_bootstrap_repo_failed_notification(self):
client = xmlrpc_client.Server(TASKOMATIC_XMLRPC_URL)
log_debug(2, "Calling createBootstrapRepoFailedNotification({0}, {1})".format(self.identifier, self.details))
return client.tasko.createBootstrapRepoFailedNotification(self.identifier, self.details)
0707010000000D000081B400000000000000000000000164462CA600001D49000000000000000000000000000000000000002300000000uyuni-common-libs/common/rhnLib.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 re
import time
from datetime import tzinfo, timedelta
try:
# python 2
import urlparse
except ImportError:
# python3
import urllib.parse as urlparse # pylint: disable=F0401,E0611
from uyuni.common import usix
def setHeaderValue(mp_table, name, values):
"""
Function that correctly sets headers in an Apache-like table
The values may be a string (which are set as for a dictionary),
or an array.
"""
# mp_table is an Apache mp_table (like headers_in or headers_out)
# Sets the header name to the values
if isinstance(values, (usix.ListType, usix.TupleType)):
for v in values:
mp_table.add(name, str(v))
else:
mp_table[name] = str(values)
rfc822_days = ('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun')
rfc822_mons = ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec')
def rfc822time(arg):
"""
Return time as a string formatted such as: 'Wed, 23 Jun 2001 23:08:35 GMT'.
We must not use locale-specific functions such as strftime here because
the RFC explicitly requires C-locale only formatting. To satisfy this
requirement, we declare our own days and months here and do the formatting
manually.
This function accepts a single argument. If it is a List or Tuple type,
it is assumed to be of the form struct_time, as specified in the Python
time module reference. If the argument is a float, it is expected to be
the number of seconds from the epoch.
NOTE: In all cases, the argument is assumed to be in local time. It will
be translated to GMT in the return value.
"""
if isinstance(arg, (usix.ListType, usix.TupleType)):
# Convert to float.
arg = time.mktime(tuple(arg))
# Now, the arg must be a float.
(tm_year, tm_mon, tm_mday, tm_hour, tm_min,
tm_sec, tm_wday, _tm_yday_, _tm_isdst_) = time.gmtime(arg)
return \
"%s, %02d %s %04d %02d:%02d:%02d %s" % \
(rfc822_days[tm_wday], tm_mday, rfc822_mons[tm_mon - 1], tm_year,
tm_hour, tm_min, tm_sec, "GMT")
def timestamp(s):
"""
Converts the string in format YYYYMMDDHHMISS to seconds from the epoch
"""
if isinstance(s, (usix.IntType, usix.FloatType)):
# Presumably already a timestamp
return s
if len(s) == 14:
format_string = "%Y%m%d%H%M%S"
elif len(s) == 19:
format_string = "%Y-%m-%d %H:%M:%S"
else:
raise TypeError("String '%s' is not a YYYYMMDDHHMISS" % s)
# Get the current DST setting
timeval = list(time.strptime(s, format_string))
# No daylight information available
timeval[8] = -1
return time.mktime(tuple(timeval))
def checkValue(val, *args):
""" A type/value checker
Check value against the list of acceptable values / types
"""
for a in args:
if isinstance(a, usix.TypeType):
# Is val of type a?
if isinstance(val, a):
return 1
else:
# This is an actual value we allow
if val == a:
return 1
return 0
def parseUrl(url):
""" urlparse is more complicated than what we need.
We make the assumption that the URL has real URL information.
NOTE: http/https ONLY for right now.
The normal behavior of urlparse:
- if no {http[s],file}:// then the string is considered everything
that normally follows the URL, e.g. /XMLRPC
- if {http[s],file}:// exists, anything between that and the next /
is the URL.
The behavior of *this* function:
- if no {http[s],file}:// then the string is simply assumed to be a
URL without the {http[s],file}:// attached. The parsed info is
reparsed as one would think it would be:
- returns: (addressing scheme, network location, path,
parameters, query, fragment identifier).
NOTE: netloc (or network location) can be HOSTNAME:PORT
"""
schemes = ('http', 'https')
if url is None:
return None
parsed = list(urlparse.urlparse(url))
if not parsed[0] or parsed[0] not in schemes:
url = 'https://' + url
parsed = list(urlparse.urlparse(url))
parsed[0] = ''
return tuple(parsed)
def hash_object_id(object_id, factor):
"""Given an object id (assumed to be <label>-<number>), returns the
last few digits for the number. For instance, (812345, 3) should
return 345"""
# Grab the digits after -
num_id = object_id.split('-')[-1]
# get last 'factor' numbers
num_id = num_id[-factor:]
return num_id.rjust(factor, '0')
# reg exp for splitting rpm package names.
re_rpmName = re.compile("^(.*)-([^-]*)-([^-]*)$")
def parseRPMName(pkgName):
""" IN: Package string in, n-n-n-v.v.v-r.r_r, format.
OUT: Four strings (in a tuple): name, epoch, version, release.
"""
reg = re_rpmName.match(pkgName)
if reg is None:
return None, None, None, None
n, v, r = reg.group(1, 2, 3)
e = None
ind = r.find(':')
if ind >= 0: # epoch found
e = r[ind + 1:]
r = r[0:ind]
return str(n), e, str(v), str(r)
def parseDEBName(pkgName):
""" IN: Package string in, n-n_v.v-v.v-r.r, format.
OUT: Four strings (in a tuple): name, epoch, version, release.
"""
if pkgName.find('_') == -1:
return None, None, None, None
e = None
n, version = pkgName.split('_')
if version.find(':') != -1:
e, version = version.split(':')
version_tmpArr = version.split('-')
v = '-'.join(version_tmpArr[:-1])
r = version_tmpArr[-1]
return str(n), e, str(v), str(r)
def isSUSE():
"""Return true if this is a SUSE system, otherwise false"""
if not os.path.exists('/etc/os-release'):
return False
cpe_name = ''
try:
lines = open('/etc/os-release', 'r').readlines()
for line in lines:
# Skip empty and comment-only lines
if re.match(r'[ \t]*(#|$)', line):
continue
# now split it into keys and values. We allow for max one
# split/cut (the first one)
(key, val) = [c.strip() for c in line.split('=', 1)]
if key == 'CPE_NAME':
cpe_name = val
break
except (IOError, OSError):
pass
if 'cpe:/o:opensuse:' in cpe_name or 'cpe:/o:suse:' in cpe_name:
return True
return False
class UTC(tzinfo):
"""Used for creating offset-aware datetime objects in Python 2."""
# pylint: disable=W0613
def utcoffset(self, dt):
return timedelta(0)
def tzname(self, dt):
return "UTC"
def dst(self, dt):
return timedelta(0)
utc = UTC()
0707010000000E000081B400000000000000000000000164462CA60000139B000000000000000000000000000000000000002400000000uyuni-common-libs/common/rhn_deb.py#
# Copyright (c) 2010--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.
#
#
# Meta-package manager
#
# Author: Lukas Durfina <lukas.durfina@gmail.com>
import sys
import tempfile
from debian import debfile
from uyuni.common.usix import raise_with_tb
from uyuni.common import checksum
from uyuni.common.rhn_pkg import A_Package, InvalidPackageError
# bare-except and broad-except
# pylint: disable=W0702,W0703
DEB_CHECKSUM_TYPE = 'sha256' # FIXME: this should be a configuration option
class deb_Header:
"Wrapper class for an deb header - we need to store a flag is_source"
def __init__(self, stream):
self.packaging = 'deb'
self.signatures = []
self.is_source = 0
self.deb = None
try:
self.deb = debfile.DebFile(stream.name)
except Exception:
e = sys.exc_info()[1]
raise_with_tb(InvalidPackageError(e), sys.exc_info()[2])
try:
# Fill info about package
debcontrol = self.deb.debcontrol()
self.hdr = {
'name': debcontrol.get_as_string('Package'),
'arch': debcontrol.get_as_string('Architecture') + '-deb',
'summary': debcontrol.get_as_string('Description').splitlines()[0],
'epoch': '',
'version': 0,
'release': 0,
'description': debcontrol.get_as_string('Description'),
}
for hdr_k, deb_k in [('requires', 'Depends'),
('provides', 'Provides'),
('conflicts', 'Conflicts'),
('obsoletes', 'Replaces'),
('recommends', 'Recommends'),
('suggests', 'Suggests'),
('breaks', 'Breaks'),
('predepends', 'Pre-Depends'),
('payload_size', 'Installed-Size'),
('maintainer', 'Maintainer')]:
if deb_k in debcontrol:
self.hdr[hdr_k] = debcontrol.get_as_string(deb_k)
for k in list(debcontrol.keys()):
if k not in self.hdr:
self.hdr[k] = debcontrol.get_as_string(k)
version = debcontrol.get_as_string('Version')
if version.find(':') != -1:
self.hdr['epoch'], version = version.split(':')
self.hdr['version'] = version
if version.find('-') != -1:
version_tmpArr = version.split('-')
self.hdr['version'] = '-'.join(version_tmpArr[:-1])
self.hdr['release'] = version_tmpArr[-1]
else:
self.hdr['version'] = version
self.hdr['release'] = 'X'
except Exception:
e = sys.exc_info()[1]
raise_with_tb(InvalidPackageError(e), sys.exc_info()[2])
@staticmethod
def checksum_type():
return DEB_CHECKSUM_TYPE
@staticmethod
def is_signed():
return 0
def __getitem__(self, name):
return self.hdr.get(str(name))
def __setitem__(self, name, item):
self.hdr[name] = item
def __delitem__(self, name):
del self.hdr[name]
def __getattr__(self, name):
return getattr(self.hdr, name)
def __len__(self):
return len(self.hdr)
class DEB_Package(A_Package):
def __init__(self, input_stream=None):
A_Package.__init__(self, input_stream)
self.header_data = tempfile.NamedTemporaryFile()
self.checksum_type = DEB_CHECKSUM_TYPE
def read_header(self):
self._stream_copy(self.input_stream, self.header_data)
self.header_end = self.header_data.tell()
try:
self.header_data.seek(0, 0)
self.header = deb_Header(self.header_data)
except:
e = sys.exc_info()[1]
raise_with_tb(InvalidPackageError(e), sys.exc_info()[2])
def save_payload(self, output_stream):
c_hash = checksum.getHashlibInstance(self.checksum_type, False)
if output_stream:
output_start = output_stream.tell()
self._stream_copy(self.header_data, output_stream, c_hash)
self.checksum = c_hash.hexdigest()
if output_stream:
self.payload_stream = output_stream
self.payload_size = output_stream.tell() - output_start
0707010000000F000081B400000000000000000000000164462CA60000241F000000000000000000000000000000000000002400000000uyuni-common-libs/common/rhn_mpm.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 gzip
try:
# python 2
import cStringIO
except ImportError:
# python3
import io as cStringIO
import tempfile
try:
# python 2
import xmlrpclib
except ImportError:
# python3
import xmlrpc.client as xmlrpclib # pylint: disable=F0401
import struct
import sys
from uyuni.common import fileutils
from uyuni.common.usix import ListType, TupleType
from uyuni.common.usix import raise_with_tb
from uyuni.common import checksum
from uyuni.common.rhn_pkg import A_Package, InvalidPackageError
# bare-except and broad-except
# pylint: disable=W0702,W0703
MPM_CHECKSUM_TYPE = 'md5' # FIXME: this should be a configuration option
def labelCompare(l1, l2):
try:
from uyuni.common import rhn_rpm
except ImportError:
# rhn_rpm not avalable; return a dummy comparison function
return -1
return rhn_rpm.labelCompare(l1, l2)
def get_package_header(filename=None, file_obj=None, fd=None):
return load(filename=filename, file_obj=file_obj, fd=fd)[0]
def load(filename=None, file_obj=None, fd=None):
""" Loads an MPM and returns its header and its payload """
if (filename is None and file_obj is None and fd is None):
raise ValueError("No parameters passed")
if filename is not None:
f = open(filename)
elif file_obj is not None:
f = file_obj
else: # fd is not None
f = os.fdopen(os.dup(fd), "r")
f.seek(0, 0)
p = MPM_Package()
try:
p.load(f)
except InvalidPackageError:
e = sys.exc_info()[1]
try:
return load_rpm(f)
except InvalidPackageError:
raise_with_tb(e, sys.exc_info()[2])
except:
raise_with_tb(e, sys.exc_info()[2])
return p.header, p.payload_stream
def load_rpm(stream):
# Hmm, maybe an rpm
try:
from uyuni.common import rhn_rpm
except ImportError:
raise_with_tb(InvalidPackageError, sys.exc_info()[2])
# Dup the file descriptor, we don't want it to get closed before we read
# the payload
newfd = os.dup(stream.fileno())
stream = os.fdopen(newfd, "r")
stream.flush()
stream.seek(0, 0)
try:
header = rhn_rpm.get_package_header(file_obj=stream)
except InvalidPackageError:
e = sys.exc_info()[1]
raise_with_tb(InvalidPackageError(*e.args), sys.exc_info()[2])
except rhn_rpm.error:
e = sys.exc_info()[1]
raise_with_tb(InvalidPackageError(e), sys.exc_info()[2])
except:
raise_with_tb(InvalidPackageError, sys.exc_info()[2])
stream.seek(0, 0)
return header, stream
class MPM_Header:
"Wrapper class for an mpm header - we need to store a flag is_source"
def __init__(self, hdr):
self.hdr = hdr
self.is_source = hdr.get('is_source')
self.packaging = 'mpm'
self.signatures = []
def __getitem__(self, name):
return self.hdr.get(name)
def __setitem__(self, name, item):
self.hdr[name] = item
def __delitem__(self, name):
del self.hdr[name]
def __getattr__(self, name):
return getattr(self.hdr, name)
def __len__(self):
return len(self.hdr)
@staticmethod
def is_signed():
return 0
@staticmethod
def checksum_type():
return MPM_CHECKSUM_TYPE
@staticmethod
def unload():
return None
MPM_HEADER_COMPRESSED_GZIP = 1
MPM_PAYLOAD_COMPRESSED_GZIP = 1
class MPM_Package(A_Package):
# pylint: disable=R0902
_lead_format = '!16sB3s4L92s'
_magic = 'mpmpackage012345'
def __init__(self, input_stream=None):
A_Package.__init__(self, input_stream)
self.header_flags = MPM_HEADER_COMPRESSED_GZIP
self.header_size = 0
self.payload_flags = 0
assert(len(self._magic) == 16)
self._buffer_size = 16384
self.file_size = 0
def read_header(self):
arr = self._read_lead(self.input_stream)
magic = arr[0]
if magic != self._magic:
raise InvalidPackageError()
header_len, payload_len = int(arr[5]), int(arr[6])
self.header_flags, self.payload_flags = arr[3], arr[4]
self.file_size = 128 + header_len + payload_len
header_data = self._read_bytes(self.input_stream, header_len)
self._read_header(header_data, self.header_flags)
self.checksum_type = self.header.checksum_type()
def _read_lead(self, stream):
# Lead has the following format:
# 16 bytes magic
# 1 bytes version
# 3 bytes unused
# 4 bytes header flags
# 4 bytes payload flags
# 4 bytes header length
# 4 bytes payload length
# 92 bytes padding to 128 bytes
lead = self._read_bytes(stream, 128)
if len(lead) != 128:
raise InvalidPackageError()
arr = struct.unpack(self._lead_format, lead)
return arr
def load(self, input_stream):
# Clean up
self.__init__()
self.input_stream = input_stream
# Read the header
self.read_header()
payload_stream = fileutils.payload(input_stream.name, input_stream.tell())
input_stream.seek(self.file_size)
if self.file_size != input_stream.tell():
raise InvalidPackageError()
self._read_payload(payload_stream, self.payload_flags)
def _read_header(self, header_data, header_flags):
if header_flags & MPM_HEADER_COMPRESSED_GZIP:
t = cStringIO.StringIO(header_data)
g = gzip.GzipFile(None, "r", 0, t)
header_data = g.read()
g.close()
t.close()
try:
params, _x = xmlrpclib.loads(header_data)
except:
# XXX
raise
self.header = MPM_Header(params[0])
def _read_payload(self, payload_stream, payload_flags):
payload_stream.seek(0, 0)
if payload_flags & MPM_PAYLOAD_COMPRESSED_GZIP:
g = gzip.GzipFile(None, "r", 0, payload_stream)
t = tempfile.TemporaryFile()
self._stream_copy(g, t)
g.close()
payload_stream = t
self.payload_stream = payload_stream
def write(self, output_stream):
if self.header is None:
raise Exception()
output_stream.seek(128, 0)
self._encode_header(output_stream)
self._encode_payload(output_stream)
# pylint: disable=E0012,W1401
# now we know header and payload size so rewind back and write lead
lead_arr = (self._magic, 1, "\0" * 3, self.header_flags,
self.payload_flags, self.header_size, self.payload_size, '\0' * 92)
# lead
lead = struct.pack(self._lead_format, *lead_arr)
output_stream.seek(0, 0)
output_stream.write(lead)
output_stream.seek(0, 2)
def _encode_header(self, stream):
assert(self.header is not None)
data = xmlrpclib.dumps((_replace_null(self.header), ))
start = stream.tell()
if self.header_flags & MPM_HEADER_COMPRESSED_GZIP:
f = gzip.GzipFile(None, "wb", 9, stream)
f.write(data)
f.close()
else:
stream.write(data)
stream.flush()
self.header_size = stream.tell() - start
def _encode_payload(self, stream, c_hash=None):
assert(self.payload_stream is not None)
if stream:
start = stream.tell()
if stream and self.payload_flags & MPM_PAYLOAD_COMPRESSED_GZIP:
f = gzip.GzipFile(None, "wb", 9, stream)
self._stream_copy(self.payload_stream, f, c_hash)
f.close()
else:
self._stream_copy(self.payload_stream, stream, c_hash)
if stream:
self.payload_size = stream.tell() - start
def save_payload(self, output_stream):
self.payload_stream = self.input_stream
c_hash = checksum.getHashlibInstance(self.header.checksum_type(), False)
self._encode_payload(output_stream, c_hash)
self.checksum = c_hash.hexdigest()
if output_stream:
self.payload_stream = output_stream
def _replace_null(obj):
if obj is None:
return ''
if isinstance(obj, ListType):
return list(map(_replace_null, obj))
if isinstance(obj, TupleType):
return tuple(_replace_null(list(obj)))
if hasattr(obj, 'items'):
obj_dict = {}
for k, v in list(obj.items()):
obj_dict[_replace_null(k)] = _replace_null(v)
return obj_dict
return obj
07070100000010000081B400000000000000000000000164462CA6000011E9000000000000000000000000000000000000002400000000uyuni-common-libs/common/rhn_pkg.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
from rhn.stringutils import bstr
from uyuni.common import checksum
def get_package_header(filename=None, file_obj=None, fd=None):
# pylint: disable=E1103
if filename is not None:
stream = open(filename, mode='rb')
need_close = True
elif file_obj is not None:
stream = file_obj
else:
stream = os.fdopen(os.dup(fd), "r")
need_close = True
if stream.name.endswith('.deb'):
packaging = 'deb'
elif stream.name.endswith('.rpm'):
packaging = 'rpm'
else:
packaging = 'mpm'
a_pkg = package_from_stream(stream, packaging)
a_pkg.read_header()
if need_close:
stream.close()
return a_pkg.header
def package_from_stream(stream, packaging):
if packaging == 'deb':
from uyuni.common import rhn_deb
a_pkg = rhn_deb.DEB_Package(stream)
elif packaging == 'rpm':
from uyuni.common import rhn_rpm
a_pkg = rhn_rpm.RPM_Package(stream)
elif packaging == 'mpm':
from uyuni.common import rhn_mpm
a_pkg = rhn_mpm.MPM_Package(stream)
else:
a_pkg = None
return a_pkg
def package_from_filename(filename):
if filename.endswith('.deb'):
packaging = 'deb'
elif filename.endswith('.rpm') or filename.endswith('.hdr'):
packaging = 'rpm'
else:
packaging = 'mpm'
stream = open(filename, mode='rb')
return package_from_stream(stream, packaging)
BUFFER_SIZE = 8388608
DEFAULT_CHECKSUM_TYPE = 'md5'
class A_Package:
"""virtual class that implements shared methods for RPM/MPM/DEB package object"""
# pylint: disable=R0902
def __init__(self, input_stream=None):
self.header = None
self.header_start = 0
self.header_end = 0
self.input_stream = input_stream
self.checksum_type = DEFAULT_CHECKSUM_TYPE
self.checksum = None
self.payload_stream = None
self.payload_size = None
def read_header(self):
"""reads header from self.input_file"""
pass
def save_payload(self, output_stream):
"""saves payload to output_stream"""
c_hash = checksum.getHashlibInstance(self.checksum_type, False)
if output_stream:
output_start = output_stream.tell()
self._stream_copy(self.input_stream, output_stream, c_hash)
self.checksum = c_hash.hexdigest()
if output_stream:
self.payload_stream = output_stream
self.payload_size = output_stream.tell() - output_start
def payload_checksum(self):
# just read and compute checksum
start = self.input_stream.tell()
self.save_payload(None)
self.payload_size = self.input_stream.tell() - start + self.header_end
self.payload_stream = self.input_stream
def set_checksum_type(self, ctype=None):
"""set ctype as checksum type. If ctype is None; reset to default"""
if self.checksum_type == ctype:
return
if ctype == None and DEFAULT_CHECKSUM_TYPE != self.checksum_type:
self.checksum_type = DEFAULT_CHECKSUM_TYPE
self.payload_checksum()
elif self.checksum_type != ctype:
self.checksum_type = ctype
self.payload_checksum()
@staticmethod
def _stream_copy(source, dest, c_hash=None):
"""copies data from the source stream to the destination stream"""
while True:
buf = source.read(BUFFER_SIZE)
if not buf:
break
if dest:
dest.write(buf)
if c_hash:
c_hash.update(buf)
@staticmethod
def _read_bytes(stream, amt):
ret = bstr('')
while amt:
buf = stream.read(min(amt, BUFFER_SIZE))
if not buf:
return ret
ret = ret + buf
amt = amt - len(buf)
return ret
class InvalidPackageError(Exception):
pass
07070100000011000081B400000000000000000000000164462CA600003C8C000000000000000000000000000000000000002400000000uyuni-common-libs/common/rhn_rpm.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 sys
import struct
import tempfile
import functools
import rpm
from uyuni.common.usix import raise_with_tb
from uyuni.common.usix import next as usix_next
from uyuni.common import checksum
from uyuni.common.rhn_pkg import A_Package, InvalidPackageError
from rhn.stringutils import sstr
# bare-except and broad-except
# pylint: disable=W0702,W0703
if not hasattr(tempfile, 'SpooledTemporaryFile'):
# RHEL5
tempfile.SpooledTemporaryFile = tempfile.NamedTemporaryFile
# pylint: disable=E1101
# Expose a bunch of useful constants from rpm
error = rpm.error
sym, val = None, None
for sym, val in list(rpm.__dict__.items()):
if sym[:3] == 'RPM':
# A constant, probably - import it into our namespace
globals()[sym] = val
del sym, val
# need this for rpm-pyhon < 4.6 (e.g. on RHEL5)
rpm.RPMTAG_FILEDIGESTALGO = 5011
rpm.RPMTAG_MODULARITYLABEL = 5096
# these values are taken from /usr/include/rpm/rpmpgp.h
# PGPHASHALGO_MD5 = 1, /*!< MD5 */
# PGPHASHALGO_SHA1 = 2, /*!< SHA1 */
# PGPHASHALGO_RIPEMD160 = 3, /*!< RIPEMD160 */
# PGPHASHALGO_MD2 = 5, /*!< MD2 */
# PGPHASHALGO_TIGER192 = 6, /*!< TIGER192 */
# PGPHASHALGO_HAVAL_5_160 = 7, /*!< HAVAL-5-160 */
# PGPHASHALGO_SHA256 = 8, /*!< SHA256 */
# PGPHASHALGO_SHA384 = 9, /*!< SHA384 */
# PGPHASHALGO_SHA512 = 10, /*!< SHA512 */
PGPHASHALGO = {
1: 'md5',
2: 'sha1',
3: 'ripemd160',
5: 'md2',
6: 'tiger192',
7: 'haval-5-160',
8: 'sha256',
9: 'sha384',
10: 'sha512',
}
class RPM_Header:
"Wrapper class for an rpm header - we need to store a flag is_source"
def __init__(self, hdr, is_source=None):
self.hdr = hdr
self.is_source = is_source
self.packaging = 'rpm'
self.signatures = []
self._extract_signatures()
def __getitem__(self, name):
item = self.hdr[name]
if isinstance(item, bytes):
item = sstr(item)
elif isinstance(item, list):
item = [sstr(i) if isinstance(i, bytes) else i for i in item]
return item
def __contains__(self, name):
return True if name in self.hdr else False
def __setitem__(self, name, item):
self.hdr[name] = item
def __delitem__(self, name):
del self.hdr[name]
def __getattr__(self, name):
item = getattr(self.hdr, name)
if isinstance(item, bytes):
item = sstr(item)
elif isinstance(item, list):
item = [sstr(i) if isinstance(i, bytes) else i for i in item]
return item
def __len__(self):
return len(self.hdr)
def __nonzero__(self):
return bool(self.hdr)
__bool__ = __nonzero__
def get(self, name, default=None):
return self.hdr[name] if name in self.hdr else default
def modularity_label(self):
"""
Get modularity label tag.
Returns string of modularity label or None if tag is not there.
Fix: Some distributions use the DISTTAG (1155) tag instead of
MODULARITYLABEL (5096) to label modular packages in the format:
`module(n:s:v:c:a)`. We need to check this tag as a fallback
(bsc#1192487).
"""
mtag = None
if rpm.RPMTAG_MODULARITYLABEL in self.hdr.keys():
mtag = self.hdr[rpm.RPMTAG_MODULARITYLABEL]
elif rpm.RPMTAG_DISTTAG in self.hdr.keys() \
and self.hdr[rpm.RPMTAG_DISTTAG].startswith(b"module("):
# Strip away 'module(...)' wrap
mtag = self.hdr[rpm.RPMTAG_DISTTAG][7:-1]
return mtag
def checksum_type(self):
if self.hdr[rpm.RPMTAG_FILEDIGESTALGO] \
and self.hdr[rpm.RPMTAG_FILEDIGESTALGO] in PGPHASHALGO:
checksum_type = PGPHASHALGO[self.hdr[rpm.RPMTAG_FILEDIGESTALGO]]
else:
checksum_type = 'md5'
return checksum_type
def is_signed(self):
if hasattr(rpm, "RPMTAG_DSAHEADER"):
dsaheader = self.hdr["dsaheader"]
else:
dsaheader = 0
if self.hdr["siggpg"] or self.hdr["sigpgp"] or dsaheader:
return 1
return 0
def _extract_signatures(self):
header_tags = [
[rpm.RPMTAG_DSAHEADER, "dsa"],
[rpm.RPMTAG_RSAHEADER, "rsa"],
[rpm.RPMTAG_SIGGPG, "gpg"],
[rpm.RPMTAG_SIGPGP, 'pgp'],
]
for ht, sig_type in header_tags:
ret = self.hdr[ht]
if not ret:
continue
ret_len = len(ret)
if ret_len < 17:
continue
# Get the key id - hopefully we get it right
elif ret_len <= 65: # V3 DSA signature
key_id = ret[9:17]
elif ret_len <= 72: # V4 DSA signature
key_id = ret[18:26]
elif ret_len <= 280: # V3 RSA/8 signature
key_id = ret[10:18]
elif ret_len <= 287: # V4 RSA/SHA1 signature
key_id = ret[19:27]
elif ret_len <= 536: # V3 RSA/SHA256 signature
key_id = ret[10:18]
else: # ret_len > 543 # V4 RSA/SHA signature
key_id = ret[19:27]
key_id_len = len(key_id)
fmt = "%dB" % key_id_len
t = struct.unpack(fmt, key_id)
fmt = "%02x" * key_id_len
key_id = fmt % t
self.signatures.append({
'signature_type': sig_type,
'key_id': key_id,
'signature': ret,
})
class RPM_Package(A_Package):
# pylint: disable=R0902
def __init__(self, input_stream=None):
A_Package.__init__(self, input_stream)
self.header = None
self.header_data = tempfile.SpooledTemporaryFile()
self.header_start = None
self.header_end = None
self.checksum_type = None
self.checksum = None
self.payload_stream = None
self.payload_size = None
def read_header(self):
self._get_header_byte_range()
try:
self.header = get_package_header(file_obj=self.header_data)
except InvalidPackageError:
e = sys.exc_info()[1]
raise_with_tb(InvalidPackageError(*e.args), sys.exc_info()[2])
except error:
e = sys.exc_info()[1]
raise_with_tb(InvalidPackageError(e), sys.exc_info()[2])
except:
raise_with_tb(InvalidPackageError, sys.exc_info()[2])
self.checksum_type = self.header.checksum_type()
def _get_header_byte_range(self):
"""
Return the start and end bytes of the rpm header object.
Raw header data are then stored in self.header_data.
For details of the rpm file format, see:
http://www.rpm.org/max-rpm/s1-rpm-file-format-rpm-file-format.html
"""
lead_size = 96
struct_lead_size = 16
# Move past the rpm lead
buf = self._read_bytes(self.input_stream, lead_size)
self.header_data.write(buf)
buf = self._read_bytes(self.input_stream, struct_lead_size)
self.header_data.write(buf)
sig_size = self._get_header_struct_size(buf)
# Now we can find the start of the actual header.
self.header_start = lead_size + sig_size
buf = self._read_bytes(self.input_stream, sig_size - struct_lead_size)
self.header_data.write(buf)
buf = self._read_bytes(self.input_stream, struct_lead_size)
self.header_data.write(buf)
header_size = self._get_header_struct_size(buf)
self.header_end = self.header_start + header_size
buf = self._read_bytes(self.input_stream, header_size - struct_lead_size)
self.header_data.write(buf)
@staticmethod
def _get_header_struct_size(struct_lead):
"""
Compute the size in bytes of the rpm header struct starting at the current
position in package_file.
"""
try:
# Read the number of index entries
header_index = struct_lead[8:12]
(header_index_value, ) = struct.unpack('>I', header_index)
# Read the the size of the header data store
header_store = struct_lead[12:16]
(header_store_value, ) = struct.unpack('>I', header_store)
except:
raise InvalidPackageError
# The total size of the header. Each index entry is 16 bytes long.
header_size = 8 + 4 + 4 + header_index_value * 16 + header_store_value
# Headers end on an 8-byte boundary. Round out the extra data.
round_out = header_size % 8
if round_out != 0:
header_size = header_size + (8 - round_out)
return header_size
def save_payload(self, output_stream):
c_hash = checksum.getHashlibInstance(self.checksum_type, False)
if output_stream:
output_start = output_stream.tell()
self.header_data.seek(0, 0)
self._stream_copy(self.header_data, output_stream, c_hash)
self._stream_copy(self.input_stream, output_stream, c_hash)
self.checksum = c_hash.hexdigest()
self.header_data.close()
if output_stream:
self.payload_stream = output_stream
self.payload_size = output_stream.tell() - output_start
def get_header_byte_range(package_file):
"""
Return the start and end bytes of the rpm header object.
For details of the rpm file format, see:
http://www.rpm.org/max-rpm/s1-rpm-file-format-rpm-file-format.html
"""
lead_size = 96
# Move past the rpm lead
package_file.seek(lead_size)
sig_size = get_header_struct_size(package_file)
# Now we can find the start of the actual header.
header_start = lead_size + sig_size
package_file.seek(header_start)
header_size = get_header_struct_size(package_file)
header_end = header_start + header_size
return (header_start, header_end)
def get_header_struct_size(package_file):
"""
Compute the size in bytes of the rpm header struct starting at the current
position in package_file.
"""
# Move past the header preamble
package_file.seek(8, 1)
try:
# Read the number of index entries
header_index = package_file.read(4)
(header_index_value, ) = struct.unpack('>I', header_index)
# Read the the size of the header data store
header_store = package_file.read(4)
(header_store_value, ) = struct.unpack('>I', header_store)
except:
raise InvalidPackageError
# The total size of the header. Each index entry is 16 bytes long.
header_size = 8 + 4 + 4 + header_index_value * 16 + header_store_value
# Headers end on an 8-byte boundary. Round out the extra data.
round_out = header_size % 8
if round_out != 0:
header_size = header_size + (8 - round_out)
return header_size
SHARED_TS = None
def get_package_header(filename=None, file_obj=None, fd=None):
""" Loads the package header from a file / stream / file descriptor
Raises rpm.error if an error is found, or InvalidPacageError if package is
busted
"""
global SHARED_TS
# XXX Deal with exceptions better
if (filename is None and file_obj is None and fd is None):
raise ValueError("No parameters passed")
if filename is not None:
f = open(filename, 'r')
elif file_obj is not None:
f = file_obj
f.seek(0, 0)
else: # fd is not None
f = None
if f is None:
os.lseek(fd, 0, 0)
file_desc = fd
else:
file_desc = f.fileno()
# don't try to use rpm.readHeaderFromFD() here, it brokes signatures
# see commit message
if not SHARED_TS:
SHARED_TS = rpm.ts()
SHARED_TS.setVSFlags(-1)
rpm.addMacro('_dbpath', '/var/cache/rhn/rhnpush-rpmdb')
try:
hdr = SHARED_TS.hdrFromFdno(file_desc)
rpm.delMacro('_dbpath')
except:
rpm.delMacro('_dbpath')
raise
if hdr is None:
raise InvalidPackageError
is_source = hdr[rpm.RPMTAG_SOURCEPACKAGE]
return RPM_Header(hdr, is_source)
class MatchIterator:
def __init__(self, tag_name=None, value=None):
# Query by name, by default
if not tag_name:
tag_name = "name"
# rpm 4.1 or later
self.ts = rpm.TransactionSet()
self.ts.setVSFlags(8)
m_args = (tag_name,)
if value:
m_args += (value,)
# pylint: disable=E1101
self.mi = self.ts.dbMatch(*m_args)
def pattern(self, tag_name, mode, pattern):
self.mi.pattern(tag_name, mode, pattern)
def next(self):
try:
hdr = usix_next(self.mi)
except StopIteration:
hdr = None
if hdr is None:
return None
is_source = hdr[rpm.RPMTAG_SOURCEPACKAGE]
return RPM_Header(hdr, is_source)
def headerLoad(data):
hdr = rpm.headerLoad(data)
is_source = hdr[rpm.RPMTAG_SOURCEPACKAGE]
return RPM_Header(hdr, is_source)
def labelCompare(t1, t2):
return rpm.labelCompare(t1, t2)
def nvre_compare(t1, t2):
def build_evr(p):
evr = [p[3], p[1], p[2]]
evr = list(map(str, evr))
if evr[0] == "":
evr[0] = None
return evr
if t1[0] != t2[0]:
raise ValueError("You should only compare packages with the same name")
evr1, evr2 = (build_evr(t1), build_evr(t2))
return rpm.labelCompare(evr1, evr2)
def hdrLabelCompare(hdr1, hdr2):
""" take two RPMs or headers and compare them for order """
if hdr1['name'] == hdr2['name']:
hdr1 = [hdr1['epoch'] or None, hdr1['version'], hdr1['release']]
hdr2 = [hdr2['epoch'] or None, hdr2['version'], hdr2['release']]
if hdr1[0]:
hdr1[0] = str(hdr1[0])
if hdr2[0]:
hdr2[0] = str(hdr2[0])
return rpm.labelCompare(hdr1, hdr2)
elif hdr1['name'] < hdr2['name']:
return -1
return 1
def sortRPMs(rpms):
""" Sorts a list of RPM files. They *must* exist. """
assert isinstance(rpms, type([]))
# Build a list of (header, rpm)
helper = [(get_package_header(x), x) for x in rpms]
# Sort the list using the headers as a comparison
sort_cmp=lambda x, y: hdrLabelCompare(x[0], y[0])
try:
helper.sort(sort_cmp)
except TypeError:
helper.sort(key=functools.cmp_to_key(sort_cmp))
# Extract the rpm names now
return [x[1] for x in helper]
def getInstalledHeader(rpmName):
""" quieries the RPM DB for a header matching rpmName. """
matchiter = MatchIterator("name")
matchiter.pattern("name", rpm.RPMMIRE_STRCMP, rpmName)
return matchiter.next()
if __name__ == '__main__':
pass
07070100000012000081B400000000000000000000000164462CA6000004C8000000000000000000000000000000000000002B00000000uyuni-common-libs/common/timezone_utils.py"""
Copyright (C) 2017 Oracle and/or its affiliates. All rights reserved.
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, version 2
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.
Utility to get system UTC offset and format as needed by DBs.
"""
import time
def get_utc_offset():
"""Return the UTC offset, allowing for DST."""
is_dst = time.daylight and time.localtime().tm_isdst > 0
utc_offset = - time.timezone
if is_dst:
utc_offset = - time.altzone
mins = divmod(utc_offset, 60)[0]
hours, mins = divmod(mins, 60)
return '{0:+03d}:{1:02d}'.format(hours, mins)
if __name__ == "__main__":
print("UTC offset (allowing for DST if in effect): %s" % get_utc_offset())
07070100000013000081B400000000000000000000000164462CA600000966000000000000000000000000000000000000002100000000uyuni-common-libs/common/usix.py#
# Copyright (c) 2013--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.
#
"""
Usix is a library to bring compatibility between Python2 and Python3.
"""
# pylint: disable=E1101
import sys
import types
PY2 = sys.version_info[0] == 2
PY3 = sys.version_info[0] == 3
# Common data types
# Common data types
if PY3:
BufferType = bytes
UnicodeType = bytes
StringType = str
DictType = dict
IntType = int
LongType = int
ListType = list
ClassType = type
FloatType = float
TupleType = tuple
TypeType = type
InstanceType = object
else:
BufferType = types.BufferType
UnicodeType = unicode # pylint: disable=E0602
StringType = types.StringType
DictType = types.DictType
IntType = types.IntType
LongType = types.LongType
ListType = types.ListType
ClassType = types.BufferType
FloatType = types.FloatType
TupleType = types.TupleType
TypeType = types.TypeType
InstanceType = types.InstanceType
# Common limits
if PY3:
MaxInt = sys.maxsize
else:
MaxInt = sys.maxint
# Common methods
# raise exception with traceback
# pylint: disable=W0122
if PY3:
def raise_with_tb(value, tb=None):
"""
Re-raise an exception with the traceback.
"""
try:
if value.__traceback__ is not tb:
raise value.with_traceback(tb)
raise value
finally:
value = None
tb = None
else:
exec("""
def raise_with_tb(value, tb=None):
try:
raise value, None, tb
finally:
tb = None
""")
# code from original 'six' module
# added for compatibility with Python 2.4
try:
advance_iterator = next
except NameError:
def advance_iterator(it):
"""
Iterator invocation.
"""
return it.next()
next = advance_iterator # pylint: disable=W0622
07070100000014000081B400000000000000000000000164462CA600000D38000000000000000000000000000000000000001B00000000uyuni-common-libs/pylintrc# spacewalk pylint configuration
[MASTER]
# Profiled execution.
profile=no
# Pickle collected data for later comparisons.
persistent=no
suggestion-mode=no
[MESSAGES CONTROL]
# No disabled messages in usix
# disable=
[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=
07070100000015000081B400000000000000000000000164462CA600000F65000000000000000000000000000000000000002C00000000uyuni-common-libs/uyuni-common-libs.changes-------------------------------------------------------------------
Mon Apr 24 09:15:26 CEST 2023 - jgonzalez@suse.com
- version 4.3.8-1
* Allow default component for context manager
-------------------------------------------------------------------
Wed Jan 11 12:45:26 CET 2023 - jgonzalez@suse.com
- version 4.3.7-1
* unify user notification code on java side
-------------------------------------------------------------------
Mon Sep 26 12:29:05 UTC 2022 - marina.latini@suse.com
- version 4.3.6-1
* Do not allow creating path if nonexistent user or group in fileutils.
-------------------------------------------------------------------
Wed Jul 06 16:24:17 CEST 2022 - jgonzalez@suse.com
- version 4.3.5-1
* Fix reposync issue about 'rpm.hdr' object has no attribute 'get'
-------------------------------------------------------------------
Tue Apr 19 12:14:45 CEST 2022 - jgonzalez@suse.com
- version 4.3.4-1
* implement more decompression algorithms for reposync (bsc#1196704)
-------------------------------------------------------------------
Fri Mar 11 15:46:23 CET 2022 - jgonzalez@suse.com
- version 4.3.3-1
* Reorganize python files
-------------------------------------------------------------------
Tue Jan 18 14:09:04 CET 2022 - jgonzalez@suse.com
- version 4.3.2-1
* Read modularity data from DISTTAG tag as fallback (bsc#1192487)
* Add decompression of zck files to fileutils
* require python macros for building
-------------------------------------------------------------------
Mon Aug 09 11:12:24 CEST 2021 - jgonzalez@suse.com
- version 4.3.1-1
- Handle broken RPM packages to prevent exceptions
causing fails on repository synchronization (bsc#1186650)
-------------------------------------------------------------------
Fri May 28 09:11:32 CEST 2021 - jgonzalez@suse.com
- version 4.2.4-1
- Maintainer field in debian packages are only recommended (bsc#1186508)
-------------------------------------------------------------------
Wed Jan 27 13:17:30 CET 2021 - jgonzalez@suse.com
- version 4.2.3-1
- Section in Debian packages in now treated as optional (bsc#1179555)
-------------------------------------------------------------------
Wed Nov 25 12:37:09 CET 2020 - jgonzalez@suse.com
- version 4.2.2-1
- Cleaning up unused Python 2 build leftovers.
- Disabled debug package build.
-------------------------------------------------------------------
Fri Sep 18 12:32:52 CEST 2020 - jgonzalez@suse.com
- version 4.2.1-1
- Fix issues importing RPM packages with long RPM headers (bsc#1174965)
- Update package version to 4.2.0
-------------------------------------------------------------------
Wed May 20 11:08:34 CEST 2020 - jgonzalez@suse.com
- version 4.1.5-1
- uyuni-common-libs obsoletes python3-spacewalk-usix and
python3-spacewalk-backend-libs (bsc#1170684)
- reposync speedup fixes
-------------------------------------------------------------------
Mon Apr 13 09:38:18 CEST 2020 - jgonzalez@suse.com
- version 4.1.4-1
- implement notification utility
- Do not break when syncing Oracle 7 yum channel (bsc#1158463)
-------------------------------------------------------------------
Thu Mar 19 12:18:16 CET 2020 - jgonzalez@suse.com
- version 4.1.3-1
- Add MODULARITYLABEL tag support
-------------------------------------------------------------------
Wed Jan 22 12:26:04 CET 2020 - jgonzalez@suse.com
- version 4.1.2-1
- remove conflicts to spacewalk-backend-libs packages
-------------------------------------------------------------------
Wed Nov 27 17:12:01 CET 2019 - jgonzalez@suse.com
- version 4.1.1-1
- Fix building for CentOS6/RHEL6/Expanded Support 6
- add conflicts to spacewalk-backend-libs and spacewalk-usix to
remove them on update
-------------------------------------------------------------------
Fri Nov 1 11:20:21 UTC 2019 - Michael Calmer <mc@suse.com>
- initial release
- replaces spacewalk-backend-libs and spacewalk-usix
07070100000016000081B400000000000000000000000164462CA600000FDE000000000000000000000000000000000000002900000000uyuni-common-libs/uyuni-common-libs.spec#
# spec file for package uyuni-common-libs
#
# Copyright (c) 2021 SUSE LLC
#
# 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/
#
%global debug_package %{nil}
%if 0%{?fedora} || 0%{?suse_version} >= 1500 || 0%{?rhel} >= 8
%{!?python3_sitelib: %global python3_sitelib %(%{__python3} -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())")}
%global python3root %{python3_sitelib}/uyuni
%global build_py3 1
%endif
%if ( 0%{?rhel} && 0%{?rhel} < 8 ) || 0%{?suse_version}
%global build_py2 1
%endif
%define pythonX %{?build_py3:python3}%{!?build_py3:python}
%if 0%{?suse_version} >= 1500
%global python_prefix python3
%else
%if 0%{?fedora} >= 28 || 0%{?rhel} >= 8
%global python_prefix python2
%else
%global python_prefix python
%endif
%endif
%{!?python2_sitelib: %global python2_sitelib %(%{__python} -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())")}
%global python2root %{python2_sitelib}/uyuni
Name: uyuni-common-libs
Summary: Uyuni server and client libs
License: GPL-2.0-only
Group: Development/Languages/Python
Version: 4.3.8
Release: 1
URL: https://github.com/uyuni-project/uyuni
Source0: %{name}-%{version}.tar.gz
BuildRequires: fdupes
BuildRoot: %{_tmppath}/%{name}-%{version}-build
%description
Uyuni server and client libs
%if 0%{?build_py2}
%package -n python2-%{name}
Summary: Uyuni server and client tools libraries for python2
Group: Development/Languages/Python
Requires: python
%if 0%{?suse_version}
BuildRequires: python-devel
%else
BuildRequires: python2-devel
%endif
%if 0%{?suse_version} || 0%{?rhel} >= 8
Recommends: zchunk
Recommends: zstd
%endif
%description -n python2-%{name}
Python 2 libraries required by both Uyuni server and client tools.
%endif
%if 0%{?build_py3}
%package -n python3-%{name}
Summary: Uyuni server and client tools libraries for python3
Group: Development/Languages/Python
BuildRequires: python3-devel
BuildRequires: python3-rpm-macros
Conflicts: %{name} < 1.7.0
%if 0%{?suse_version}
Requires: python3-base
%else
Requires: python3-libs
%endif
%if 0%{?suse_version} || 0%{?rhel} >= 8
Recommends: zchunk
Recommends: zstd
%endif
Obsoletes: python3-spacewalk-backend-libs
Obsoletes: python3-spacewalk-usix
%description -n python3-%{name}
Python 3 libraries required by both Uyuni server and client tools.
%endif
%prep
%setup -q
%build
make -f Makefile.common-libs all PYTHON_BIN=%{pythonX}
%install
make -f Makefile.common-libs install PREFIX=$RPM_BUILD_ROOT \
MANDIR=%{_mandir} PYTHON_BIN=%{pythonX}
%if 0%{?build_py3}
install -d $RPM_BUILD_ROOT%{python2root}/common
cp $RPM_BUILD_ROOT%{python3root}/__init__.py \
$RPM_BUILD_ROOT%{python2root}/
cp $RPM_BUILD_ROOT%{python3root}/common/*.py \
$RPM_BUILD_ROOT%{python2root}/common
%endif
%if 0%{?suse_version}
%if 0%{?build_py2}
%py_compile -O %{buildroot}/%{python2root}
%fdupes %{buildroot}/%{python2root}
%endif
%if 0%{?build_py3}
%py3_compile -O %{buildroot}/%{python3root}
%fdupes %{buildroot}/%{python3root}
%endif
%endif
%if !(0%{?build_py2})
rm -Rf $RPM_BUILD_ROOT%{python2root}
%endif
%if 0%{?build_py2}
%files -n python2-%{name}
%defattr(-,root,root)
%{!?_licensedir:%global license %doc}
%license LICENSE
%{python2root}
%endif
%if 0%{?build_py3}
%files -n python3-%{name}
%defattr(-,root,root)
%license LICENSE
%{python3root}
%endif
%changelog
07070100000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000B00000000TRAILER!!!