Skip to content

Commit

Permalink
OpenBSD, FreeBSD and NetBSD support
Browse files Browse the repository at this point in the history
  • Loading branch information
philpep committed Mar 29, 2015
1 parent 95a6cd4 commit 5dce243
Show file tree
Hide file tree
Showing 17 changed files with 428 additions and 260 deletions.
2 changes: 0 additions & 2 deletions doc/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,6 @@ Interface
Package
~~~~~~~

.. warning:: Support is currently limited to APT based distributions

.. class:: testinfra.modules.Package(name)

.. attribute:: is_installed
Expand Down
5 changes: 3 additions & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
pytest>=2.6.4,<3
six>=1.9.0,<2.0
pytest
six
paramiko
1 change: 1 addition & 0 deletions test-requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
mock
pytest-cov
pytest-xdist
125 changes: 114 additions & 11 deletions testinfra/modules/file.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@

import datetime

import pytest

from testinfra.modules.base import Module


Expand Down Expand Up @@ -75,7 +77,7 @@ def user(self):
>>> File("/etc/passwd").group
'root'
"""
return self.check_output("stat -c %%U %s", self.path)
raise NotImplementedError

@property
def uid(self):
Expand All @@ -84,15 +86,15 @@ def uid(self):
>>> File("/etc/passwd").uid
0
"""
return int(self.check_output("stat -c %%u %s", self.path))
raise NotImplementedError

@property
def group(self):
return self.check_output("stat -c %%G %s", self.path)
raise NotImplementedError

@property
def gid(self):
return int(self.check_output("stat -c %%g %s", self.path))
raise NotImplementedError

@property
def mode(self):
Expand All @@ -101,19 +103,18 @@ def mode(self):
>>> File("/etc/passwd").mode
644
"""
return int(self.check_output("stat -c %%a %s", self.path))
raise NotImplementedError

def contains(self, pattern):
return self.run_test("grep -qs -- %s %s", pattern, self.path).rc == 0

@property
def md5sum(self):
return self.check_output("md5sum %s | cut -d' ' -f1", self.path)
raise NotImplementedError

@property
def sha256sum(self):
return self.check_output(
"sha256sum %s | cut -d ' ' -f 1", self.path)
raise NotImplementedError

def _get_content(self, decode):
out = self.run_test("cat -- %s", self.path)
Expand Down Expand Up @@ -149,13 +150,115 @@ def mtime(self):
>>> File("/etc/passwd").mtime
datetime.datetime(2015, 3, 15, 20, 25, 40)
"""
ts = self.check_output("stat -c %%Y %s", self.path)
return datetime.datetime.fromtimestamp(float(ts))
raise NotImplementedError

@property
def size(self):
"""Return size of file in bytes"""
return int(self.check_output("stat -c %%s %s", self.path))
raise NotImplementedError

def __repr__(self):
return "<file %s>" % (self.path,)

@classmethod
def as_fixture(cls):
@pytest.fixture(scope="session")
def f(SystemInfo):
if SystemInfo.type == "linux":
return GNUFile
elif SystemInfo.type == "netbsd":
return NetBSDFile
elif SystemInfo.type.endswith("bsd"):
return BSDFile
else:
raise NotImplementedError
f.__doc__ = cls.__doc__
return f


class GNUFile(File):
@property
def user(self):
return self.check_output("stat -c %%U %s", self.path)

@property
def uid(self):
return int(self.check_output("stat -c %%u %s", self.path))

@property
def group(self):
return self.check_output("stat -c %%G %s", self.path)

@property
def gid(self):
return int(self.check_output("stat -c %%g %s", self.path))

@property
def mode(self):
return int(self.check_output("stat -c %%a %s", self.path))

@property
def mtime(self):
ts = self.check_output("stat -c %%Y %s", self.path)
return datetime.datetime.fromtimestamp(float(ts))

@property
def size(self):
return int(self.check_output("stat -c %%s %s", self.path))

@property
def md5sum(self):
return self.check_output("md5sum %s | cut -d' ' -f1", self.path)

@property
def sha256sum(self):
return self.check_output(
"sha256sum %s | cut -d ' ' -f 1", self.path)


class BSDFile(File):
@property
def user(self):
return self.check_output("stat -f %%Su %s", self.path)

@property
def uid(self):
return int(self.check_output("stat -f %%u %s", self.path))

@property
def group(self):
return self.check_output("stat -f %%Sg %s", self.path)

@property
def gid(self):
return int(self.check_output("stat -f %%g %s", self.path))

@property
def mode(self):
return int(self.check_output("stat -f %%Lp %s", self.path))

@property
def mtime(self):
ts = self.check_output("stat -f %%m %s", self.path)
return datetime.datetime.fromtimestamp(float(ts))

@property
def size(self):
return int(self.check_output("stat -f %%z %s", self.path))

@property
def md5sum(self):
return self.check_output("md5 < %s", self.path)

@property
def sha256sum(self):
return self.check_output(
"sha256 < %s", self.path)


class NetBSDFile(BSDFile):

@property
def sha256sum(self):
return self.check_output(
"cksum -a sha256 < %s", self.path)
35 changes: 33 additions & 2 deletions testinfra/modules/package.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,12 @@ def __repr__(self):
@classmethod
def as_fixture(cls):
@pytest.fixture(scope="session")
def f(Command):
if Command.run_test("which apt-get").rc == 0:
def f(Command, SystemInfo):
if SystemInfo.type == "freebsd":
return FreeBSDPackage
elif SystemInfo.type in ("openbsd", "netbsd"):
return OpenBSDPackage
elif Command.run_test("which apt-get").rc == 0:
return DebianPackage
else:
raise NotImplementedError
Expand All @@ -63,3 +67,30 @@ def version(self):
return self.check_output((
"dpkg-query -f '${Status} ${Version}' -W %s | "
"sed -n 's/^install ok installed //p'"), self.name)


class FreeBSDPackage(Package):

@property
def is_installed(self):
EX_UNAVAILABLE = 69
return self.run_expect(
[0, EX_UNAVAILABLE], "pkg query %%n %s", self.name).rc == 0

@property
def version(self):
return self.check_output("pkg query %%v %s", self.name)


class OpenBSDPackage(Package):

@property
def is_installed(self):
return self.run_test("pkg_info -e %s", "%s-*" % (self.name,)).rc == 0

@property
def version(self):
out = self.check_output("pkg_info -e %s", "%s-*" % (self.name,))
# OpenBSD: inst:zsh-5.0.5p0
# NetBSD: zsh-5.0.7nb1
return out.split(self.name + "-", 1)[1]
71 changes: 66 additions & 5 deletions testinfra/modules/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@

from __future__ import unicode_literals

import pytest

from testinfra.modules.base import Module


Expand All @@ -27,9 +29,40 @@ def __init__(self, name):

@property
def is_running(self):
out = self.run("service %s status", self.name)
assert out.rc != 127, "Unexpected exit status 127"
return out.rc == 0
"""Check if service is running"""
raise NotImplementedError

@property
def is_enabled(self):
"""Check if service is enabled"""
raise NotImplementedError

@classmethod
def as_fixture(cls):
@pytest.fixture(scope="session")
def f(SystemInfo):
if SystemInfo.type == "linux":
return LinuxService
elif SystemInfo.type == "freebsd":
return FreeBSDService
elif SystemInfo.type == "openbsd":
return OpenBSDService
elif SystemInfo.type == "netbsd":
return NetBSDService
else:
raise NotImplementedError
f.__doc__ = cls.__doc__
return f

def __repr__(self):
return "<service %s>" % (self.name,)


class LinuxService(Service):

@property
def is_running(self):
return self.run_test("service %s status", self.name).rc == 0

@property
def is_enabled(self):
Expand All @@ -50,5 +83,33 @@ def is_enabled_with_level(self, level):
else:
return False

def __repr__(self):
return "<service %s>" % (self.name,)

class FreeBSDService(Service):

@property
def is_running(self):
return self.run_test("service %s onestatus", self.name).rc == 0

@property
def is_enabled(self):
# Return list of enabled services like
# /etc/rc.d/sshd
# /etc/rc.d/sendmail
for path in self.check_output("service -e").splitlines():
if path and path.rsplit("/", 1)[1] == self.name:
return True
return False


class OpenBSDService(Service):

@property
def is_running(self):
return self.run_test("/etc/rc.d/%s check", self.name).rc == 0


class NetBSDService(Service):

@property
def is_running(self):
return self.run_test("/etc/rc.d/%s onestatus", self.name).rc == 0

0 comments on commit 5dce243

Please sign in to comment.