Browse code

Move from md5 to sha1 to work on fips-140 enabled systems

Toshio Kuratomi authored on 2014/11/07 14:28:04
Showing 31 changed files
... ...
@@ -58,7 +58,14 @@ Some other notable changes:
58 58
 * ec2_ami_search: support for SSD and IOPS provisioned EBS images
59 59
 * can set ansible_sudo_exe as an inventory variable which allows specifying
60 60
   a different sudo (or equivalent) command
61
-* git module: Submodule handling has changed.  Previously if you used the ``recursive`` parameter to handle submodules, ansible would track the submodule upstream's head revision.  This has been changed to checkout the version of the submodule specified in the superproject's git repository.  This is inline with what git submodule update does.  If you want the old behaviour use the new module parameter track_submodules=yes
61
+* git module: Submodule handling has changed.  Previously if you used the
62
+  ``recursive`` parameter to handle submodules, ansible would track the
63
+  submodule upstream's head revision.  This has been changed to checkout the
64
+  version of the submodule specified in the superproject's git repository.
65
+  This is inline with what git submodule update does.  If you want the old
66
+  behaviour use the new module parameter track_submodules=yes
67
+* Checksumming of transferred files has been made more portable and now uses
68
+  the sha1 algorithm instead of md5 to be compatible with FIPS-140.
62 69
 
63 70
 And various other bug fixes and improvements ...
64 71
 
