-
Notifications
You must be signed in to change notification settings - Fork 66
/
dish_check_update.py
executable file
·142 lines (110 loc) · 4.52 KB
/
dish_check_update.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
#!/usr/bin/env python3
"""Check whether there is a software update pending on a Starlink user terminal.
Optionally, reboot the dish to initiate install if there is an update pending.
"""
import argparse
from datetime import datetime
import logging
import sys
import time
import grpc
import loop_util
import starlink_grpc
# This is the enum value spacex.api.device.dish_pb2.SoftwareUpdateState.REBOOT_REQUIRED
REBOOT_REQUIRED = 6
# This is the enum value spacex.api.device.dish_pb2.SoftwareUpdateState.DISABLED
UPDATE_DISABLED = 7
def loop_body(opts, context):
now = time.time()
try:
status = starlink_grpc.get_status(context)
except (AttributeError, ValueError, grpc.RpcError) as e:
logging.error("Failed getting dish status: %s", str(starlink_grpc.GrpcError(e)))
return 1
# There are at least 3 and maybe 4 redundant flags that indicate whether or
# not a software update is pending. In order to be robust against future
# changes in the protocol and/or implementation of it, this scripts checks
# them all, while allowing for the possibility that some of them have been
# obsoleted and thus no longer present in the reflected protocol classes.
try:
alert_flag = status.alerts.install_pending
except (AttributeError, ValueError):
alert_flag = None
try:
state_flag = status.software_update_state == REBOOT_REQUIRED
state_dflag = status.software_update_state == UPDATE_DISABLED
except (AttributeError, ValueError):
state_flag = None
state_dflag = None
try:
stats_flag = status.software_update_stats.software_update_state == REBOOT_REQUIRED
stats_dflag = status.software_update_stats.software_update_state == UPDATE_DISABLED
except (AttributeError, ValueError):
stats_flag = None
stats_dflag = None
try:
ready_flag = status.swupdate_reboot_ready
except (AttributeError, ValueError):
ready_flag = None
try:
sw_version = status.device_info.software_version
except (AttributeError, ValueError):
sw_version = "UNKNOWN"
if opts.verbose >= 2:
print("Pending flags:", alert_flag, state_flag, stats_flag, ready_flag)
print("Disable flags:", state_dflag, stats_dflag)
if state_dflag or stats_dflag:
logging.warning("Software updates appear to be disabled")
# The swupdate_reboot_ready field does not appear to be in use, so may
# mean something other than what it sounds like. Only use it if none of
# the others are available.
if alert_flag is None and state_flag is None and stats_flag is None:
install_pending = bool(ready_flag)
else:
install_pending = alert_flag or state_flag or stats_flag
if opts.verbose:
dtnow = datetime.fromtimestamp(now, tz=getattr(opts, "timezone", None))
print(dtnow.replace(microsecond=0, tzinfo=None).isoformat(), "- ", end="")
if install_pending:
print("Install pending, current version:", sw_version)
if opts.install:
print("Rebooting dish to initiate install")
try:
starlink_grpc.reboot(context)
except starlink_grpc.GrpcError as e:
logging.error("Failed reboot request: %s", str(e))
return 1
elif opts.verbose:
print("No install pending, current version:", sw_version)
return 0
def parse_args():
parser = argparse.ArgumentParser(description="Check for Starlink user terminal software update")
parser.add_argument(
"-i",
"--install",
action="store_true",
help="Initiate dish reboot to perform install if there is an update pending")
parser.add_argument("-g",
"--target",
help="host:port of dish to query, default is the standard IP address "
"and port (192.168.100.1:9200)")
parser.add_argument("-v",
"--verbose",
action="count",
default=0,
help="Increase verbosity, may be used multiple times")
loop_util.add_args(parser)
opts = parser.parse_args()
loop_util.check_args(opts, parser)
return opts
def main():
opts = parse_args()
logging.basicConfig(format="%(levelname)s: %(message)s")
context = starlink_grpc.ChannelContext(target=opts.target)
try:
rc = loop_util.run_loop(opts, loop_body, opts, context)
finally:
context.close()
sys.exit(rc)
if __name__ == "__main__":
main()