First functional monitoring server - can return the trust router version
[trust_router.git] / mon / mons_handlers_show.c
1 /*
2  * Copyright (c) 2018, JANET(UK)
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * 3. Neither the name of JANET(UK) nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
25  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
31  * OF THE POSSIBILITY OF SUCH DAMAGE.
32  *
33  */
34
35 /* Handlers for monitoring "show" requests */
36
37 #include <jansson.h>
38 #include <talloc.h>
39
40 #include <tr_debug.h>
41 #include <mon_internal.h>
42 #include "mons_handlers.h"
43
44 typedef json_t *(MONS_SHOW_FUNC)(MONS_INSTANCE *mons);
45
46 /* prototypes for the dispatch table */
47 static json_t *handle_show_version(MONS_INSTANCE *mons);
48
49 struct dispatch_table_entry {
50   MON_OPT_TYPE opt_type;
51   MONS_SHOW_FUNC *handler;
52 };
53
54 struct dispatch_table_entry dispatch_table[] = {
55     {OPT_TYPE_SHOW_VERSION, handle_show_version},
56     {OPT_TYPE_SHOW_SERIAL, NULL},
57     {OPT_TYPE_SHOW_UPTIME, NULL},
58     {OPT_TYPE_SHOW_TID_REQ_COUNT, NULL},
59     {OPT_TYPE_SHOW_TID_REQ_PENDING, NULL},
60     {OPT_TYPE_SHOW_ROUTES, NULL},
61     {OPT_TYPE_SHOW_COMMUNITIES, NULL},
62     {OPT_TYPE_UNKNOWN} /* must be the last entry */
63 };
64
65 /**
66  * Should we include this opt_type in our response to this request?
67  *
68  * Returns 1 if the opt_type is in the options list, or if the options list
69  * is empty.
70  *
71  * @param opt_type
72  * @param req
73  * @return 1 if the opt_type should be included, else 0
74  */
75 static int opt_requested(MON_OPT_TYPE opt_type, MON_REQ *req)
76 {
77   size_t ii;
78
79   /* empty options list is a wildcard - return everything */
80   if (mon_req_opt_count(req) == 0)
81     return 1;
82
83   /* check whether this opt_type is in the list */
84   for (ii=0; ii<mon_req_opt_count(req); ii++) {
85     if (opt_type == mon_req_opt_index(req, ii)->type)
86       return 1;
87   }
88   return 0;
89 }
90
91 MON_RESP *mons_handle_show(TALLOC_CTX *mem_ctx, MONS_INSTANCE *mons, MON_REQ *req)
92 {
93   struct dispatch_table_entry *entry = NULL;
94   MON_RESP *resp = NULL;
95   json_t *payload = NULL; /* entire payload */
96   json_t *payload_item = NULL; /* payload for a single option */
97
98   tr_debug("mons_handle_show: Handling a request");
99
100   /* Start off by allocating our response with a generic error message */
101   resp = mon_resp_new(mem_ctx,
102                       MON_RESP_ERROR,
103                       "Error processing show request",
104                       NULL);
105   if (resp == NULL) {
106     /* we can't respond, just return */
107     tr_crit("mons_handle_show: Error allocating response structure.");
108     goto cleanup;
109   }
110
111   /* Now get a JSON object for our return payload */
112   payload = json_object();
113   if (payload == NULL) {
114     tr_crit("mons_handle_show: Error allocating response payload.");
115     goto cleanup; /* This will return the generic error message set earlier */
116   }
117
118   tr_debug("mons_handle_show: Processing options");
119
120   /* Now step through the dispatch table. Call each requested option type. */
121   for (entry = dispatch_table; entry->opt_type != OPT_TYPE_UNKNOWN; entry++) {
122     if (! opt_requested(entry->opt_type, req)) {
123       tr_debug("mons_handle_show: Not including %s in response",
124                mon_opt_type_to_string(entry->opt_type));
125     } else {
126       /* This option is needed. Add its response to our payload. */
127       if (entry->handler == NULL) {
128         tr_debug("mons_handle_show: Would include %s in response, but its handler is null",
129                  mon_opt_type_to_string(entry->opt_type));
130         continue;
131       }
132
133       tr_debug("mons_handle_show: Including %s in response",
134                mon_opt_type_to_string(entry->opt_type));
135
136       payload_item = entry->handler(mons);
137       if (payload_item == NULL) {
138         tr_err("mons_handle_show: Error processing option %s", mon_opt_type_to_string(entry->opt_type));
139         goto cleanup;
140       }
141       /* this steals the reference to payload_item */
142       json_object_set_new(payload,
143                           mon_opt_type_to_string(entry->opt_type),
144                           payload_item);
145     }
146   }
147
148   /* If we get here, then we successfully processed the request. Return a successful reply. */
149   if (mon_resp_set_message(resp, "success") == 0) {
150     /* Failed to set the response message to success - fail ironically */
151     tr_crit("mons_handle_show: Error setting response message to 'success'");
152     goto cleanup;
153   }
154
155   /* Attach the accumulated payload to the response */
156   if (json_object_size(payload) > 0)
157     mon_resp_set_payload(resp, payload);
158
159   resp->code = MON_RESP_SUCCESS; /* at last... */
160
161 cleanup:
162   if (payload)
163     json_decref(payload);
164   return resp;
165 }
166
167
168 static json_t *handle_show_version(MONS_INSTANCE *mons)
169 {
170   return json_string(PACKAGE_VERSION);
171 }