From 72bdcdfff24da6157810685add43833fff56b708 Mon Sep 17 00:00:00 2001 From: Piotr Wojciechowski <23406016+WojciechowskiPiotr@users.noreply.github.com> Date: Tue, 26 Feb 2019 22:41:16 +0100 Subject: [PATCH] docker_swarm update to use shared Swarm library (#52886) * docker_swarm: Update code to use AnsibleDockerSwarmClient instead of AnsibleDockerClient * docker_swarm: Update check_if_swarm_node_is_down() with repetitive attempts to check node status to reflect original method implementation * docker_swarm: Add information that `state: inspect` will be removed in future release * docker_swarm: Fix sanity error * docker_swarm: Check_mode conditional for failing during the swarm init * docker_swarm: Small cleanup of a code * docker_swarm: Moving the warning message before dispatching * Commit to solve problems with Shippable --- lib/ansible/module_utils/docker/swarm.py | 15 +++- .../modules/cloud/docker/docker_swarm.py | 73 ++++++------------- 2 files changed, 35 insertions(+), 53 deletions(-) diff --git a/lib/ansible/module_utils/docker/swarm.py b/lib/ansible/module_utils/docker/swarm.py index 5e9cfd4ace2..11fbb4b8d5f 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 f076c3a3f45..7f049257aaf 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,