diff --git a/lib/ansible/module_utils/docker/swarm.py b/lib/ansible/module_utils/docker/swarm.py index 5e9cfd4ace..11fbb4b8d5 100644 --- a/lib/ansible/module_utils/docker/swarm.py +++ b/lib/ansible/module_utils/docker/swarm.py @@ -3,6 +3,7 @@ # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) import json +from time import sleep try: from docker.errors import APIError @@ -108,23 +109,29 @@ class AnsibleDockerSwarmClient(AnsibleDockerClient): return True return False - def check_if_swarm_node_is_down(self, node_id=None): + def check_if_swarm_node_is_down(self, node_id=None, repeat_check=1): """ Checks if node status on Swarm manager is 'down'. If node_id is provided it query manager about node specified in parameter, otherwise it query manager itself. If run on Swarm Worker node or host that is not part of Swarm it will fail the playbook + :param repeat_check: number of check attempts with 5 seconds delay between them, by default check only once :param node_id: node ID or name, if None then method will try to get node_id of host module run on :return: True if node is part of swarm but its state is down, False otherwise """ + if repeat_check < 1: + repeat_check = 1 + if node_id is None: node_id = self.get_swarm_node_id() - node_info = self.get_node_inspect(node_id=node_id) - if node_info['Status']['State'] == 'down': - return True + for retry in range(0, repeat_check): + node_info = self.get_node_inspect(node_id=node_id) + if node_info['Status']['State'] == 'down': + return True + sleep(5) return False def get_node_inspect(self, node_id=None, skip_missing=False): diff --git a/lib/ansible/modules/cloud/docker/docker_swarm.py b/lib/ansible/modules/cloud/docker/docker_swarm.py index f076c3a3f4..7f049257aa 100644 --- a/lib/ansible/modules/cloud/docker/docker_swarm.py +++ b/lib/ansible/modules/cloud/docker/docker_swarm.py @@ -159,6 +159,7 @@ requirements: - Docker API >= 1.25 author: - Thierry Bouvet (@tbouvet) + - Piotr Wojciechowski (@WojciechowskiPiotr) ''' EXAMPLES = ''' @@ -229,7 +230,7 @@ actions: ''' import json -from time import sleep + try: from docker.errors import APIError except ImportError: @@ -237,10 +238,12 @@ except ImportError: pass from ansible.module_utils.docker.common import ( - AnsibleDockerClient, DockerBaseClass, DifferenceTracker, ) + +from ansible.module_utils.docker.swarm import AnsibleDockerSwarmClient + from ansible.module_utils._text import to_native @@ -253,6 +256,7 @@ class TaskParameters(DockerBaseClass): self.force_new_cluster = None self.remote_addrs = None self.join_token = None + self.force = None # Spec self.snapshot_interval = None @@ -389,6 +393,11 @@ class SwarmManager(DockerBaseClass): "inspect": self.inspect_swarm } + if self.state == 'inspect': + self.client.module.deprecate( + "The 'inspect' state is deprecated, please use 'docker_swarm_facts' to inspect swarm cluster", + version='2.12') + choice_map.get(self.state)() if self.client.module._diff or self.parameters.debug: @@ -396,15 +405,6 @@ class SwarmManager(DockerBaseClass): diff['before'], diff['after'] = self.differences.get_before_after() self.results['diff'] = diff - def __isSwarmManager(self): - try: - data = self.client.inspect_swarm() - json_str = json.dumps(data, ensure_ascii=False) - self.swarm_info = json.loads(json_str) - return True - except APIError: - return False - def inspect_swarm(self): try: data = self.client.inspect_swarm() @@ -416,7 +416,7 @@ class SwarmManager(DockerBaseClass): return def init_swarm(self): - if self.__isSwarmManager(): + if self.client.check_if_swarm_manager(): self.__update_swarm() return @@ -428,7 +428,10 @@ class SwarmManager(DockerBaseClass): except APIError as exc: self.client.fail("Can not create a new Swarm Cluster: %s" % to_native(exc)) - self.__isSwarmManager() + if not self.client.check_if_swarm_manager(): + if not self.check_mode: + self.client.fail("Swarm not created or other error!") + self.inspect_swarm() self.results['actions'].append("New Swarm cluster created: %s" % (self.swarm_info.get('ID'))) self.differences.add('state', parameter='absent', active='present') self.results['changed'] = True @@ -460,26 +463,15 @@ class SwarmManager(DockerBaseClass): self.results['actions'].append("Swarm cluster updated") self.results['changed'] = True - def __isSwarmNode(self): - info = self.client.info() - if info: - json_str = json.dumps(info, ensure_ascii=False) - self.swarm_info = json.loads(json_str) - if self.swarm_info['Swarm']['NodeID']: - return True - if self.swarm_info['Swarm']['LocalNodeState'] in ('active', 'pending', 'locked'): - return True - return False - def join(self): - if self.__isSwarmNode(): + if self.client.check_if_swarm_node(): self.results['actions'].append("This node is already part of a swarm.") return if not self.check_mode: try: self.client.join_swarm( - remote_addrs=self.parameters.remote_addrs, join_token=self.parameters.join_token, listen_addr=self.parameters.listen_addr, - advertise_addr=self.parameters.advertise_addr) + remote_addrs=self.parameters.remote_addrs, join_token=self.parameters.join_token, + listen_addr=self.parameters.listen_addr, advertise_addr=self.parameters.advertise_addr) except APIError as exc: self.client.fail("Can not join the Swarm Cluster: %s" % to_native(exc)) self.results['actions'].append("New node is added to swarm cluster") @@ -487,7 +479,7 @@ class SwarmManager(DockerBaseClass): self.results['changed'] = True def leave(self): - if not(self.__isSwarmNode()): + if not(self.client.check_if_swarm_node()): self.results['actions'].append("This node is not part of a swarm.") return if not self.check_mode: @@ -499,33 +491,16 @@ class SwarmManager(DockerBaseClass): self.differences.add('joined', parameter='absent', active='present') self.results['changed'] = True - def __get_node_info(self): - try: - node_info = self.client.inspect_node(node_id=self.parameters.node_id) - except APIError as exc: - raise exc - json_str = json.dumps(node_info, ensure_ascii=False) - node_info = json.loads(json_str) - return node_info - - def __check_node_is_down(self): - for _x in range(0, 5): - node_info = self.__get_node_info() - if node_info['Status']['State'] == 'down': - return True - sleep(5) - return False - def remove(self): - if not(self.__isSwarmManager()): + if not(self.client.check_if_swarm_manager()): self.client.fail("This node is not a manager.") try: - status_down = self.__check_node_is_down() + status_down = self.client.check_if_swarm_node_is_down(repeat_check=5) except APIError: return - if not(status_down): + if not status_down: self.client.fail("Can not remove the node. The status node is ready and not down.") if not self.check_mode: @@ -577,7 +552,7 @@ def main(): ca_force_rotate=dict(docker_api_version='1.30'), ) - client = AnsibleDockerClient( + client = AnsibleDockerSwarmClient( argument_spec=argument_spec, supports_check_mode=True, required_if=required_if,