1"""
2Configuration of the alternatives system
3
4Control the alternatives system
5
6.. code-block:: jinja
7
8  {% set my_hadoop_conf = '/opt/hadoop/conf' %}
9
10  {{ my_hadoop_conf }}:
11    file.directory
12
13  hadoop-0.20-conf:
14    alternatives.install:
15      - name: hadoop-0.20-conf
16      - link: /etc/hadoop-0.20/conf
17      - path: {{ my_hadoop_conf }}
18      - priority: 30
19      - require:
20        - file: {{ my_hadoop_conf }}
21
22  hadoop-0.20-conf:
23    alternatives.remove:
24      - name: hadoop-0.20-conf
25      - path: {{ my_hadoop_conf }}
26
27"""
28
29# Define a function alias in order not to shadow built-in's
30__func_alias__ = {"set_": "set"}
31
32
33def __virtual__():
34    """
35    Only load if alternatives execution module is available.
36    """
37    if "alternatives.auto" in __salt__:
38        return True
39    return (False, "alernatives module could not be loaded")
40
41
42def install(name, link, path, priority):
43    """
44    Install new alternative for defined <name>
45
46    name
47        is the master name for this link group
48        (e.g. pager)
49
50    link
51        is the symlink pointing to /etc/alternatives/<name>.
52        (e.g. /usr/bin/pager)
53
54    path
55        is the location of the new alternative target.
56        NB: This file / directory must already exist.
57        (e.g. /usr/bin/less)
58
59    priority
60        is an integer; options with higher numbers have higher priority in
61        automatic mode.
62    """
63    ret = {
64        "name": name,
65        "link": link,
66        "path": path,
67        "priority": priority,
68        "result": True,
69        "changes": {},
70        "comment": "",
71    }
72
73    if __salt__["alternatives.check_exists"](name, path):
74        ret["comment"] = "Alternative {} for {} is already registered".format(
75            path, name
76        )
77    else:
78        if __opts__["test"]:
79            ret[
80                "comment"
81            ] = "Alternative will be set for {} to {} with priority {}".format(
82                name, path, priority
83            )
84            ret["result"] = None
85            return ret
86
87        out = __salt__["alternatives.install"](name, link, path, priority)
88        if __salt__["alternatives.check_exists"](name, path):
89            if __salt__["alternatives.check_installed"](name, path):
90                ret[
91                    "comment"
92                ] = "Alternative for {} set to path {} with priority {}".format(
93                    name, path, priority
94                )
95            else:
96                ret["comment"] = (
97                    "Alternative {} for {} registered with priority {} and "
98                    "not set to default".format(path, name, priority)
99                )
100            ret["changes"] = {
101                "name": name,
102                "link": link,
103                "path": path,
104                "priority": priority,
105            }
106        else:
107            ret["result"] = False
108            ret["comment"] = "Alternative for {} not installed: {}".format(name, out)
109
110    return ret
111
112
113def remove(name, path):
114    """
115    Removes installed alternative for defined <name> and <path>
116    or fallback to default alternative, if some defined before.
117
118    name
119        is the master name for this link group
120        (e.g. pager)
121
122    path
123        is the location of one of the alternative target files.
124        (e.g. /usr/bin/less)
125    """
126    ret = {"name": name, "path": path, "result": True, "changes": {}, "comment": ""}
127
128    isinstalled = __salt__["alternatives.check_exists"](name, path)
129    if isinstalled:
130        if __opts__["test"]:
131            ret["comment"] = "Alternative for {} will be removed".format(name)
132            ret["result"] = None
133            return ret
134        __salt__["alternatives.remove"](name, path)
135        current = __salt__["alternatives.show_current"](name)
136        if current:
137            ret["result"] = True
138            ret[
139                "comment"
140            ] = "Alternative for {} removed. Falling back to path {}".format(
141                name, current
142            )
143            ret["changes"] = {"path": current}
144            return ret
145
146        ret["comment"] = "Alternative for {} removed".format(name)
147        ret["changes"] = {}
148        return ret
149
150    current = __salt__["alternatives.show_current"](name)
151    if current:
152        ret["result"] = True
153        ret["comment"] = "Alternative for {} is set to it's default path {}".format(
154            name, current
155        )
156        return ret
157
158    ret["result"] = False
159    ret["comment"] = "Alternative for {} doesn't exist".format(name)
160
161    return ret
162
163
164def auto(name):
165    """
166    .. versionadded:: 0.17.0
167
168    Instruct alternatives to use the highest priority
169    path for <name>
170
171    name
172        is the master name for this link group
173        (e.g. pager)
174
175    """
176    ret = {"name": name, "result": True, "comment": "", "changes": {}}
177
178    display = __salt__["alternatives.display"](name)
179    line = display.splitlines()[0]
180    if line.endswith(" auto mode"):
181        ret["comment"] = "{} already in auto mode".format(name)
182        return ret
183
184    if __opts__["test"]:
185        ret["comment"] = "{} will be put in auto mode".format(name)
186        ret["result"] = None
187        return ret
188    ret["changes"]["result"] = __salt__["alternatives.auto"](name)
189    return ret
190
191
192def set_(name, path):
193    """
194    .. versionadded:: 0.17.0
195
196    Sets alternative for <name> to <path>, if <path> is defined
197    as an alternative for <name>.
198
199    name
200        is the master name for this link group
201        (e.g. pager)
202
203    path
204        is the location of one of the alternative target files.
205        (e.g. /usr/bin/less)
206
207    .. code-block:: yaml
208
209        foo:
210          alternatives.set:
211            - path: /usr/bin/foo-2.0
212    """
213    ret = {"name": name, "path": path, "result": True, "changes": {}, "comment": ""}
214
215    current = __salt__["alternatives.show_current"](name)
216    if current == path:
217        ret["comment"] = "Alternative for {} already set to {}".format(name, path)
218        return ret
219
220    display = __salt__["alternatives.display"](name)
221    isinstalled = False
222    for line in display.splitlines():
223        if line.startswith(path):
224            isinstalled = True
225            break
226
227    if isinstalled:
228        if __opts__["test"]:
229            ret["comment"] = "Alternative for {} will be set to path {}".format(
230                name, path
231            )
232            ret["result"] = None
233            return ret
234        __salt__["alternatives.set"](name, path)
235        current = __salt__["alternatives.show_current"](name)
236        if current == path:
237            ret["comment"] = "Alternative for {} set to path {}".format(name, current)
238            ret["changes"] = {"path": current}
239        else:
240            ret["comment"] = "Alternative for {} not updated".format(name)
241
242        return ret
243
244    else:
245        ret["result"] = False
246        ret["comment"] = "Alternative {} for {} doesn't exist".format(path, name)
247
248    return ret
249