... ...
@@ -262,7 +262,7 @@ And failures are just as simple (where 'msg' is a required parameter to explain
262 262
 
263 263
     module.fail_json(msg="Something fatal happened")
264 264
 
265
-There are also other useful functions in the module class, such as module.md5(path).  See
265
+There are also other useful functions in the module class, such as module.sha1(path).  See
266 266
 lib/ansible/module_common.py in the source checkout for implementation details.
267 267
 
268 268
 Again, modules developed this way are best tested with the hacking/test-module script in the git
... ...
@@ -55,7 +55,7 @@ entered value so you can use it, for instance, with the user module to define a
55 55
      - name: "my_password2"
56 56
        prompt: "Enter password2"
57 57
        private: yes
58
-       encrypt: "md5_crypt"
58
+       encrypt: "sha512_crypt"
59 59
        confirm: yes
60 60
        salt_size: 7
61 61
 
... ...
@@ -327,9 +327,9 @@ To work with Base64 encoded strings::
327 327
     {{ encoded | b64decode }}
328 328
     {{ decoded | b64encode }}
329 329
 
330
-To take an md5sum of a filename::
330
+To take a sha1sum of a filename::
331 331
 
332
-    {{ filename | md5 }}
332
+    {{ filename | sha1 }}
333 333
 
334 334
 To cast values as certain types, such as when you input a string as "True" from a vars_prompt and the system
335 335
 doesn't know it is a boolean value::
... ...
@@ -87,9 +87,14 @@ except ImportError:
87 87
 
88 88
 HAVE_HASHLIB=False
89 89
 try:
90
-    from hashlib import md5 as _md5
90
+    from hashlib import sha1 as _sha1
91 91
     HAVE_HASHLIB=True
92 92
 except ImportError:
93
+    from sha import sha as _sha1
94
+
95
+try:
96
+    from hashlib import md5 as _md5
97
+except ImportError:
93 98
     from md5 import md5 as _md5
94 99
 
95 100
 try:
... ...
@@ -1236,6 +1241,10 @@ class AnsibleModule(object):
1236 1236
         ''' Return MD5 hex digest of local file using digest_from_file(). '''
1237 1237
         return self.digest_from_file(filename, _md5())
1238 1238
 
1239
+    def sha1(self, filename):
1240
+        ''' Return SHA1 hex digest of local file using digest_from_file(). '''
1241
+        return self.digest_from_file(filename, _sha1())
1242
+
1239 1243
     def sha256(self, filename):
1240 1244
         ''' Return SHA-256 hex digest of local file using digest_from_file(). '''
1241 1245
         if not HAVE_HASHLIB:
... ...
@@ -1 +1 @@
1
-Subproject commit 2970b339eb8ea6031e6153cabe45459bc2bd5754
1
+Subproject commit 6317d3a988f7269340cb7a0d105d2c671ca1cd1e
... ...
@@ -1 +1 @@
1
-Subproject commit ad181b7aa949848e3085065e09195cb28c34fdf7
1
+Subproject commit 5a514ccddae85ccc5802eea8751401600e45c32f
... ...
@@ -53,9 +53,9 @@ from ansible.utils import update_hash
53 53
 module_replacer = ModuleReplacer(strip_comments=False)
54 54
 
55 55
 try:
56
-    from hashlib import md5 as _md5
56
+    from hashlib import sha1
57 57
 except ImportError:
58
-    from md5 import md5 as _md5
58
+    from sha import sha as sha1
59 59
 
60 60
 HAS_ATFORK=True
61 61
 try:
... ...
@@ -209,7 +209,7 @@ class Runner(object):
209 209
         self.su_user_var      = su_user
210 210
         self.su_user          = None
211 211
         self.su_pass          = su_pass
212
-        self.omit_token       = '__omit_place_holder__%s' % _md5(os.urandom(64)).hexdigest()
212
+        self.omit_token       = '__omit_place_holder__%s' % sha1(os.urandom(64)).hexdigest()
213 213
         self.vault_pass       = vault_pass
214 214
         self.no_log           = no_log
215 215
         self.run_once         = run_once
... ...
@@ -1159,26 +1159,29 @@ class Runner(object):
1159 1159
 
1160 1160
     # *****************************************************
1161 1161
 
1162
-    def _remote_md5(self, conn, tmp, path):
1163
-        ''' takes a remote md5sum without requiring python, and returns 1 if no file '''
1164
-        cmd = conn.shell.md5(path)
1162
+    def _remote_checksum(self, conn, tmp, path):
1163
+        ''' takes a remote checksum and returns 1 if no file '''
1164
+        inject = self.get_inject_vars(conn.host)
1165
+        hostvars = HostVars(inject['combined_cache'], self.inventory, vault_password=self.vault_pass)
1166
+        python_interp = hostvars[conn.host].get('ansible_python_interpreter', 'python')
1167
+        cmd = conn.shell.checksum(path, python_interp)
1165 1168
         data = self._low_level_exec_command(conn, cmd, tmp, sudoable=True)
1166 1169
         data2 = utils.last_non_blank_line(data['stdout'])
1167 1170
         try:
1168 1171
             if data2 == '':
1169 1172
                 # this may happen if the connection to the remote server
1170
-                # failed, so just return "INVALIDMD5SUM" to avoid errors
1171
-                return "INVALIDMD5SUM"
1173
+                # failed, so just return "INVALIDCHECKSUM" to avoid errors
1174
+                return "INVALIDCHECKSUM"
1172 1175
             else:
1173 1176
                 return data2.split()[0]
1174 1177
         except IndexError:
1175
-            sys.stderr.write("warning: md5sum command failed unusually, please report this to the list so it can be fixed\n")
1176
-            sys.stderr.write("command: %s\n" % md5s)
1178
+            sys.stderr.write("warning: Calculating checksum failed unusually, please report this to the list so it can be fixed\n")
1179
+            sys.stderr.write("command: %s\n" % cmd)
1177 1180
             sys.stderr.write("----\n")
1178 1181
             sys.stderr.write("output: %s\n" % data)
1179 1182
             sys.stderr.write("----\n")
1180 1183
             # this will signal that it changed and allow things to keep going
1181
-            return "INVALIDMD5SUM"
1184
+            return "INVALIDCHECKSUM"
1182 1185
 
1183 1186
     # *****************************************************
1184 1187
 
... ...
@@ -108,10 +108,10 @@ class ActionModule(object):
108 108
         # Does all work assembling the file
109 109
         path = self._assemble_from_fragments(src, delimiter, _re)
110 110
 
111
-        pathmd5 = utils.md5s(path)
112
-        remote_md5 = self.runner._remote_md5(conn, tmp, dest)
111
+        path_checksum = utils.checksum_s(path)
112
+        remote_checksum = self.runner._remote_checksum(conn, tmp, dest)
113 113
 
114
-        if pathmd5 != remote_md5:
114
+        if path_checksum != remote_checksum:
115 115
             resultant = file(path).read()
116 116
             if self.runner.diff:
117 117
                 dest_result = self.runner._execute_module(conn, tmp, 'slurp', "path=%s" % dest, inject=inject, persist_files=True)
... ...
@@ -158,11 +158,11 @@ class ActionModule(object):
158 158
                 tmp_path = self.runner._make_tmp_path(conn)
159 159
 
160 160
         for source_full, source_rel in source_files:
161
-            # Generate the MD5 hash of the local file.
162
-            local_md5 = utils.md5(source_full)
161
+            # Generate a hash of the local file.
162
+            local_checksum = utils.checksum(source_full)
163 163
 
164
-            # If local_md5 is not defined we can't find the file so we should fail out.
165
-            if local_md5 is None:
164
+            # If local_checksum is not defined we can't find the file so we should fail out.
165
+            if local_checksum is None:
166 166
                 result = dict(failed=True, msg="could not find src=%s" % source_full)
167 167
                 return ReturnData(conn=conn, result=result)
168 168
 
... ...
@@ -174,27 +174,27 @@ class ActionModule(object):
174 174
             else:
175 175
                 dest_file = conn.shell.join_path(dest)
176 176
 
177
-            # Attempt to get the remote MD5 Hash.
178
-            remote_md5 = self.runner._remote_md5(conn, tmp_path, dest_file)
177
+            # Attempt to get the remote checksum
178
+            remote_checksum = self.runner._remote_checksum(conn, tmp_path, dest_file)
179 179
 
180
-            if remote_md5 == '3':
181
-                # The remote_md5 was executed on a directory.
180
+            if remote_checksum == '3':
181
+                # The remote_checksum was executed on a directory.
182 182
                 if content is not None:
183 183
                     # If source was defined as content remove the temporary file and fail out.
184 184
                     self._remove_tempfile_if_content_defined(content, content_tempfile)
185 185
                     result = dict(failed=True, msg="can not use content with a dir as dest")
186 186
                     return ReturnData(conn=conn, result=result)
187 187
                 else:
188
-                    # Append the relative source location to the destination and retry remote_md5.
188
+                    # Append the relative source location to the destination and retry remote_checksum
189 189
                     dest_file = conn.shell.join_path(dest, source_rel)
190
-                    remote_md5 = self.runner._remote_md5(conn, tmp_path, dest_file)
190
+                    remote_checksum = self.runner._remote_checksum(conn, tmp_path, dest_file)
191 191
 
192
-            if remote_md5 != '1' and not force:
192
+            if remote_checksum != '1' and not force:
193 193
                 # remote_file does not exist so continue to next iteration.
194 194
                 continue
195 195
 
196
-            if local_md5 != remote_md5:
197
-                # The MD5 hashes don't match and we will change or error out.
196
+            if local_checksum != remote_checksum:
197
+                # The checksums don't match and we will change or error out.
198 198
                 changed = True
199 199
 
200 200
                 # Create a tmp_path if missing only if this is not recursive.
... ...
@@ -254,7 +254,7 @@ class ActionModule(object):
254 254
                 module_executed = True
255 255
 
256 256
             else:
257
-                # no need to transfer the file, already correct md5, but still need to call
257
+                # no need to transfer the file, already correct hash, but still need to call
258 258
                 # the file module in case we want to change attributes
259 259
                 self._remove_tempfile_if_content_defined(content, content_tempfile)
260 260
 
... ...
@@ -283,8 +283,8 @@ class ActionModule(object):
283 283
                 module_executed = True
284 284
 
285 285
             module_result = module_return.result
286
-            if not module_result.get('md5sum'):
287
-                module_result['md5sum'] = local_md5
286
+            if not module_result.get('checksum'):
287
+                module_result['checksum'] = local_checksum
288 288
             if module_result.get('failed') == True:
289 289
                 return module_return
290 290
             if module_result.get('changed') == True:
... ...
@@ -50,26 +50,40 @@ class ActionModule(object):
50 50
         flat = utils.boolean(flat)
51 51
         fail_on_missing = options.get('fail_on_missing', False)
52 52
         fail_on_missing = utils.boolean(fail_on_missing)
53
-        validate_md5 = options.get('validate_md5', True)
54
-        validate_md5 = utils.boolean(validate_md5)
53
+        validate_checksum = options.get('validate_checksum', None)
54
+        if validate_checksum is not None:
55
+            validate_checksum = utils.boolean(validate_checksum)
56
+        # Alias for validate_checksum (old way of specifying it)
57
+        validate_md5 = options.get('validate_md5', None)
58
+        if validate_md5 is not None:
59
+            validate_md5 = utils.boolean(validate_md5)
60
+        if validate_md5 is None and validate_checksum is None:
61
+            # Default
62
+            validate_checksum = True
63
+        elif validate_checksum is None:
64
+            validate_checksum = validate_md5
65
+        elif validate_md5 is not None and validate_checksum is not None:
66
+            results = dict(failed=True, msg="validate_checksum and validate_md5 cannot both be specified")
67
+            return ReturnData(conn, result=results)
68
+
55 69
         if source is None or dest is None:
56 70
             results = dict(failed=True, msg="src and dest are required")
57 71
             return ReturnData(conn=conn, result=results)
58 72
 
59 73
         source = conn.shell.join_path(source)
60 74
 
61
-        # calculate md5 sum for the remote file
62
-        remote_md5 = self.runner._remote_md5(conn, tmp, source)
75
+        # calculate checksum for the remote file
76
+        remote_checksum = self.runner._remote_checksum(conn, tmp, source)
63 77
 
64 78
         # use slurp if sudo and permissions are lacking
65 79
         remote_data = None
66
-        if remote_md5 in ('1', '2') or self.runner.sudo:
80
+        if remote_checksum in ('1', '2') or self.runner.sudo:
67 81
             slurpres = self.runner._execute_module(conn, tmp, 'slurp', 'src=%s' % source, inject=inject)
68 82
             if slurpres.is_successful():
69 83
                 if slurpres.result['encoding'] == 'base64':
70 84
                     remote_data = base64.b64decode(slurpres.result['content'])
71 85
                 if remote_data is not None:
72
-                    remote_md5 = utils.md5s(remote_data)
86
+                    remote_checksum = utils.checksum_s(remote_data)
73 87
                 # the source path may have been expanded on the
74 88
                 # target system, so we compare it here and use the
75 89
                 # expanded version if it's different
... ...
@@ -101,23 +115,23 @@ class ActionModule(object):
101 101
 
102 102
         # these don't fail because you may want to transfer a log file that possibly MAY exist
103 103
         # but keep going to fetch other log files
104
-        if remote_md5 == '0':
104
+        if remote_checksum == '0':
105 105
             result = dict(msg="unable to calculate the md5 sum of the remote file", file=source, changed=False)
106 106
             return ReturnData(conn=conn, result=result)
107
-        if remote_md5 == '1':
107
+        if remote_checksum == '1':
108 108
             if fail_on_missing:
109 109
                 result = dict(failed=True, msg="the remote file does not exist", file=source)
110 110
             else:
111 111
                 result = dict(msg="the remote file does not exist, not transferring, ignored", file=source, changed=False)
112 112
             return ReturnData(conn=conn, result=result)
113
-        if remote_md5 == '2':
113
+        if remote_checksum == '2':
114 114
             result = dict(msg="no read permission on remote file, not transferring, ignored", file=source, changed=False)
115 115
             return ReturnData(conn=conn, result=result)
116 116
 
117
-        # calculate md5 sum for the local file
118
-        local_md5 = utils.md5(dest)
117
+        # calculate checksum for the local file
118
+        local_checksum = utils.checksum(dest)
119 119
 
120
-        if remote_md5 != local_md5:
120
+        if remote_checksum != local_checksum:
121 121
             # create the containing directories, if needed
122 122
             if not os.path.isdir(os.path.dirname(dest)):
123 123
                 os.makedirs(os.path.dirname(dest))
... ...
@@ -129,13 +143,27 @@ class ActionModule(object):
129 129
                 f = open(dest, 'w')
130 130
                 f.write(remote_data)
131 131
                 f.close()
132
-            new_md5 = utils.md5(dest)
133
-            if validate_md5 and new_md5 != remote_md5:
134
-                result = dict(failed=True, md5sum=new_md5, msg="md5 mismatch", file=source, dest=dest, remote_md5sum=remote_md5)
132
+            new_checksum = utils.secure_hash(dest)
133
+            # For backwards compatibility.  We'll return None on FIPS enabled
134
+            # systems
135
+            try:
136
+                new_md5 = utils.md5(dest)
137
+            except ValueError:
138
+                new_md5 = None
139
+
140
+            if validate_checksum and new_checksum != remote_checksum:
141
+                result = dict(failed=True, md5sum=new_md5, msg="checksum mismatch", file=source, dest=dest, remote_md5sum=None, checksum=new_checksum, remote_checksum=remote_checksum)
135 142
                 return ReturnData(conn=conn, result=result)
136
-            result = dict(changed=True, md5sum=new_md5, dest=dest, remote_md5sum=remote_md5)
143
+            result = dict(changed=True, md5sum=new_md5, dest=dest, remote_md5sum=None, checksum=new_checksum, remote_checksum=remote_checksum)
137 144
             return ReturnData(conn=conn, result=result)
138 145
         else:
139
-            result = dict(changed=False, md5sum=local_md5, file=source, dest=dest)
146
+            # For backwards compatibility.  We'll return None on FIPS enabled
147
+            # systems
148
+            try:
149
+                local_md5 = utils.md5(dest)
150
+            except ValueError:
151
+                local_md5 = None
152
+
153
+            result = dict(changed=False, md5sum=local_md5, file=source, dest=dest, checksum=local_checksum)
140 154
             return ReturnData(conn=conn, result=result)
141 155
 
... ...
@@ -87,10 +87,10 @@ class ActionModule(object):
87 87
             result = dict(failed=True, msg=type(e).__name__ + ": " + str(e))
88 88
             return ReturnData(conn=conn, comm_ok=False, result=result)
89 89
 
90
-        local_md5 = utils.md5s(resultant)
91
-        remote_md5 = self.runner._remote_md5(conn, tmp, dest)
90
+        local_checksum = utils.checksum_s(resultant)
91
+        remote_checksum = self.runner._remote_checksum(conn, tmp, dest)
92 92
 
93
-        if local_md5 != remote_md5:
93
+        if local_checksum != remote_checksum:
94 94
 
95 95
             # template is different from the remote value
96 96
 
... ...
@@ -62,8 +62,8 @@ class ActionModule(object):
62 62
             else:
63 63
                 source = utils.path_dwim(self.runner.basedir, source)
64 64
 
65
-        remote_md5 = self.runner._remote_md5(conn, tmp, dest)
66
-        if remote_md5 != '3':
65
+        remote_checksum = self.runner._remote_checksum(conn, tmp, dest)
66
+        if remote_checksum != '3':
67 67
             result = dict(failed=True, msg="dest '%s' must be an existing dir" % dest)
68 68
             return ReturnData(conn=conn, result=result)
69 69
 
... ...
@@ -26,7 +26,7 @@ import re
26 26
 import collections
27 27
 import operator as py_operator
28 28
 from ansible import errors
29
-from ansible.utils import md5s
29
+from ansible.utils import md5s, checksum_s
30 30
 from distutils.version import LooseVersion, StrictVersion
31 31
 from random import SystemRandom
32 32
 from jinja2.filters import environmentfilter
... ...
@@ -281,8 +281,13 @@ class FilterModule(object):
281 281
             # quote string for shell usage
282 282
             'quote': quote,
283 283
 
284
+            # hash filters
284 285
             # md5 hex digest of string
285 286
             'md5': md5s,
287
+            # sha1 hex digeset of string
288
+            'sha1': checksum_s,
289
+            # checksum of string as used by ansible for checksuming files
290
+            'checksum': checksum_s,
286 291
 
287 292
             # file glob
288 293
             'fileglob': fileglob,
... ...
@@ -59,23 +59,17 @@ class ShellModule(object):
59 59
         cmd += ' && echo %s' % basetmp
60 60
         return cmd
61 61
 
62
-    def md5(self, path):
62
+    def checksum(self, path, python_interp):
63 63
         path = pipes.quote(path)
64 64
         # The following test needs to be SH-compliant.  BASH-isms will
65 65
         # not work if /bin/sh points to a non-BASH shell.
66 66
         test = "rc=0; [ -r \"%s\" ] || rc=2; [ -f \"%s\" ] || rc=1; [ -d \"%s\" ] && echo 3 && exit 0" % ((path,) * 3)
67
-        md5s = [
68
-            "(/usr/bin/md5sum %s 2>/dev/null)" % path,          # Linux
69
-            "(/sbin/md5sum -q %s 2>/dev/null)" % path,          # ?
70
-            "(/usr/bin/digest -a md5 %s 2>/dev/null)" % path,   # Solaris 10+
71
-            "(/sbin/md5 -q %s 2>/dev/null)" % path,             # Freebsd
72
-            "(/usr/bin/md5 -n %s 2>/dev/null)" % path,          # Netbsd
73
-            "(/bin/md5 -q %s 2>/dev/null)" % path,              # Openbsd
74
-            "(/usr/bin/csum -h MD5 %s 2>/dev/null)" % path,     # AIX
75
-            "(/bin/csum -h MD5 %s 2>/dev/null)" % path          # AIX also
67
+        csums = [
68
+            "(%s -c 'import hashlib; print(hashlib.sha1(open(\"%s\", \"rb\").read()).hexdigest())' 2>/dev/null)" % (python_interp, path),      # Python > 2.4 (including python3)
69
+            "(%s -c 'import sha; print(sha.sha(open(\"%s\", \"rb\").read()).hexdigest())' 2>/dev/null)" % (python_interp, path),        # Python == 2.4
76 70
         ]
77 71
 
78
-        cmd = " || ".join(md5s)
72
+        cmd = " || ".join(csums)
79 73
         cmd = "%s; %s || (echo \"${rc}  %s\")" % (test, cmd, path)
80 74
         return cmd
81 75
 
... ...
@@ -68,6 +68,14 @@ try:
68 68
 except ImportError:
69 69
     import simplejson as json
70 70
 
71
+# Note, sha1 is the only hash algorithm compatible with python2.4 and with
72
+# FIPS-140 mode (as of 11-2014)
73
+try:
74
+    from hashlib import sha1 as sha1
75
+except ImportError:
76
+    from sha import sha as sha1
77
+
78
+# Backwards compat only
71 79
 try:
72 80
     from hashlib import md5 as _md5
73 81
 except ImportError:
... ...
@@ -821,22 +829,22 @@ def merge_hash(a, b):
821 821
 
822 822
     return result
823 823
 
824
-def md5s(data):
825
-    ''' Return MD5 hex digest of data. '''
824
+def secure_hash_s(data, hash_func=sha1):
825
+    ''' Return a secure hash hex digest of data. '''
826 826
 
827
-    digest = _md5()
827
+    digest = hash_func()
828 828
     try:
829 829
         digest.update(data)
830 830
     except UnicodeEncodeError:
831 831
         digest.update(data.encode('utf-8'))
832 832
     return digest.hexdigest()
833 833
 
834
-def md5(filename):
835
-    ''' Return MD5 hex digest of local file, None if file is not present or a directory. '''
834
+def secure_hash(filename, hash_func=sha1):
835
+    ''' Return a secure hash hex digest of local file, None if file is not present or a directory. '''
836 836
 
837 837
     if not os.path.exists(filename) or os.path.isdir(filename):
838 838
         return None
839
-    digest = _md5()
839
+    digest = hash_func()
840 840
     blocksize = 64 * 1024
841 841
     try:
842 842
         infile = open(filename, 'rb')
... ...
@@ -849,6 +857,19 @@ def md5(filename):
849 849
         raise errors.AnsibleError("error while accessing the file %s, error was: %s" % (filename, e))
850 850
     return digest.hexdigest()
851 851
 
852
+# The checksum algorithm must match with the algorithm in ShellModule.checksum() method
853
+checksum = secure_hash
854
+checksum_s = secure_hash_s
855
+
856
+# Backwards compat.  Some modules include md5s in their return values
857
+# Continue to support that for now.  As of ansible-1.8, all of those modules
858
+# should also return "checksum" (sha1 for now)
859
+def md5s(data):
860
+    return secure_hash_s(data, _md5)
861
+
862
+def md5(filename):
863
+    return secure_hash(filename, _md5)
864
+
852 865
 def default(value, function):
853 866
     ''' syntactic sugar around lazy evaluation of defaults '''
854 867
     if value is None:
... ...
@@ -26,6 +26,8 @@ from io import BytesIO
26 26
 from subprocess import call
27 27
 from ansible import errors
28 28
 from hashlib import sha256
29
+# Note: Only used for loading obsolete VaultAES files.  All files are written
30
+# using the newer VaultAES256 which does not require md5
29 31
 from hashlib import md5
30 32
 from binascii import hexlify
31 33
 from binascii import unhexlify
... ...
@@ -37,7 +37,19 @@
37 37
   assert:
38 38
     that:
39 39
     - "result.state == 'file'"
40
-    - "result.md5sum == '96905702a2ece40de6bf3a94b5062513'"
40
+    - "result.changed == True"
41
+    - "result.checksum == '048a1bd1951aa5ccc427eeb4ca19aee45e9c68b3'"
42
+
43
+- name: test assemble with all fragments
44
+  assemble: src="{{output_dir}}/src" dest="{{output_dir}}/assembled1"
45
+  register: result
46
+
47
+- name: assert that the same assemble made no changes
48
+  assert:
49
+    that:
50
+    - "result.state == 'file'"
51
+    - "result.changed == False"
52
+    - "result.checksum == '048a1bd1951aa5ccc427eeb4ca19aee45e9c68b3'"
41 53
 
42 54
 - name: test assemble with fragments matching a regex
43 55
   assemble: src="{{output_dir}}/src" dest="{{output_dir}}/assembled2" regexp="^fragment[1-3]$"
... ...
@@ -47,7 +59,7 @@
47 47
   assert:
48 48
     that:
49 49
     - "result.state == 'file'"
50
-    - "result.md5sum == 'eb9e3486a9cd6943b5242e573b9b9349'"
50
+    - "result.checksum == 'edfe2d7487ef8f5ebc0f1c4dc57ba7b70a7b8e2b'"
51 51
 
52 52
 - name: test assemble with a delimiter
53 53
   assemble: src="{{output_dir}}/src" dest="{{output_dir}}/assembled3" delimiter="#--- delimiter ---#"
... ...
@@ -57,7 +69,7 @@
57 57
   assert:
58 58
     that:
59 59
     - "result.state == 'file'"
60
-    - "result.md5sum == '4773eac67aba3f0be745876331c8a450'"
60
+    - "result.checksum == '505359f48c65b3904127cf62b912991d4da7ed6d'"
61 61
 
62 62
 - name: test assemble with remote_src=False
63 63
   assemble: src="./" dest="{{output_dir}}/assembled4" remote_src=no
... ...
@@ -67,7 +79,7 @@
67 67
   assert:
68 68
     that:
69 69
     - "result.state == 'file'"
70
-    - "result.md5sum == '96905702a2ece40de6bf3a94b5062513'"
70
+    - "result.checksum == '048a1bd1951aa5ccc427eeb4ca19aee45e9c68b3'"
71 71
 
72 72
 - name: test assemble with remote_src=False and a delimiter
73 73
   assemble: src="./" dest="{{output_dir}}/assembled5" remote_src=no delimiter="#--- delimiter ---#"
... ...
@@ -77,5 +89,5 @@
77 77
   assert:
78 78
     that:
79 79
     - "result.state == 'file'"
80
-    - "result.md5sum == '4773eac67aba3f0be745876331c8a450'"
80
+    - "result.checksum == '505359f48c65b3904127cf62b912991d4da7ed6d'"
81 81
 
... ...
@@ -185,7 +185,7 @@
185 185
     "multiline echo" \
186 186
     "with a new line
187 187
     in quotes" \
188
-    | md5sum \
188
+    | sha1sum \
189 189
     | tr -s ' ' \
190 190
     | cut -f1 -d ' '
191 191
     echo "this is a second line"
... ...
@@ -197,7 +197,7 @@
197 197
   assert:
198 198
     that:
199 199
       - "shell_result6.changed"
200
-      - "shell_result6.stdout == '32f3cc201b69ed8afa3902b80f554ca8\nthis is a second line'"
200
+      - "shell_result6.stdout == '5575bb6b71c9558db0b6fbbf2f19909eeb4e3b98\nthis is a second line'"
201 201
 
202 202
 - name: execute a shell command using a literal multiline block with arguments in it
203 203
   shell: |
... ...
@@ -40,6 +40,7 @@
40 40
       - "'group' in copy_result"
41 41
       - "'gid' in copy_result"
42 42
       - "'md5sum' in copy_result"
43
+      - "'checksum' in copy_result"
43 44
       - "'owner' in copy_result"
44 45
       - "'size' in copy_result"
45 46
       - "'src' in copy_result"
... ...
@@ -51,10 +52,11 @@
51 51
     that:
52 52
       - "copy_result.changed == true"
53 53
 
54
-- name: verify that the file md5sum is correct
55
-  assert: 
56
-    that: 
54
+- name: verify that the file checksums are correct
55
+  assert:
56
+    that:
57 57
       - "copy_result.md5sum == 'c47397529fe81ab62ba3f85e9f4c71f2'"
58
+      - "copy_result.checksum == 'c79a6506c1c948be0d456ab5104d5e753ab2f3e6'"
58 59
 
59 60
 - name: check the stat results of the file
60 61
   stat: path={{output_file}}
... ...
@@ -71,6 +73,7 @@
71 71
       - "stat_results.stat.isreg == true"
72 72
       - "stat_results.stat.issock == false"
73 73
       - "stat_results.stat.md5 == 'c47397529fe81ab62ba3f85e9f4c71f2'"
74
+      - "stat_results.stat.checksum == 'c79a6506c1c948be0d456ab5104d5e753ab2f3e6'"
74 75
 
75 76
 - name: overwrite the file via same means
76 77
   copy: src=foo.txt dest={{output_file}}
... ...
@@ -180,7 +183,7 @@
180 180
     that:
181 181
       - "copy_result6.changed"
182 182
       - "copy_result6.dest == '{{output_dir|expanduser}}/multiline.txt'"
183
-      - "copy_result6.md5sum == '1627d51e7e607c92cf1a502bf0c6cce3'"
183
+      - "copy_result6.checksum == '9cd0697c6a9ff6689f0afb9136fa62e0b3fee903'"
184 184
 
185 185
 # test overwriting a file as an unprivileged user (pull request #8624)
186 186
 # this can't be relative to {{output_dir}} as ~root usually has mode 700
... ...
@@ -202,7 +205,7 @@
202 202
     that:
203 203
       - "copy_result7.changed"
204 204
       - "copy_result7.dest == '/tmp/worldwritable/file.txt'"
205
-      - "copy_result7.md5sum == '73feffa4b7f6bb68e44cf984c85f6e88'"
205
+      - "copy_result7.checksum == 'bbe960a25ea311d21d40669e93df2003ba9b90a2'"
206 206
 
207 207
 - name: clean up
208 208
   file: dest=/tmp/worldwritable state=absent
... ...
@@ -230,10 +233,10 @@
230 230
     - stat_link_result.stat.islnk
231 231
 
232 232
 - name: get the md5 of the link target
233
-  shell: md5sum {{output_dir}}/follow_test | cut -f1 -sd ' '
233
+  shell: sha1sum {{output_dir}}/follow_test | cut -f1 -sd ' '
234 234
   register: target_file_result
235 235
 
236 236
 - name: assert that the link target was updated
237 237
   assert:
238 238
     that:
239
-    - replace_follow_result.md5sum == target_file_result.stdout
239
+    - replace_follow_result.checksum == target_file_result.stdout
... ...
@@ -24,7 +24,7 @@
24 24
   assert:
25 25
     that:
26 26
     - "result.changed == true"
27
-    - "result.md5sum == '6be7fb7fa7fb758c80a6dc0722979c40'"
27
+    - "result.checksum == '5feac65e442c91f557fc90069ce6efc4d346ab51'"
28 28
     - "result.state == 'file'"
29 29
 
30 30
 - name: insert a line at the beginning of the file, and back it up
... ...
@@ -42,19 +42,19 @@
42 42
   stat: path={{result.backup}}
43 43
   register: result
44 44
 
45
-- name: assert the backup file matches the previous md5
45
+- name: assert the backup file matches the previous hash
46 46
   assert:
47 47
     that:
48
-    - "result.stat.md5 == '6be7fb7fa7fb758c80a6dc0722979c40'"
48
+    - "result.stat.checksum == '5feac65e442c91f557fc90069ce6efc4d346ab51'"
49 49
 
50 50
 - name: stat the test after the insert at the head
51 51
   stat: path={{output_dir}}/test.txt
52 52
   register: result
53 53
 
54
-- name: assert test md5 matches after the insert at the head
54
+- name: assert test hash is what we expect for the file with the insert at the head
55 55
   assert:
56 56
     that:
57
-    - "result.stat.md5 == '07c16434644a2a3cc1807c685917443a'"
57
+    - "result.stat.checksum == '7eade4042b23b800958fe807b5bfc29f8541ec09'"
58 58
 
59 59
 - name: insert a line at the end of the file
60 60
   lineinfile: dest={{output_dir}}/test.txt state=present line="New line at the end" insertafter="EOF"
... ...
@@ -70,10 +70,10 @@
70 70
   stat: path={{output_dir}}/test.txt
71 71
   register: result
72 72
 
73
-- name: assert test md5 matches after the insert at the end
73
+- name: assert test checksum matches after the insert at the end
74 74
   assert:
75 75
     that:
76
-    - "result.stat.md5 == 'da4c2150e5782fcede1840280ab87eff'"
76
+    - "result.stat.checksum == 'fb57af7dc10a1006061b000f1f04c38e4bef50a9'"
77 77
 
78 78
 - name: insert a line after the first line
79 79
   lineinfile: dest={{output_dir}}/test.txt state=present line="New line after line 1" insertafter="^This is line 1$"
... ...
@@ -89,10 +89,10 @@
89 89
   stat: path={{output_dir}}/test.txt
90 90
   register: result
91 91
 
92
-- name: assert test md5 matches after the insert after the first line
92
+- name: assert test checksum matches after the insert after the first line
93 93
   assert:
94 94
     that:
95
-    - "result.stat.md5 == '196722c8faaa28b960bee66fa4cce58c'"
95
+    - "result.stat.checksum == '5348da605b1bc93dbadf3a16474cdf22ef975bec'"
96 96
 
97 97
 - name: insert a line before the last line
98 98
   lineinfile: dest={{output_dir}}/test.txt state=present line="New line after line 5" insertbefore="^This is line 5$"
... ...
@@ -108,10 +108,10 @@
108 108
   stat: path={{output_dir}}/test.txt
109 109
   register: result
110 110
 
111
-- name: assert test md5 matches after the insert before the last line
111
+- name: assert test checksum matches after the insert before the last line
112 112
   assert:
113 113
     that:
114
-    - "result.stat.md5 == 'd5955ee042139dfef16dbe3a7334475f'"
114
+    - "result.stat.checksum == 'e1cae425403507feea4b55bb30a74decfdd4a23e'"
115 115
 
116 116
 - name: replace a line with backrefs
117 117
   lineinfile: dest={{output_dir}}/test.txt state=present line="This is line 3" backrefs=yes regexp="^(REF) .* \\1$"
... ...
@@ -127,16 +127,16 @@
127 127
   stat: path={{output_dir}}/test.txt
128 128
   register: result
129 129
 
130
-- name: assert test md5 matches after backref line was replaced
130
+- name: assert test checksum matches after backref line was replaced
131 131
   assert:
132 132
     that:
133
-    - "result.stat.md5 == '0f585270054e17be242743dd31c6f593'"
133
+    - "result.stat.checksum == '2ccdf45d20298f9eaece73b713648e5489a52444'"
134 134
 
135 135
 - name: remove the middle line
136 136
   lineinfile: dest={{output_dir}}/test.txt state=absent regexp="^This is line 3$"
137 137
   register: result
138 138
 
139
-- name: assert that the line was inserted at the head of the file
139
+- name: assert that the line was removed
140 140
   assert:
141 141
     that:
142 142
     - "result.changed == true"
... ...
@@ -146,10 +146,10 @@
146 146
   stat: path={{output_dir}}/test.txt
147 147
   register: result
148 148
 
149
-- name: assert test md5 matches after the middle line was removed
149
+- name: assert test checksum matches after the middle line was removed
150 150
   assert:
151 151
     that:
152
-    - "result.stat.md5 == '661603660051991b79429c2dc68d9a67'"
152
+    - "result.stat.checksum == 'a6ba6865547c19d4c203c38a35e728d6d1942c75'"
153 153
 
154 154
 - name: run a validation script that succeeds
155 155
   lineinfile: dest={{output_dir}}/test.txt state=absent regexp="^This is line 5$" validate="true %s"
... ...
@@ -165,10 +165,10 @@
165 165
   stat: path={{output_dir}}/test.txt
166 166
   register: result
167 167
 
168
-- name: assert test md5 matches after the validation succeeded
168
+- name: assert test checksum matches after the validation succeeded
169 169
   assert:
170 170
     that:
171
-    - "result.stat.md5 == '9af984939bd859f7794661e501b4f1a4'"
171
+    - "result.stat.checksum == '76955a4516a00a38aad8427afc9ee3e361024ba5'"
172 172
 
173 173
 - name: run a validation script that fails
174 174
   lineinfile: dest={{output_dir}}/test.txt state=absent regexp="^This is line 1$" validate="/bin/false %s"
... ...
@@ -184,10 +184,10 @@
184 184
   stat: path={{output_dir}}/test.txt
185 185
   register: result
186 186
 
187
-- name: assert test md5 matches the previous after the validation failed
187
+- name: assert test checksum matches the previous after the validation failed
188 188
   assert:
189 189
     that:
190
-    - "result.stat.md5 == '9af984939bd859f7794661e501b4f1a4'"
190
+    - "result.stat.checksum == '76955a4516a00a38aad8427afc9ee3e361024ba5'"
191 191
 
192 192
 - name: use create=yes
193 193
   lineinfile: dest={{output_dir}}/new_test.txt create=yes insertbefore=BOF state=present line="This is a new file"
... ...
@@ -204,10 +204,10 @@
204 204
   register: result
205 205
   ignore_errors: yes
206 206
 
207
-- name: assert the newly created test md5 matches
207
+- name: assert the newly created test checksum matches
208 208
   assert:
209 209
     that:
210
-    - "result.stat.md5 == 'fef1d487711facfd7aa2c87d788c19d9'"
210
+    - "result.stat.checksum == '038f10f9e31202451b093163e81e06fbac0c6f3a'"
211 211
 
212 212
 # Test EOF in cases where file has no newline at EOF
213 213
 - name: testnoeof deploy the file for lineinfile
... ...
@@ -238,10 +238,10 @@
238 238
   stat: path={{output_dir}}/testnoeof.txt
239 239
   register: result
240 240
 
241
-- name: testnoeof assert test md5 matches after the insert at the end
241
+- name: testnoeof assert test checksum matches after the insert at the end
242 242
   assert:
243 243
     that:
244
-    - "result.stat.md5 == 'f75c9d51f45afd7295000e63ce655220'"
244
+    - "result.stat.checksum == 'f9af7008e3cb67575ce653d094c79cabebf6e523'"
245 245
 
246 246
 # Test EOF with empty file to make sure no unneccessary newline is added
247 247
 - name: testempty deploy the testempty file for lineinfile
... ...
@@ -262,18 +262,18 @@
262 262
   stat: path={{output_dir}}/testempty.txt
263 263
   register: result
264 264
 
265
-- name: testempty assert test md5 matches after the insert at the end
265
+- name: testempty assert test checksum matches after the insert at the end
266 266
   assert:
267 267
     that:
268
-    - "result.stat.md5 == '357dcbee8dfb4436f63bab00a235c45a'"
268
+    - "result.stat.checksum == 'f440dc65ea9cec3fd496c1479ddf937e1b949412'"
269 269
 
270 270
 - stat: path={{output_dir}}/test.txt
271 271
   register: result
272 272
 
273
-- name: assert test md5 matches after insert the multiple lines
273
+- name: assert test checksum matches after inserting multiple lines
274 274
   assert:
275 275
     that:
276
-    - "result.stat.md5 == 'c2510d5bc8fdef8e752b8f8e74c784c2'"
276
+    - "result.stat.checksum == 'bf5b711f8f0509355aaeb9d0d61e3e82337c1365'"
277 277
 
278 278
 - name: replace a line with backrefs included in the line
279 279
   lineinfile: dest={{output_dir}}/test.txt state=present line="New \\1 created with the backref" backrefs=yes regexp="^This is (line 4)$"
... ...
@@ -289,10 +289,10 @@
289 289
   stat: path={{output_dir}}/test.txt
290 290
   register: result
291 291
 
292
-- name: assert test md5 matches after backref line was replaced
292
+- name: assert test checksum matches after backref line was replaced
293 293
   assert:
294 294
     that:
295
-    - "result.stat.md5 == '65f955c2a9722fd43d07103d7756ff9b'"
295
+    - "result.stat.checksum == '04b7a54d0fb233a4e26c9e625325bb4874841b3c'"
296 296
 
297 297
 ###################################################################
298 298
 # issue 8535
... ...
@@ -332,10 +332,10 @@
332 332
   stat: path={{output_dir}}/test_quoting.txt
333 333
   register: result
334 334
 
335
-- name: assert test md5 matches after backref line was replaced
335
+- name: assert test checksum matches after backref line was replaced
336 336
   assert:
337 337
     that:
338
-    - "result.stat.md5 == '29f349baf1b9c6703beeb346fe8dc669'"
338
+    - "result.stat.checksum == '7dc3cb033c3971e73af0eaed6623d4e71e5743f1'"
339 339
 
340 340
 - name: insert a line into the quoted file with a single quote
341 341
   lineinfile: dest={{output_dir}}/test_quoting.txt line="import g'"
... ...
@@ -350,9 +350,9 @@
350 350
   stat: path={{output_dir}}/test_quoting.txt
351 351
   register: result
352 352
 
353
-- name: assert test md5 matches after backref line was replaced
353
+- name: assert test checksum matches after backref line was replaced
354 354
   assert:
355 355
     that:
356
-    - "result.stat.md5 == 'fbe9c4ba2490f70eb1974ce31ec4a39f'"
356
+    - "result.stat.checksum == '73b271c2cc1cef5663713bc0f00444b4bf9f4543'"
357 357
 
358 358
 ###################################################################
... ...
@@ -6,7 +6,7 @@
6 6
   assert:
7 7
     that:
8 8
     - "install_result.dest == '/usr/sbin/ansible_test_service'"
9
-    - "install_result.md5sum == '9ad49eaf390b30b1206b793ec71200ed'"
9
+    - "install_result.checksum == 'baaa79448a976922c080f1971321d203c6df0961'"
10 10
     - "install_result.state == 'file'"
11 11
     - "install_result.mode == '0755'"
12 12
 
... ...
@@ -12,7 +12,7 @@
12 12
     - "install_systemd_result.dest == '/usr/lib/systemd/system/ansible_test.service'"
13 13
     - "install_systemd_result.state == 'file'"
14 14
     - "install_systemd_result.mode == '0644'"
15
-    - "install_systemd_result.md5sum == '6be64a1e44e9e72a467e70a0b562444f'"
15
+    - "install_systemd_result.checksum == 'ca4b413fdf3cb2002f51893b9e42d2e449ec5afb'"
16 16
     - "install_broken_systemd_result.dest == '/usr/lib/systemd/system/ansible_test_broken.service'"
17 17
     - "install_broken_systemd_result.state == 'link'"
18 18
 
... ...
@@ -8,5 +8,5 @@
8 8
     - "install_sysv_result.dest == '/etc/init.d/ansible_test'"
9 9
     - "install_sysv_result.state == 'file'"
10 10
     - "install_sysv_result.mode == '0755'"
11
-    - "install_sysv_result.md5sum == 'ebf6a9064ca8628187f3a6caf8e2a279'"
11
+    - "install_sysv_result.md5sum == '174fa255735064b420600e4c8637ea0eff28d0c1'"
12 12
 
... ...
@@ -12,8 +12,8 @@
12 12
     - "install_upstart_result.dest == '/etc/init/ansible_test.conf'"
13 13
     - "install_upstart_result.state == 'file'"
14 14
     - "install_upstart_result.mode == '0644'"
15
-    - "install_upstart_result.md5sum == 'ab3900ea4de8423add764c12aeb90c01'"
15
+    - "install_upstart_result.checksum == '5c314837b6c4dd6c68d1809653a2974e9078e02a'"
16 16
     - "install_upstart_broken_result.dest == '/etc/init/ansible_broken_test.conf'"
17 17
     - "install_upstart_broken_result.state == 'file'"
18 18
     - "install_upstart_broken_result.mode == '0644'"
19
-    - "install_upstart_broken_result.md5sum == '015e183d10c311276c3e269cbeb309b7'"
19
+    - "install_upstart_broken_result.checksum == 'e66497894f2b2bf71e1380a196cc26089cc24a10'"
... ...
@@ -46,6 +46,8 @@
46 46
         - "'isuid' in stat_result.stat" 
47 47
         - "'md5' in stat_result.stat"
48 48
         - "stat_result.stat.md5 == '5eb63bbbe01eeed093cb22bb8f5acdc3'" 
49
+        - "'checksum' in stat_result.stat"
50
+        - "stat_result.stat.checksum == '2aae6c35c94fcfb415dbe95f408b9ce91ee846ed'"
49 51
         - "'mode' in stat_result.stat" # why is this 420?
50 52
         - "'mtime' in stat_result.stat" 
51 53
         - "'nlink' in stat_result.stat" 
... ...
@@ -27,6 +27,7 @@
27 27
         - "'group' in template_result" 
28 28
         - "'gid' in template_result" 
29 29
         - "'md5sum' in template_result" 
30
+        - "'checksum' in template_result"
30 31
         - "'owner' in template_result" 
31 32
         - "'size' in template_result" 
32 33
         - "'src' in template_result" 
... ...
@@ -7,7 +7,7 @@ from nose.tools import timed
7 7
 
8 8
 from ansible import errors
9 9
 from ansible.module_common import ModuleReplacer
10
-from ansible.utils import md5 as utils_md5
10
+from ansible.utils import checksum as utils_checksum
11 11
 
12 12
 TEST_MODULE_DATA = """
13 13
 from ansible.module_utils.basic import *
... ...
@@ -113,8 +113,8 @@ class TestModuleUtilsBasic(unittest.TestCase):
113 113
             (rc, out, err) = self.module.run_command('echo "foo bar" > %s' % tmp_path, use_unsafe_shell=True)
114 114
             self.assertEqual(rc, 0)
115 115
             self.assertTrue(os.path.exists(tmp_path))
116
-            md5sum = utils_md5(tmp_path)
117
-            self.assertEqual(md5sum, '5ceaa7ed396ccb8e959c02753cb4bd18')
116
+            checksum = utils_checksum(tmp_path)
117
+            self.assertEqual(checksum, 'd53a205a336e07cf9eac45471b3870f9489288ec')
118 118
         except:
119 119
             raise
120 120
         finally:
... ...
@@ -127,8 +127,8 @@ class TestModuleUtilsBasic(unittest.TestCase):
127 127
             (rc, out, err) = self.module.run_command('echo "foo bar" >> %s' % tmp_path, use_unsafe_shell=True)
128 128
             self.assertEqual(rc, 0)
129 129
             self.assertTrue(os.path.exists(tmp_path))
130
-            md5sum = utils_md5(tmp_path)
131
-            self.assertEqual(md5sum, '5ceaa7ed396ccb8e959c02753cb4bd18')
130
+            checksum = utils_checksum(tmp_path)
131
+            self.assertEqual(checksum, 'd53a205a336e07cf9eac45471b3870f9489288ec')
132 132
         except:
133 133
             raise
134 134
         finally:
... ...
@@ -366,6 +366,16 @@ class TestUtils(unittest.TestCase):
366 366
         self.assertEqual(ansible.utils.md5(os.path.join(os.path.dirname(__file__), 'ansible.cf')),
367 367
                          None)
368 368
 
369
+    def test_checksum_s(self):
370
+        self.assertEqual(ansible.utils.checksum_s('ansible'), 'bef45157a43c9e5f469d188810814a4a8ab9f2ed')
371
+        # Need a test that causes UnicodeEncodeError See 4221
372
+
373
+    def test_checksum(self):
374
+        self.assertEqual(ansible.utils.checksum(os.path.join(os.path.dirname(__file__), 'ansible.cfg')),
375
+                         '658b67c8ac7595adde7048425ff1f9aba270721a')
376
+        self.assertEqual(ansible.utils.md5(os.path.join(os.path.dirname(__file__), 'ansible.cf')),
377
+                         None)
378
+
369 379
     def test_default(self):
370 380
         self.assertEqual(ansible.utils.default(None, lambda: {}), {})
371 381
         self.assertEqual(ansible.utils.default(dict(foo='bar'), lambda: {}), dict(foo='bar'))
... ...
@@ -30,6 +30,8 @@ from io import BytesIO
30 30
 from subprocess import call
31 31
 from ansible import errors
32 32
 from hashlib import sha256
33
+# Note: Only used for loading obsolete VaultAES files.  All files are written
34
+# using the newer VaultAES256 which does not require md5
33 35
 from hashlib import md5
34 36
 from binascii import hexlify
35 37
 from binascii import unhexlify
... ...
@@ -23,7 +23,7 @@ from six import iteritems, string_types
23 23
 
24 24
 import os
25 25
 
26
-from hashlib import md5
26
+from hashlib import sha1
27 27
 from types import NoneType
28 28
 
29 29
 from ansible.errors import AnsibleError, AnsibleParserError
... ...
@@ -39,7 +39,7 @@ __all__ = ['Role', 'ROLE_CACHE']
39 39
 
40 40
 
41 41
 # The role cache is used to prevent re-loading roles, which
42
-# may already exist. Keys into this cache are the MD5 hash
42
+# may already exist. Keys into this cache are the SHA1 hash
43 43
 # of the role definition (for dictionary definitions, this
44 44
 # will be based on the repr() of the dictionary object)
45 45
 ROLE_CACHE = dict()
... ...
@@ -60,7 +60,7 @@ class Role:
60 60
         self._handler_blocks   = []
61 61
         self._default_vars     = dict()
62 62
         self._role_vars        = dict()
63
-        
63
+
64 64
     def __repr__(self):
65 65
         return self.get_name()
66 66