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
pull/53033/head
Piotr Wojciechowski 6 years ago committed by ansibot
parent c6ae23062b
commit 72bdcdfff2

@ -3,6 +3,7 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
import json import json
from time import sleep
try: try:
from docker.errors import APIError from docker.errors import APIError
@ -108,23 +109,29 @@ class AnsibleDockerSwarmClient(AnsibleDockerClient):
return True return True
return False 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 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 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 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 :param node_id: node ID or name, if None then method will try to get node_id of host module run on
:return: :return:
True if node is part of swarm but its state is down, False otherwise 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: if node_id is None:
node_id = self.get_swarm_node_id() node_id = self.get_swarm_node_id()
node_info = self.get_node_inspect(node_id=node_id) for retry in range(0, repeat_check):
if node_info['Status']['State'] == 'down': node_info = self.get_node_inspect(node_id=node_id)
return True if node_info['Status']['State'] == 'down':
return True
sleep(5)
return False return False
def get_node_inspect(self, node_id=None, skip_missing=False): def get_node_inspect(self, node_id=None, skip_missing=False):

@ -159,6 +159,7 @@ requirements:
- Docker API >= 1.25 - Docker API >= 1.25
author: author:
- Thierry Bouvet (@tbouvet) - Thierry Bouvet (@tbouvet)
- Piotr Wojciechowski (@WojciechowskiPiotr)
''' '''
EXAMPLES = ''' EXAMPLES = '''
@ -229,7 +230,7 @@ actions:
''' '''
import json import json
from time import sleep
try: try:
from docker.errors import APIError from docker.errors import APIError
except ImportError: except ImportError:
@ -237,10 +238,12 @@ except ImportError:
pass pass
from ansible.module_utils.docker.common import ( from ansible.module_utils.docker.common import (
AnsibleDockerClient,
DockerBaseClass, DockerBaseClass,
DifferenceTracker, DifferenceTracker,
) )
from ansible.module_utils.docker.swarm import AnsibleDockerSwarmClient
from ansible.module_utils._text import to_native from ansible.module_utils._text import to_native
@ -253,6 +256,7 @@ class TaskParameters(DockerBaseClass):
self.force_new_cluster = None self.force_new_cluster = None
self.remote_addrs = None self.remote_addrs = None
self.join_token = None self.join_token = None
self.force = None
# Spec # Spec
self.snapshot_interval = None self.snapshot_interval = None
@ -389,6 +393,11 @@ class SwarmManager(DockerBaseClass):
"inspect": self.inspect_swarm "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)() choice_map.get(self.state)()
if self.client.module._diff or self.parameters.debug: 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() diff['before'], diff['after'] = self.differences.get_before_after()
self.results['diff'] = diff 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): def inspect_swarm(self):
try: try:
data = self.client.inspect_swarm() data = self.client.inspect_swarm()
@ -416,7 +416,7 @@ class SwarmManager(DockerBaseClass):
return return
def init_swarm(self): def init_swarm(self):
if self.__isSwarmManager(): if self.client.check_if_swarm_manager():
self.__update_swarm() self.__update_swarm()
return return
@ -428,7 +428,10 @@ class SwarmManager(DockerBaseClass):
except APIError as exc: except APIError as exc:
self.client.fail("Can not create a new Swarm Cluster: %s" % to_native(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.results['actions'].append("New Swarm cluster created: %s" % (self.swarm_info.get('ID')))
self.differences.add('state', parameter='absent', active='present') self.differences.add('state', parameter='absent', active='present')
self.results['changed'] = True self.results['changed'] = True
@ -460,26 +463,15 @@ class SwarmManager(DockerBaseClass):
self.results['actions'].append("Swarm cluster updated") self.results['actions'].append("Swarm cluster updated")
self.results['changed'] = True 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): 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.") self.results['actions'].append("This node is already part of a swarm.")
return return
if not self.check_mode: if not self.check_mode:
try: try:
self.client.join_swarm( self.client.join_swarm(
remote_addrs=self.parameters.remote_addrs, join_token=self.parameters.join_token, listen_addr=self.parameters.listen_addr, remote_addrs=self.parameters.remote_addrs, join_token=self.parameters.join_token,
advertise_addr=self.parameters.advertise_addr) listen_addr=self.parameters.listen_addr, advertise_addr=self.parameters.advertise_addr)
except APIError as exc: except APIError as exc:
self.client.fail("Can not join the Swarm Cluster: %s" % to_native(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") self.results['actions'].append("New node is added to swarm cluster")
@ -487,7 +479,7 @@ class SwarmManager(DockerBaseClass):
self.results['changed'] = True self.results['changed'] = True
def leave(self): 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.") self.results['actions'].append("This node is not part of a swarm.")
return return
if not self.check_mode: if not self.check_mode:
@ -499,33 +491,16 @@ class SwarmManager(DockerBaseClass):
self.differences.add('joined', parameter='absent', active='present') self.differences.add('joined', parameter='absent', active='present')
self.results['changed'] = True 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): def remove(self):
if not(self.__isSwarmManager()): if not(self.client.check_if_swarm_manager()):
self.client.fail("This node is not a manager.") self.client.fail("This node is not a manager.")
try: try:
status_down = self.__check_node_is_down() status_down = self.client.check_if_swarm_node_is_down(repeat_check=5)
except APIError: except APIError:
return 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.") self.client.fail("Can not remove the node. The status node is ready and not down.")
if not self.check_mode: if not self.check_mode:
@ -577,7 +552,7 @@ def main():
ca_force_rotate=dict(docker_api_version='1.30'), ca_force_rotate=dict(docker_api_version='1.30'),
) )
client = AnsibleDockerClient( client = AnsibleDockerSwarmClient(
argument_spec=argument_spec, argument_spec=argument_spec,
supports_check_mode=True, supports_check_mode=True,
required_if=required_if, required_if=required_if,

Loading…
Cancel
Save