mirror of
https://github.com/saltstack/salt.git
synced 2025-04-17 10:10:20 +00:00
Merge 3006.x into master
This commit is contained in:
commit
112cbda97a
29 changed files with 541 additions and 335 deletions
4
.github/config.yml
vendored
4
.github/config.yml
vendored
|
@ -13,7 +13,7 @@ newIssueWelcomeComment: >
|
|||
|
||||
- [Community Wiki](https://github.com/saltstack/community/wiki)
|
||||
- [Salt’s Contributor Guide](https://docs.saltproject.io/en/master/topics/development/contributing.html)
|
||||
- [Join our Community Slack](https://join.slack.com/t/saltstackcommunity/shared_invite/zt-3av8jjyf-oBQ2M0vhXOhJpNpRkPWBvg)
|
||||
- [Join our Community Slack](https://join.slack.com/t/saltstackcommunity/shared_invite/zt-1zlfxffs1-NuEH~G9TzOeuNGdsfZIl3w)
|
||||
- [IRC on LiberaChat](https://web.libera.chat/#salt)
|
||||
- [Salt Project YouTube channel](https://www.youtube.com/channel/UCpveTIucFx9ljGelW63-BWg)
|
||||
- [Salt Project Twitch channel](https://www.twitch.tv/saltprojectoss)
|
||||
|
@ -39,7 +39,7 @@ newPRWelcomeComment: >
|
|||
|
||||
- [Community Wiki](https://github.com/saltstack/community/wiki)
|
||||
- [Salt’s Contributor Guide](https://docs.saltproject.io/en/master/topics/development/contributing.html)
|
||||
- [Join our Community Slack](https://join.slack.com/t/saltstackcommunity/shared_invite/zt-3av8jjyf-oBQ2M0vhXOhJpNpRkPWBvg)
|
||||
- [Join our Community Slack](https://join.slack.com/t/saltstackcommunity/shared_invite/zt-1zlfxffs1-NuEH~G9TzOeuNGdsfZIl3w)
|
||||
- [IRC on LiberaChat](https://web.libera.chat/#salt)
|
||||
- [Salt Project YouTube channel](https://www.youtube.com/channel/UCpveTIucFx9ljGelW63-BWg)
|
||||
- [Salt Project Twitch channel](https://www.twitch.tv/saltprojectoss)
|
||||
|
|
|
@ -8,7 +8,7 @@ in a number of ways:
|
|||
- Use Salt and open well-written bug reports.
|
||||
- Join a `working group <https://github.com/saltstack/community>`__.
|
||||
- Answer questions on `irc <https://web.libera.chat/#salt>`__,
|
||||
the `community Slack <https://join.slack.com/t/saltstackcommunity/shared_invite/zt-3av8jjyf-oBQ2M0vhXOhJpNpRkPWBvg>`__,
|
||||
the `community Slack <https://join.slack.com/t/saltstackcommunity/shared_invite/zt-1zlfxffs1-NuEH~G9TzOeuNGdsfZIl3w>`__,
|
||||
the `salt-users mailing
|
||||
list <https://groups.google.com/forum/#!forum/salt-users>`__,
|
||||
`Server Fault <https://serverfault.com/questions/tagged/saltstack>`__,
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
.. image:: https://img.shields.io/badge/slack-@saltstackcommunity-blue.svg?logo=slack
|
||||
:alt: Salt Project Slack Community
|
||||
:target: https://join.slack.com/t/saltstackcommunity/shared_invite/zt-3av8jjyf-oBQ2M0vhXOhJpNpRkPWBvg
|
||||
:target: https://join.slack.com/t/saltstackcommunity/shared_invite/zt-1zlfxffs1-NuEH~G9TzOeuNGdsfZIl3w
|
||||
|
||||
.. image:: https://img.shields.io/twitch/status/saltprojectoss
|
||||
:alt: Salt Project Twitch Channel
|
||||
|
@ -71,7 +71,8 @@ In addition to configuration management Salt can also:
|
|||
|
||||
About our sponsors
|
||||
==================
|
||||
Salt powers VMware's `vRealize Automation SaltStack Config`_, and can be found
|
||||
Salt powers VMware's `VMware Aria Automation Config`_
|
||||
(previously vRealize Automation SaltStack Config / SaltStack Enterprise), and can be found
|
||||
under the hood of products from Juniper, Cisco, Cloudflare, Nutanix, SUSE, and
|
||||
Tieto, to name a few.
|
||||
|
||||
|
@ -179,8 +180,8 @@ used by external modules.
|
|||
A complete list of attributions and dependencies can be found here:
|
||||
`salt/DEPENDENCIES.md <https://github.com/saltstack/salt/blob/master/DEPENDENCIES.md>`_
|
||||
|
||||
.. _Salt Project Community Slack: https://join.slack.com/t/saltstackcommunity/shared_invite/zt-3av8jjyf-oBQ2M0vhXOhJpNpRkPWBvg
|
||||
.. _vRealize Automation SaltStack Config: https://www.vmware.com/products/vrealize-automation/saltstack-config.html
|
||||
.. _Salt Project Community Slack: https://join.slack.com/t/saltstackcommunity/shared_invite/zt-1zlfxffs1-NuEH~G9TzOeuNGdsfZIl3w
|
||||
.. _VMware Aria Automation Config: https://www.vmware.com/products/vrealize-automation/saltstack-config.html
|
||||
.. _Latest Salt Documentation: https://docs.saltproject.io/en/latest/
|
||||
.. _Open an issue: https://github.com/saltstack/salt/issues/new/choose
|
||||
.. _SECURITY.md: https://github.com/saltstack/salt/blob/master/SECURITY.md
|
||||
|
|
|
@ -11,7 +11,7 @@ it may take a few moments for someone to reply.
|
|||
**SaltStack Slack** - Alongside IRC is our SaltStack Community Slack for the
|
||||
SaltStack Working groups. Use the following link to request an invitation.
|
||||
|
||||
`<https://join.slack.com/t/saltstackcommunity/shared_invite/zt-3av8jjyf-oBQ2M0vhXOhJpNpRkPWBvg>`_
|
||||
`<https://join.slack.com/t/saltstackcommunity/shared_invite/zt-1zlfxffs1-NuEH~G9TzOeuNGdsfZIl3w>`_
|
||||
|
||||
**Mailing List** - The SaltStack community users mailing list is hosted by
|
||||
Google groups. Anyone can post to ask questions about SaltStack products and
|
||||
|
|
1
changelog/64622.fixed.md
Normal file
1
changelog/64622.fixed.md
Normal file
|
@ -0,0 +1 @@
|
|||
Added support for Chocolatey 2.0.0+
|
1
changelog/64687.security.md
Normal file
1
changelog/64687.security.md
Normal file
|
@ -0,0 +1 @@
|
|||
Bump to `aiohttp==3.8.5` due to https://github.com/advisories/GHSA-45c4-8wx5-qw6w
|
|
@ -174,7 +174,7 @@ rst_prolog = """\
|
|||
.. _`salt-users`: https://groups.google.com/forum/#!forum/salt-users
|
||||
.. _`salt-announce`: https://groups.google.com/forum/#!forum/salt-announce
|
||||
.. _`salt-packagers`: https://groups.google.com/forum/#!forum/salt-packagers
|
||||
.. _`salt-slack`: https://join.slack.com/t/saltstackcommunity/shared_invite/zt-3av8jjyf-oBQ2M0vhXOhJpNpRkPWBvg
|
||||
.. _`salt-slack`: https://join.slack.com/t/saltstackcommunity/shared_invite/zt-1zlfxffs1-NuEH~G9TzOeuNGdsfZIl3w
|
||||
.. |windownload| raw:: html
|
||||
|
||||
<p>Python3 x86: <a
|
||||
|
|
|
@ -1197,8 +1197,8 @@ seconds each iteration.
|
|||
|
||||
Default: ``False``
|
||||
|
||||
If the master rejects the minion's public key, retry instead of exiting.
|
||||
Rejected keys will be handled the same as waiting on acceptance.
|
||||
If the master denies or rejects the minion's public key, retry instead of
|
||||
exiting. These keys will be handled the same as waiting on acceptance.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#
|
||||
# pip-compile --no-emit-index-url --output-file=requirements/static/ci/py3.10/darwin.txt requirements/darwin.txt requirements/pytest.txt requirements/static/ci/common.in requirements/static/ci/darwin.in requirements/static/pkg/darwin.in
|
||||
#
|
||||
aiohttp==3.8.4
|
||||
aiohttp==3.8.5
|
||||
# via etcd3-py
|
||||
aiosignal==1.3.1
|
||||
# via aiohttp
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#
|
||||
# pip-compile --no-emit-index-url --output-file=requirements/static/ci/py3.10/freebsd.txt requirements/base.txt requirements/pytest.txt requirements/static/ci/common.in requirements/static/ci/freebsd.in requirements/static/pkg/freebsd.in requirements/zeromq.txt
|
||||
#
|
||||
aiohttp==3.8.4
|
||||
aiohttp==3.8.5
|
||||
# via etcd3-py
|
||||
aiosignal==1.3.1
|
||||
# via aiohttp
|
||||
|
|
|
@ -6,12 +6,12 @@
|
|||
#
|
||||
aiohttp-retry==2.8.3
|
||||
# via twilio
|
||||
aiohttp==3.8.4
|
||||
aiohttp==3.8.5
|
||||
# via
|
||||
# aiohttp-retry
|
||||
# etcd3-py
|
||||
# twilio
|
||||
aiosignal==1.3.1
|
||||
aiosignal==1.2.0
|
||||
# via aiohttp
|
||||
ansible-core==2.15.0
|
||||
# via ansible
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#
|
||||
# pip-compile --no-emit-index-url --output-file=requirements/static/ci/py3.10/windows.txt requirements/pytest.txt requirements/static/ci/common.in requirements/static/ci/windows.in requirements/static/pkg/windows.in requirements/windows.txt
|
||||
#
|
||||
aiohttp==3.8.4
|
||||
aiohttp==3.8.5
|
||||
# via etcd3-py
|
||||
aiosignal==1.3.1
|
||||
# via aiohttp
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#
|
||||
# pip-compile --no-emit-index-url --output-file=requirements/static/ci/py3.11/windows.txt requirements/pytest.txt requirements/static/ci/common.in requirements/static/ci/windows.in requirements/static/pkg/windows.in requirements/windows.txt
|
||||
#
|
||||
aiohttp==3.8.4
|
||||
aiohttp==3.8.5
|
||||
# via etcd3-py
|
||||
aiosignal==1.3.1
|
||||
# via aiohttp
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#
|
||||
# pip-compile --no-emit-index-url --output-file=requirements/static/ci/py3.8/freebsd.txt requirements/base.txt requirements/pytest.txt requirements/static/ci/common.in requirements/static/ci/freebsd.in requirements/static/pkg/freebsd.in requirements/zeromq.txt
|
||||
#
|
||||
aiohttp==3.8.4
|
||||
aiohttp==3.8.5
|
||||
# via etcd3-py
|
||||
aiosignal==1.3.1
|
||||
# via aiohttp
|
||||
|
|
|
@ -6,12 +6,12 @@
|
|||
#
|
||||
aiohttp-retry==2.8.3
|
||||
# via twilio
|
||||
aiohttp==3.8.4
|
||||
aiohttp==3.8.5
|
||||
# via
|
||||
# aiohttp-retry
|
||||
# etcd3-py
|
||||
# twilio
|
||||
aiosignal==1.3.1
|
||||
aiosignal==1.2.0
|
||||
# via aiohttp
|
||||
ansible-core==2.11.12
|
||||
# via ansible
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#
|
||||
# pip-compile --no-emit-index-url --output-file=requirements/static/ci/py3.8/windows.txt requirements/pytest.txt requirements/static/ci/common.in requirements/static/ci/windows.in requirements/static/pkg/windows.in requirements/windows.txt
|
||||
#
|
||||
aiohttp==3.8.4
|
||||
aiohttp==3.8.5
|
||||
# via etcd3-py
|
||||
aiosignal==1.3.1
|
||||
# via aiohttp
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#
|
||||
# pip-compile --no-emit-index-url --output-file=requirements/static/ci/py3.9/darwin.txt requirements/darwin.txt requirements/pytest.txt requirements/static/ci/common.in requirements/static/ci/darwin.in requirements/static/pkg/darwin.in
|
||||
#
|
||||
aiohttp==3.8.4
|
||||
aiohttp==3.8.5
|
||||
# via etcd3-py
|
||||
aiosignal==1.3.1
|
||||
# via aiohttp
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#
|
||||
# pip-compile --no-emit-index-url --output-file=requirements/static/ci/py3.9/freebsd.txt requirements/base.txt requirements/pytest.txt requirements/static/ci/common.in requirements/static/ci/freebsd.in requirements/static/pkg/freebsd.in requirements/zeromq.txt
|
||||
#
|
||||
aiohttp==3.8.4
|
||||
aiohttp==3.8.5
|
||||
# via etcd3-py
|
||||
aiosignal==1.3.1
|
||||
# via aiohttp
|
||||
|
|
|
@ -6,12 +6,12 @@
|
|||
#
|
||||
aiohttp-retry==2.8.3
|
||||
# via twilio
|
||||
aiohttp==3.8.4
|
||||
aiohttp==3.8.5
|
||||
# via
|
||||
# aiohttp-retry
|
||||
# etcd3-py
|
||||
# twilio
|
||||
aiosignal==1.3.1
|
||||
aiosignal==1.2.0
|
||||
# via aiohttp
|
||||
ansible-core==2.15.0
|
||||
# via ansible
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#
|
||||
# pip-compile --no-emit-index-url --output-file=requirements/static/ci/py3.9/windows.txt requirements/pytest.txt requirements/static/ci/common.in requirements/static/ci/windows.in requirements/static/pkg/windows.in requirements/windows.txt
|
||||
#
|
||||
aiohttp==3.8.4
|
||||
aiohttp==3.8.5
|
||||
# via etcd3-py
|
||||
aiosignal==1.3.1
|
||||
# via aiohttp
|
||||
|
|
|
@ -340,8 +340,6 @@ class LoadAuth:
|
|||
load["user"] == self.opts.get("user", "root") or load["user"] == "root"
|
||||
):
|
||||
for check_key in key:
|
||||
dgm_user = self.opts.get("user", "root")
|
||||
dgm_check_key = key[check_key]
|
||||
if auth_key == key[check_key]:
|
||||
return True
|
||||
log.warning(
|
||||
|
|
|
@ -460,7 +460,11 @@ def list_(
|
|||
salt '*' chocolatey.list <narrow> all_versions=True
|
||||
"""
|
||||
choc_path = _find_chocolatey()
|
||||
cmd = [choc_path, "list"]
|
||||
# https://docs.chocolatey.org/en-us/guides/upgrading-to-chocolatey-v2-v6
|
||||
if Version(chocolatey_version()) < Version("2.0.0"):
|
||||
cmd = [choc_path, "list"]
|
||||
else:
|
||||
cmd = [choc_path, "search"]
|
||||
if narrow:
|
||||
cmd.append(narrow)
|
||||
if salt.utils.data.is_true(all_versions):
|
||||
|
@ -518,7 +522,11 @@ def list_webpi():
|
|||
salt '*' chocolatey.list_webpi
|
||||
"""
|
||||
choc_path = _find_chocolatey()
|
||||
cmd = [choc_path, "list", "--source", "webpi"]
|
||||
# https://docs.chocolatey.org/en-us/guides/upgrading-to-chocolatey-v2-v6
|
||||
if Version(chocolatey_version()) < Version("2.0.0"):
|
||||
cmd = [choc_path, "list", "--source", "webpi"]
|
||||
else:
|
||||
cmd = [choc_path, "search", "--source", "webpi"]
|
||||
result = __salt__["cmd.run_all"](cmd, python_shell=False)
|
||||
|
||||
if result["retcode"] != 0:
|
||||
|
@ -543,7 +551,11 @@ def list_windowsfeatures():
|
|||
salt '*' chocolatey.list_windowsfeatures
|
||||
"""
|
||||
choc_path = _find_chocolatey()
|
||||
cmd = [choc_path, "list", "--source", "windowsfeatures"]
|
||||
# https://docs.chocolatey.org/en-us/guides/upgrading-to-chocolatey-v2-v6
|
||||
if Version(chocolatey_version()) < Version("2.0.0"):
|
||||
cmd = [choc_path, "list", "--source", "windowsfeatures"]
|
||||
else:
|
||||
cmd = [choc_path, "search", "--source", "windowsfeatures"]
|
||||
result = __salt__["cmd.run_all"](cmd, python_shell=False)
|
||||
|
||||
if result["retcode"] != 0:
|
||||
|
|
|
@ -30,8 +30,8 @@ salt/modules/(aix_group|groupadd|mac_group|pw_group|solaris_group|win_groupadd)\
|
|||
|
||||
salt/modules/(debian_service|freebsdservice|gentoo_service|launchctl_service|mac_service|netbsdservice|openbsdrcctl_service|openbsdservice|rh_service|runit|linux_service|smf_service|systemd_service|upstart_service|win_service)\.py:
|
||||
- pytests.unit.states.test_service
|
||||
- integration.modules.test_service
|
||||
- integration.states.test_service
|
||||
- pytests.functional.modules.test_service
|
||||
- pytests.functional.states.test_service
|
||||
|
||||
|
||||
salt/modules/ansiblegate.py:
|
||||
|
|
|
@ -1,183 +0,0 @@
|
|||
import pytest
|
||||
|
||||
import salt.utils.path
|
||||
import salt.utils.platform
|
||||
import salt.utils.systemd
|
||||
from tests.support.case import ModuleCase
|
||||
|
||||
|
||||
@pytest.mark.destructive_test
|
||||
@pytest.mark.windows_whitelisted
|
||||
class ServiceModuleTest(ModuleCase):
|
||||
"""
|
||||
Module testing the service module
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
self.service_name = "cron"
|
||||
cmd_name = "crontab"
|
||||
os_family = self.run_function("grains.get", ["os_family"])
|
||||
os_release = self.run_function("grains.get", ["osrelease"])
|
||||
if os_family == "RedHat":
|
||||
if os_release[0] == "7":
|
||||
self.skipTest(
|
||||
"Disabled on CentOS 7 until we can fix SSH connection issues."
|
||||
)
|
||||
self.service_name = "crond"
|
||||
elif os_family == "Arch":
|
||||
self.service_name = "sshd"
|
||||
cmd_name = "systemctl"
|
||||
elif os_family == "NILinuxRT":
|
||||
self.service_name = "syslog"
|
||||
cmd_name = "syslog-ng"
|
||||
elif os_family == "MacOS":
|
||||
self.service_name = "com.apple.AirPlayXPCHelper"
|
||||
elif salt.utils.platform.is_windows():
|
||||
self.service_name = "Spooler"
|
||||
|
||||
self.pre_srv_status = self.run_function("service.status", [self.service_name])
|
||||
self.pre_srv_enabled = (
|
||||
True
|
||||
if self.service_name in self.run_function("service.get_enabled")
|
||||
else False
|
||||
)
|
||||
|
||||
if (
|
||||
salt.utils.path.which(cmd_name) is None
|
||||
and not salt.utils.platform.is_windows()
|
||||
):
|
||||
self.skipTest("{} is not installed".format(cmd_name))
|
||||
|
||||
def tearDown(self):
|
||||
post_srv_status = self.run_function("service.status", [self.service_name])
|
||||
post_srv_enabled = (
|
||||
True
|
||||
if self.service_name in self.run_function("service.get_enabled")
|
||||
else False
|
||||
)
|
||||
|
||||
if post_srv_status != self.pre_srv_status:
|
||||
if self.pre_srv_status:
|
||||
self.run_function("service.enable", [self.service_name])
|
||||
else:
|
||||
self.run_function("service.disable", [self.service_name])
|
||||
|
||||
if post_srv_enabled != self.pre_srv_enabled:
|
||||
if self.pre_srv_enabled:
|
||||
self.run_function("service.enable", [self.service_name])
|
||||
else:
|
||||
self.run_function("service.disable", [self.service_name])
|
||||
del self.service_name
|
||||
|
||||
@pytest.mark.flaky(max_runs=4)
|
||||
@pytest.mark.slow_test
|
||||
def test_service_status_running(self):
|
||||
"""
|
||||
test service.status execution module
|
||||
when service is running
|
||||
"""
|
||||
self.run_function("service.start", [self.service_name])
|
||||
check_service = self.run_function("service.status", [self.service_name])
|
||||
self.assertTrue(check_service)
|
||||
|
||||
@pytest.mark.slow_test
|
||||
def test_service_status_dead(self):
|
||||
"""
|
||||
test service.status execution module
|
||||
when service is dead
|
||||
"""
|
||||
self.run_function("service.stop", [self.service_name])
|
||||
check_service = self.run_function("service.status", [self.service_name])
|
||||
self.assertFalse(check_service)
|
||||
|
||||
@pytest.mark.slow_test
|
||||
def test_service_restart(self):
|
||||
"""
|
||||
test service.restart
|
||||
"""
|
||||
self.assertTrue(self.run_function("service.restart", [self.service_name]))
|
||||
|
||||
@pytest.mark.slow_test
|
||||
def test_service_enable(self):
|
||||
"""
|
||||
test service.get_enabled and service.enable module
|
||||
"""
|
||||
# disable service before test
|
||||
self.assertTrue(self.run_function("service.disable", [self.service_name]))
|
||||
|
||||
self.assertTrue(self.run_function("service.enable", [self.service_name]))
|
||||
self.assertIn(self.service_name, self.run_function("service.get_enabled"))
|
||||
|
||||
@pytest.mark.slow_test
|
||||
def test_service_disable(self):
|
||||
"""
|
||||
test service.get_disabled and service.disable module
|
||||
"""
|
||||
# enable service before test
|
||||
self.assertTrue(self.run_function("service.enable", [self.service_name]))
|
||||
|
||||
self.assertTrue(self.run_function("service.disable", [self.service_name]))
|
||||
if salt.utils.platform.is_darwin():
|
||||
self.assertTrue(self.run_function("service.disabled", [self.service_name]))
|
||||
else:
|
||||
self.assertIn(self.service_name, self.run_function("service.get_disabled"))
|
||||
|
||||
@pytest.mark.slow_test
|
||||
def test_service_disable_doesnot_exist(self):
|
||||
"""
|
||||
test service.get_disabled and service.disable module
|
||||
when service name does not exist
|
||||
"""
|
||||
# enable service before test
|
||||
srv_name = "doesnotexist"
|
||||
enable = self.run_function("service.enable", [srv_name])
|
||||
systemd = salt.utils.systemd.booted()
|
||||
|
||||
# check service was not enabled
|
||||
try:
|
||||
self.assertFalse(enable)
|
||||
except AssertionError:
|
||||
self.assertIn("ERROR", enable)
|
||||
|
||||
# check service was not disabled
|
||||
if (
|
||||
tuple(
|
||||
self.run_function("grains.item", ["osrelease_info"])["osrelease_info"]
|
||||
)
|
||||
== (14, 0o4)
|
||||
and not systemd
|
||||
):
|
||||
# currently upstart does not have a mechanism to report if disabling a service fails if does not exist
|
||||
self.assertTrue(self.run_function("service.disable", [srv_name]))
|
||||
elif (
|
||||
self.run_function("grains.item", ["os"])["os"] == "Debian"
|
||||
and self.run_function("grains.item", ["osmajorrelease"])["osmajorrelease"]
|
||||
< 9
|
||||
and systemd
|
||||
):
|
||||
# currently disabling a service via systemd that does not exist
|
||||
# on Debian 8 results in a True return code
|
||||
self.assertTrue(self.run_function("service.disable", [srv_name]))
|
||||
else:
|
||||
try:
|
||||
disable = self.run_function("service.disable", [srv_name])
|
||||
self.assertFalse(disable)
|
||||
except AssertionError:
|
||||
self.assertTrue("error" in disable.lower())
|
||||
|
||||
if salt.utils.platform.is_darwin():
|
||||
self.assertEqual(
|
||||
self.run_function("service.disabled", [srv_name]),
|
||||
"ERROR: Service not found: {}".format(srv_name),
|
||||
)
|
||||
else:
|
||||
self.assertNotIn(srv_name, self.run_function("service.get_disabled"))
|
||||
|
||||
@pytest.mark.skip_unless_on_windows
|
||||
@pytest.mark.slow_test
|
||||
def test_service_get_service_name(self):
|
||||
"""
|
||||
test service.get_service_name
|
||||
"""
|
||||
ret = self.run_function("service.get_service_name")
|
||||
self.assertIn(self.service_name, ret.values())
|
|
@ -1,119 +0,0 @@
|
|||
"""
|
||||
Tests for the service state
|
||||
"""
|
||||
|
||||
import re
|
||||
|
||||
import pytest
|
||||
|
||||
import salt.utils.path
|
||||
import salt.utils.platform
|
||||
from tests.support.case import ModuleCase
|
||||
from tests.support.mixins import SaltReturnAssertsMixin
|
||||
|
||||
INIT_DELAY = 5
|
||||
|
||||
|
||||
@pytest.mark.windows_whitelisted
|
||||
@pytest.mark.destructive_test
|
||||
class ServiceTest(ModuleCase, SaltReturnAssertsMixin):
|
||||
"""
|
||||
Validate the service state
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
self.service_name = "cron"
|
||||
cmd_name = "crontab"
|
||||
os_family = self.run_function("grains.get", ["os_family"])
|
||||
os_release = self.run_function("grains.get", ["osrelease"])
|
||||
is_systemd = self.run_function("grains.get", ["systemd"])
|
||||
self.stopped = False
|
||||
self.running = True
|
||||
if os_family == "RedHat":
|
||||
self.service_name = "crond"
|
||||
elif os_family == "Arch":
|
||||
self.service_name = "sshd"
|
||||
cmd_name = "systemctl"
|
||||
elif os_family == "MacOS":
|
||||
self.service_name = "com.apple.AirPlayXPCHelper"
|
||||
elif os_family == "Windows":
|
||||
self.service_name = "Spooler"
|
||||
|
||||
self.pre_srv_enabled = (
|
||||
True
|
||||
if self.service_name in self.run_function("service.get_enabled")
|
||||
else False
|
||||
)
|
||||
self.post_srv_disable = False
|
||||
if not self.pre_srv_enabled:
|
||||
self.run_function("service.enable", name=self.service_name)
|
||||
self.post_srv_disable = True
|
||||
|
||||
if os_family != "Windows" and salt.utils.path.which(cmd_name) is None:
|
||||
self.skipTest("{} is not installed".format(cmd_name))
|
||||
|
||||
if is_systemd and self.run_function("service.offline"):
|
||||
self.skipTest("systemd is OFFLINE")
|
||||
|
||||
def tearDown(self):
|
||||
if self.post_srv_disable:
|
||||
self.run_function("service.disable", name=self.service_name)
|
||||
|
||||
def check_service_status(self, exp_return):
|
||||
"""
|
||||
helper method to check status of service
|
||||
"""
|
||||
check_status = self.run_function("service.status", name=self.service_name)
|
||||
|
||||
try:
|
||||
if not re.match(exp_return, check_status):
|
||||
self.fail("status of service is not returning correctly")
|
||||
except TypeError:
|
||||
if check_status is not exp_return:
|
||||
self.fail("status of service is not returning correctly")
|
||||
|
||||
@pytest.mark.slow_test
|
||||
def test_service_running(self):
|
||||
"""
|
||||
test service.running state module
|
||||
"""
|
||||
if self.run_function("service.status", name=self.service_name):
|
||||
stop_service = self.run_function("service.stop", name=self.service_name)
|
||||
self.assertTrue(stop_service)
|
||||
self.check_service_status(self.stopped)
|
||||
|
||||
if salt.utils.platform.is_darwin():
|
||||
# make sure the service is enabled on macosx
|
||||
enable = self.run_function("service.enable", name=self.service_name)
|
||||
|
||||
start_service = self.run_state("service.running", name=self.service_name)
|
||||
self.assertTrue(start_service)
|
||||
self.check_service_status(self.running)
|
||||
|
||||
@pytest.mark.slow_test
|
||||
def test_service_dead(self):
|
||||
"""
|
||||
test service.dead state module
|
||||
"""
|
||||
start_service = self.run_state("service.running", name=self.service_name)
|
||||
self.assertSaltTrueReturn(start_service)
|
||||
self.check_service_status(self.running)
|
||||
|
||||
ret = self.run_state("service.dead", name=self.service_name)
|
||||
self.assertSaltTrueReturn(ret)
|
||||
self.check_service_status(self.stopped)
|
||||
|
||||
@pytest.mark.slow_test
|
||||
def test_service_dead_init_delay(self):
|
||||
"""
|
||||
test service.dead state module with init_delay arg
|
||||
"""
|
||||
start_service = self.run_state("service.running", name=self.service_name)
|
||||
self.assertSaltTrueReturn(start_service)
|
||||
self.check_service_status(self.running)
|
||||
|
||||
ret = self.run_state(
|
||||
"service.dead", name=self.service_name, init_delay=INIT_DELAY
|
||||
)
|
||||
self.assertSaltTrueReturn(ret)
|
||||
self.check_service_status(self.stopped)
|
157
tests/pytests/functional/modules/test_service.py
Normal file
157
tests/pytests/functional/modules/test_service.py
Normal file
|
@ -0,0 +1,157 @@
|
|||
import os
|
||||
|
||||
import pytest
|
||||
|
||||
import salt.utils.path
|
||||
import salt.utils.platform
|
||||
import salt.utils.systemd
|
||||
from salt.exceptions import CommandExecutionError
|
||||
|
||||
pytestmark = [
|
||||
pytest.mark.windows_whitelisted,
|
||||
pytest.mark.destructive_test,
|
||||
pytest.mark.slow_test,
|
||||
]
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def service_name(grains, modules):
|
||||
# For local testing purposes
|
||||
env_name = os.environ.get("SALT_FUNCTIONAL_TEST_SERVICE_NAME")
|
||||
if env_name is not None:
|
||||
return env_name
|
||||
|
||||
service_name = "cron"
|
||||
cmd_name = "crontab"
|
||||
os_family = grains.get("os_family")
|
||||
is_systemd = grains.get("systemd")
|
||||
if os_family == "RedHat":
|
||||
service_name = "crond"
|
||||
elif os_family == "Arch":
|
||||
service_name = "sshd"
|
||||
cmd_name = "systemctl"
|
||||
elif os_family == "MacOS":
|
||||
service_name = "com.apple.AirPlayXPCHelper"
|
||||
elif os_family == "Windows":
|
||||
service_name = "Spooler"
|
||||
|
||||
if os_family != "Windows" and salt.utils.path.which(cmd_name) is None:
|
||||
pytest.skip("{} is not installed".format(cmd_name))
|
||||
|
||||
if is_systemd and modules.service.offline():
|
||||
pytest.skip("systemd is OFFLINE")
|
||||
|
||||
return service_name
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def setup_service(service_name, modules):
|
||||
pre_srv_status = modules.service.status(service_name)
|
||||
pre_srv_enabled = service_name in modules.service.get_enabled()
|
||||
|
||||
try:
|
||||
yield pre_srv_status
|
||||
finally:
|
||||
post_srv_status = modules.service.status(service_name)
|
||||
post_srv_enabled = service_name in modules.service.get_enabled()
|
||||
|
||||
if post_srv_status != pre_srv_status:
|
||||
if pre_srv_status:
|
||||
modules.service.start(service_name)
|
||||
else:
|
||||
modules.service.stop(service_name)
|
||||
|
||||
if post_srv_enabled != pre_srv_enabled:
|
||||
if pre_srv_enabled:
|
||||
modules.service.enable(service_name)
|
||||
else:
|
||||
modules.service.disable(service_name)
|
||||
|
||||
|
||||
def test_service_status_running(modules, service_name):
|
||||
"""
|
||||
test service.status execution module
|
||||
when service is running
|
||||
"""
|
||||
modules.service.start(service_name)
|
||||
check_service = modules.service.status(service_name)
|
||||
assert check_service
|
||||
|
||||
|
||||
def test_service_status_dead(modules, service_name):
|
||||
"""
|
||||
test service.status execution module
|
||||
when service is dead
|
||||
"""
|
||||
modules.service.stop(service_name)
|
||||
check_service = modules.service.status(service_name)
|
||||
assert not check_service
|
||||
|
||||
|
||||
def test_service_restart(modules, service_name):
|
||||
"""
|
||||
test service.restart
|
||||
"""
|
||||
assert modules.service.stop(service_name)
|
||||
|
||||
|
||||
def test_service_enable(modules, service_name):
|
||||
"""
|
||||
test service.get_enabled and service.enable module
|
||||
"""
|
||||
# disable service before test
|
||||
assert modules.service.disable(service_name)
|
||||
|
||||
assert modules.service.enable(service_name)
|
||||
assert service_name in modules.service.get_enabled()
|
||||
|
||||
|
||||
def test_service_disable(modules, service_name):
|
||||
"""
|
||||
test service.get_disabled and service.disable module
|
||||
"""
|
||||
# enable service before test
|
||||
assert modules.service.enable(service_name)
|
||||
|
||||
assert modules.service.disable(service_name)
|
||||
if salt.utils.platform.is_darwin():
|
||||
assert modules.service.disabled(service_name)
|
||||
else:
|
||||
assert service_name in modules.service.get_disabled()
|
||||
|
||||
|
||||
def test_service_disable_doesnot_exist(modules):
|
||||
"""
|
||||
test service.get_disabled and service.disable module
|
||||
when service name does not exist
|
||||
"""
|
||||
# enable service before test
|
||||
srv_name = "doesnotexist"
|
||||
try:
|
||||
enable = modules.service.enable(srv_name)
|
||||
assert not enable
|
||||
except CommandExecutionError as exc:
|
||||
assert srv_name in exc.error or "no such file or directory" in exc.error.lower()
|
||||
|
||||
try:
|
||||
disable = modules.service.disable(srv_name)
|
||||
assert not disable
|
||||
except CommandExecutionError as exc:
|
||||
assert srv_name in exc.error or "no such file or directory" in exc.error.lower()
|
||||
|
||||
if salt.utils.platform.is_darwin():
|
||||
with pytest.raises(
|
||||
CommandExecutionError, match=f"Service not found: {srv_name}"
|
||||
):
|
||||
modules.service.disabled(srv_name)
|
||||
else:
|
||||
assert srv_name not in modules.service.get_disabled()
|
||||
|
||||
|
||||
@pytest.mark.skip_unless_on_windows
|
||||
def test_service_get_service_name(modules, service_name):
|
||||
"""
|
||||
test service.get_service_name
|
||||
"""
|
||||
ret = modules.service.get_service_name()
|
||||
assert service_name in ret.values()
|
132
tests/pytests/functional/states/test_service.py
Normal file
132
tests/pytests/functional/states/test_service.py
Normal file
|
@ -0,0 +1,132 @@
|
|||
"""
|
||||
Tests for the service state
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
import pytest
|
||||
|
||||
import salt.utils.path
|
||||
import salt.utils.platform
|
||||
|
||||
pytestmark = [
|
||||
pytest.mark.windows_whitelisted,
|
||||
pytest.mark.destructive_test,
|
||||
pytest.mark.slow_test,
|
||||
]
|
||||
|
||||
|
||||
INIT_DELAY = 5
|
||||
STOPPED = False
|
||||
RUNNING = True
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def service_name(grains, modules):
|
||||
# For local testing purposes
|
||||
env_name = os.environ.get("SALT_FUNCTIONAL_TEST_SERVICE_NAME")
|
||||
if env_name is not None:
|
||||
return env_name
|
||||
|
||||
service_name = "cron"
|
||||
cmd_name = "crontab"
|
||||
os_family = grains.get("os_family")
|
||||
is_systemd = grains.get("systemd")
|
||||
if os_family == "RedHat":
|
||||
service_name = "crond"
|
||||
elif os_family == "Arch":
|
||||
service_name = "sshd"
|
||||
cmd_name = "systemctl"
|
||||
elif os_family == "MacOS":
|
||||
service_name = "com.apple.AirPlayXPCHelper"
|
||||
elif os_family == "Windows":
|
||||
service_name = "Spooler"
|
||||
|
||||
if os_family != "Windows" and salt.utils.path.which(cmd_name) is None:
|
||||
pytest.skip("{} is not installed".format(cmd_name))
|
||||
|
||||
if is_systemd and modules.service.offline():
|
||||
pytest.skip("systemd is OFFLINE")
|
||||
|
||||
return service_name
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def setup_service(service_name, modules):
|
||||
pre_srv_status = modules.service.status(service_name)
|
||||
pre_srv_enabled = service_name in modules.service.get_enabled()
|
||||
|
||||
try:
|
||||
yield pre_srv_status
|
||||
finally:
|
||||
post_srv_status = modules.service.status(service_name)
|
||||
post_srv_enabled = service_name in modules.service.get_enabled()
|
||||
|
||||
if post_srv_status != pre_srv_status:
|
||||
if pre_srv_status:
|
||||
modules.service.start(service_name)
|
||||
else:
|
||||
modules.service.stop(service_name)
|
||||
|
||||
if post_srv_enabled != pre_srv_enabled:
|
||||
if pre_srv_enabled:
|
||||
modules.service.enable(service_name)
|
||||
else:
|
||||
modules.service.disable(service_name)
|
||||
|
||||
|
||||
def check_service_status(exp_return, modules, service_name):
|
||||
"""
|
||||
helper method to check status of service
|
||||
"""
|
||||
check_status = modules.service.status(service_name)
|
||||
|
||||
if check_status is not exp_return:
|
||||
pytest.fail("status of service is not returning correctly")
|
||||
|
||||
|
||||
@pytest.mark.slow_test
|
||||
def test_service_running(service_name, modules, states):
|
||||
"""
|
||||
test service.running state module
|
||||
"""
|
||||
if modules.service.status(service_name):
|
||||
stop_service = modules.service.stop(service_name)
|
||||
assert stop_service is True
|
||||
check_service_status(STOPPED, modules, service_name)
|
||||
|
||||
if salt.utils.platform.is_darwin():
|
||||
# make sure the service is enabled on macosx
|
||||
enable = modules.service.enable(service_name)
|
||||
|
||||
start_service = states.service.running(service_name)
|
||||
assert start_service.full_return["result"] is True
|
||||
check_service_status(RUNNING, modules, service_name)
|
||||
|
||||
|
||||
@pytest.mark.slow_test
|
||||
def test_service_dead(service_name, modules, states):
|
||||
"""
|
||||
test service.dead state module
|
||||
"""
|
||||
start_service = states.service.running(service_name)
|
||||
assert start_service.full_return["result"] is True
|
||||
check_service_status(RUNNING, modules, service_name)
|
||||
|
||||
ret = states.service.dead(service_name)
|
||||
assert ret.full_return["result"] is True
|
||||
check_service_status(STOPPED, modules, service_name)
|
||||
|
||||
|
||||
@pytest.mark.slow_test
|
||||
def test_service_dead_init_delay(service_name, modules, states):
|
||||
"""
|
||||
test service.dead state module
|
||||
"""
|
||||
start_service = states.service.running(service_name)
|
||||
assert start_service.full_return["result"] is True
|
||||
check_service_status(RUNNING, modules, service_name)
|
||||
|
||||
ret = states.service.dead(service_name, init_delay=INIT_DELAY)
|
||||
assert ret.full_return["result"] is True
|
||||
check_service_status(STOPPED, modules, service_name)
|
|
@ -262,3 +262,75 @@ def test_add_source(choco_path):
|
|||
"source_name", "source_location", priority="priority"
|
||||
)
|
||||
cmd_run_all_mock.assert_called_with(expected_call, python_shell=False)
|
||||
|
||||
|
||||
def test_list_pre_2_0_0():
|
||||
mock_version = MagicMock(return_value="1.2.1")
|
||||
mock_find = MagicMock(return_value=choco_path)
|
||||
mock_run = MagicMock(return_value={"stdout": "No packages", "retcode": 0})
|
||||
with patch.object(chocolatey, "chocolatey_version", mock_version), patch.object(
|
||||
chocolatey, "_find_chocolatey", mock_find
|
||||
), patch.dict(chocolatey.__salt__, {"cmd.run_all": mock_run}):
|
||||
chocolatey.list_()
|
||||
expected_call = [choco_path, "list", "--limit-output"]
|
||||
mock_run.assert_called_with(expected_call, python_shell=False)
|
||||
|
||||
|
||||
def test_list_post_2_0_0():
|
||||
mock_version = MagicMock(return_value="2.0.1")
|
||||
mock_find = MagicMock(return_value=choco_path)
|
||||
mock_run = MagicMock(return_value={"stdout": "No packages", "retcode": 0})
|
||||
with patch.object(chocolatey, "chocolatey_version", mock_version), patch.object(
|
||||
chocolatey, "_find_chocolatey", mock_find
|
||||
), patch.dict(chocolatey.__salt__, {"cmd.run_all": mock_run}):
|
||||
chocolatey.list_()
|
||||
expected_call = [choco_path, "search", "--limit-output"]
|
||||
mock_run.assert_called_with(expected_call, python_shell=False)
|
||||
|
||||
|
||||
def test_list_webpi_pre_2_0_0():
|
||||
mock_version = MagicMock(return_value="1.2.1")
|
||||
mock_find = MagicMock(return_value=choco_path)
|
||||
mock_run = MagicMock(return_value={"stdout": "No packages", "retcode": 0})
|
||||
with patch.object(chocolatey, "chocolatey_version", mock_version), patch.object(
|
||||
chocolatey, "_find_chocolatey", mock_find
|
||||
), patch.dict(chocolatey.__salt__, {"cmd.run_all": mock_run}):
|
||||
chocolatey.list_webpi()
|
||||
expected_call = [choco_path, "list", "--source", "webpi"]
|
||||
mock_run.assert_called_with(expected_call, python_shell=False)
|
||||
|
||||
|
||||
def test_list_webpi_post_2_0_0():
|
||||
mock_version = MagicMock(return_value="2.0.1")
|
||||
mock_find = MagicMock(return_value=choco_path)
|
||||
mock_run = MagicMock(return_value={"stdout": "No packages", "retcode": 0})
|
||||
with patch.object(chocolatey, "chocolatey_version", mock_version), patch.object(
|
||||
chocolatey, "_find_chocolatey", mock_find
|
||||
), patch.dict(chocolatey.__salt__, {"cmd.run_all": mock_run}):
|
||||
chocolatey.list_webpi()
|
||||
expected_call = [choco_path, "search", "--source", "webpi"]
|
||||
mock_run.assert_called_with(expected_call, python_shell=False)
|
||||
|
||||
|
||||
def test_list_windowsfeatures_pre_2_0_0():
|
||||
mock_version = MagicMock(return_value="1.2.1")
|
||||
mock_find = MagicMock(return_value=choco_path)
|
||||
mock_run = MagicMock(return_value={"stdout": "No packages", "retcode": 0})
|
||||
with patch.object(chocolatey, "chocolatey_version", mock_version), patch.object(
|
||||
chocolatey, "_find_chocolatey", mock_find
|
||||
), patch.dict(chocolatey.__salt__, {"cmd.run_all": mock_run}):
|
||||
chocolatey.list_windowsfeatures()
|
||||
expected_call = [choco_path, "list", "--source", "windowsfeatures"]
|
||||
mock_run.assert_called_with(expected_call, python_shell=False)
|
||||
|
||||
|
||||
def test_list_windowsfeatures_post_2_0_0():
|
||||
mock_version = MagicMock(return_value="2.0.1")
|
||||
mock_find = MagicMock(return_value=choco_path)
|
||||
mock_run = MagicMock(return_value={"stdout": "No packages", "retcode": 0})
|
||||
with patch.object(chocolatey, "chocolatey_version", mock_version), patch.object(
|
||||
chocolatey, "_find_chocolatey", mock_find
|
||||
), patch.dict(chocolatey.__salt__, {"cmd.run_all": mock_run}):
|
||||
chocolatey.list_windowsfeatures()
|
||||
expected_call = [choco_path, "search", "--source", "windowsfeatures"]
|
||||
mock_run.assert_called_with(expected_call, python_shell=False)
|
||||
|
|
134
tools/vm.py
134
tools/vm.py
|
@ -563,6 +563,140 @@ def download_artifacts(ctx: Context, name: str):
|
|||
vm.download_artifacts()
|
||||
|
||||
|
||||
@vm.command(
|
||||
name="sync-cache",
|
||||
arguments={
|
||||
"key_name": {"help": "The SSH key name."},
|
||||
"delete": {
|
||||
"help": "Delete the entries in the cache that don't align with ec2",
|
||||
"action": "store_true",
|
||||
},
|
||||
},
|
||||
)
|
||||
def sync_cache(
|
||||
ctx: Context,
|
||||
key_name: str = os.environ.get("RUNNER_NAME"), # type: ignore[assignment]
|
||||
delete: bool = False,
|
||||
):
|
||||
"""
|
||||
Sync the cache
|
||||
"""
|
||||
ec2_instances = _filter_instances_by_state(
|
||||
_get_instances_by_key(ctx, key_name),
|
||||
{"running"},
|
||||
)
|
||||
|
||||
cached_instances = {}
|
||||
if STATE_DIR.exists():
|
||||
for state_path in STATE_DIR.iterdir():
|
||||
instance_id = (state_path / "instance-id").read_text()
|
||||
cached_instances[instance_id] = state_path.name
|
||||
|
||||
# Find what instances we are missing in our cached states
|
||||
to_write = {}
|
||||
to_remove = cached_instances.copy()
|
||||
for instance in ec2_instances:
|
||||
if instance.id not in cached_instances:
|
||||
for tag in instance.tags:
|
||||
if tag.get("Key") == "vm-name":
|
||||
to_write[tag.get("Value")] = instance
|
||||
break
|
||||
else:
|
||||
del to_remove[instance.id]
|
||||
|
||||
for cached_id, vm_name in to_remove.items():
|
||||
if delete:
|
||||
shutil.rmtree(STATE_DIR / vm_name)
|
||||
log.info(
|
||||
f"REMOVED {vm_name} ({cached_id.strip()}) from cache at {STATE_DIR / vm_name}"
|
||||
)
|
||||
else:
|
||||
log.info(
|
||||
f"Would remove {vm_name} ({cached_id.strip()}) from cache at {STATE_DIR / vm_name}"
|
||||
)
|
||||
if not delete and to_remove:
|
||||
log.info("To force the removal of the above cache entries, pass --delete")
|
||||
|
||||
for name_tag, vm_instance in to_write.items():
|
||||
vm_write = VM(ctx=ctx, name=name_tag, region_name=ctx.parser.options.region)
|
||||
vm_write.instance = vm_instance
|
||||
vm_write.write_state()
|
||||
|
||||
|
||||
@vm.command(
|
||||
name="list",
|
||||
arguments={
|
||||
"key_name": {"help": "The SSH key name."},
|
||||
"states": {
|
||||
"help": "The instance state to filter by.",
|
||||
"flags": ["-s", "-state"],
|
||||
"action": "append",
|
||||
},
|
||||
},
|
||||
)
|
||||
def list_vms(
|
||||
ctx: Context,
|
||||
key_name: str = os.environ.get("RUNNER_NAME"), # type: ignore[assignment]
|
||||
states: set[str] = None,
|
||||
):
|
||||
"""
|
||||
List the vms associated with the given key.
|
||||
"""
|
||||
instances = _filter_instances_by_state(
|
||||
_get_instances_by_key(ctx, key_name),
|
||||
states,
|
||||
)
|
||||
|
||||
for instance in instances:
|
||||
vm_state = instance.state["Name"]
|
||||
ip_addr = instance.public_ip_address
|
||||
ami = instance.image_id
|
||||
vm_name = None
|
||||
for tag in instance.tags:
|
||||
if tag.get("Key") == "vm-name":
|
||||
vm_name = tag.get("Value")
|
||||
break
|
||||
|
||||
if vm_name is not None:
|
||||
sep = "\n "
|
||||
extra_info = {
|
||||
"IP": ip_addr,
|
||||
"AMI": ami,
|
||||
}
|
||||
extras = sep + sep.join(
|
||||
[f"{key}: {value}" for key, value in extra_info.items()]
|
||||
)
|
||||
log.info(f"{vm_name} ({vm_state}){extras}")
|
||||
|
||||
|
||||
def _get_instances_by_key(ctx: Context, key_name: str):
|
||||
if key_name is None:
|
||||
ctx.exit(1, "We need a key name to filter the instances by.")
|
||||
ec2 = boto3.resource("ec2", region_name=ctx.parser.options.region)
|
||||
# First let's get the instances on AWS associated with the key given
|
||||
filters = [
|
||||
{"Name": "key-name", "Values": [key_name]},
|
||||
]
|
||||
try:
|
||||
instances = list(
|
||||
ec2.instances.filter(
|
||||
Filters=filters,
|
||||
)
|
||||
)
|
||||
except ClientError as exc:
|
||||
if "RequestExpired" not in str(exc):
|
||||
raise
|
||||
ctx.error(str(exc))
|
||||
ctx.exit(1)
|
||||
return instances
|
||||
|
||||
|
||||
def _filter_instances_by_state(instances: list[Instance], states: set[str] | None):
|
||||
if states is None:
|
||||
return instances
|
||||
return [instance for instance in instances if instance.state["Name"] in states]
|
||||
|
||||
|
||||
@attr.s(frozen=True, kw_only=True)
|
||||
class AMIConfig:
|
||||
ami: str = attr.ib()
|
||||
|
|
Loading…
Add table
Reference in a new issue