Skip to content

Commit 09aca6a

Browse files
Jonathas-Conceicaootavio
authored andcommitted
Update API to agent v2
Signed-off-by: Jonathas-Conceicao <[email protected]>
1 parent f7947ab commit 09aca6a

File tree

4 files changed

+76
-60
lines changed

4 files changed

+76
-60
lines changed

examples/api.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ def main():
2424
print(api.probe("http://www.example.com:8080"))
2525
print("")
2626
print(api.abort_download())
27+
print("")
28+
print(api.local_install("/tmp/update.uhu"))
29+
print("")
30+
print(api.remote_install("https://foo.bar/update.uhu"))
2731

2832

2933
if __name__ == '__main__':

examples/state_change_listener.py

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,8 @@
44
"enter download" state.
55
"""
66

7-
from __future__ import print_function
8-
97
import signal
108
import sys
11-
import time
129

1310
import updatehub.listener
1411

@@ -21,11 +18,11 @@ def signal_handler(*args): # pylint: disable=unused-argument
2118
sys.exit(0)
2219

2320

24-
def callback(action, state, command):
21+
def download_callback(state, command):
2522
"""
2623
Callback that will be called after the "enter download" is received.
2724
"""
28-
print("CALLBACK: " + action + " " + state)
25+
print("CALLBACK: " + state)
2926
print("Canceling the command...")
3027
command.cancel()
3128
print("Done!")
@@ -41,6 +38,16 @@ def error_callback(error_message, command):
4138
print("Done!")
4239

4340

41+
def rebooting_callback(state, _command):
42+
"""
43+
Callback that will be called after the "enter download" is received.
44+
"""
45+
print("CALLBACK: " + state)
46+
print("Stopping listener...")
47+
SCL.stop()
48+
sys.exit(0)
49+
50+
4451
def main():
4552
"""
4653
Main method. Instantiates a StateChangeListener, adds callbacks to the
@@ -49,15 +56,13 @@ def main():
4956
signal.signal(signal.SIGINT, signal_handler)
5057
signal.signal(signal.SIGQUIT, signal_handler)
5158
signal.signal(signal.SIGTERM, signal_handler)
52-
SCL.on_state_change(updatehub.listener.Action.ENTER,
53-
updatehub.listener.State.DOWNLOADING,
54-
callback)
59+
SCL.on_state_change(updatehub.listener.State.DOWNLOADING,
60+
download_callback)
61+
SCL.on_state_change(updatehub.listener.State.REBOOTING,
62+
rebooting_callback)
5563
SCL.on_error(error_callback)
5664

5765
SCL.start()
5866

59-
while True:
60-
time.sleep(1)
61-
6267
if __name__ == '__main__':
6368
main()

updatehub/api.py

Lines changed: 33 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,14 @@ class Api:
3939
"""
4040
Path to trigger a new probe for updates.
4141
"""
42+
LOCAL_INSTALL_PATH = "/local_install"
43+
"""
44+
Path to trigger the installation of a local package.
45+
"""
46+
REMOTE_INSTALL_PATH = "/remote_install"
47+
"""
48+
Path to trigger the installation of a package from a direct URL.
49+
"""
4250
SERVER_URL = "http://localhost:8080"
4351
"""
4452
URL to the agent API.
@@ -74,37 +82,46 @@ def get_log(self):
7482
"""
7583
return self._request('GET', self.__class__.LOG_PATH)
7684

77-
def probe(self, host=None, ignore_probe_asap=False):
85+
def probe(self, host=None):
7886
"""
7987
Initiate a probe looking for a new update.
8088
"""
81-
data = {}
89+
data = None
8290
if host is not None:
83-
data["server-address"] = host
84-
if ignore_probe_asap is not False:
85-
data["ignore-probe-asap"] = ignore_probe_asap
91+
data = {"custom_server": host}
8692
return self._request('POST', self.__class__.PROBE_PATH, data)
8793

94+
def local_install(self, path):
95+
"""
96+
Requests the agent to install a local package.
97+
"""
98+
data = {"file": path}
99+
return self._request('POST', self.__class__.LOCAL_INSTALL_PATH, data)
100+
101+
def remote_install(self, url):
102+
"""
103+
Requests the agent to install a local package.
104+
"""
105+
data = {"url": url}
106+
return self._request('POST', self.__class__.REMOTE_INSTALL_PATH, data)
107+
88108
def _get_uri(self, path):
89109
uri = urlparse(self.__class__.SERVER_URL)
90110
uri = uri._replace(path=path)
91111
return uri.geturl()
92112

93113
def _request(self, method, path, data=None):
94114
uri = self._get_uri(path)
95-
96-
if method == 'POST':
97-
if data is None:
98-
data = {}
99-
request_body = json.dumps(data)
115+
headers = {}
116+
if data is not None:
117+
data = json.dumps(data)
100118
try:
101-
request_body = request_body.encode('utf-8')
102-
request = Request(uri, data=request_body)
119+
data = data.encode('utf-8')
103120
except TypeError:
104-
request = Request(uri, data=request_body)
105-
else:
106-
request = Request(uri)
107-
request.add_header("Content-Type", "application/json")
121+
pass
122+
headers = {"Content-Type": "application/json"}
123+
124+
request = Request(uri, data=data, method=method, headers=headers)
108125
try:
109126
response = urlopen(request)
110127
except HTTPError as exception:

