#!/usr/bin/python
# -*- coding: utf-8 -*-

# (c) 2020, Simon Dodsley (simon@purestorage.com)
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)

from __future__ import absolute_import, division, print_function

__metaclass__ = type

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

DOCUMENTATION = r"""
---
module: purefa_fs
version_added: '1.5.0'
short_description: Manage FlashArray File Systems
description:
- Create/Delete FlashArray File Systems
author:
- Pure Storage Ansible Team (@sdodsley) <pure-ansible-team@purestorage.com>
options:
  name:
    description:
    - Name of the file system
    type: str
    required: true
  state:
    description:
    - Define whether the file system should exist or not.
    default: present
    choices: [ absent, present ]
    type: str
  eradicate:
    description:
    - Define whether to eradicate the file system on delete or leave in trash.
    type: bool
    default: false
  rename:
    description:
    - Value to rename the specified file system to
    - Rename only applies to the container the current filesystem is in.
    - There is no requirement to specify the pod name as this is implied.
    type: str
  move:
    description:
    - Move a filesystem in and out of a pod
    - Provide the name of pod to move the filesystem to
    - Pod names must be unique in the array
    - To move to the local array, specify C(local)
    - This is not idempotent - use C(ignore_errors) in the play
    type: str
    version_added: '1.13.0'
extends_documentation_fragment:
- purestorage.flasharray.purestorage.fa
"""

EXAMPLES = r"""
- name: Create file system foo
  purestorage.flasharray.purefa_fs:
    name: foo
    fa_url: 10.10.10.2
    api_token: e31060a7-21fc-e277-6240-25983c6c4592

- name: Delete and eradicate file system foo
  purestorage.flasharray.purefa_fs:
    name: foo
    eradicate: true
    state: absent
    fa_url: 10.10.10.2
    api_token: e31060a7-21fc-e277-6240-25983c6c4592

- name: Rename file system foo to bar
  purestorage.flasharray.purefa_fs:
    name: foo
    rename: bar
    fa_url: 10.10.10.2
    api_token: e31060a7-21fc-e277-6240-25983c6c4592
"""

RETURN = r"""
"""

HAS_PURESTORAGE = True
try:
    from pypureclient import flasharray
except ImportError:
    HAS_PURESTORAGE = False

from ansible.module_utils.basic import AnsibleModule
from ansible_collections.purestorage.flasharray.plugins.module_utils.purefa import (
    get_array,
    purefa_argument_spec,
)
from ansible_collections.purestorage.flasharray.plugins.module_utils.version import (
    LooseVersion,
)

MIN_REQUIRED_API_VERSION = "2.2"
REPL_SUPPORT_API = "2.13"


def delete_fs(module, array):
    """Delete a file system"""
    changed = True
    if not module.check_mode:
        try:
            file_system = flasharray.FileSystemPatch(destroyed=True)
            array.patch_file_systems(
                names=[module.params["name"]], file_system=file_system
            )
        except Exception:
            module.fail_json(
                msg="Failed to delete file system {0}".format(module.params["name"])
            )
        if module.params["eradicate"]:
            try:
                array.delete_file_systems(names=[module.params["name"]])
            except Exception:
                module.fail_json(
                    msg="Eradication of file system {0} failed".format(
                        module.params["name"]
                    )
                )
    module.exit_json(changed=changed)


def recover_fs(module, array):
    """Recover a deleted file system"""
    changed = True
    if not module.check_mode:
        try:
            file_system = flasharray.FileSystemPatch(destroyed=False)
            array.patch_file_systems(
                names=[module.params["name"]], file_system=file_system
            )
        except Exception:
            module.fail_json(
                msg="Failed to recover file system {0}".format(module.params["name"])
            )
    module.exit_json(changed=changed)


def eradicate_fs(module, array):
    """Eradicate a file system"""
    changed = True
    if not module.check_mode:
        try:
            array.delete_file_systems(names=[module.params["name"]])
        except Exception:
            module.fail_json(
                msg="Failed to eradicate file system {0}".format(module.params["name"])
            )
    module.exit_json(changed=changed)


def rename_fs(module, array):
    """Rename a file system"""
    changed = False
    target_name = module.params["rename"]
    if "::" in module.params["name"]:
        pod_name = module.params["name"].split("::")[0]
        target_name = pod_name + "::" + module.params["rename"]
    try:
        target = list(array.get_file_systems(names=[target_name]).items)[0]
    except Exception:
        target = None
    if not target:
        changed = True
        if not module.check_mode:
            try:
                file_system = flasharray.FileSystemPatch(name=target_name)
                array.patch_file_systems(
                    names=[module.params["name"]], file_system=file_system
                )
            except Exception:
                module.fail_json(
                    msg="Failed to rename file system {0}".format(module.params["name"])
                )
    else:
        module.fail_json(
            msg="Target file system {0} already exists".format(module.params["rename"])
        )
    module.exit_json(changed=changed)


