~canonical-ci-engineering/ubuntu-ci-services-itself/ansible

« back to all changes in this revision

Viewing changes to library/utilities/wait_for

  • Committer: Package Import Robot
  • Author(s): Michael Vogt
  • Date: 2013-11-24 10:41:27 UTC
  • mfrom: (1.1.3)
  • Revision ID: package-import@ubuntu.com-20131124104127-zppejr80jahk3av6
Tags: 1.4.0+dfsg-1
* new upstream version
* debian/rules:
  - remove sed manpage fixes, fixed upstream
* debian/patches/fix-html-makefile:
  - removed, fixed upstream

Show diffs side-by-side

added added

removed removed

Lines of Context:
22
22
import datetime
23
23
import time
24
24
import sys
 
25
import re
25
26
 
26
27
DOCUMENTATION = '''
27
28
---
28
29
module: wait_for
29
 
short_description: Waits for a given port to become accessible on a server.
 
30
short_description: Waits for a condition before continuing.
30
31
description:
31
 
     - This is useful for when services are not immediately available after
32
 
       their init scripts return - which is true of certain Java application
33
 
       servers. It is also useful when starting guests with the M(virt) module and
34
 
       needing to pause until they are ready.
 
32
     - Waiting for a port to become available is useful for when services 
 
33
       are not immediately available after their init scripts return - 
 
34
       which is true of certain Java application servers. It is also 
 
35
       useful when starting guests with the M(virt) module and
 
36
       needing to pause until they are ready. This module can 
 
37
       also be used to wait for a file to be available on the filesystem
 
38
       or with a regex match a string to be present in a file.
35
39
version_added: "0.7"
36
40
options:
37
41
  host:
53
57
  port:
54
58
    description:
55
59
      - port number to poll
56
 
    required: true
 
60
    required: false
57
61
  state:
58
62
    description:
59
 
      - either C(started), or C(stopped) depending on whether the module should 
60
 
        poll for the port being open or closed.
61
 
    choices: [ "started", "stopped" ]
 
63
      - either C(present), C(started), or C(stopped) 
 
64
      - When checking a port C(started) will ensure the port is open, C(stopped) will check that it is closed
 
65
      - When checking for a file or a search string C(present) or C(started) will ensure that the file or string is present before continuing
 
66
    choices: [ "present", "started", "stopped" ]
62
67
    default: "started"
 
68
  path:
 
69
    version_added: "1.4"
 
70
    required: false
 
71
    description:
 
72
      - path to a file on the filesytem that must exist before continuing
 
73
  search_regex:
 
74
    version_added: "1.4"
 
75
    required: false
 
76
    description:
 
77
      - with the path option can be used match a string in the file that must match before continuing.  Defaults to a multiline regex.
 
78
   
63
79
notes: []
64
80
requirements: []
65
 
author: Jeroen Hoekx
 
81
author: Jeroen Hoekx, John Jarvis
66
82
'''
67
83
 
68
84
EXAMPLES = '''
 
85
 
69
86
# wait 300 seconds for port 8000 to become open on the host, don't start checking for 10 seconds
70
87
- wait_for: port=8000 delay=10"
 
88
 
 
89
# wait until the file /tmp/foo is present before continuing
 
90
- wait_for: path=/tmp/foo
 
91
 
 
92
# wait until the string "completed" is in the file /tmp/foo before continuing
 
93
- wait_for: path=/tmp/foo search_regex=completed
 
94
 
71
95
'''
72
96
 
73
97
def main():
78
102
            timeout=dict(default=300),
79
103
            connect_timeout=dict(default=5),
80
104
            delay=dict(default=0),
81
 
            port=dict(required=True),
82
 
            state=dict(default='started', choices=['started', 'stopped']),
 
105
            port=dict(default=None),
 
106
            path=dict(default=None),
 
107
            search_regex=dict(default=None),
 
108
            state=dict(default='started', choices=['started', 'stopped', 'present']),
