Code

Replaced sdb_store_<type> with sdb_plugin_store_<type>.
[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_strbuf_t *buf, sdb_strbuf_t *errbuf, int type,
75                 const char *hostname, const char *name, sdb_store_matcher_t *filter)
76 {
77         uint32_t res_type = htonl(SDB_CONNECTION_FETCH);
79         sdb_store_obj_t *host;
80         sdb_store_obj_t *obj;
82         sdb_store_json_formatter_t *f;
84         if ((! name) || ((type == SDB_HOST) && hostname)
85                         || ((type != SDB_HOST) && (! hostname))) {
86                 /* This is a programming error, not something the client did wrong */
87                 sdb_strbuf_sprintf(errbuf, "INTERNAL ERROR: invalid "
88                                 "arguments to FETCH(%s, %s, %s)",
89                                 SDB_STORE_TYPE_TO_NAME(type), hostname, name);
90                 return -1;
91         }
92         if (type == SDB_HOST)
93                 hostname = name;
95         host = sdb_store_get_host(hostname);
96         if ((! host)
97                         || (filter && (! sdb_store_matcher_matches(filter, host, NULL)))) {
98                 sdb_strbuf_sprintf(errbuf, "Failed to fetch %s %s: "
99                                 "host %s not found", SDB_STORE_TYPE_TO_NAME(type),
100                                 name, hostname);
101                 sdb_object_deref(SDB_OBJ(host));
102                 return -1;
103         }
104         if (type == SDB_HOST) {
105                 obj = host;
106         }
107         else {
108                 obj = sdb_store_get_child(host, type, name);
109                 if ((! obj)
110                                 || (filter && (! sdb_store_matcher_matches(filter, obj, NULL)))) {
111                         sdb_strbuf_sprintf(errbuf, "Failed to fetch %s %s.%s: "
112                                         "%s not found", SDB_STORE_TYPE_TO_NAME(type),
113                                         hostname, name, name);
114                         if (obj)
115                                 sdb_object_deref(SDB_OBJ(obj));
116                         sdb_object_deref(SDB_OBJ(host));
117                         return -1;
118                 }
119                 sdb_object_deref(SDB_OBJ(host));
120         }
121         host = NULL;
123         f = sdb_store_json_formatter(buf, type, /* flags = */ 0);
124         if (! f) {
125                 char err[1024];
126                 sdb_log(SDB_LOG_ERR, "frontend: Failed to create "
127                                 "JSON formatter to handle FETCH command: %s",
128                                 sdb_strerror(errno, err, sizeof(err)));
130                 sdb_strbuf_sprintf(errbuf, "Out of memory");
131                 sdb_object_deref(SDB_OBJ(obj));
132                 return -1;
133         }
135         sdb_strbuf_memcpy(buf, &res_type, sizeof(uint32_t));
136         if (sdb_store_json_emit_full(f, obj, filter)) {
137                 sdb_log(SDB_LOG_ERR, "frontend: Failed to serialize "
138                                 "%s %s.%s to JSON", SDB_STORE_TYPE_TO_NAME(type),
139                                 hostname, name);
140                 sdb_strbuf_sprintf(errbuf, "Out of memory");
141                 free(f);
142                 sdb_object_deref(SDB_OBJ(obj));
143                 return -1;
144         }
146         sdb_object_deref(SDB_OBJ(obj));
147         sdb_store_json_finish(f);
148         free(f);
150         return SDB_CONNECTION_DATA;
151 } /* exec_fetch */
153 static int
154 exec_list(sdb_strbuf_t *buf, sdb_strbuf_t *errbuf, int type,
155                 sdb_store_matcher_t *filter)
157         uint32_t res_type = htonl(SDB_CONNECTION_LIST);
158         sdb_store_json_formatter_t *f;
160         f = sdb_store_json_formatter(buf, type, SDB_WANT_ARRAY);
161         if (! f) {
162                 char err[1024];
163                 sdb_log(SDB_LOG_ERR, "frontend: Failed to create "
164                                 "JSON formatter to handle LIST command: %s",
165                                 sdb_strerror(errno, err, sizeof(err)));
167                 sdb_strbuf_sprintf(errbuf, "Out of memory");
168                 return -1;
169         }
171         sdb_strbuf_memcpy(buf, &res_type, sizeof(uint32_t));
172         if (sdb_store_scan(type, /* m = */ NULL, filter, list_tojson, f)) {
173                 sdb_log(SDB_LOG_ERR, "frontend: Failed to serialize "
174                                 "store to JSON");
175                 sdb_strbuf_sprintf(errbuf, "Out of memory");
176                 free(f);
177                 return -1;
178         }
180         sdb_store_json_finish(f);
181         free(f);
183         return SDB_CONNECTION_DATA;
184 } /* exec_list */
186 static int
187 exec_lookup(sdb_strbuf_t *buf, sdb_strbuf_t *errbuf, int type,
188                 sdb_store_matcher_t *m, sdb_store_matcher_t *filter)
190         uint32_t res_type = htonl(SDB_CONNECTION_LOOKUP);
191         sdb_store_json_formatter_t *f;
193         f = sdb_store_json_formatter(buf, type, SDB_WANT_ARRAY);
194         if (! f) {
195                 char err[1024];
196                 sdb_log(SDB_LOG_ERR, "frontend: Failed to create "
197                                 "JSON formatter to handle LOOKUP command: %s",
198                                 sdb_strerror(errno, err, sizeof(err)));
200                 sdb_strbuf_sprintf(errbuf, "Out of memory");
201                 return -1;
202         }
204         sdb_strbuf_memcpy(buf, &res_type, sizeof(uint32_t));
206         if (sdb_store_scan(type, m, filter, lookup_tojson, f)) {
207                 sdb_log(SDB_LOG_ERR, "frontend: Failed to lookup %ss",
208                                 SDB_STORE_TYPE_TO_NAME(type));
209                 sdb_strbuf_sprintf(errbuf, "Failed to lookup %ss",
210                                 SDB_STORE_TYPE_TO_NAME(type));
211                 free(f);
212                 return -1;
213         }
215         sdb_store_json_finish(f);
216         free(f);
218         return SDB_CONNECTION_DATA;
219 } /* exec_lookup */
221 static int
222 exec_store(sdb_strbuf_t *buf, sdb_strbuf_t *errbuf, sdb_ast_store_t *st)
224         char name[sstrlen(st->hostname) + sstrlen(st->parent) + sstrlen(st->name) + 3];
225         sdb_metric_store_t metric_store;
226         int type = st->obj_type, status = -1;
228         switch (st->obj_type) {
229         case SDB_HOST:
230                 strncpy(name, st->name, sizeof(name));
231                 status = sdb_plugin_store_host(st->name, st->last_update);
232                 break;
234         case SDB_SERVICE:
235                 snprintf(name, sizeof(name), "%s.%s", st->hostname, st->name);
236                 status = sdb_plugin_store_service(st->hostname, st->name, st->last_update);
237                 break;
239         case SDB_METRIC:
240                 snprintf(name, sizeof(name), "%s.%s", st->hostname, st->name);
241                 metric_store.type = st->store_type;
242                 metric_store.id = st->store_id;
243                 status = sdb_plugin_store_metric(st->hostname, st->name,
244                                 &metric_store, st->last_update);
245                 break;
247         case SDB_ATTRIBUTE:
248                 type |= st->parent_type;
250                 if (st->parent)
251                         snprintf(name, sizeof(name), "%s.%s.%s",
252                                         st->hostname, st->parent, st->name);
253                 else
254                         snprintf(name, sizeof(name), "%s.%s", st->hostname, st->name);
256                 switch (st->parent_type) {
257                 case 0:
258                         type |= SDB_HOST;
259                         status = sdb_plugin_store_attribute(st->hostname,
260                                         st->name, &st->value, st->last_update);
261                         break;
263                 case SDB_SERVICE:
264                         status = sdb_plugin_store_service_attribute(st->hostname, st->parent,
265                                         st->name, &st->value, st->last_update);
266                         break;
268                 case SDB_METRIC:
269                         status = sdb_plugin_store_metric_attribute(st->hostname, st->parent,
270                                         st->name, &st->value, st->last_update);
271                         break;
273                 default:
274                         sdb_log(SDB_LOG_ERR, "store: Invalid parent type in STORE: %s",
275                                         SDB_STORE_TYPE_TO_NAME(st->parent_type));
276                         return -1;
277                 }
278                 break;
280         default:
281                 sdb_log(SDB_LOG_ERR, "store: Invalid object type in STORE: %s",
282                                 SDB_STORE_TYPE_TO_NAME(st->obj_type));
283                 return -1;
284         }
286         if (status < 0) {
287                 sdb_strbuf_sprintf(errbuf, "STORE: Failed to store %s object",
288                                 SDB_STORE_TYPE_TO_NAME(type));
289                 return -1;
290         }
292         if (! status) {
293                 sdb_strbuf_sprintf(buf, "Successfully stored %s %s",
294                                 SDB_STORE_TYPE_TO_NAME(type), name);
295         }
296         else {
297                 char type_str[32];
298                 strncpy(type_str, SDB_STORE_TYPE_TO_NAME(type), sizeof(type_str));
299                 type_str[0] = (char)toupper((int)type_str[0]);
300                 sdb_strbuf_sprintf(buf, "%s %s already up to date", type_str, name);
301         }
303         return SDB_CONNECTION_OK;
304 } /* exec_store */
306 static int
307 exec_timeseries(sdb_strbuf_t *buf, sdb_strbuf_t *errbuf,
308                 const char *hostname, const char *metric,
309                 sdb_timeseries_opts_t *opts)
311         uint32_t res_type = htonl(SDB_CONNECTION_TIMESERIES);
313         sdb_strbuf_memcpy(buf, &res_type, sizeof(uint32_t));
314         if (sdb_store_fetch_timeseries(hostname, metric, opts, buf)) {
315                 sdb_log(SDB_LOG_ERR, "frontend: Failed to fetch time-series");
316                 sdb_strbuf_sprintf(errbuf, "Failed to fetch time-series");
317                 return -1;
318         }
320         return SDB_CONNECTION_DATA;
321 } /* exec_timeseries */
323 /*
324  * public API
325  */
327 int
328 sdb_store_query_execute(sdb_store_query_t *m,
329                 sdb_strbuf_t *buf, sdb_strbuf_t *errbuf)
331         sdb_timeseries_opts_t ts_opts;
332         sdb_ast_node_t *ast;
334         if (! m)
335                 return -1;
336         if (! QUERY(m)->ast) {
337                 sdb_log(SDB_LOG_ERR, "store: Invalid empty query");
338                 return -1;
339         }
341         ast = QUERY(m)->ast;
342         switch (ast->type) {
343         case SDB_AST_TYPE_FETCH:
344                 return exec_fetch(buf, errbuf, SDB_AST_FETCH(ast)->obj_type,
345                                 SDB_AST_FETCH(ast)->hostname, SDB_AST_FETCH(ast)->name,
346                                 QUERY(m)->filter);
348         case SDB_AST_TYPE_LIST:
349                 return exec_list(buf, errbuf, SDB_AST_LIST(ast)->obj_type,
350                                 QUERY(m)->filter);
352         case SDB_AST_TYPE_LOOKUP:
353                 return exec_lookup(buf, errbuf, SDB_AST_LOOKUP(ast)->obj_type,
354                                 QUERY(m)->matcher, QUERY(m)->filter);
356         case SDB_AST_TYPE_STORE:
357                 if (ast->type != SDB_AST_TYPE_STORE) {
358                         sdb_log(SDB_LOG_ERR, "store: Invalid AST node for STORE command: %s",
359                                         SDB_AST_TYPE_TO_STRING(ast));
360                         return -1;
361                 }
362                 return exec_store(buf, errbuf, SDB_AST_STORE(ast));
364         case SDB_AST_TYPE_TIMESERIES:
365                 ts_opts.start = SDB_AST_TIMESERIES(ast)->start;
366                 ts_opts.end = SDB_AST_TIMESERIES(ast)->end;
367                 return exec_timeseries(buf, errbuf, SDB_AST_TIMESERIES(ast)->hostname,
368                                 SDB_AST_TIMESERIES(ast)->metric, &ts_opts);
370         default:
371                 sdb_log(SDB_LOG_ERR, "store: Invalid query of type %s",
372                                 SDB_AST_TYPE_TO_STRING(ast));
373                 return -1;
374         }
376         return 0;
377 } /* sdb_store_query_execute */
379 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */