Coverage for src/edwh_uptime_plugin/uptime_plugin.py: 0%

113 statements  

« prev     ^ index     » next       coverage.py v7.4.0, created at 2024-01-18 16:57 +0100

1import json 

2from typing import Optional 

3 

4import edwh 

5from invoke import Context, task 

6 

7from .uptimerobot import MonitorType, UptimeRobotMonitor, uptime_robot 

8 

9 

10@task() 

11def status(_: Context, url: str) -> None: 

12 """ 

13 Show a specific monitor by (partial) url or label. 

14 

15 :param url: required positional argument of the URL to show the status for 

16 """ 

17 monitors = uptime_robot.get_monitors(url) 

18 if not monitors: 

19 print("No monitor found!") 

20 return 

21 

22 for monitor in monitors: 

23 print(f"- {monitor['url']}:", uptime_robot.format_status(monitor["status"])) 

24 

25 

26@task(name="monitors") 

27def monitors_verbose(_: Context, search: str = "") -> None: 

28 """ 

29 Show all monitors full data as dict. 

30 You can optionally add a search term, which will look in the URL and label. 

31 

32 :param search: (partial) URL or monitor name to filter by 

33 """ 

34 print(json.dumps(uptime_robot.get_monitors(search), indent=2)) 

35 

36 

37@task(name="list") 

38def list_statuses(_: Context, search: str = "") -> None: 

39 """ 

40 Show the status for each monitor. 

41 

42 :param search: (partial) URL or monitor name to filter by 

43 """ 

44 for monitor in uptime_robot.get_monitors(search): 

45 print(f"- {monitor['url']}:", uptime_robot.format_status(monitor["status"])) 

46 

47 

48@task() 

49def up(_: Context, strict: bool = False) -> None: 

50 """ 

51 List monitors that are up (probably). 

52 

53 :param strict: If strict is True, only status 2 is allowed 

54 """ 

55 min_status = 2 if strict else 0 

56 max_status = 3 

57 

58 monitors = uptime_robot.get_monitors() 

59 monitors = [_ for _ in monitors if min_status <= _["status"] < max_status] 

60 

61 for monitor in monitors: 

62 print(f"- {monitor['url']}:", uptime_robot.format_status(monitor["status"])) 

63 

64 

65@task() 

66def down(_: Context, strict: bool = False) -> None: 

67 """ 

68 List monitors that are down (probably). 

69 

70 :param strict: If strict is True, 'seems down' is ignored 

71 """ 

72 min_status = 9 if strict else 8 

73 

74 monitors = uptime_robot.get_monitors() 

75 monitors = [_ for _ in monitors if _["status"] >= min_status] 

76 

77 for monitor in monitors: 

78 print(f"- {monitor['url']}:", uptime_robot.format_status(monitor["status"])) 

79 

80 

81def extract_friendly_name(url: str) -> str: 

82 name = url.split("/")[2] 

83 

84 return name.removesuffix(".edwh.nl").removesuffix(".meteddie.nl").removeprefix("www.") 

85 

86 

87def normalize_url(url: str) -> tuple[str, str]: 

88 if not url.startswith(("https://", "http://")): 

89 if "://" in url: 

90 protocol = url.split("://")[0] 

91 raise ValueError(f"protocol {protocol} not supported, please use http(s)://") 

92 url = f"https://{url}" 

93 

94 # search for existing and confirm: 

95 domain = url.split("/")[2] 

96 

97 return url, domain 

98 

99 

100@task(aliases=("create",)) 

101def add(_: Context, url: str, friendly_name: str = "") -> None: 

102 """ 

103 Create a new monitor. 

104 Requires a positional argument 'url' and an optional --friendly-name label 

105 

106 :param url: Which domain name to add 

107 :param friendly_name: Human-readable label (defaults to part of URL) 

108 """ 

109 url, domain = normalize_url(url) 

110 

111 if existing := uptime_robot.get_monitors(domain): 

112 print("A similar domain was already added:") 

113 for monitor in existing: 

114 print(monitor["friendly_name"], monitor["url"]) 

115 if not edwh.confirm("Are you sure you want to continue? [yN]", default=False): 

116 return 

117 

118 friendly_name = friendly_name or extract_friendly_name(url) 

119 

120 monitor_id = uptime_robot.new_monitor( 

121 friendly_name, 

122 url, 

123 ) 

124 

125 if not monitor_id: 

126 print("No monitor was added") 

127 else: 

128 print(f"Monitor '{friendly_name}' was added: {monitor_id}") 

129 

130 

131def select_monitor(url: str) -> UptimeRobotMonitor | None: 

132 """ 

133 Interactively select a monitor by url. 

134 

135 :param url: Which domain name to select 

136 :return: Selected monitor 

137 """ 

138 monitors = uptime_robot.get_monitors(url) 

139 if not monitors: 

140 print(f"No such monitor could be found {url}") 

141 return None 

142 if len(monitors) > 1: 

143 print(f"Ambiguous url {url} could mean:") 

144 for idx, monitor in enumerate(monitors): 

145 print(idx + 1, monitor["friendly_name"], monitor["url"]) 

146 

147 print("0", "Exit") 

148 

149 _which_one = input("Which monitor would you like to select? ") 

150 if not _which_one.isdigit(): 

151 print(f"Invalid number {_which_one}!") 

152 return None 

153 

154 which_one = int(_which_one) 

155 if which_one > len(monitors): 

156 print(f"Invalid selection {which_one}!") 

157 return None 

158 

159 elif which_one == 0: 

160 return None 

161 else: 

162 # zero-index: 

163 which_one -= 1 

164 

165 else: 

166 which_one = 0 

167 

168 return monitors[which_one] 

169 

170 

171@task(aliases=("delete",)) 

172def remove(_: Context, url: str) -> None: 

173 """ 

174 Remove a specific monitor by url. 

175 

176 :param url: Which domain name to remove 

177 """ 

178 if not (monitor := select_monitor(url)): 

179 return 

180 

181 monitor_id = monitor["id"] 

182 

183 if uptime_robot.delete_monitor(monitor_id): 

184 print(f"Monitor {monitor['friendly_name']} removed!") 

185 else: 

186 print(f"Monitor {monitor['friendly_name']} could not be deleted.") 

187 

188 

189@task(aliases=("update",)) 

190def edit(_: Context, url: str, friendly_name: Optional[str] = None) -> None: 

191 """ 

192 Edit a specific monitor by url. 

193 

194 :param url: Which domain name to edit 

195 :param friendly_name: new human-readable label 

196 """ 

197 monitor = select_monitor(url) 

198 if monitor is None: 

199 return 

200 

201 monitor_id = monitor["id"] 

202 

203 url, _domain = normalize_url(url) 

204 

205 # Here you can define the new data for the monitor 

206 new_data = { 

207 "url": url, 

208 "friendly_name": friendly_name or monitor.get("friendly_name", ""), 

209 "monitor_type": monitor.get("type", MonitorType.HTTP), # todo: support more? 

210 # ... 

211 } 

212 

213 if uptime_robot.edit_monitor(monitor_id, new_data): 

214 print(f"Monitor {monitor['friendly_name']} updated!") 

215 else: 

216 print(f"Monitor {monitor['friendly_name']} could not be updated.") 

217 

218 

219@task() 

220def reset(_: Context, url: str) -> None: 

221 """ 

222 Reset a specific monitor by url. 

223 

224 :param url: Which domain name to reset 

225 """ 

226 if not (monitor := select_monitor(url)): 

227 return 

228 

229 monitor_id = monitor["id"] 

230 

231 if uptime_robot.reset_monitor(monitor_id): 

232 print(f"Monitor {monitor['friendly_name']} reset!") 

233 else: 

234 print(f"Monitor {monitor['friendly_name']} could not be reset.") 

235 

236 

237@task() 

238def account(_: Context) -> None: 

239 """ 

240 Show information about the acccount related to the current API key. 

241 """ 

242 

243 print(json.dumps(uptime_robot.get_account_details(), indent=2))