Newer
Older
""" Connected client management package.
This package store classes representing each client's role and the associated
sjRPC handler.
"""
import logging
from datetime import datetime
from ccserver.handlers import CCHandler, listed
from ccserver.exceptions import RightError
from ccserver.db import RemoteTag
from cloudcontrol.common.tql.db.tag import CallbackTag
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
class RegisteredCCHandler(CCHandler):
""" Basic handler for all registered clients.
"""
def __getitem__(self, name):
self.client.top()
return super(RegisteredCCHandler, self).__getitem__(name)
def on_disconnect(self, conn):
logging.info('Client %s disconnected', self.client.login)
self.client.shutdown()
def check(self, method, tql=None):
""" Check if the client have access to this method.
"""
allow = self.client.server.check(self.client.login, method, tql)
if not allow:
raise RightError('You are not allowed to do this action.')
#
# Tags registration handler functions:
#
@listed
def tags_register(self, name, ttl=None, value=None):
""" Register a new tag on the calling node.
:param name: name of the tag to register
:param ttl: ttl of the tag (or None if not applicable)
:param value: value to fill the tag (optionnal)
"""
self.client.tags_register(name, ttl, value)
@listed
def tags_unregister(self, name):
""" Unregister a tag on the calling node.
:param name: name of the tag to unregister
"""
self.client.tags_unregister(name)
@listed
def tags_drop(self, name):
""" Drop the tag value of the specified tag on the calling node.
:param name: name of the tag to drop
"""
self.client.tags_drop(name)
@listed
def tags_update(self, name, value, ttl=None):
""" Update the value of the specified tag on the calling node.
:param name: name of the tag to update
:param value: new tag value
:param ttl: new ttl value
"""
self.client.tags_update(name, value, ttl)
class Client(object):
""" Base class for all types cc-server clients.
:param login: login of the client
:param server: server instance
:param connection: rpc connection to the client
"""
ROLE = None
RPC_HANDLER = RegisteredCCHandler
roles = {}
def __init__(self, login, server, connection, tql_object):
self._login = login
self._server = server
self._connection = connection
self._tql_object = tql_object
self._handler = self.RPC_HANDLER(self)
self._last_action = datetime.now()
self._connection_date = datetime.now()
# Set the role's handler for the client:
self._connection.rpc.set_handler(self._handler)
# Remote tags registered:
self._remote_tags = set()
# Register the server defined client tags:
self._tql_object.register(CallbackTag('con', lambda: self.uptime, ttl=0))
self._tql_object.register(CallbackTag('idle', lambda: self.idle, ttl=0))
self._tql_object.register(CallbackTag('ip', lambda: self.ip))
@classmethod
def register_client_class(cls, class_):
""" Register a new client class.
"""
cls.roles[class_.ROLE] = class_
@classmethod
def from_role(cls, role, login, server, connection, tql_object):
return cls.roles[role](login, server, connection, tql_object)
#
# Properties
#
@property
def object(self):
""" Return the tql object of this client.
"""
return self._tql_object
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
@property
def login(self):
""" Return the login of this client.
"""
return self._login
@property
def server(self):
""" Return the cc-server binded to this client.
"""
return self._server
@property
def conn(self):
""" Return the sjrpc connection to the client.
"""
return self._connection
@property
def uptime(self):
""" Get the uptime of the client connection in seconds.
:return: uptime of the client
"""
dt = datetime.now() - self._connection_date
return dt.seconds + dt.days * 86400
@property
def idle(self):
""" Get the idle time of the client connection in seconds.
:return: idle of the client
"""
dt = datetime.now() - self._last_action
return dt.seconds + dt.days * 86400
@property
def ip(self):
""" Get client remote ip address.
"""
peer = self.conn.getpeername()
return ':'.join(peer.split(':')[:-1])
def get_tags(self, tags): # DEPRECATED
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
""" Get tags on the remote node.
:param tags: tags is the list of tags to fetch
"""
return self._connection.call('get_tags', tags)
def shutdown(self):
""" Shutdown the connection to the client.
"""
# Unregister all remote tags:
for tag in self._remote_tags.copy():
self.tags_unregister(tag)
# Unrefister all server defined client tags:
self._tql_object.unregister('con')
self._tql_object.unregister('idle')
self._tql_object.unregister('ip')
self._server.rpc.unregister(self.conn, shutdown=True)
self._server.unregister(self)
def top(self):
""" Reset the "last action" date to now.
"""
self._last_action = datetime.now()
def get_remote_tags(self, tag): # DEPRECATED
return self.conn.call('get_tags', (tag,))[tag]
def async_remote_tags(self, watcher, robj, tags):
""" Asynchronously update tags from the remote client using
specified watcher.
"""
watcher.register(self.conn, 'get_tags', tags, _data=robj)
def tags_register(self, name, ttl=None, value=None):
""" Register a new remote tag for the client.
:param name: name of the tag to register
:param ttl: TTL of the tag if applicable (None = no TTL, the tag will
never expire)
:param value: value of the tag
"""
tag = RemoteTag(name, self, ttl=ttl)
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
self._tql_object.register(tag)
self._remote_tags.add(name)
def tags_unregister(self, name):
"""
Unregister a remote tag for the client.
:param name: name of the tag to unregister
"""
self._tql_object.unregister(name)
self._remote_tags.discard(name)
def tags_drop(self, name):
""" Drop the cached value of a remote tag for the client.
:param name: name of the tag to drop
"""
tag = self._tql_object.get(name)
if tag is not None:
tag.invalidate()
def tags_update(self, name, value=None, ttl=None):
""" Update a remote tag.
:param name: name of the tag to update
:param value: new value of the tag
:param ttl: new ttl of the tag
"""
tag = self._tql_object.get(name)
if tag is not None:
if value is not None:
if ttl is not None:
tag.ttl = ttl