83
109
        ),
84
110
    )
85
111
 
89
115
    timeout = int(params['timeout'])
90
116
    connect_timeout = int(params['connect_timeout'])
91
117
    delay = int(params['delay'])
92
 
    port = int(params['port'])
 
118
    if params['port']:
 
119
        port = int(params['port'])
 
120
    else:
 
121
        port = None
93
122
    state = params['state']
94
 
 
 
123
    path = params['path']
 
124
    search_regex = params['search_regex']
 
125
    
 
126
    if port and path:
 
127
        module.fail_json(msg="port and path parameter can not both be passed to wait_for")
 
128
    if path and state == 'stopped':
 
129
        module.fail_json(msg="state=stopped should only be used for checking a port in the wait_for module")
 
130
        
95
131
    start = datetime.datetime.now()
96
132
 
97
133
    if delay:
98
134
        time.sleep(delay)
99
135
 
100
136
    if state == 'stopped':
101
 
        ### first wait for the host to go down
 
137
        ### first wait for the stop condition
102
138
        end = start + datetime.timedelta(seconds=timeout)
103
139
 
104
140
        while datetime.datetime.now() < end:
115
151
            elapsed = datetime.datetime.now() - start
116
152
            module.fail_json(msg="Timeout when waiting for %s:%s to stop." % (host, port), elapsed=elapsed.seconds)
117
153
 
118
 
    elif state == 'started':
119
 
        ### wait for the host to come up
 
154
    elif state in ['started', 'present']:
 
155
        ### wait for start condition
120
156
        end = start + datetime.timedelta(seconds=timeout)
121
 
 
122
157
        while datetime.datetime.now() < end:
123
 
            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
124
 
            s.settimeout(connect_timeout)
125
 
            try:
126
 
                s.connect( (host, port) )
127
 
                s.shutdown(socket.SHUT_RDWR)
128
 
                s.close()
129
 
                break
130
 
            except:
131
 
                time.sleep(1)
132
 
                pass
 
158
            if path:
 
159
                try:
 
160
                    with open(path) as f:
 
161
                        if search_regex:
 
162
                            if re.search(search_regex, f.read(), re.MULTILINE):
 
163
                                break
 
164
                            else:
 
165
                                time.sleep(1)
 
166
                        else:
 
167
                            break
 
168
                except IOError:
 
169
                    time.sleep(1)
 
170
                    pass
 
171
            elif port:
 
172
                s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 
173
                s.settimeout(connect_timeout)
 
174
                try:
 
175
                    s.connect( (host, port) )
 
176
                    s.shutdown(socket.SHUT_RDWR)
 
177
                    s.close()
 
178
                    break
 
179
                except:
 
180
                    time.sleep(1)
 
181
                    pass
133
182
        else:
134
183
            elapsed = datetime.datetime.now() - start
135
 
            module.fail_json(msg="Timeout when waiting for %s:%s" % (host, port), elapsed=elapsed.seconds)
 
184
            if port:
 
185
                module.fail_json(msg="Timeout when waiting for %s:%s" % (host, port), elapsed=elapsed.seconds)
 
186
            elif path:
 
187
                if search_regex:
 
188
                    module.fail_json(msg="Timeout when waiting for search string %s in %s" % (search_regex, path), elapsed=elapsed.seconds)
 
189
                else:
 
190
                    module.fail_json(msg="Timeout when waiting for file %s" % (path), elapsed=elapsed.seconds)
 
191
 
136
192
 
137
193
    elapsed = datetime.datetime.now() - start
138
 
    module.exit_json(state=state, port=port, elapsed=elapsed.seconds)
 
194
    module.exit_json(state=state, port=port, search_regex=search_regex, path=path, elapsed=elapsed.seconds)
139
195
 
140
196
# this is magic, see lib/ansible/module_common.py
141
197
#<<INCLUDE_ANSIBLE_MODULE_COMMON>>