Code

6c68dc5fd1d4b9fce1486dea01ff2e44d97e96ab
[sysdb.git] / src / core / store_exec.c
1 /*
2  * SysDB - src/core/store_exec.c
3  * Copyright (C) 2014-2015 Sebastian 'tokkee' Harl <sh@tokkee.org>
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
17  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
19  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
28 #include "core/object.h"
29 #include "core/store-private.h"
30 #include "frontend/connection.h"
31 #include "parser/ast.h"
32 #include "utils/error.h"
34 #include <errno.h>
36 #include <arpa/inet.h>
37 #include <ctype.h>
38 #include <stdlib.h>
39 #include <string.h>
41 /*
42  * private helper functions
43  */
45 static int
46 list_tojson(sdb_store_obj_t *obj,
47                 sdb_store_matcher_t __attribute__((unused)) *filter,
48                 void *user_data)
49 {
50         sdb_store_json_formatter_t *f = user_data;
51         return sdb_store_json_emit(f, obj);
52 } /* list_tojson */
54 static int
55 lookup_tojson(sdb_store_obj_t *obj, sdb_store_matcher_t *filter,
56                 void *user_data)
57 {
58         sdb_store_json_formatter_t *f = user_data;
59         return sdb_store_json_emit_full(f, obj, filter);
60 } /* lookup_tojson */
62 static size_t
63 sstrlen(const char *s)
64 {
65         return s ? strlen(s) : 0;
66 } /* sstrlen */
68 /*
69  * query implementations
70  */
72 static int
73 exec_fetch(sdb_strbuf_t *buf, sdb_strbuf_t *errbuf, int type,
74                 const char *hostname, const char *name, sdb_store_matcher_t *filter)
75 {
76         uint32_t res_type = htonl(SDB_CONNECTION_FETCH);
78         sdb_store_obj_t *host;
79         sdb_store_obj_t *obj;
81         sdb_store_json_formatter_t *f;
83         if ((! name) || ((type == SDB_HOST) && hostname)
84                         || ((type != SDB_HOST) && (! hostname))) {
85                 /* This is a programming error, not something the client did wrong */
86                 sdb_strbuf_sprintf(errbuf, "INTERNAL ERROR: invalid "
87                                 "arguments to FETCH(%s, %s, %s)",
88                                 SDB_STORE_TYPE_TO_NAME(type), hostname, name);
89                 return -1;
90         }
91         if (type == SDB_HOST)
92                 hostname = name;
94         host = sdb_store_get_host(hostname);
95         if ((! host)
96                         || (filter && (! sdb_store_matcher_matches(filter, host, NULL)))) {
97                 sdb_strbuf_sprintf(errbuf, "Failed to fetch %s %s: "
98                                 "host %s not found", SDB_STORE_TYPE_TO_NAME(type),
99                                 name, hostname);
100                 sdb_object_deref(SDB_OBJ(host));
101                 return -1;
102         }
103         if (type == SDB_HOST) {
104                 obj = host;
105         }
106         else {
107                 obj = sdb_store_get_child(host, type, name);
108                 if ((! obj)
109                                 || (filter && (! sdb_store_matcher_matches(filter, obj, NULL)))) {
110                         sdb_strbuf_sprintf(errbuf, "Failed to fetch %s %s.%s: "
111                                         "%s not found", SDB_STORE_TYPE_TO_NAME(type),
112                                         hostname, name, name);
113                         if (obj)
114                                 sdb_object_deref(SDB_OBJ(obj));
115                         sdb_object_deref(SDB_OBJ(host));
116                         return -1;
117                 }
118                 sdb_object_deref(SDB_OBJ(host));
119         }
120         host = NULL;
122         f = sdb_store_json_formatter(buf, type, /* flags = */ 0);
123         if (! f) {
124                 char err[1024];
125                 sdb_log(SDB_LOG_ERR, "frontend: Failed to create "
126                                 "JSON formatter to handle FETCH command: %s",
127                                 sdb_strerror(errno, err, sizeof(err)));
129                 sdb_strbuf_sprintf(errbuf, "Out of memory");
130                 sdb_object_deref(SDB_OBJ(obj));
131                 return -1;
132         }
134         sdb_strbuf_memcpy(buf, &res_type, sizeof(uint32_t));
135         if (sdb_store_json_emit_full(f, obj, filter)) {
136                 sdb_log(SDB_LOG_ERR, "frontend: Failed to serialize "
137                                 "%s %s.%s to JSON", SDB_STORE_TYPE_TO_NAME(type),
138                                 hostname, name);
139                 sdb_strbuf_sprintf(errbuf, "Out of memory");
140                 free(f);
141                 sdb_object_deref(SDB_OBJ(obj));
142                 return -1;
143         }
145         sdb_object_deref(SDB_OBJ(obj));
146         sdb_store_json_finish(f);
147         free(f);
149         return SDB_CONNECTION_DATA;
150 } /* exec_fetch */
152 static int
153 exec_list(sdb_strbuf_t *buf, sdb_strbuf_t *errbuf, int type,
154                 sdb_store_matcher_t *filter)
156         uint32_t res_type = htonl(SDB_CONNECTION_LIST);
157         sdb_store_json_formatter_t *f;
159         f = sdb_store_json_formatter(buf, type, SDB_WANT_ARRAY);
160         if (! f) {
161                 char err[1024];
162                 sdb_log(SDB_LOG_ERR, "frontend: Failed to create "
163                                 "JSON formatter to handle LIST command: %s",
164                                 sdb_strerror(errno, err, sizeof(err)));
166                 sdb_strbuf_sprintf(errbuf, "Out of memory");
167                 return -1;
168         }
170         sdb_strbuf_memcpy(buf, &res_type, sizeof(uint32_t));
171         if (sdb_store_scan(type, /* m = */ NULL, filter, list_tojson, f)) {
172                 sdb_log(SDB_LOG_ERR, "frontend: Failed to serialize "
173                                 "store to JSON");
174                 sdb_strbuf_sprintf(errbuf, "Out of memory");
175                 free(f);
176                 return -1;
177         }
179         sdb_store_json_finish(f);
180         free(f);
182         return SDB_CONNECTION_DATA;
183 } /* exec_list */
185 static int
186 exec_lookup(sdb_strbuf_t *buf, sdb_strbuf_t *errbuf, int type,
187                 sdb_store_matcher_t *m, sdb_store_matcher_t *filter)
189         uint32_t res_type = htonl(SDB_CONNECTION_LOOKUP);
190         sdb_store_json_formatter_t *f;
192         f = sdb_store_json_formatter(buf, type, SDB_WANT_ARRAY);
193         if (! f) {
194                 char err[1024];
195                 sdb_log(SDB_LOG_ERR, "frontend: Failed to create "
196                                 "JSON formatter to handle LOOKUP command: %s",
197                                 sdb_strerror(errno, err, sizeof(err)));
199                 sdb_strbuf_sprintf(errbuf, "Out of memory");
200                 return -1;
201         }
203         sdb_strbuf_memcpy(buf, &res_type, sizeof(uint32_t));
205         if (sdb_store_scan(type, m, filter, lookup_tojson, f)) {
206                 sdb_log(SDB_LOG_ERR, "frontend: Failed to lookup %ss",
207                                 SDB_STORE_TYPE_TO_NAME(type));
208                 sdb_strbuf_sprintf(errbuf, "Failed to lookup %ss",
209                                 SDB_STORE_TYPE_TO_NAME(type));
210                 free(f);
211                 return -1;
212         }
214         sdb_store_json_finish(f);
215         free(f);
217         return SDB_CONNECTION_DATA;
218 } /* exec_lookup */
220 static int
221 exec_store(sdb_strbuf_t *buf, sdb_strbuf_t *errbuf, sdb_ast_store_t *st)
223         char name[sstrlen(st->hostname) + sstrlen(st->parent) + sstrlen(st->name) + 3];
224         sdb_metric_store_t metric_store;
225         int type = st->obj_type, status = -1;
227         switch (st->obj_type) {
228         case SDB_HOST:
229                 strncpy(name, st->name, sizeof(name));
230                 status = sdb_store_host(st->name, st->last_update);
231                 break;
233         case SDB_SERVICE:
234                 snprintf(name, sizeof(name), "%s.%s", st->hostname, st->name);
235                 status = sdb_store_service(st->hostname, st->name, st->last_update);
236                 break;
238         case SDB_METRIC:
239                 snprintf(name, sizeof(name), "%s.%s", st->hostname, st->name);
240                 metric_store.type = st->store_type;
241                 metric_store.id = st->store_id;
242                 status = sdb_store_metric(st->hostname, st->name,
243                                 &metric_store, st->last_update);
244                 break;
246         case SDB_ATTRIBUTE:
247                 type |= st->parent_type;
249                 if (st->parent)
250                         snprintf(name, sizeof(name), "%s.%s.%s",
251                                         st->hostname, st->parent, st->name);
252                 else
253                         snprintf(name, sizeof(name), "%s.%s", st->hostname, st->name);
255                 switch (st->parent_type) {
256                 case 0:
257                         type |= SDB_HOST;
258                         status = sdb_store_attribute(st->hostname,
259                                         st->name, &st->value, st->last_update);
260                         break;
262                 case SDB_SERVICE:
263                         status = sdb_store_service_attr(st->hostname, st->parent,
264                                         st->name, &st->value, st->last_update);
265                         break;
267                 case SDB_METRIC:
268                         status = sdb_store_metric_attr(st->hostname, st->parent,
269                                         st->name, &st->value, st->last_update);
270                         break;
272                 default:
273                         sdb_log(SDB_LOG_ERR, "store: Invalid parent type in STORE: %s",
274                                         SDB_STORE_TYPE_TO_NAME(st->parent_type));
275                         return -1;
276                 }
277                 break;
279         default:
280                 sdb_log(SDB_LOG_ERR, "store: Invalid object type in STORE: %s",
281                                 SDB_STORE_TYPE_TO_NAME(st->obj_type));
282                 return -1;
283         }
285         if (status < 0) {
286                 sdb_strbuf_sprintf(errbuf, "STORE: Failed to store %s object",
287                                 SDB_STORE_TYPE_TO_NAME(type));
288                 return -1;
289         }
291         if (! status) {
292                 sdb_strbuf_sprintf(buf, "Successfully stored %s %s",
293                                 SDB_STORE_TYPE_TO_NAME(type), name);
294         }
295         else {
296                 char type_str[32];
297                 strncpy(type_str, SDB_STORE_TYPE_TO_NAME(type), sizeof(type_str));
298                 type_str[0] = (char)toupper((int)type_str[0]);
299                 sdb_strbuf_sprintf(buf, "%s %s already up to date", type_str, name);
300         }
302         return SDB_CONNECTION_OK;
303 } /* exec_store */
305 static int
306 exec_timeseries(sdb_strbuf_t *buf, sdb_strbuf_t *errbuf,
307                 const char *hostname, const char *metric,
308                 sdb_timeseries_opts_t *opts)
310         uint32_t res_type = htonl(SDB_CONNECTION_TIMESERIES);
312         sdb_strbuf_memcpy(buf, &res_type, sizeof(uint32_t));
313         if (sdb_store_fetch_timeseries(hostname, metric, opts, buf)) {
314                 sdb_log(SDB_LOG_ERR, "frontend: Failed to fetch time-series");
315                 sdb_strbuf_sprintf(errbuf, "Failed to fetch time-series");
316                 return -1;
317         }
319         return SDB_CONNECTION_DATA;
320 } /* exec_timeseries */
322 /*
323  * public API
324  */
326 int
327 sdb_store_query_execute(sdb_store_query_t *m,
328                 sdb_strbuf_t *buf, sdb_strbuf_t *errbuf)
330         sdb_timeseries_opts_t ts_opts;
331         sdb_ast_node_t *ast;
333         if (! m)
334                 return -1;
335         if (! QUERY(m)->ast) {
336                 sdb_log(SDB_LOG_ERR, "store: Invalid empty query");
337                 return -1;
338         }
340         ast = QUERY(m)->ast;
341         switch (ast->type) {
342         case SDB_AST_TYPE_FETCH:
343                 return exec_fetch(buf, errbuf, SDB_AST_FETCH(ast)->obj_type,
344                                 SDB_AST_FETCH(ast)->hostname, SDB_AST_FETCH(ast)->name,
345                                 QUERY(m)->filter);
347         case SDB_AST_TYPE_LIST:
348                 return exec_list(buf, errbuf, SDB_AST_LIST(ast)->obj_type,
349                                 QUERY(m)->filter);
351         case SDB_AST_TYPE_LOOKUP:
352                 return exec_lookup(buf, errbuf, SDB_AST_LOOKUP(ast)->obj_type,
353                                 QUERY(m)->matcher, QUERY(m)->filter);
355         case SDB_AST_TYPE_STORE:
356                 if (ast->type != SDB_AST_TYPE_STORE) {
357                         sdb_log(SDB_LOG_ERR, "store: Invalid AST node for STORE command: %s",
358                                         SDB_AST_TYPE_TO_STRING(ast));
359                         return -1;
360                 }
361                 return exec_store(buf, errbuf, SDB_AST_STORE(ast));
363         case SDB_AST_TYPE_TIMESERIES:
364                 ts_opts.start = SDB_AST_TIMESERIES(ast)->start;
365                 ts_opts.end = SDB_AST_TIMESERIES(ast)->end;
366                 return exec_timeseries(buf, errbuf, SDB_AST_TIMESERIES(ast)->hostname,
367                                 SDB_AST_TIMESERIES(ast)->metric, &ts_opts);
369         default:
370                 sdb_log(SDB_LOG_ERR, "store: Invalid query of type %s",
371                                 SDB_AST_TYPE_TO_STRING(ast));
372                 return -1;
373         }
375         return 0;
376 } /* sdb_store_query_execute */
378 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */