Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add obsdpkg: package management for OpenBSD. #2275

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
222 changes: 222 additions & 0 deletions library/obsdpkg
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-

# (c) 2013, Patrik Lundin <patrik.lundin.swe@gmail.com>
#
# This file is part of Ansible
#
# Ansible 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 3 of the License, or
# (at your option) any later version.
#
# Ansible 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 Ansible. If not, see <http://www.gnu.org/licenses/>.

import re

DOCUMENTATION = '''
---
module: obsdpkg
author: Patrik Lundin
version_added: 1.1
short_description: Manage packages on OpenBSD.
description:
- Manage packages on OpenBSD using the pkg tools.
options:
name:
required: true
description:
- Name of the package.
state:
required: true
choices: [ present, latest, absent ]
description:
C(present) will make sure the package is installed.
C(latest) will make sure the latest version of the package is installed.
C(absent) will make sure the specified package is not installed.
examples:
- description: Make sure nmap is installed
code: "obsdpkg: name=nmap state=present"
- description: Make sure nmap is the latest version
code: "obsdpkg: name=nmap state=latest"
- description: Make sure nmap is not installed
code: "obsdpkg: name=nmap state=absent"
'''

# select whether we dump additional debug info through syslog
syslogging = False

# Function used for executing commands.
def execute_command(cmd, syslogging):
if syslogging:
syslog.openlog('ansible-%s' % os.path.basename(__file__))
syslog.syslog(syslog.LOG_NOTICE, 'Command %s' % '|'.join(cmd))

p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(out, err) = p.communicate()
rc = p.returncode
return (rc, out, err)

# Function used for getting the name of a currently installed package.
def get_current_name(name, specific_version):
info_cmd = 'pkg_info'
(rc, stdout, stderr) = execute_command("%s" % (info_cmd), syslogging)
if rc != 0:
return (rc, stdout, stderr)

if specific_version:
syntax = "%s"
else:
syntax = "%s-"

for line in stdout.splitlines():
if syntax % name in line:
current_name = line.split()[0]

return current_name

# Function used to find out if a package is currently installed.
def get_package_state(name, specific_version):
info_cmd = 'pkg_info -e'

if specific_version:
syntax = "%s %s"
else:
syntax = "%s %s-*"

rc, stdout, stderr = execute_command(syntax % (info_cmd, name), syslogging)

if rc == 0:
return True
else:
return False

# Function used to make sure a package is present.
def package_present(name, installed_state):
install_cmd = 'pkg_add -I'
if installed_state is False:
rc, stdout, stderr = execute_command("%s %s" % (install_cmd, name), syslogging)
# pkg_add returns 0 even if the package does not exist
# so depend on stderr instead if something bad happened.
if stderr:
rc = 1
changed=False
else:
changed=True
else:
rc = 0
stdout = ''
stderr = ''
changed=False

return (rc, stdout, stderr, changed)

# Function used to make sure a package is the latest available version.
def package_latest(name, installed_state, specific_version):

upgrade_cmd = 'pkg_add -u'
pre_upgrade_name = ''
post_upgrade_name = ''
if installed_state is True:

# pkg_add -u exits 0 even if no update was needed, so compare the
# installed package before and after to know if we changed anything.
pre_upgrade_name = get_current_name(name, specific_version)

(rc, stdout, stderr) = execute_command("%s %s" % (upgrade_cmd, name), syslogging)

# 'pkg_add -u' returns 0 even when something strange happened, stdout
# should be empty if everything went fine.
if stdout:
rc=1

post_upgrade_name = get_current_name(name, specific_version)

if pre_upgrade_name == post_upgrade_name:
changed = False
else:
changed = True

return (rc, stdout, stderr, changed)

else:
# If package was not installed at all just make it present.
return package_present(name, installed_state)

# Function used to make sure a package is not installed.
def package_absent(name, installed_state):
remove_cmd = 'pkg_delete -I'
if installed_state is True:
rc, stdout, stderr = execute_command("%s %s" % (remove_cmd, name), syslogging)

if rc == 0:
changed=True
else:
changed=False
else:
rc = 0
stdout = ''
stderr = ''
changed=False

return (rc, stdout, stderr, changed)

# ===========================================
# Main control flow

def main():
module = AnsibleModule(
argument_spec = dict(
name = dict(required=True),
state = dict(required=True, choices=['absent', 'installed', 'latest', 'present', 'removed']),
)
)

name = module.params['name']
state = module.params['state']

rc = 0
stdout = ''
stderr = ''
result = {}
result['name'] = name
result['state'] = state

# Decide if the name contains a version number.
# This regex is based on packages-specs(7).
match = re.search("-[0-9]", name)
if match:
specific_version = True
else:
specific_version = False

# Get package state
installed_state = get_package_state(name, specific_version)

# Perform requested action
if state in ['installed', 'present']:
(rc, stdout, stderr, changed) = package_present(name, installed_state)
elif state in ['absent', 'removed']:
(rc, stdout, stderr, changed) = package_absent(name, installed_state)
elif state == 'latest':
(rc, stdout, stderr, changed) = package_latest(name, installed_state, specific_version)

if rc != 0:
if stderr:
module.fail_json(msg=stderr)
else:
module.fail_json(msg=stdout)

result['changed'] = changed

module.exit_json(**result)

# this is magic, see lib/ansible/module_common.py
#<<INCLUDE_ANSIBLE_MODULE_COMMON>>
main()
2 changes: 2 additions & 0 deletions library/setup
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,8 @@ class Facts(object):
for pkg in Facts.PKG_MGRS:
if os.path.exists(pkg['path']):
self.facts['pkg_mgr'] = pkg['name']
if self.facts['system'] == 'OpenBSD':
self.facts['pkg_mgr'] = 'obsdpkg'

def get_lsb_facts(self):
lsb_path = module.get_bin_path('lsb_release')
Expand Down