1"""
2Wrap the cp module allowing for managed ssh file transfers
3"""
4
5import logging
6import os
7
8import salt.client.ssh
9import salt.utils.files
10import salt.utils.stringutils
11import salt.utils.templates
12from salt.exceptions import CommandExecutionError
13
14log = logging.getLogger(__name__)
15
16
17def get_file(path, dest, saltenv="base", makedirs=False, template=None, gzip=None):
18    """
19    Send a file from the master to the location in specified
20
21    .. note::
22
23        gzip compression is not supported in the salt-ssh version of
24        cp.get_file. The argument is only accepted for interface compatibility.
25    """
26    if gzip is not None:
27        log.warning("The gzip argument to cp.get_file in salt-ssh is unsupported")
28
29    if template is not None:
30        (path, dest) = _render_filenames(path, dest, saltenv, template)
31
32    src = __context__["fileclient"].cache_file(
33        path, saltenv, cachedir=os.path.join("salt-ssh", __salt__.kwargs["id_"])
34    )
35    single = salt.client.ssh.Single(__opts__, "", **__salt__.kwargs)
36    ret = single.shell.send(src, dest, makedirs)
37    return not ret[2]
38
39
40def get_dir(path, dest, saltenv="base"):
41    """
42    Transfer a directory down
43    """
44    src = __context__["fileclient"].cache_dir(
45        path, saltenv, cachedir=os.path.join("salt-ssh", __salt__.kwargs["id_"])
46    )
47    src = " ".join(src)
48    single = salt.client.ssh.Single(__opts__, "", **__salt__.kwargs)
49    ret = single.shell.send(src, dest)
50    return not ret[2]
51
52
53def get_url(path, dest, saltenv="base"):
54    """
55    retrieve a URL
56    """
57    src = __context__["fileclient"].cache_file(
58        path, saltenv, cachedir=os.path.join("salt-ssh", __salt__.kwargs["id_"])
59    )
60    single = salt.client.ssh.Single(__opts__, "", **__salt__.kwargs)
61    ret = single.shell.send(src, dest)
62    return not ret[2]
63
64
65def list_states(saltenv="base"):
66    """
67    List all the available state modules in an environment
68    """
69    return __context__["fileclient"].list_states(saltenv)
70
71
72def list_master(saltenv="base", prefix=""):
73    """
74    List all of the files stored on the master
75    """
76    return __context__["fileclient"].file_list(saltenv, prefix)
77
78
79def list_master_dirs(saltenv="base", prefix=""):
80    """
81    List all of the directories stored on the master
82    """
83    return __context__["fileclient"].dir_list(saltenv, prefix)
84
85
86def list_master_symlinks(saltenv="base", prefix=""):
87    """
88    List all of the symlinks stored on the master
89    """
90    return __context__["fileclient"].symlink_list(saltenv, prefix)
91
92
93def _render_filenames(path, dest, saltenv, template):
94    """
95    Process markup in the :param:`path` and :param:`dest` variables (NOT the
96    files under the paths they ultimately point to) according to the markup
97    format provided by :param:`template`.
98    """
99    if not template:
100        return (path, dest)
101
102    # render the path as a template using path_template_engine as the engine
103    if template not in salt.utils.templates.TEMPLATE_REGISTRY:
104        raise CommandExecutionError(
105            "Attempted to render file paths with unavailable engine {}".format(template)
106        )
107
108    kwargs = {}
109    kwargs["salt"] = __salt__.value()
110    kwargs["pillar"] = __pillar__.value()
111    kwargs["grains"] = __grains__.value()
112    kwargs["opts"] = __opts__
113    kwargs["saltenv"] = saltenv
114
115    def _render(contents):
116        """
117        Render :param:`contents` into a literal pathname by writing it to a
118        temp file, rendering that file, and returning the result.
119        """
120        # write out path to temp file
121        tmp_path_fn = salt.utils.files.mkstemp()
122        with salt.utils.files.fopen(tmp_path_fn, "w+") as fp_:
123            fp_.write(salt.utils.stringutils.to_str(contents))
124        data = salt.utils.templates.TEMPLATE_REGISTRY[template](
125            tmp_path_fn, to_str=True, **kwargs
126        )
127        salt.utils.files.safe_rm(tmp_path_fn)
128        if not data["result"]:
129            # Failed to render the template
130            raise CommandExecutionError(
131                "Failed to render file path with error: {}".format(data["data"])
132            )
133        else:
134            return data["data"]
135
136    path = _render(path)
137    dest = _render(dest)
138    return (path, dest)
139