From 555eb62199998fc1640186fede2d68abc4285f71 Mon Sep 17 00:00:00 2001 From: Justin Bronn Date: Wed, 14 Oct 2020 13:18:04 -0600 Subject: [PATCH] solaris_zone: fix zone configuration with python3 (#1082) * * Explicitly open up temporary file in text mode. * Add test for `solaris_zone` creation. * Update changelog fragment. Co-authored-by: Felix Fontein * Add tests for zone deletion and invalid zone names. Co-authored-by: Felix Fontein --- .../fragments/1081-solaris_zone-python3.yml | 3 + plugins/modules/system/solaris_zone.py | 2 +- .../modules/system/test_solaris_zone.py | 115 ++++++++++++++++++ 3 files changed, 119 insertions(+), 1 deletion(-) create mode 100644 changelogs/fragments/1081-solaris_zone-python3.yml create mode 100644 tests/unit/plugins/modules/system/test_solaris_zone.py diff --git a/changelogs/fragments/1081-solaris_zone-python3.yml b/changelogs/fragments/1081-solaris_zone-python3.yml new file mode 100644 index 0000000000..40cd448f5e --- /dev/null +++ b/changelogs/fragments/1081-solaris_zone-python3.yml @@ -0,0 +1,3 @@ +--- +bugfixes: + - solaris_zone - fixed issue trying to configure zone in Python 3 (https://github.com/ansible-collections/community.general/issues/1081). diff --git a/plugins/modules/system/solaris_zone.py b/plugins/modules/system/solaris_zone.py index c188fea326..867b0df56a 100644 --- a/plugins/modules/system/solaris_zone.py +++ b/plugins/modules/system/solaris_zone.py @@ -193,7 +193,7 @@ class Zone(object): self.module.fail_json(msg='Missing required argument: path') if not self.module.check_mode: - t = tempfile.NamedTemporaryFile(delete=False) + t = tempfile.NamedTemporaryFile(delete=False, mode='wt') if self.sparse: t.write('create %s\n' % self.create_options) diff --git a/tests/unit/plugins/modules/system/test_solaris_zone.py b/tests/unit/plugins/modules/system/test_solaris_zone.py new file mode 100644 index 0000000000..4cf5c5ff7a --- /dev/null +++ b/tests/unit/plugins/modules/system/test_solaris_zone.py @@ -0,0 +1,115 @@ +# Copyright (c) 2020 Justin Bronn +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + +import json +import platform + +import pytest +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.community.general.plugins.modules.system import ( + solaris_zone +) +from ansible_collections.community.general.tests.unit.plugins.modules.utils import ( + set_module_args, +) + + +ZONEADM = "/usr/sbin/zoneadm" + + +def mocker_zone_set(mocker, rc=0, out="", err="", zone_exists=False, zone_status=None): + """ + Configure common mocker object for Solaris Zone tests + """ + exists = mocker.patch.object(solaris_zone.Zone, "exists") + exists.return_value = zone_exists + get_bin_path = mocker.patch.object(AnsibleModule, "get_bin_path") + get_bin_path.return_value = ZONEADM + run_command = mocker.patch.object(AnsibleModule, "run_command") + run_command.return_value = (rc, out, err) + platform_release = mocker.patch.object(platform, "release") + platform_release.return_value = "5.11" + platform_system = mocker.patch.object(platform, "system") + platform_system.return_value = "SunOS" + if zone_status is not None: + status = mocker.patch.object(solaris_zone.Zone, "status") + status.return_value = zone_status + + +@pytest.fixture +def mocked_zone_create(mocker): + mocker_zone_set(mocker) + + +@pytest.fixture +def mocked_zone_delete(mocker): + mocker_zone_set(mocker, zone_exists=True, zone_status="running") + + +def test_zone_create(mocked_zone_create, capfd): + """ + test zone creation + """ + set_module_args( + { + "name": "z1", + "state": "installed", + "path": "/zones/z1", + "_ansible_check_mode": False, + } + ) + with pytest.raises(SystemExit): + solaris_zone.main() + + out, err = capfd.readouterr() + results = json.loads(out) + assert not results.get("failed") + assert results["changed"] + + +def test_zone_delete(mocked_zone_delete, capfd): + """ + test zone deletion + """ + set_module_args( + { + "name": "z1", + "state": "absent", + "path": "/zones/z1", + "_ansible_check_mode": False, + } + ) + with pytest.raises(SystemExit): + solaris_zone.main() + + out, err = capfd.readouterr() + results = json.loads(out) + assert not results.get("failed") + assert results["changed"] + + +def test_zone_create_invalid_names(mocked_zone_create, capfd): + """ + test zone creation with invalid names + """ + # 1. Invalid character ('!'). + # 2. Zone name > 64 characters. + # 3. Zone name beginning with non-alphanumeric character. + for invalid_name in ('foo!bar', 'z' * 65, '_zone'): + set_module_args( + { + "name": invalid_name, + "state": "installed", + "path": "/zones/" + invalid_name, + "_ansible_check_mode": False, + } + ) + with pytest.raises(SystemExit): + solaris_zone.main() + + out, err = capfd.readouterr() + results = json.loads(out) + assert results.get("failed")