def create_fs(module, array):
    """Create a file system"""
    changed = True
    if "::" in module.params["name"]:
        pod_name = module.params["name"].split("::")[0]
        try:
            pod = list(array.get_pods(names=[pod_name]).items)[0]
        except Exception:
            module.fail_json(
                msg="Failed to create filesystem. Pod {0} does not exist".format(
                    pod_name
                )
            )
        if pod.promotion_status == "demoted":
            module.fail_json(msg="Filesystem cannot be created in a demoted pod")
    if not module.check_mode:
        try:
            array.post_file_systems(names=[module.params["name"]])
        except Exception:
            module.fail_json(
                msg="Failed to create file system {0}".format(module.params["name"])
            )
    module.exit_json(changed=changed)


def move_fs(module, array):
    """Move filesystem between pods or local array"""
    changed = False
    target_exists = False
    pod_name = ""
    fs_name = module.params["name"]
    if "::" in module.params["name"]:
        fs_name = module.params["name"].split("::")[1]
        pod_name = module.params["name"].split("::")[0]
    if module.params["move"] == "local":
        target_location = ""
        if "::" not in module.params["name"]:
            module.fail_json(msg="Source and destination [local] cannot be the same.")
        try:
            target_exists = list(array.get_file_systems(names=[fs_name]).items)[0]
        except Exception:
            target_exists = False
        if target_exists:
            module.fail_json(msg="Target filesystem {0} already exists".format(fs_name))
    else:
        try:
            pod = list(array.get_pods(names=[module.params["move"]]).items)[0]
            if len(pod.arrays) > 1:
                module.fail_json(msg="Filesystem cannot be moved into a stretched pod")
            if pod.link_target_count != 0:
                module.fail_json(
                    msg="Filesystem cannot be moved into a linked source pod"
                )
            if pod.promotion_status == "demoted":
                module.fail_json(msg="Volume cannot be moved into a demoted pod")
        except Exception:
            module.fail_json(
                msg="Failed to move filesystem. Pod {0} does not exist".format(pod_name)
            )
        if "::" in module.params["name"]:
            pod = list(array.get_pods(names=[module.params["move"]]).items)[0]
            if len(pod.arrays) > 1:
                module.fail_json(
                    msg="Filesystem cannot be moved out of a stretched pod"
                )
            if pod.linked_target_count != 0:
                module.fail_json(
                    msg="Filesystem cannot be moved out of a linked source pod"
                )
            if pod.promotion_status == "demoted":
                module.fail_json(msg="Volume cannot be moved out of a demoted pod")
        target_location = module.params["move"]
    changed = True
    if not module.check_mode:
        file_system = flasharray.FileSystemPatch(
            pod=flasharray.Reference(name=target_location)
        )
        move_res = array.patch_file_systems(
            names=[module.params["name"]], file_system=file_system
        )
        if move_res.status_code != 200:
            module.fail_json(
                msg="Move of filesystem {0} failed. Error: {1}".format(
                    module.params["name"], move_res.errors[0].message
                )
            )
    module.exit_json(changed=changed)


def main():
    argument_spec = purefa_argument_spec()
    argument_spec.update(
        dict(
            state=dict(type="str", default="present", choices=["absent", "present"]),
            eradicate=dict(type="bool", default=False),
            name=dict(type="str", required=True),
            move=dict(type="str"),
            rename=dict(type="str"),
        )
    )

    mutually_exclusive = [["move", "rename"]]
    module = AnsibleModule(
        argument_spec, mutually_exclusive=mutually_exclusive, supports_check_mode=True
    )

    if not HAS_PURESTORAGE:
        module.fail_json(msg="py-pure-client sdk is required for this module")

    array = get_array(module)
    api_version = array.get_rest_version()

    if LooseVersion(MIN_REQUIRED_API_VERSION) > LooseVersion(api_version):
        module.fail_json(
            msg="FlashArray REST version not supported. "
            "Minimum version required: {0}".format(MIN_REQUIRED_API_VERSION)
        )
    if (
        LooseVersion(REPL_SUPPORT_API) > LooseVersion(api_version)
        and "::" in module.params["name"]
    ):
        module.fail_json(
            msg="Filesystem Replication is only supported in Purity//FA 6.3.0 or higher"
        )
    state = module.params["state"]

    try:
        filesystem = list(array.get_file_systems(names=[module.params["name"]]).items)[
            0
        ]
        exists = True
    except Exception:
        exists = False

    if state == "present" and not exists and not module.params["move"]:
        create_fs(module, array)
    elif (
        state == "present"
        and exists
        and module.params["move"]
        and not filesystem.destroyed
    ):
        move_fs(module, array)
    elif (
        state == "present"
        and exists
        and module.params["rename"]
        and not filesystem.destroyed
    ):
        rename_fs(module, array)
    elif (
        state == "present"
        and exists
        and filesystem.destroyed
        and not module.params["rename"]
        and not module.params["move"]
    ):
        recover_fs(module, array)
    elif (
        state == "present" and exists and filesystem.destroyed and module.params["move"]
    ):
        module.fail_json(
            msg="Filesystem {0} exists, but in destroyed state".format(
                module.params["name"]
            )
        )
    elif state == "absent" and exists and not filesystem.destroyed:
        delete_fs(module, array)
    elif (
        state == "absent"
        and exists
        and module.params["eradicate"]
        and filesystem.destroyed
    ):
        eradicate_fs(module, array)

    module.exit_json(changed=False)


if __name__ == "__main__":
    main()