updatehub/listener.py

Lines changed: 23 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -3,30 +3,16 @@
33
Use this package to be notified of changes on the current state of the
44
updatehub agent by registering callbacks.
55
"""
6-
from __future__ import print_function
76

87
import io
98
import os
10-
import sys
119
import socket
1210
import threading
1311

1412
from enum import Enum
1513
from enum import unique
1614

1715

18-
@unique # pylint: disable=too-few-public-methods
19-
class Action(Enum):
20-
"""
21-
A enum class that contains both actions for each updatehub agent state.
22-
23-
:ENTER: action event triggered when the updatehub agent enters a state.
24-
:LEAVE: action event triggered when the updatehub agent leaves a state.
25-
"""
26-
ENTER = "enter"
27-
LEAVE = "leave"
28-
29-
3016
@unique # pylint: disable=too-few-public-methods
3117
class State(Enum):
3218
"""
@@ -152,10 +138,10 @@ def _get_state(cls, line):
152138
if parts[0] == "error":
153139
raise StateError(" ".join(parts[1:]))
154140

155-
if len(parts) < 2:
141+
if len(parts) < 1:
156142
raise MalformedState()
157143

158-
return parts[0], parts[1]
144+
return parts[0]
159145

160146
@classmethod
161147
def _readline(cls, conn):
@@ -177,16 +163,15 @@ def __init__(self):
177163
self.running = False
178164
self.thread = threading.Thread(target=self._loop)
179165

180-
def on_state_change(self, action, state, callback):
166+
def on_state_change(self, state, callback):
181167
"""
182-
Adds a new callback method to a state change action.
168+
Adds a new callback method to a state change.
183169
184-
:action: the monitored Action for this callback.
185170
:state: the monitored state for this callback.
186171
:callback: the method that will be called once a message containing the
187-
action and the state is received by the listener.
172+
state being entered is received by the listener.
188173
"""
189-
key = action.value + "_" + state.value
174+
key = state.value
190175
if self.listeners.get(key) is None:
191176
self.listeners[key] = []
192177
self.listeners[key].append(callback)
@@ -207,8 +192,8 @@ def start(self):
207192
path (see the SDK_TRIGGER_FILENAME constante above).
208193
"""
209194
if not os.path.isfile(StateChangeListener.SDK_TRIGGER_FILENAME):
210-
print("updatehub-sdk-statechange-trigger not found!")
211-
sys.exit()
195+
print("WARNING: updatehub-sdk-statechange-trigger not found on",
196+
StateChangeListener.SDK_TRIGGER_FILENAME)
212197

213198
self.running = True
214199
self.thread.start()
@@ -219,8 +204,11 @@ def stop(self):
219204
close the Unix socket and wait for the thread to finish execution.
220205
"""
221206
self.running = False
207+
socket_path = os.getenv("UH_LISTENER_TEST",
208+
default=StateChangeListener.SOCKET_PATH)
209+
222210
client = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
223-
client.connect(StateChangeListener.SOCKET_PATH)
211+
client.connect(socket_path)
224212
client.close()
225213
if threading.current_thread() != self.thread:
226214
self.thread.join()
@@ -245,27 +233,29 @@ def _wait_for_state(self):
245233
if not self.running:
246234
break
247235
line = self._readline(conn)
248-
action, state = self._get_state(line)
249-
self._emit(action, state, conn)
236+
state = self._get_state(line)
237+
self._emit(state, conn)
250238
except StateError as exception:
251239
self._throw_error(exception, conn)
252240
finally:
253241
if conn is not None:
254242
conn.close()
255243

256244
def _connect(self):
257-
if os.path.exists(StateChangeListener.SOCKET_PATH):
258-
os.remove(StateChangeListener.SOCKET_PATH)
245+
socket_path = os.getenv("UH_LISTENER_TEST",
246+
default=StateChangeListener.SOCKET_PATH)
247+
248+
if os.path.exists(socket_path):
249+
os.remove(socket_path)
259250

260251
self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
261-
self.sock.bind(StateChangeListener.SOCKET_PATH)
252+
self.sock.bind(socket_path)
262253
self.sock.listen(1)
263254

264-
def _emit(self, action, state, connection):
265-
key = action + "_" + state
266-
for callback in self.listeners.get(key) or []:
255+
def _emit(self, state, connection):
256+
for callback in self.listeners.get(state) or []:
267257
command = StateCommand(connection)
268-
callback(action, state, command)
258+
callback(state, command)
269259

270260
def _throw_error(self, exception, connection):
271261
for callback in self.error_handlers:

0 commit comments

Comments
 (0)