Code

store: All store functions now accept a store object.
[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/plugin.h"
30 #include "core/store-private.h"
31 #include "frontend/connection.h"
32 #include "parser/ast.h"
33 #include "utils/error.h"
35 #include <errno.h>
37 #include <arpa/inet.h>
38 #include <ctype.h>
39 #include <stdlib.h>
40 #include <string.h>
42 /*
43  * private helper functions
44  */
46 static int
47 list_tojson(sdb_store_obj_t *obj,
48                 sdb_store_matcher_t __attribute__((unused)) *filter,
49                 void *user_data)
50 {
51         sdb_store_json_formatter_t *f = user_data;
52         return sdb_store_json_emit(f, obj);
53 } /* list_tojson */
55 static int
56 lookup_tojson(sdb_store_obj_t *obj, sdb_store_matcher_t *filter,
57                 void *user_data)
58 {
59         sdb_store_json_formatter_t *f = user_data;
60         return sdb_store_json_emit_full(f, obj, filter);
61 } /* lookup_tojson */
63 static size_t
64 sstrlen(const char *s)
65 {
66         return s ? strlen(s) : 0;
67 } /* sstrlen */
69 /*
70  * query implementations
71  */
73 static int
74 exec_fetch(sdb_store_t *store, sdb_strbuf_t *buf, sdb_strbuf_t *errbuf,
75                 int type, const char *hostname, const char *name,
76                 sdb_store_matcher_t *filter)
77 {
78         uint32_t res_type = htonl(SDB_CONNECTION_FETCH);
80         sdb_store_obj_t *host;
81         sdb_store_obj_t *obj;
83         sdb_store_json_formatter_t *f;
85         if ((! name) || ((type == SDB_HOST) && hostname)
86                         || ((type != SDB_HOST) && (! hostname))) {
87                 /* This is a programming error, not something the client did wrong */
88                 sdb_strbuf_sprintf(errbuf, "INTERNAL ERROR: invalid "
89                                 "arguments to FETCH(%s, %s, %s)",
90                                 SDB_STORE_TYPE_TO_NAME(type), hostname, name);
91                 return -1;
92         }
93         if (type == SDB_HOST)
94                 hostname = name;
96         host = sdb_store_get_host(store, hostname);
97         if ((! host)
98                         || (filter && (! sdb_store_matcher_matches(filter, host, NULL)))) {
99                 sdb_strbuf_sprintf(errbuf, "Failed to fetch %s %s: "
100                                 "host %s not found", SDB_STORE_TYPE_TO_NAME(type),
101                                 name, hostname);
102                 sdb_object_deref(SDB_OBJ(host));
103                 return -1;
104         }
105         if (type == SDB_HOST) {
106                 obj = host;
107         }
108         else {
109                 obj = sdb_store_get_child(host, type, name);
110                 if ((! obj)
111                                 || (filter && (! sdb_store_matcher_matches(filter, obj, NULL)))) {
112                         sdb_strbuf_sprintf(errbuf, "Failed to fetch %s %s.%s: "
113                                         "%s not found", SDB_STORE_TYPE_TO_NAME(type),
114                                         hostname, name, name);
115                         if (obj)
116                                 sdb_object_deref(SDB_OBJ(obj));
117                         sdb_object_deref(SDB_OBJ(host));
118                         return -1;
119                 }
120                 sdb_object_deref(SDB_OBJ(host));
121         }
122         host = NULL;
124         f = sdb_store_json_formatter(buf, type, /* flags = */ 0);
125         if (! f) {
126                 char err[1024];
127                 sdb_log(SDB_LOG_ERR, "frontend: Failed to create "
128                                 "JSON formatter to handle FETCH command: %s",
129                                 sdb_strerror(errno, err, sizeof(err)));
131                 sdb_strbuf_sprintf(errbuf, "Out of memory");
132                 sdb_object_deref(SDB_OBJ(obj));
133                 return -1;
134         }
136         sdb_strbuf_memcpy(buf, &res_type, sizeof(uint32_t));
137         if (sdb_store_json_emit_full(f, obj, filter)) {
138                 sdb_log(SDB_LOG_ERR, "frontend: Failed to serialize "
139                                 "%s %s.%s to JSON", SDB_STORE_TYPE_TO_NAME(type),
140                                 hostname, name);
141                 sdb_strbuf_sprintf(errbuf, "Out of memory");
142                 sdb_object_deref(SDB_OBJ(f));
143                 sdb_object_deref(SDB_OBJ(obj));
144                 return -1;
145         }
147         sdb_object_deref(SDB_OBJ(obj));
148         sdb_store_json_finish(f);
149         sdb_object_deref(SDB_OBJ(f));
151         return SDB_CONNECTION_DATA;
152 } /* exec_fetch */
154 static int
155 exec_list(sdb_store_t *store, sdb_strbuf_t *buf, sdb_strbuf_t *errbuf,
156                 int type, sdb_store_matcher_t *filter)
158         uint32_t res_type = htonl(SDB_CONNECTION_LIST);
159         sdb_store_json_formatter_t *f;
161         f = sdb_store_json_formatter(buf, type, SDB_WANT_ARRAY);
162         if (! f) {
163                 char err[1024];
164                 sdb_log(SDB_LOG_ERR, "frontend: Failed to create "
165                                 "JSON formatter to handle LIST command: %s",
166                                 sdb_strerror(errno, err, sizeof(err)));
168                 sdb_strbuf_sprintf(errbuf, "Out of memory");
169                 return -1;
170         }
172         sdb_strbuf_memcpy(buf, &res_type, sizeof(uint32_t));
173         if (sdb_store_scan(store, type, /* m = */ NULL, filter, list_tojson, f)) {
174                 sdb_log(SDB_LOG_ERR, "frontend: Failed to serialize "
175                                 "store to JSON");
176                 sdb_strbuf_sprintf(errbuf, "Out of memory");
177                 sdb_object_deref(SDB_OBJ(f));
178                 return -1;
179         }
181         sdb_store_json_finish(f);
182         sdb_object_deref(SDB_OBJ(f));
184         return SDB_CONNECTION_DATA;
185 } /* exec_list */
187 static int
188 exec_lookup(sdb_store_t *store, sdb_strbuf_t *buf, sdb_strbuf_t *errbuf,
189                 int type, sdb_store_matcher_t *m, sdb_store_matcher_t *filter)
191         uint32_t res_type = htonl(SDB_CONNECTION_LOOKUP);
192         sdb_store_json_formatter_t *f;
194         f = sdb_store_json_formatter(buf, type, SDB_WANT_ARRAY);
195         if (! f) {
196                 char err[1024];
197                 sdb_log(SDB_LOG_ERR, "frontend: Failed to create "
198                                 "JSON formatter to handle LOOKUP command: %s",
199                                 sdb_strerror(errno, err, sizeof(err)));
201                 sdb_strbuf_sprintf(errbuf, "Out of memory");
202                 return -1;
203         }
205         sdb_strbuf_memcpy(buf, &res_type, sizeof(uint32_t));
207         if (sdb_store_scan(store, type, m, filter, lookup_tojson, f)) {
208                 sdb_log(SDB_LOG_ERR, "frontend: Failed to lookup %ss",
209                                 SDB_STORE_TYPE_TO_NAME(type));
210                 sdb_strbuf_sprintf(errbuf, "Failed to lookup %ss",
211                                 SDB_STORE_TYPE_TO_NAME(type));
212                 sdb_object_deref(SDB_OBJ(f));
213                 return -1;
214         }
216         sdb_store_json_finish(f);
217         sdb_object_deref(SDB_OBJ(f));
219         return SDB_CONNECTION_DATA;
220 } /* exec_lookup */
222 static int
223 exec_store(sdb_strbuf_t *buf, sdb_strbuf_t *errbuf, sdb_ast_store_t *st)
225         char name[sstrlen(st->hostname) + sstrlen(st->parent) + sstrlen(st->name) + 3];
226         sdb_metric_store_t metric_store;
227         int type = st->obj_type, status = -1;
229         switch (st->obj_type) {
230         case SDB_HOST:
231                 strncpy(name, st->name, sizeof(name));
232                 status = sdb_plugin_store_host(st->name, st->last_update);
233                 break;
235         case SDB_SERVICE:
236                 snprintf(name, sizeof(name), "%s.%s", st->hostname, st->name);
237                 status = sdb_plugin_store_service(st->hostname, st->name, st->last_update);
238                 break;
240         case SDB_METRIC:
241                 snprintf(name, sizeof(name), "%s.%s", st->hostname, st->name);
242                 metric_store.type = st->store_type;
243                 metric_store.id = st->store_id;
244                 status = sdb_plugin_store_metric(st->hostname, st->name,
245                                 &metric_store, st->last_update);
246                 break;
248         case SDB_ATTRIBUTE:
249                 type |= st->parent_type;
251                 if (st->parent)
252                         snprintf(name, sizeof(name), "%s.%s.%s",
253                                         st->hostname, st->parent, st->name);
254                 else
255                         snprintf(name, sizeof(name), "%s.%s", st->hostname, st->name);
257                 switch (st->parent_type) {
258                 case 0:
259                         type |= SDB_HOST;
260                         status = sdb_plugin_store_attribute(st->hostname,
261                                         st->name, &st->value, st->last_update);
262                         break;
264                 case SDB_SERVICE:
265                         status = sdb_plugin_store_service_attribute(st->hostname, st->parent,
266                                         st->name, &st->value, st->last_update);
267                         break;
269                 case SDB_METRIC:
270                         status = sdb_plugin_store_metric_attribute(st->hostname, st->parent,
271                                         st->name, &st->value, st->last_update);
272                         break;
274                 default:
275                         sdb_log(SDB_LOG_ERR, "store: Invalid parent type in STORE: %s",
276                                         SDB_STORE_TYPE_TO_NAME(st->parent_type));
277                         return -1;
278                 }
279                 break;
281         default:
282                 sdb_log(SDB_LOG_ERR, "store: Invalid object type in STORE: %s",
283                                 SDB_STORE_TYPE_TO_NAME(st->obj_type));
284                 return -1;
285         }
287         if (status < 0) {
288                 sdb_strbuf_sprintf(errbuf, "STORE: Failed to store %s object",
289                                 SDB_STORE_TYPE_TO_NAME(type));
290                 return -1;
291         }
293         if (! status) {
294                 sdb_strbuf_sprintf(buf, "Successfully stored %s %s",
295                                 SDB_STORE_TYPE_TO_NAME(type), name);
296         }
297         else {
298                 char type_str[32];
299                 strncpy(type_str, SDB_STORE_TYPE_TO_NAME(type), sizeof(type_str));
300                 type_str[0] = (char)toupper((int)type_str[0]);
301                 sdb_strbuf_sprintf(buf, "%s %s already up to date", type_str, name);
302         }
304         return SDB_CONNECTION_OK;
305 } /* exec_store */
307 static int
308 exec_timeseries(sdb_store_t *store, sdb_strbuf_t *buf, sdb_strbuf_t *errbuf,
309                 const char *hostname, const char *metric,
310                 sdb_timeseries_opts_t *opts)
312         uint32_t res_type = htonl(SDB_CONNECTION_TIMESERIES);
314         sdb_strbuf_memcpy(buf, &res_type, sizeof(uint32_t));
315         if (sdb_store_fetch_timeseries(store, hostname, metric, opts, buf)) {
316                 sdb_log(SDB_LOG_ERR, "frontend: Failed to fetch time-series");
317                 sdb_strbuf_sprintf(errbuf, "Failed to fetch time-series");
318                 return -1;
319         }
321         return SDB_CONNECTION_DATA;
322 } /* exec_timeseries */
324 /*
325  * public API
326  */
328 int
329 sdb_store_query_execute(sdb_store_t *store, sdb_store_query_t *q,
330                 sdb_strbuf_t *buf, sdb_strbuf_t *errbuf)
332         sdb_timeseries_opts_t ts_opts;
333         sdb_ast_node_t *ast;
335         if (! q)
336                 return -1;
337         if (! q->ast) {
338                 sdb_log(SDB_LOG_ERR, "store: Invalid empty query");
339                 return -1;
340         }
342         ast = q->ast;
343         switch (ast->type) {
344         case SDB_AST_TYPE_FETCH:
345                 return exec_fetch(store, buf, errbuf, SDB_AST_FETCH(ast)->obj_type,
346                                 SDB_AST_FETCH(ast)->hostname, SDB_AST_FETCH(ast)->name,
347                                 q->filter);
349         case SDB_AST_TYPE_LIST:
350                 return exec_list(store, buf, errbuf, SDB_AST_LIST(ast)->obj_type,
351                                 q->filter);
353         case SDB_AST_TYPE_LOOKUP:
354                 return exec_lookup(store, buf, errbuf, SDB_AST_LOOKUP(ast)->obj_type,
355                                 q->matcher, q->filter);
357         case SDB_AST_TYPE_STORE:
358                 if (ast->type != SDB_AST_TYPE_STORE) {
359                         sdb_log(SDB_LOG_ERR, "store: Invalid AST node for STORE command: %s",
360                                         SDB_AST_TYPE_TO_STRING(ast));
361                         return -1;
362                 }
363                 return exec_store(buf, errbuf, SDB_AST_STORE(ast));
365         case SDB_AST_TYPE_TIMESERIES:
366                 ts_opts.start = SDB_AST_TIMESERIES(ast)->start;
367                 ts_opts.end = SDB_AST_TIMESERIES(ast)->end;
368                 return exec_timeseries(store, buf, errbuf,
369                                 SDB_AST_TIMESERIES(ast)->hostname,
370                                 SDB_AST_TIMESERIES(ast)->metric, &ts_opts);
372         default:
373                 sdb_log(SDB_LOG_ERR, "store: Invalid query of type %s",
374                                 SDB_AST_TYPE_TO_STRING(ast));
375                 return -1;
376         }
378         return 0;
379 } /* sdb_store_query_execute */
381 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */