/src/trafficserver/include/proxy/HostStatus.h
Line | Count | Source |
1 | | /** @file |
2 | | |
3 | | A brief file description |
4 | | |
5 | | @section license License |
6 | | |
7 | | Licensed to the Apache Software Foundation (ASF) under one |
8 | | or more contributor license agreements. See the NOTICE file |
9 | | distributed with this work for additional information |
10 | | regarding copyright ownership. The ASF licenses this file |
11 | | to you under the Apache License, Version 2.0 (the |
12 | | "License"); you may not use this file except in compliance |
13 | | with the License. You may obtain a copy of the License at |
14 | | |
15 | | http://www.apache.org/licenses/LICENSE-2.0 |
16 | | |
17 | | Unless required by applicable law or agreed to in writing, software |
18 | | distributed under the License is distributed on an "AS IS" BASIS, |
19 | | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
20 | | See the License for the specific language governing permissions and |
21 | | limitations under the License. |
22 | | */ |
23 | | |
24 | | /***************************************************************************** |
25 | | * |
26 | | * HostStatus.h - Interface to Host Status System |
27 | | * |
28 | | * |
29 | | ****************************************************************************/ |
30 | | |
31 | | #pragma once |
32 | | #include "iocore/eventsystem/Continuation.h" |
33 | | #include "iocore/eventsystem/Event.h" |
34 | | #include "records/RecCore.h" |
35 | | #include "tscore/Filenames.h" |
36 | | #include "tscore/Layout.h" |
37 | | #include "tsutil/Bravo.h" |
38 | | |
39 | | #include <ctime> |
40 | | #include <string> |
41 | | #include <sstream> |
42 | | #include <unordered_map> |
43 | | |
44 | | // host_status stats prefix. |
45 | | static const std::string stat_prefix = "proxy.process.host_status."; |
46 | | |
47 | | static const constexpr char *HostStatusNames[3] = {"HOST_STATUS_INIT", "HOST_STATUS_DOWN", "HOST_STATUS_UP"}; |
48 | | static const constexpr char *ReasonStatus[2] = {"UP", "DOWN"}; |
49 | | |
50 | | struct Reason { |
51 | | static constexpr const unsigned int ACTIVE = 0x1; |
52 | | static constexpr const unsigned int LOCAL = 0x2; |
53 | | static constexpr const unsigned int MANUAL = 0x4; |
54 | | static constexpr const unsigned int SELF_DETECT = 0x8; |
55 | | static constexpr const unsigned int ALL = 0xf; |
56 | | |
57 | | static constexpr const char *ACTIVE_REASON = "active"; |
58 | | static constexpr const char *LOCAL_REASON = "local"; |
59 | | static constexpr const char *MANUAL_REASON = "manual"; |
60 | | static constexpr const char *SELF_DETECT_REASON = "self_detect"; |
61 | | static constexpr const char *ALL_REASON = "all"; |
62 | | |
63 | | static constexpr const char *reasons[3] = {ACTIVE_REASON, LOCAL_REASON, MANUAL_REASON}; |
64 | | |
65 | | static bool |
66 | | validReason(const char *reason) |
67 | 0 | { |
68 | 0 | for (const char *i : reasons) { |
69 | 0 | if (strcmp(i, reason) == 0) { |
70 | 0 | return true; |
71 | 0 | } |
72 | 0 | } |
73 | 0 | return false; |
74 | 0 | } |
75 | | |
76 | | static unsigned int |
77 | | getReason(const char *reason_str) |
78 | 0 | { |
79 | 0 | if (strcmp(reason_str, ACTIVE_REASON) == 0) { |
80 | 0 | return ACTIVE; |
81 | 0 | } else if (strcmp(reason_str, LOCAL_REASON) == 0) { |
82 | 0 | return LOCAL; |
83 | 0 | } else if (strcmp(reason_str, MANUAL_REASON) == 0) { |
84 | 0 | return MANUAL; |
85 | 0 | } else if (strcmp(reason_str, SELF_DETECT_REASON) == 0) { |
86 | 0 | return SELF_DETECT; |
87 | 0 | } else if (strcmp(reason_str, ALL_REASON) == 0) { |
88 | 0 | return ALL; |
89 | 0 | } |
90 | | // default is MANUAL |
91 | 0 | return MANUAL; |
92 | 0 | } |
93 | | }; |
94 | | |
95 | | struct HostStatuses { |
96 | | std::string hostname; |
97 | | std::string status; |
98 | | }; |
99 | | |
100 | | // host status POD |
101 | | struct HostStatRec { |
102 | | TSHostStatus status{TSHostStatus::TS_HOST_STATUS_INIT}; |
103 | | unsigned int reasons{0}; |
104 | | // time the host was marked down for a given reason. |
105 | | time_t active_marked_down{0}; |
106 | | time_t local_marked_down{0}; |
107 | | time_t manual_marked_down{0}; |
108 | | time_t self_detect_marked_down{0}; |
109 | | // number of seconds that the host should be marked down for a given reason. |
110 | | unsigned int active_down_time{0}; |
111 | | unsigned int local_down_time{0}; |
112 | | unsigned int manual_down_time{0}; |
113 | | |
114 | | HostStatRec(); |
115 | | HostStatRec(std::string str); |
116 | | HostStatRec(const HostStatRec &src) |
117 | 0 | { |
118 | 0 | status = src.status; |
119 | 0 | reasons = src.reasons; |
120 | 0 | active_marked_down = src.active_marked_down; |
121 | 0 | active_down_time = src.active_down_time; |
122 | 0 | local_marked_down = src.local_marked_down; |
123 | 0 | local_down_time = src.local_down_time; |
124 | 0 | manual_marked_down = src.manual_marked_down; |
125 | 0 | manual_down_time = src.manual_down_time; |
126 | 0 | self_detect_marked_down = src.self_detect_marked_down; |
127 | 0 | } |
128 | 0 | ~HostStatRec() {} |
129 | | |
130 | | HostStatRec &operator=(const HostStatRec &source) = default; |
131 | | |
132 | | // serialize this HostStatusRec |
133 | | std::stringstream & |
134 | | operator<<(std::stringstream &os) |
135 | 0 | { |
136 | 0 | unsigned int r = getReasonState(Reason::ACTIVE); |
137 | 0 | os << HostStatusNames[status]; |
138 | 0 | os << ",ACTIVE:" << ReasonStatus[r] << ":" << active_marked_down << ":" << active_down_time; |
139 | 0 | r = getReasonState(Reason::LOCAL); |
140 | 0 | os << ",LOCAL:" << ReasonStatus[r] << ":" << local_marked_down << ":" << local_down_time; |
141 | 0 | r = getReasonState(Reason::MANUAL); |
142 | 0 | os << ",MANUAL:" << ReasonStatus[r] << ":" << manual_marked_down << ":" << manual_down_time; |
143 | 0 | r = getReasonState(Reason::SELF_DETECT); |
144 | 0 | os << ",SELF_DETECT:" << ReasonStatus[r] << ":" << self_detect_marked_down; |
145 | 0 |
|
146 | 0 | return os; |
147 | 0 | } |
148 | | |
149 | | // serialize a HostStatRec |
150 | | friend std::stringstream & |
151 | | operator<<(std::stringstream &os, HostStatRec &hs) |
152 | 0 | { |
153 | 0 | unsigned int r = hs.getReasonState(Reason::ACTIVE); |
154 | 0 | os << HostStatusNames[hs.status]; |
155 | 0 | os << ",ACTIVE:" << ReasonStatus[r] << ":" << hs.active_marked_down << ":" << hs.active_down_time; |
156 | 0 | r = hs.getReasonState(Reason::LOCAL); |
157 | 0 | os << ",LOCAL:" << ReasonStatus[r] << ":" << hs.local_marked_down << ":" << hs.local_down_time; |
158 | 0 | r = hs.getReasonState(Reason::MANUAL); |
159 | 0 | os << ",MANUAL:" << ReasonStatus[r] << ":" << hs.manual_marked_down << ":" << hs.manual_down_time; |
160 | 0 | r = hs.getReasonState(Reason::SELF_DETECT); |
161 | 0 | os << ",SELF_DETECT:" << ReasonStatus[r] << ":" << hs.self_detect_marked_down; |
162 | |
|
163 | 0 | return os; |
164 | 0 | } |
165 | | |
166 | | inline unsigned int |
167 | | getReasonState(unsigned int reason) |
168 | 0 | { |
169 | 0 | unsigned int r = 0; |
170 | 0 | if (reasons == 0) { |
171 | 0 | r = 0; |
172 | 0 | } else if (reasons & reason) { |
173 | 0 | r = 1; |
174 | 0 | } |
175 | 0 | return r; |
176 | 0 | } |
177 | | }; |
178 | | |
179 | | class HostStatusSync : public Continuation |
180 | | { |
181 | | private: |
182 | | HostStatusSync() |
183 | 0 | { |
184 | 0 | getHostStatusPersistentFilePath(); |
185 | |
|
186 | 0 | SET_HANDLER(&HostStatusSync::mainEvent); |
187 | 0 | } |
188 | | |
189 | 0 | ~HostStatusSync() = default; |
190 | | |
191 | | public: |
192 | | HostStatusSync(HostStatusSync const &) = delete; |
193 | | |
194 | | std::string hostRecordsFile; |
195 | | |
196 | | static HostStatusSync * |
197 | | new_instance() |
198 | 0 | { |
199 | 0 | return new HostStatusSync; |
200 | 0 | } |
201 | | |
202 | | void sync_task(); |
203 | | void |
204 | | getHostStatusPersistentFilePath() |
205 | 0 | { |
206 | 0 | std::string rundir(RecConfigReadRuntimeDir()); |
207 | 0 | hostRecordsFile = Layout::relative_to(rundir, ts::filename::HOST_RECORDS); |
208 | 0 | } |
209 | | |
210 | | // Deletes instance. |
211 | | int |
212 | | mainEvent(int /* event ATS_UNUSED */, Event * /* e ATS_UNUSED */) |
213 | 0 | { |
214 | 0 | sync_task(); |
215 | |
|
216 | 0 | delete this; |
217 | |
|
218 | 0 | return EVENT_DONE; |
219 | 0 | } |
220 | | }; |
221 | | |
222 | | /** |
223 | | * Singleton placeholder for next hop status. |
224 | | */ |
225 | | struct HostStatus { |
226 | | ~HostStatus(); |
227 | | |
228 | | static HostStatus & |
229 | | instance() |
230 | 0 | { |
231 | 0 | static HostStatus instance; |
232 | 0 | return instance; |
233 | 0 | } |
234 | | void setHostStatus(const std::string_view name, const TSHostStatus status, const unsigned int down_time, |
235 | | const unsigned int reason); |
236 | | void loadFromPersistentStore(); |
237 | | void loadRecord(std::string_view name, HostStatRec &h); |
238 | | HostStatRec *getHostStatus(const std::string_view name); |
239 | | void getAllHostStatuses(std::vector<HostStatuses> &hosts); |
240 | | std::string |
241 | | getHostStatusPersistentFilePath() |
242 | 0 | { |
243 | 0 | std::string rundir(RecConfigReadRuntimeDir()); |
244 | 0 | return Layout::relative_to(rundir, ts::filename::HOST_RECORDS); |
245 | 0 | } |
246 | | |
247 | | private: |
248 | | HostStatus(); |
249 | | HostStatus(const HostStatus &obj) = delete; |
250 | | HostStatus &operator=(HostStatus const &) = delete; |
251 | | |
252 | | // next hop status, key is hostname or ip string, data is HostStatRec |
253 | | std::unordered_map<std::string, HostStatRec *> hosts_statuses; |
254 | | |
255 | | ts::bravo::shared_mutex host_status_rwlock; |
256 | | }; |