Skip to content

Instantly share code, notes, and snippets.

@reywood
Last active August 29, 2015 14:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save reywood/fc752efbdd85a87d5316 to your computer and use it in GitHub Desktop.
Save reywood/fc752efbdd85a87d5316 to your computer and use it in GitHub Desktop.
Salt state for fetching a file from an S3 bucket. Place s3_file.py in /srv/salt/[ENV]/_states/
import os
import os.path
import salt.exceptions
from tempfile import mkstemp
def get(name, bucket, path, md5, access_key=None, secret_key=None):
ret = {'name': name, 'changes': {}, 'result': False, 'comment': ''}
if md5 is None or len(md5) != 32:
raise salt.exceptions.SaltInvocationError('Argument "md5" does not appear to be a valid hash')
current_md5 = _get_current_m5_or_none(name)
if os.path.exists(name) and current_md5 == md5:
ret['result'] = True
ret['comment'] = 'System already in the correct state'
return ret
ret['changes'] = {
'old': 'MD5: {0}'.format(current_md5),
'new': 'MD5: {0}'.format(md5),
}
if __opts__['test'] == True:
ret['comment'] = 'The state of "{0}" will be changed.'.format(name)
ret['result'] = None
return ret
_get_file_from_s3(bucket, path, name, access_key, secret_key, md5)
ret['comment'] = 'The state of "{0}" was changed!'.format(name)
ret['result'] = True
return ret
def _get_current_m5_or_none(file_path):
if os.path.exists(file_path):
return __salt__['file.get_hash'](file_path)
return None
def _get_file_from_s3(bucket, path, file_path, access_key, secret_key, md5):
temp_file_path = _get_temp_file_path()
s3_get_kwargs = {
'bucket': bucket,
'path': path,
'return_bin': True,
'local_file': temp_file_path
}
if access_key is not None and secret_key is not None:
s3_get_kwargs['keyid'] = access_key
s3_get_kwargs['key'] = secret_key
__salt__['s3.get'](**s3_get_kwargs)
_delete_and_raise_if_file_hash_does_not_match(temp_file_path, md5)
if os.path.exists(file_path):
os.unlink(file_path)
os.rename(temp_file_path, file_path)
def _get_temp_file_path():
fd, path = mkstemp()
os.close(fd)
return path
def _delete_and_raise_if_file_hash_does_not_match(file_path, expected_md5):
actual_md5 = __salt__['file.get_hash'](file_path)
if actual_md5 != expected_md5:
os.unlink(file_path)
message = 'Hash for {0} did not match. expected: {1}, actual: {2}'.format(file_path, expected_md5, actual_md5)
raise salt.exceptions.SaltInvocationError(message)
my_file:
s3_file.get:
- name: /path/to/file/destination/on/minion
- bucket: my-s3-bucket
- path: path/to/file/in/s3/bucket
- md5: 51e44977f4cb6c39beca301db66be0ea
- access_key: AKIAIHDN626R2Z7NFFWQ
- secret_key: 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
@reywood
Copy link
Author

reywood commented Aug 24, 2014

Uses salt.modules.s3.get to get the file. This means that you can omit the access_key and secret_key state params if your minion is an EC2 instance with an IAM role assigned to it. Just make sure the IAM role has access to the S3 file in question.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment