1 /*
2 * SysDB - src/plugins/backend/store/network.c
3 * Copyright (C) 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 #if HAVE_CONFIG_H
29 # include "config.h"
30 #endif
32 #include "sysdb.h"
33 #include "core/plugin.h"
34 #include "client/sock.h"
35 #include "utils/error.h"
36 #include "utils/proto.h"
37 #include "utils/os.h"
39 #include "liboconfig/utils.h"
41 #include <errno.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <strings.h>
47 SDB_PLUGIN_MAGIC;
49 /*
50 * private data types
51 */
53 typedef struct {
54 sdb_client_t *client;
55 char *addr;
56 char *username;
57 } user_data_t;
58 #define UD(obj) ((user_data_t *)(obj))
59 #define CLIENT(obj) UD(SDB_OBJ_WRAPPER(obj)->data)->client
61 static void
62 user_data_destroy(void *obj)
63 {
64 user_data_t *ud = UD(obj);
66 if (! ud)
67 return;
69 if (ud->client)
70 sdb_client_destroy(ud->client);
71 ud->client = NULL;
72 if (ud->addr)
73 free(ud->addr);
74 ud->addr = NULL;
75 if (ud->username)
76 free(ud->username);
77 ud->username = NULL;
79 free(ud);
80 } /* user_data_destroy */
82 /*
83 * store writer implementation
84 */
86 static int
87 store_rpc(sdb_client_t *client, const char *msg, size_t msg_len)
88 {
89 sdb_strbuf_t *buf = sdb_strbuf_create(128);
90 uint32_t rstatus = 0;
91 ssize_t status;
93 status = sdb_client_rpc(client, SDB_CONNECTION_STORE,
94 (uint32_t)msg_len, msg, &rstatus, buf);
95 if (status < 0)
96 sdb_log(SDB_LOG_ERR, "store::network: %s", sdb_strbuf_string(buf));
97 else if (rstatus != SDB_CONNECTION_OK) {
98 sdb_log(SDB_LOG_ERR, "store::network: Failed to send object: %s",
99 sdb_strbuf_string(buf));
100 status = -1;
101 }
103 sdb_strbuf_destroy(buf);
104 if (status < 0)
105 return -1;
106 return 0;
107 } /* store_rpc */
109 static int
110 store_host(const char *name, sdb_time_t last_update, sdb_object_t *user_data)
111 {
112 sdb_proto_host_t host = { last_update, name };
113 size_t len = sdb_proto_marshal_host(NULL, 0, &host);
114 char buf[len];
116 sdb_proto_marshal_host(buf, len, &host);
117 return store_rpc(CLIENT(user_data), buf, len);
118 } /* store_host */
120 static int
121 store_service(const char *hostname, const char *name, sdb_time_t last_update,
122 sdb_object_t *user_data)
123 {
124 sdb_proto_service_t svc = { last_update, hostname, name };
125 ssize_t len = sdb_proto_marshal_service(NULL, 0, &svc);
126 char buf[len];
128 sdb_proto_marshal_service(buf, len, &svc);
129 return store_rpc(CLIENT(user_data), buf, len);
130 } /* store_service */
132 static int
133 store_metric(const char *hostname, const char *name,
134 sdb_metric_store_t *store, sdb_time_t last_update,
135 sdb_object_t *user_data)
136 {
137 sdb_proto_metric_t metric = {
138 last_update, hostname, name,
139 store ? store->type : NULL, store ? store->id : NULL,
140 };
141 size_t len = sdb_proto_marshal_metric(NULL, 0, &metric);
142 char buf[len];
144 sdb_proto_marshal_metric(buf, len, &metric);
145 return store_rpc(CLIENT(user_data), buf, len);
146 } /* store_metric */
148 static int
149 store_attr(const char *hostname, const char *key, const sdb_data_t *value,
150 sdb_time_t last_update, sdb_object_t *user_data)
151 {
152 sdb_proto_attribute_t attr = {
153 last_update, SDB_HOST, NULL, hostname, key, *value,
154 };
155 size_t len = sdb_proto_marshal_attribute(NULL, 0, &attr);
156 char buf[len];
158 sdb_proto_marshal_attribute(buf, len, &attr);
159 return store_rpc(CLIENT(user_data), buf, len);
160 } /* store_attr */
162 static int
163 store_service_attr(const char *hostname, const char *service,
164 const char *key, const sdb_data_t *value, sdb_time_t last_update,
165 sdb_object_t *user_data)
166 {
167 sdb_proto_attribute_t attr = {
168 last_update, SDB_SERVICE, hostname, service, key, *value,
169 };
170 size_t len = sdb_proto_marshal_attribute(NULL, 0, &attr);
171 char buf[len];
173 sdb_proto_marshal_attribute(buf, len, &attr);
174 return store_rpc(CLIENT(user_data), buf, len);
175 } /* store_service_attr */
177 static int
178 store_metric_attr(const char *hostname, const char *metric,
179 const char *key, const sdb_data_t *value, sdb_time_t last_update,
180 sdb_object_t *user_data)
181 {
182 sdb_proto_attribute_t attr = {
183 last_update, SDB_METRIC, hostname, metric, key, *value,
184 };
185 size_t len = sdb_proto_marshal_attribute(NULL, 0, &attr);
186 char buf[len];
188 sdb_proto_marshal_attribute(buf, len, &attr);
189 return store_rpc(CLIENT(user_data), buf, len);
190 } /* store_metric_attr */
192 static sdb_store_writer_t store_impl = {
193 store_host, store_service, store_metric,
194 store_attr, store_service_attr, store_metric_attr,
195 };
197 /*
198 * plugin API
199 */
201 static int
202 store_init(sdb_object_t *user_data)
203 {
204 user_data_t *ud;
206 if (! user_data)
207 return -1;
209 ud = SDB_OBJ_WRAPPER(user_data)->data;
210 if (sdb_client_connect(ud->client, ud->username)) {
211 sdb_log(SDB_LOG_ERR, "store::network: Failed to connect "
212 "to SysDB at %s as user %s", ud->addr, ud->username);
213 return -1;
214 }
216 sdb_log(SDB_LOG_ERR, "store::network: Successfully connected "
217 "to SysDB at %s as user %s", ud->addr, ud->username);
218 return 0;
219 } /* store_init */
221 static int
222 store_config_server(oconfig_item_t *ci)
223 {
224 sdb_object_t *user_data;
225 user_data_t *ud;
227 int i;
229 ud = calloc(1, sizeof(*ud));
230 if (! ud) {
231 char errbuf[1024];
232 sdb_log(SDB_LOG_ERR, "store::network: Failed to allocate "
233 "a user-data object: %s",
234 sdb_strerror(errno, errbuf, sizeof(errbuf)));
235 return -1;
236 }
238 if (oconfig_get_string(ci, &ud->addr)) {
239 sdb_log(SDB_LOG_ERR, "store::network: Server requires "
240 "a single string argument\n\tUsage: <Server ADDRESS>");
241 user_data_destroy(ud);
242 return -1;
243 }
244 ud->addr = strdup(ud->addr);
245 if (! ud->addr) {
246 sdb_log(SDB_LOG_ERR, "store::network: Failed to duplicate "
247 "a string");
248 user_data_destroy(ud);
249 return -1;
250 }
252 ud->client = sdb_client_create(ud->addr);
253 if (! ud->client) {
254 char errbuf[1024];
255 sdb_log(SDB_LOG_ERR, "store::network: Failed to create client "
256 "connecting to '%s': %s", ud->addr,
257 sdb_strerror(errno, errbuf, sizeof(errbuf)));
258 user_data_destroy(ud);
259 return -1;
260 }
262 for (i = 0; i < ci->children_num; ++i) {
263 oconfig_item_t *child = ci->children + i;
265 if (! strcasecmp(child->key, "Username"))
266 oconfig_get_string(child, &ud->username);
267 else
268 sdb_log(SDB_LOG_WARNING, "store::network: Ignoring "
269 "unknown config option '%s' inside <Server %s>.",
270 child->key, ud->addr);
271 }
273 if (ud->username)
274 ud->username = strdup(ud->username);
275 if (! ud->username)
276 ud->username = sdb_get_current_user();
278 user_data = sdb_object_create_wrapper("store-network-userdata", ud,
279 user_data_destroy);
280 if (! user_data) {
281 char errbuf[1024];
282 sdb_log(SDB_LOG_ERR, "store::network: Failed to allocate "
283 "a user-data wrapper object: %s",
284 sdb_strerror(errno, errbuf, sizeof(errbuf)));
285 user_data_destroy(ud);
286 return -1;
287 }
289 sdb_plugin_register_init(ud->addr, store_init, user_data);
290 sdb_plugin_register_writer(ud->addr, &store_impl, user_data);
291 sdb_object_deref(user_data);
292 return 0;
293 } /* store_config_server */
295 static int
296 store_config(oconfig_item_t *ci)
297 {
298 int i;
300 if (! ci) /* nothing to do to deconfigure this plugin */
301 return 0;
303 for (i = 0; i < ci->children_num; ++i) {
304 oconfig_item_t *child = ci->children + i;
306 if (! strcasecmp(child->key, "Server"))
307 store_config_server(child);
308 else
309 sdb_log(SDB_LOG_WARNING, "store::network: Ignoring "
310 "unknown config option '%s'.", child->key);
311 }
312 return 0;
313 } /* store_config */
315 int
316 sdb_module_init(sdb_plugin_info_t *info)
317 {
318 sdb_plugin_set_info(info, SDB_PLUGIN_INFO_DESC,
319 "send stored objects to a remote SysDB instance");
320 sdb_plugin_set_info(info, SDB_PLUGIN_INFO_COPYRIGHT,
321 "Copyright (C) 2015 Sebastian 'tokkee' Harl <sh@tokkee.org>");
322 sdb_plugin_set_info(info, SDB_PLUGIN_INFO_LICENSE, "BSD");
323 sdb_plugin_set_info(info, SDB_PLUGIN_INFO_VERSION, SDB_VERSION);
324 sdb_plugin_set_info(info, SDB_PLUGIN_INFO_PLUGIN_VERSION, SDB_VERSION);
326 sdb_plugin_register_config(store_config);
327 return 0;
328 } /* sdb_module_init */
330 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */