Skip to content

Commit

Permalink
Issues:
Browse files Browse the repository at this point in the history
Fixes #1116

Problem:
This issue is a few fold:
1. RPM spec file format was not being followed properly
  * Requires: <module> <modifier> <version>, [repeat]
2. RPM was not actually installing dependencies during test
3. RPM was not failing when project package failed to install during test
4. DEB was not actually installing dependencies during test
5. DEB was not fialing when project package failed to install during test

Analysis:
1. added a check_requires() function that will add the proper formatting
  * Change performed in the build-rpm.py
2. Changed the Dependency.cmd to be handled differently with a
Dependency.install_cmd
  * Change performed in the redhat's fetch_and_install_deps.py
3. Fix was multi-fold, but all under redhat's fetch_and_install_deps.py:
  * runCommand() was changed to use subprocess.check_output
  * runCommand()'s call for rpm -i <project> now has a status check
  * a last verification against rpm -qa is performed
4. Made a Dependency._install_req to be cond. exec. by parent
  * This is always executed by F5Dependency
  * This is added to the ubuntu's fetch_and_install_deps.py
5. Again multi-fold in the ubuntu's fetch_and_install_deps.py:
  * runCommand() was changed to use subprocess.check_output
  * runCommand()'s call for dpkg -i <project> now has a status check
  * a last verification against dpkg -l is performed

Tests:
This is a test in and of itself; however, there is now an additional
ring of tests for both ubuntu and debian that assures, using its
individual packaging medium, a means to verify that the package is, in
fact, installed after the processing of the test scripts on the
associated docker container instance.
  • Loading branch information
sorensF5 committed Apr 14, 2017
1 parent 932ff20 commit f508d9f
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 21 deletions.
37 changes: 37 additions & 0 deletions f5-sdk-dist/Docker/redhat/7/build-rpm.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,13 @@
import glob
import json
import os
import re
import shutil
import subprocess
import sys
import traceback

from collections import namedtuple
from tempfile import mkdtemp


Expand Down Expand Up @@ -84,6 +86,40 @@ def make_rpms_build(config):
return rpm_build


def change_requires(buildroot, config):
spec = buildroot + "/rpmbuild/SPECS/{}.spec".format(config['project'])
try:
with open(spec, 'r') as fh:
contents = fh.read()
except IOError as Error:
print("Could not open spec file! ({})".format(Error))
raise
try:
with open(spec, 'w') as fh:
for line in contents.split("\n"):
if 'Requires' in line:
old = line.replace("Requires: ", "")
Req = namedtuple('Req', 'module, modifier, version')
breakout_re = re.compile('([^<=>]+)([<=>]+)([\d]\S+)')
change = 'Requires: '
modifier_format = "{} {} {}, "
for requirement in old.split(' '):
match = breakout_re.search(requirement)
if match:
req = Req(*match.groups())
mod = 'python-' + req.module \
if 'python-' not in req.module and \
'f5-' not in req.module else req.module
change = change + \
modifier_format.format(mod, req.modifier,
req.version)
line = change
fh.write("{}\n".format(line))
except Exception as Error:
print("Could not handle change in spec file {}".format(Error))
raise


def main():
src_dir = sys.argv[1]
os.chdir(src_dir)
Expand All @@ -103,6 +139,7 @@ def main():
fh.write('%s_topdir %s/rpmbuild' % ('%', buildroot))
cmd = "python setup.py bdist_rpm --spec-only --dist-dir rpmbuild/SPECS"
print(subprocess.check_output([cmd], shell=True))
change_requires(buildroot, config)
cmd = "rpmbuild -ba rpmbuild/SPECS/%s.spec" % project
print(subprocess.check_output([cmd], shell=True))
nonarch_pkg = None
Expand Down
30 changes: 20 additions & 10 deletions f5-sdk-dist/Docker/redhat/install_test/fetch_and_install_deps.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ class Dependency(object):
requirements for installation. It does depend on yum to retrieve subsquent
dependencies.
"""
cmd = "yum install -y %s"
install_cmd = "yum install -y %s"

def __init__(self, req):
match = dep_match_re.search(str(req))
Expand Down Expand Up @@ -163,9 +163,9 @@ def install_req(self):
else self.name
name = 'python-' + name if 'python-' not in name and \
'.rpm' not in name else name
results, status = runCommand(self.cmd % name)
results, status = runCommand(self.install_cmd % name)
if status:
raise InstallError(self.cmd % name, str(self.req),
raise InstallError(self.install_cmd % name, str(self.req),
msg="Unable to install dep",
frame=gfi(cf()), errno=errno.ESPIPE)

Expand All @@ -181,6 +181,7 @@ class F5Dependency(Dependency):
actions to perform for its automated installation.
"""
cmd = "rpm -qRp %s"
install_cmd = "rpm -i %s"

def __init__(self, req):
super(F5Dependency, self).__init__(req)
Expand Down Expand Up @@ -253,15 +254,15 @@ def runCommand(cmd):
"""
output = ""
try:
p = subprocess.Popen(cmd.split(),
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
(output) = p.communicate()[0]
output = subprocess.check_output(cmd, shell=True)
except OSError as e:
print("Execution failed: [%s:%s] " %
(cmd, os.listdir('/var/wdir')), str(e))
except subprocess.CalledProcessError as Error:
print("exceution failed: [{}]".format(Error))
return(output, errno.ESPIPE)
else:
return (output, p.returncode)
return (output, 0)
return ('', 99)


Expand Down Expand Up @@ -459,7 +460,9 @@ def fetch_pkg_dependencies(config, pkg_name):

print("Installing Self - %s" % pkg_name)
try:
runCommand('rpm -i %s' % tmp_pkg_name)
output, result = runCommand('rpm -i %s 2>&1' % tmp_pkg_name)
if not result == 0:
raise InstallError("Exit status was {}".format(result))
except InstallError as error:
print("Failed to get requirements for %s." % (pkg_name))
return error
Expand Down Expand Up @@ -544,7 +547,14 @@ def main(args):
if error:
sys.exit(error.errnum)
else:
sys.exit(0)
# last attempt to detect an error:
cmd = "rpm -qa | grep {}".format(config['project'])
output, status = runCommand(cmd)
if status == 0:
print("Passed last check:\n{}".format(output))
sys.exit(0)
print("Failed last level of verification:\n{}".format(cmd))
sys.exit(29)


if __name__ == '__main__':
Expand Down
40 changes: 29 additions & 11 deletions f5-sdk-dist/Docker/ubuntu/install_test/fetch_and_install_deps.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,9 @@ def install_req(self):
"""
if 'python-' not in self.name or '(' in self.name:
return
self._install_req()

def _install_req(self):
print("Installing %s(v%s)" % (self.name, self.version))
name = self.pkg_location if hasattr(self, 'pkg_location') \
else self.name
Expand Down Expand Up @@ -233,6 +236,14 @@ def _set_url(self):
self.pkg_name = pkg_name
self.url = self.url + pkg_name

def install_req(self):
"""install_req
This object method will install the attribute-defined package yielded at
object creation. This requires running commands at the command prompt.
"""
self._install_req()


def usage():
"""usage
Expand All @@ -251,16 +262,12 @@ def runCommand(cmd):
"""
output = ""
try:
p = subprocess.Popen(cmd.split(),
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
(output) = p.communicate()[0]
except OSError as e:
print("Execution failed: [%s:%s] " %
(cmd, os.listdir('/var/wdir')), str(e))
output = subprocess.check_output(cmd, shell=True)
except subprocess.CalledProcessError as e:
print("Execution failed: [{}]".format(e))
else:
return (output, p.returncode)
return ('', 99)
return (output, 0)
return (str(e), 99)


def load_requirements(cfg):
Expand Down Expand Up @@ -447,7 +454,12 @@ def fetch_pkg_dependencies(config, pkg_name):

print("Installing Self - %s" % pkg_name)
try:
runCommand('dpkg -i %s' % tmp_pkg_name)
output, result = runCommand('dpkg -l | grep f5-')
print(output)
output, result = runCommand('dpkg -i %s 2>&1' % tmp_pkg_name)
if not result == 0:
raise IOError("Result was non-zero! [{}:{}]".format(output,
result))
except InstallError as error:
print("Failed to get requirements for %s." % (pkg_name))
return error
Expand Down Expand Up @@ -548,8 +560,14 @@ def main(args):
# Instal from the tmp directory.
if error:
sys.exit(error.errnum)
else:
# last chance to check for failure:
cmd = 'dpkg -l | grep {}'.format(config['project'])
output, status = runCommand(cmd)
if status == 0:
print("passed last check:\n{}".format(output))
sys.exit(0)
print("Last check FAILED: {}".format(cmd))
sys.exit(99)


if __name__ == '__main__':
Expand Down

0 comments on commit f508d9f

Please sign in to comment.