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
This commit is contained in:
Piotr Wojciechowski 2019-02-26 22:41:16 +01:00 committed by ansibot
parent c6ae23062b
commit 72bdcdfff2
2 changed files with 35 additions and 53 deletions

View file

@ -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):

View file

@ -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,