-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathmatrix_state.py
190 lines (168 loc) · 5.2 KB
/
matrix_state.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
#!/usr/bin/python
# coding: utf-8
# (c) 2018, Jan Christian Grünhage <[email protected]>
# (c) 2020-2021, Famedly GmbH
# GNU Affero General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/agpl-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 = """
---
author: "Jan Christian Grünhage (@jcgruenhage)"
module: matrix_state
short_description: Set matrix room state
description:
- This module sets matrix room state idempotently
options:
hs_url:
description:
- URL of the homeserver, where the CS-API is reachable
required: true
type: str
user_id:
description:
- The user id of the user
required: false
type: str
password:
description:
- The password to log in with
required: false
type: str
token:
description:
- Authentication token for the API call
required: false
type: str
event_type:
description:
- Event type of the state to be set
required: true
type: str
state_key:
description:
- State key for the state event to be set
required: true
type: str
content:
description:
- The content to set the state to
required: true
type: dict
room_id:
description:
- ID of the room to set the state for
required: true
type: str
requirements:
- matrix-client (Python library)
"""
EXAMPLES = """
- name: Set the server ACL for the admin room
matrix_state:
event_type: m.room.server_acl
state_key: ""
content:
allow:
- "*"
deny:
- "bad-server.one"
- "bad-server.two"
room_id: "!LAVFnosfDouvhA9VEhiuSV:matrix.org"
hs_url: "https://matrix.org"
token: "{{ matrix_auth_token }}"
"""
RETURN = """
event_id:
description:
- ID of the created event
returned: changed
type: str
sample: $Het2Dv7EEDFNJNgY-ehLSUrdqMo8JOxZDCMnuQPSNfo
"""
import asyncio
import traceback
from ansible.module_utils.basic import missing_required_lib
LIB_IMP_ERR = None
try:
from ansible_collections.famedly.matrix.plugins.module_utils.matrix import (
AnsibleNioModule,
)
from nio import (
JoinedRoomsResponse,
JoinedRoomsError,
RoomGetStateEventResponse,
RoomPutStateResponse,
)
HAS_LIB = True
except ImportError:
LIB_IMP_ERR = traceback.format_exc()
HAS_LIB = False
async def run_module():
module_args = dict(
event_type=dict(type="str", required=True),
state_key=dict(type="str", required=True, no_log=False),
content=dict(type="dict", required=True),
room_id=dict(type="str", required=True),
)
result = dict(changed=False, message="")
module = AnsibleNioModule(module_args)
if not HAS_LIB:
await module.fail_json(msg=missing_required_lib("matrix-nio"))
await module.matrix_login()
client = module.client
if module.check_mode:
# TODO: Attempt to check if the state event is already present
# Implementation note: this might not be possible as a previous check-moded
# login token might be invalid / not provided
result["changed"] = True
await module.exit_json(**result)
failed = False
# Check if already in room
rooms_resp = await client.joined_rooms()
if isinstance(rooms_resp, JoinedRoomsError):
failed = True
result = {"msg": "Couldn't get joined rooms."}
elif module.params["room_id"] not in rooms_resp.rooms:
failed = True
result = {"msg": "Not in the room you're trying to set state for."}
else:
# Fetch state from room
state_resp = await client.room_get_state_event(
module.params["room_id"],
module.params["event_type"],
module.params["state_key"],
)
# If successful, compare with content from module and content is the same, return with changed=false and the ID of the old event
if (
isinstance(state_resp, RoomGetStateEventResponse)
and state_resp.content == module.params["content"]
):
result = {"changed": False}
# Else, try to send a new state event
else:
send_resp = await client.room_put_state(
module.params["room_id"],
module.params["event_type"],
module.params["content"],
module.params["state_key"],
)
# If successful, return with changed=true and the ID of the new event
if isinstance(send_resp, RoomPutStateResponse):
result = {"event_id": send_resp.room_id, "changed": True}
# Else, fail
else:
failed = True
result = {"msg": f"Couldn't set state: {send_resp}"}
if failed:
await module.fail_json(**result)
else:
await module.exit_json(**result)
def main():
asyncio.run(run_module())
if __name__ == "__main__":
main()