#!/usr/bin/python
# Copyright 2020 Red Hat, Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
__metaclass__ = type

from ansible.module_utils.basic import AnsibleModule

import filecmp
import os
import shutil
import subprocess
import traceback
import yaml


ANSIBLE_METADATA = {
    'metadata_version': '1.1',
    'status': ['preview'],
    'supported_by': 'community'
}


DOCUMENTATION = '''
---
module: tripleo_diff_exec
short_description: Run a command if a file is different than a previous one
version_added: "2.9"
author: "Alex Schultz (@mwhahaha)"
description:
  - Takes a file path and compares it to a previous version (created by this
    module) and runs a command if the contents are different.
options:
  command:
    description:
      - Command to run if the state file has changed since the last run. If the
        previous version of the state file does not exist, the command is run.
    required: true
    type: str
  environment:
    description:
      - Environment variables to be passed to the command being run
    required: false
    type: dict
    default: {}
  return_codes:
    description:
      - List of valid return code values for the command
    required: false
    type: list
    default: [0]
  state_file:
    description:
      - File to use to compare to the previous version
    required: true
    type: str
  state_file_suffix:
    description:
      - Suffix to use to store the previous version of the file for comparisons
        between runs
    required: false
    default: -tripleo_diff_exec
    type: str
'''

RETURN = '''
'''

EXAMPLES = '''
- name: Run command if file is changed
  tripleo_diff_exec:
    command: systemctl restart foo.service
    state_file: /var/lib/my-file
    state_file_suffix: -foo
    environment:
      FOO: bar
'''


def run(module):
    results = dict(
        changed=False
    )

    args = module.params
    command = args.get('command')
    environment = args.get('environment', {})
    return_codes = args.get('return_codes', [0])
    state_file = args.get('state_file')
    state_file_bkup = args.get('state_file') + args.get('state_file_suffix',
                                                        '-tripleo_diff_exec')

    if not os.path.exists(state_file):
        results['failed'] = True
        results['error'] = "Missing state file"
        results['msg'] = "State file does not exist: %s" % state_file
    elif (not os.path.exists(state_file_bkup)
            or not filecmp.cmp(state_file, state_file_bkup, shallow=False)):
        # run command
        try:
            tmp_environment = os.environ.copy()
            tmp_environment.update(environment)
            r = subprocess.Popen(command, shell=True, env=tmp_environment,
                                 stdout=subprocess.PIPE, stderr=subprocess.PIPE,
                                 universal_newlines=True)
            cmd_stdout, cmd_stderr = r.communicate()
            if r.returncode in return_codes:
                results['changed'] = True
                # copy old to bkup
                shutil.copy2(state_file, state_file_bkup)
            else:
                results['failed'] = True
                results['error'] = "Failed running command"
                results['msg'] = ("Error running %s. rc: %s, stdout: %s, "
                                  "stderr: %s" % (command, r.returncode,
                                                  cmd_stdout, cmd_stderr))
        except Exception as e:
            results['failed'] = True
            results['error'] = traceback.format_exc()
            results['msg'] = "Unhandled exception: %s" % e

    module.exit_json(**results)


def main():
    module = AnsibleModule(
        argument_spec=yaml.safe_load(DOCUMENTATION)['options'],
        supports_check_mode=False,
    )
    run(module)


if __name__ == '__main__':
    main()
