/src/fluent-bit/plugins/out_chronicle/chronicle_conf.c
Line | Count | Source |
1 | | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | |
3 | | /* Fluent Bit |
4 | | * ========== |
5 | | * Copyright (C) 2015-2026 The Fluent Bit Authors |
6 | | * |
7 | | * Licensed under the Apache License, Version 2.0 (the "License"); |
8 | | * you may not use this file except in compliance with the License. |
9 | | * You may obtain a copy of the License at |
10 | | * |
11 | | * http://www.apache.org/licenses/LICENSE-2.0 |
12 | | * |
13 | | * Unless required by applicable law or agreed to in writing, software |
14 | | * distributed under the License is distributed on an "AS IS" BASIS, |
15 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
16 | | * See the License for the specific language governing permissions and |
17 | | * limitations under the License. |
18 | | */ |
19 | | |
20 | | #include <fluent-bit/flb_output_plugin.h> |
21 | | #include <fluent-bit/flb_unescape.h> |
22 | | #include <fluent-bit/flb_jsmn.h> |
23 | | #include <fluent-bit/flb_pack.h> |
24 | | #include <fluent-bit/flb_utils.h> |
25 | | #include <fluent-bit/flb_aws_credentials.h> |
26 | | #include <fluent-bit/flb_slist.h> |
27 | | |
28 | | #include <ctype.h> |
29 | | #include <sys/types.h> |
30 | | #include <sys/stat.h> |
31 | | |
32 | | #include "chronicle.h" |
33 | | #include "chronicle_conf.h" |
34 | | |
35 | | |
36 | 0 | static inline int key_cmp(char *str, int len, char *cmp) { |
37 | |
|
38 | 0 | if (strlen(cmp) != len) { |
39 | 0 | return -1; |
40 | 0 | } |
41 | | |
42 | 0 | return strncasecmp(str, cmp, len); |
43 | 0 | } |
44 | | |
45 | | static void chronicle_labels_destroy(struct flb_chronicle *ctx) |
46 | 0 | { |
47 | 0 | struct mk_list *head; |
48 | 0 | struct mk_list *tmp; |
49 | 0 | struct flb_chronicle_label *label; |
50 | |
|
51 | 0 | mk_list_foreach_safe(head, tmp, &ctx->labels) { |
52 | 0 | label = mk_list_entry(head, struct flb_chronicle_label, _head); |
53 | 0 | mk_list_del(&label->_head); |
54 | |
|
55 | 0 | flb_sds_destroy(label->key); |
56 | 0 | flb_sds_destroy(label->value); |
57 | |
|
58 | 0 | if (label->ra) { |
59 | 0 | flb_ra_destroy(label->ra); |
60 | 0 | } |
61 | |
|
62 | 0 | flb_free(label); |
63 | 0 | } |
64 | 0 | } |
65 | | |
66 | | static int chronicle_label_add(struct flb_chronicle *ctx, |
67 | | char *key, size_t key_len, |
68 | | char *value, size_t value_len) |
69 | 0 | { |
70 | 0 | struct flb_chronicle_label *label; |
71 | |
|
72 | 0 | if (key == NULL || key_len == 0 || value == NULL) { |
73 | 0 | flb_plg_error(ctx->ins, "label requires a non-empty key and value"); |
74 | 0 | return -1; |
75 | 0 | } |
76 | | |
77 | 0 | label = flb_calloc(1, sizeof(struct flb_chronicle_label)); |
78 | 0 | if (!label) { |
79 | 0 | flb_errno(); |
80 | 0 | return -1; |
81 | 0 | } |
82 | | |
83 | 0 | label->key = flb_sds_create_len(key, key_len); |
84 | 0 | if (!label->key) { |
85 | 0 | flb_free(label); |
86 | 0 | return -1; |
87 | 0 | } |
88 | | |
89 | 0 | label->value = flb_sds_create_len(value, value_len); |
90 | 0 | if (!label->value) { |
91 | 0 | flb_sds_destroy(label->key); |
92 | 0 | flb_free(label); |
93 | 0 | return -1; |
94 | 0 | } |
95 | | |
96 | 0 | if (memchr(value, '$', value_len) != NULL) { |
97 | 0 | label->ra = flb_ra_create(label->value, FLB_FALSE); |
98 | 0 | if (!label->ra) { |
99 | 0 | flb_plg_error(ctx->ins, "invalid label record accessor '%s'", |
100 | 0 | label->value); |
101 | 0 | flb_sds_destroy(label->key); |
102 | 0 | flb_sds_destroy(label->value); |
103 | 0 | flb_free(label); |
104 | 0 | return -1; |
105 | 0 | } |
106 | 0 | } |
107 | | |
108 | 0 | mk_list_add(&label->_head, &ctx->labels); |
109 | 0 | return 0; |
110 | 0 | } |
111 | | |
112 | | static int chronicle_label_exists(struct flb_chronicle *ctx, flb_sds_t key) |
113 | 0 | { |
114 | 0 | struct mk_list *head; |
115 | 0 | struct flb_chronicle_label *label; |
116 | |
|
117 | 0 | mk_list_foreach(head, &ctx->labels) { |
118 | 0 | label = mk_list_entry(head, struct flb_chronicle_label, _head); |
119 | |
|
120 | 0 | if (flb_sds_len(label->key) == flb_sds_len(key) && |
121 | 0 | strncmp(label->key, key, flb_sds_len(key)) == 0) { |
122 | 0 | return FLB_TRUE; |
123 | 0 | } |
124 | 0 | } |
125 | | |
126 | 0 | return FLB_FALSE; |
127 | 0 | } |
128 | | |
129 | | static int chronicle_configure_labels(struct flb_chronicle *ctx) |
130 | 0 | { |
131 | 0 | int ret; |
132 | 0 | struct mk_list *head; |
133 | 0 | struct flb_config_map_val *mv; |
134 | 0 | struct flb_slist_entry *key; |
135 | 0 | struct flb_slist_entry *val; |
136 | |
|
137 | 0 | if (ctx->label_properties) { |
138 | 0 | flb_config_map_foreach(head, mv, ctx->label_properties) { |
139 | 0 | if (mk_list_size(mv->val.list) != 2) { |
140 | 0 | flb_plg_error(ctx->ins, "'label' expects a key and a value"); |
141 | 0 | return -1; |
142 | 0 | } |
143 | | |
144 | 0 | key = mk_list_entry_first(mv->val.list, |
145 | 0 | struct flb_slist_entry, _head); |
146 | 0 | val = mk_list_entry_last(mv->val.list, |
147 | 0 | struct flb_slist_entry, _head); |
148 | | |
149 | | /* The Chronicle API sends labels as a map keyed by label name */ |
150 | 0 | if (ctx->api == FLB_CHRONICLE_API_CHRONICLE && |
151 | 0 | chronicle_label_exists(ctx, key->str) == FLB_TRUE) { |
152 | 0 | flb_plg_error(ctx->ins, "duplicate label '%s' is not supported " |
153 | 0 | "by the Chronicle API", key->str); |
154 | 0 | return -1; |
155 | 0 | } |
156 | | |
157 | 0 | ret = chronicle_label_add(ctx, |
158 | 0 | key->str, flb_sds_len(key->str), |
159 | 0 | val->str, flb_sds_len(val->str)); |
160 | 0 | if (ret != 0) { |
161 | 0 | return -1; |
162 | 0 | } |
163 | 0 | } |
164 | 0 | } |
165 | | |
166 | 0 | return 0; |
167 | 0 | } |
168 | | |
169 | | static int flb_chronicle_read_credentials_file(struct flb_chronicle *ctx, |
170 | | char *creds, |
171 | | struct flb_chronicle_oauth_credentials *ctx_creds) |
172 | 0 | { |
173 | 0 | int i; |
174 | 0 | int ret; |
175 | 0 | int len; |
176 | 0 | int key_len; |
177 | 0 | int val_len; |
178 | 0 | int tok_size = 32; |
179 | 0 | char *buf; |
180 | 0 | char *key; |
181 | 0 | char *val; |
182 | 0 | flb_sds_t tmp; |
183 | 0 | struct stat st; |
184 | 0 | jsmn_parser parser; |
185 | 0 | jsmntok_t *t; |
186 | 0 | jsmntok_t *tokens; |
187 | | |
188 | | /* Validate credentials path */ |
189 | 0 | ret = stat(creds, &st); |
190 | 0 | if (ret == -1) { |
191 | 0 | flb_errno(); |
192 | 0 | flb_plg_error(ctx->ins, "cannot open credentials file: %s", |
193 | 0 | creds); |
194 | 0 | return -1; |
195 | 0 | } |
196 | | |
197 | 0 | if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) { |
198 | 0 | flb_plg_error(ctx->ins, "credentials file " |
199 | 0 | "is not a valid file: %s", creds); |
200 | 0 | return -1; |
201 | 0 | } |
202 | | |
203 | | /* Read file content */ |
204 | 0 | buf = mk_file_to_buffer(creds); |
205 | 0 | if (!buf) { |
206 | 0 | flb_plg_error(ctx->ins, "error reading credentials file: %s", |
207 | 0 | creds); |
208 | 0 | return -1; |
209 | 0 | } |
210 | | |
211 | | /* Parse content */ |
212 | 0 | jsmn_init(&parser); |
213 | 0 | tokens = flb_calloc(1, sizeof(jsmntok_t) * tok_size); |
214 | 0 | if (!tokens) { |
215 | 0 | flb_errno(); |
216 | 0 | flb_free(buf); |
217 | 0 | return -1; |
218 | 0 | } |
219 | | |
220 | 0 | ret = jsmn_parse(&parser, buf, st.st_size, tokens, tok_size); |
221 | 0 | if (ret <= 0) { |
222 | 0 | flb_plg_error(ctx->ins, "invalid JSON credentials file: %s", |
223 | 0 | creds); |
224 | 0 | flb_free(buf); |
225 | 0 | flb_free(tokens); |
226 | 0 | return -1; |
227 | 0 | } |
228 | | |
229 | 0 | t = &tokens[0]; |
230 | 0 | if (t->type != JSMN_OBJECT) { |
231 | 0 | flb_plg_error(ctx->ins, "invalid JSON map on file: %s", |
232 | 0 | creds); |
233 | 0 | flb_free(buf); |
234 | 0 | flb_free(tokens); |
235 | 0 | return -1; |
236 | 0 | } |
237 | | |
238 | | /* Parse JSON tokens */ |
239 | 0 | for (i = 1; i < ret; i++) { |
240 | 0 | t = &tokens[i]; |
241 | 0 | if (t->type != JSMN_STRING) { |
242 | 0 | continue; |
243 | 0 | } |
244 | | |
245 | 0 | if (t->start == -1 || t->end == -1 || (t->start == 0 && t->end == 0)){ |
246 | 0 | break; |
247 | 0 | } |
248 | | |
249 | | /* Key */ |
250 | 0 | key = buf + t->start; |
251 | 0 | key_len = (t->end - t->start); |
252 | | |
253 | | /* Value */ |
254 | 0 | i++; |
255 | 0 | t = &tokens[i]; |
256 | 0 | val = buf + t->start; |
257 | 0 | val_len = (t->end - t->start); |
258 | |
|
259 | 0 | if (key_cmp(key, key_len, "type") == 0) { |
260 | 0 | ctx_creds->type = flb_sds_create_len(val, val_len); |
261 | 0 | } |
262 | 0 | else if (key_cmp(key, key_len, "project_id") == 0) { |
263 | 0 | ctx_creds->project_id = flb_sds_create_len(val, val_len); |
264 | 0 | } |
265 | 0 | else if (key_cmp(key, key_len, "private_key_id") == 0) { |
266 | 0 | ctx_creds->private_key_id = flb_sds_create_len(val, val_len); |
267 | 0 | } |
268 | 0 | else if (key_cmp(key, key_len, "private_key") == 0) { |
269 | 0 | tmp = flb_sds_create_len(val, val_len); |
270 | 0 | if (tmp) { |
271 | | /* Unescape private key */ |
272 | 0 | len = flb_sds_len(tmp); |
273 | 0 | ctx_creds->private_key = flb_sds_create_size(len); |
274 | 0 | flb_unescape_string(tmp, len, |
275 | 0 | &ctx_creds->private_key); |
276 | 0 | flb_sds_destroy(tmp); |
277 | 0 | } |
278 | 0 | } |
279 | 0 | else if (key_cmp(key, key_len, "client_email") == 0) { |
280 | 0 | ctx_creds->client_email = flb_sds_create_len(val, val_len); |
281 | 0 | } |
282 | 0 | else if (key_cmp(key, key_len, "client_id") == 0) { |
283 | 0 | ctx_creds->client_id = flb_sds_create_len(val, val_len); |
284 | 0 | } |
285 | 0 | else if (key_cmp(key, key_len, "auth_uri") == 0) { |
286 | 0 | ctx_creds->auth_uri = flb_sds_create_len(val, val_len); |
287 | 0 | } |
288 | 0 | else if (key_cmp(key, key_len, "token_uri") == 0) { |
289 | 0 | ctx_creds->token_uri = flb_sds_create_len(val, val_len); |
290 | 0 | } |
291 | 0 | } |
292 | |
|
293 | 0 | flb_free(buf); |
294 | 0 | flb_free(tokens); |
295 | |
|
296 | 0 | return 0; |
297 | 0 | } |
298 | | |
299 | | /* Check that a value can be used as-is as a segment of the request path */ |
300 | | static int chronicle_api_check_path_segment(struct flb_chronicle *ctx, |
301 | | const char *name, flb_sds_t value) |
302 | 0 | { |
303 | 0 | size_t i; |
304 | 0 | char c; |
305 | |
|
306 | 0 | if (flb_sds_len(value) == 0) { |
307 | 0 | flb_plg_error(ctx->ins, "property '%s' cannot be empty", name); |
308 | 0 | return -1; |
309 | 0 | } |
310 | | |
311 | 0 | for (i = 0; i < flb_sds_len(value); i++) { |
312 | 0 | c = value[i]; |
313 | 0 | if (!isalnum((unsigned char) c) && |
314 | 0 | c != '-' && c != '.' && c != '_' && c != '~' && c != ':') { |
315 | 0 | flb_plg_error(ctx->ins, "property '%s' has an invalid character: '%s'", |
316 | 0 | name, value); |
317 | 0 | return -1; |
318 | 0 | } |
319 | 0 | } |
320 | | |
321 | 0 | return 0; |
322 | 0 | } |
323 | | |
324 | | /* Compose the base URI and the logs:import endpoint for the Chronicle API */ |
325 | | static int chronicle_api_configure(struct flb_chronicle *ctx) |
326 | 0 | { |
327 | 0 | size_t i; |
328 | 0 | char c; |
329 | 0 | flb_sds_t tmp; |
330 | | |
331 | | /* The region is the location of the Google SecOps instance, e.g: 'us' */ |
332 | 0 | if (ctx->region == NULL) { |
333 | 0 | ctx->location = flb_sds_create(FLB_CHRONICLE_API_DEFAULT_LOCATION); |
334 | 0 | } |
335 | 0 | else { |
336 | 0 | ctx->location = flb_sds_create(ctx->region); |
337 | 0 | } |
338 | 0 | if (!ctx->location) { |
339 | 0 | flb_errno(); |
340 | 0 | return -1; |
341 | 0 | } |
342 | | |
343 | | /* The location is also part of the hostname */ |
344 | 0 | if (flb_sds_len(ctx->location) == 0) { |
345 | 0 | flb_plg_error(ctx->ins, "property 'region' cannot be empty"); |
346 | 0 | return -1; |
347 | 0 | } |
348 | | |
349 | 0 | for (i = 0; i < flb_sds_len(ctx->location); i++) { |
350 | 0 | c = tolower((unsigned char) ctx->location[i]); |
351 | 0 | if (!isalnum((unsigned char) c) && c != '-') { |
352 | 0 | flb_plg_error(ctx->ins, "invalid region '%s' for the Chronicle API", |
353 | 0 | ctx->region); |
354 | 0 | return -1; |
355 | 0 | } |
356 | 0 | ctx->location[i] = c; |
357 | 0 | } |
358 | | |
359 | 0 | if (chronicle_api_check_path_segment(ctx, "project_id", ctx->project_id) != 0 || |
360 | 0 | chronicle_api_check_path_segment(ctx, "customer_id", ctx->customer_id) != 0 || |
361 | 0 | chronicle_api_check_path_segment(ctx, "log_type", ctx->log_type) != 0) { |
362 | 0 | return -1; |
363 | 0 | } |
364 | | |
365 | 0 | ctx->uri = flb_sds_create_size(64); |
366 | 0 | if (!ctx->uri) { |
367 | 0 | flb_errno(); |
368 | 0 | return -1; |
369 | 0 | } |
370 | | |
371 | 0 | tmp = flb_sds_printf(&ctx->uri, FLB_CHRONICLE_API_URL_BASE, ctx->location); |
372 | 0 | if (!tmp) { |
373 | 0 | return -1; |
374 | 0 | } |
375 | | |
376 | 0 | ctx->endpoint = flb_sds_create_size(256); |
377 | 0 | if (!ctx->endpoint) { |
378 | 0 | flb_errno(); |
379 | 0 | return -1; |
380 | 0 | } |
381 | | |
382 | 0 | tmp = flb_sds_printf(&ctx->endpoint, FLB_CHRONICLE_API_IMPORT_ENDPOINT, |
383 | 0 | ctx->project_id, ctx->location, |
384 | 0 | ctx->customer_id, ctx->log_type); |
385 | 0 | if (!tmp) { |
386 | 0 | return -1; |
387 | 0 | } |
388 | | |
389 | 0 | ctx->max_payload_size = FLB_CHRONICLE_API_MAX_PAYLOAD_SIZE; |
390 | |
|
391 | 0 | return 0; |
392 | 0 | } |
393 | | |
394 | | struct flb_chronicle *flb_chronicle_conf_create(struct flb_output_instance *ins, |
395 | | struct flb_config *config) |
396 | 0 | { |
397 | 0 | int ret; |
398 | 0 | const char *tmp; |
399 | 0 | struct flb_chronicle *ctx; |
400 | 0 | struct flb_chronicle_oauth_credentials *creds; |
401 | | |
402 | | /* Allocate config context */ |
403 | 0 | ctx = flb_calloc(1, sizeof(struct flb_chronicle)); |
404 | 0 | if (!ctx) { |
405 | 0 | flb_errno(); |
406 | 0 | return NULL; |
407 | 0 | } |
408 | 0 | ctx->ins = ins; |
409 | 0 | ctx->config = config; |
410 | 0 | mk_list_init(&ctx->labels); |
411 | |
|
412 | 0 | ret = flb_output_config_map_set(ins, (void *)ctx); |
413 | 0 | if (ret == -1) { |
414 | 0 | flb_plg_error(ins, "unable to load configuration"); |
415 | 0 | flb_free(ctx); |
416 | 0 | return NULL; |
417 | 0 | } |
418 | | |
419 | | /* config: 'api' */ |
420 | 0 | if (strcasecmp(ctx->api_str, "legacy") == 0) { |
421 | 0 | ctx->api = FLB_CHRONICLE_API_LEGACY; |
422 | 0 | } |
423 | 0 | else if (strcasecmp(ctx->api_str, "chronicle") == 0) { |
424 | 0 | ctx->api = FLB_CHRONICLE_API_CHRONICLE; |
425 | 0 | } |
426 | 0 | else { |
427 | 0 | flb_plg_error(ins, "invalid api '%s', expected 'legacy' or 'chronicle'", |
428 | 0 | ctx->api_str); |
429 | 0 | flb_free(ctx); |
430 | 0 | return NULL; |
431 | 0 | } |
432 | | |
433 | | /* config: 'compress' */ |
434 | 0 | ctx->compress_gzip = FLB_FALSE; |
435 | 0 | if (ctx->compress_str) { |
436 | 0 | if (strcasecmp(ctx->compress_str, "gzip") == 0) { |
437 | 0 | ctx->compress_gzip = FLB_TRUE; |
438 | 0 | } |
439 | 0 | else if (strcasecmp(ctx->compress_str, "none") != 0) { |
440 | 0 | flb_plg_error(ins, "invalid compress '%s', expected 'gzip' or 'none'", |
441 | 0 | ctx->compress_str); |
442 | 0 | flb_free(ctx); |
443 | 0 | return NULL; |
444 | 0 | } |
445 | 0 | } |
446 | | |
447 | | /* Lookup credentials file */ |
448 | 0 | creds = flb_calloc(1, sizeof(struct flb_chronicle_oauth_credentials)); |
449 | 0 | if (!creds) { |
450 | 0 | flb_errno(); |
451 | 0 | flb_free(ctx); |
452 | 0 | return NULL; |
453 | 0 | } |
454 | 0 | ctx->oauth_credentials = creds; |
455 | |
|
456 | 0 | if (ctx->credentials_file == NULL) { |
457 | 0 | tmp = getenv("GOOGLE_SERVICE_CREDENTIALS"); |
458 | 0 | if (tmp) { |
459 | 0 | ctx->credentials_file = flb_sds_create(tmp); |
460 | 0 | } |
461 | 0 | } |
462 | |
|
463 | 0 | if (ins->test_mode == FLB_FALSE) { |
464 | 0 | if (ctx->credentials_file) { |
465 | 0 | ret = flb_chronicle_read_credentials_file(ctx, |
466 | 0 | ctx->credentials_file, |
467 | 0 | ctx->oauth_credentials); |
468 | 0 | if (ret != 0) { |
469 | 0 | flb_chronicle_conf_destroy(ctx); |
470 | 0 | return NULL; |
471 | 0 | } |
472 | 0 | } |
473 | 0 | else if (!ctx->credentials_file) { |
474 | | /* |
475 | | * If no credentials file has been defined, do manual lookup of the |
476 | | * client email and the private key. |
477 | | */ |
478 | | |
479 | | /* Service Account Email */ |
480 | 0 | tmp = flb_output_get_property("service_account_email", ins); |
481 | 0 | if (tmp) { |
482 | 0 | creds->client_email = flb_sds_create(tmp); |
483 | 0 | } |
484 | 0 | else { |
485 | 0 | tmp = getenv("SERVICE_ACCOUNT_EMAIL"); |
486 | 0 | if (tmp) { |
487 | 0 | creds->client_email = flb_sds_create(tmp); |
488 | 0 | } |
489 | 0 | } |
490 | | |
491 | | /* Service Account Secret */ |
492 | 0 | tmp = flb_output_get_property("service_account_secret", ins); |
493 | 0 | if (tmp) { |
494 | 0 | creds->private_key = flb_sds_create(tmp); |
495 | 0 | } |
496 | 0 | else { |
497 | 0 | tmp = getenv("SERVICE_ACCOUNT_SECRET"); |
498 | 0 | if (tmp) { |
499 | 0 | creds->private_key = flb_sds_create(tmp); |
500 | 0 | } |
501 | 0 | } |
502 | |
|
503 | 0 | if (!creds->client_email) { |
504 | 0 | flb_plg_error(ctx->ins, "service_account_email/client_email is not defined"); |
505 | 0 | flb_chronicle_conf_destroy(ctx); |
506 | 0 | return NULL; |
507 | 0 | } |
508 | | |
509 | 0 | if (!creds->private_key) { |
510 | 0 | flb_plg_error(ctx->ins, "service_account_secret/private_key is not defined"); |
511 | 0 | flb_chronicle_conf_destroy(ctx); |
512 | 0 | return NULL; |
513 | 0 | } |
514 | 0 | } |
515 | 0 | } |
516 | | |
517 | | /* config: 'project_id' */ |
518 | 0 | if (ctx->project_id == NULL) { |
519 | 0 | if (creds->project_id) { |
520 | | /* flb_config_map_destroy uses the pointer within the config_map struct to |
521 | | * free the value so if we assign it here it is safe to free later with the |
522 | | * creds struct. If we do not we will leak here. |
523 | | */ |
524 | 0 | ctx->project_id = creds->project_id; |
525 | 0 | if (!ctx->project_id) { |
526 | 0 | flb_plg_error(ctx->ins, |
527 | 0 | "failed extracting 'project_id' from credentials."); |
528 | 0 | flb_chronicle_conf_destroy(ctx); |
529 | 0 | return NULL; |
530 | 0 | } |
531 | 0 | } |
532 | 0 | else { |
533 | 0 | flb_plg_error(ctx->ins, |
534 | 0 | "no 'project_id' configured or present in credentials."); |
535 | 0 | flb_chronicle_conf_destroy(ctx); |
536 | 0 | return NULL; |
537 | 0 | } |
538 | 0 | } |
539 | | |
540 | | /* config: 'customer_id' */ |
541 | 0 | if (ctx->customer_id == NULL) { |
542 | 0 | flb_plg_error(ctx->ins, "property 'customer_id' is not defined"); |
543 | 0 | flb_chronicle_conf_destroy(ctx); |
544 | 0 | return NULL; |
545 | 0 | } |
546 | | |
547 | | /* config: 'log_type' */ |
548 | 0 | if (ctx->log_type == NULL) { |
549 | 0 | flb_plg_error(ctx->ins, "property 'log_type' is not defined"); |
550 | 0 | flb_chronicle_conf_destroy(ctx); |
551 | 0 | return NULL; |
552 | 0 | } |
553 | | |
554 | 0 | if (ctx->namespace && flb_sds_len(ctx->namespace) == 0) { |
555 | 0 | flb_plg_error(ctx->ins, "property 'namespace' cannot be empty"); |
556 | 0 | flb_chronicle_conf_destroy(ctx); |
557 | 0 | return NULL; |
558 | 0 | } |
559 | | |
560 | 0 | if (ctx->namespace_key) { |
561 | 0 | ctx->namespace_ra = flb_ra_create(ctx->namespace_key, FLB_FALSE); |
562 | 0 | if (!ctx->namespace_ra) { |
563 | 0 | flb_plg_error(ctx->ins, "invalid namespace_key record accessor '%s'", |
564 | 0 | ctx->namespace_key); |
565 | 0 | flb_chronicle_conf_destroy(ctx); |
566 | 0 | return NULL; |
567 | 0 | } |
568 | 0 | } |
569 | | |
570 | 0 | ret = chronicle_configure_labels(ctx); |
571 | 0 | if (ret != 0) { |
572 | 0 | flb_chronicle_conf_destroy(ctx); |
573 | 0 | return NULL; |
574 | 0 | } |
575 | | |
576 | | /* Date key */ |
577 | 0 | ctx->date_key = ctx->json_date_key; |
578 | 0 | tmp = flb_output_get_property("json_date_key", ins); |
579 | 0 | if (tmp) { |
580 | | /* Just check if we have to disable it */ |
581 | 0 | if (flb_utils_bool(tmp) == FLB_FALSE) { |
582 | 0 | ctx->date_key = NULL; |
583 | 0 | } |
584 | 0 | } |
585 | | |
586 | | /* Date format for JSON output */ |
587 | 0 | ctx->json_date_format = FLB_PACK_JSON_DATE_ISO8601; |
588 | 0 | tmp = flb_output_get_property("json_date_format", ins); |
589 | 0 | if (tmp) { |
590 | 0 | ret = flb_pack_to_json_date_type(tmp); |
591 | 0 | if (ret == -1) { |
592 | 0 | flb_plg_error(ctx->ins, "invalid json_date_format '%s'. ", tmp); |
593 | 0 | return NULL; |
594 | 0 | } |
595 | 0 | else { |
596 | 0 | ctx->json_date_format = ret; |
597 | 0 | } |
598 | 0 | } |
599 | | |
600 | 0 | if (ctx->api == FLB_CHRONICLE_API_CHRONICLE) { |
601 | 0 | ret = chronicle_api_configure(ctx); |
602 | 0 | if (ret != 0) { |
603 | 0 | flb_chronicle_conf_destroy(ctx); |
604 | 0 | return NULL; |
605 | 0 | } |
606 | | |
607 | 0 | flb_plg_info(ctx->ins, "api='chronicle' project='%s' customer_id='%s' " |
608 | 0 | "location='%s'", |
609 | 0 | ctx->project_id, ctx->customer_id, ctx->location); |
610 | |
|
611 | 0 | return ctx; |
612 | 0 | } |
613 | | |
614 | 0 | ctx->max_payload_size = FLB_CHRONICLE_MAX_PAYLOAD_SIZE; |
615 | | |
616 | | /* Create the target endpoint URI */ |
617 | 0 | ctx->endpoint = flb_sds_create_size(sizeof(FLB_CHRONICLE_UNSTRUCTURED_ENDPOINT)); |
618 | 0 | if (!ctx->endpoint) { |
619 | 0 | flb_errno(); |
620 | 0 | flb_chronicle_conf_destroy(ctx); |
621 | 0 | return NULL; |
622 | 0 | } |
623 | 0 | ctx->endpoint = flb_sds_printf(&ctx->endpoint, FLB_CHRONICLE_UNSTRUCTURED_ENDPOINT); |
624 | | |
625 | | /* Create the base URI */ |
626 | 0 | if (ctx->region == NULL || strncasecmp(ctx->region, "US", 2) == 0) { |
627 | 0 | ctx->uri = flb_sds_create_size(sizeof(FLB_CHRONICLE_URL_BASE)); |
628 | 0 | if (!ctx->uri) { |
629 | 0 | flb_errno(); |
630 | 0 | flb_chronicle_conf_destroy(ctx); |
631 | 0 | return NULL; |
632 | 0 | } |
633 | 0 | ctx->uri = flb_sds_printf(&ctx->uri, FLB_CHRONICLE_URL_BASE); |
634 | 0 | } |
635 | 0 | else if (strncasecmp(ctx->region, "EU", 2) == 0){ |
636 | 0 | ctx->uri = flb_sds_create_size(sizeof(FLB_CHRONICLE_URL_BASE_EU)); |
637 | 0 | if (!ctx->uri) { |
638 | 0 | flb_errno(); |
639 | 0 | flb_chronicle_conf_destroy(ctx); |
640 | 0 | return NULL; |
641 | 0 | } |
642 | 0 | ctx->uri = flb_sds_printf(&ctx->uri, FLB_CHRONICLE_URL_BASE_EU); |
643 | 0 | } |
644 | 0 | else if (strncasecmp(ctx->region, "UK", 2) == 0) { |
645 | 0 | ctx->uri = flb_sds_create_size(sizeof(FLB_CHRONICLE_URL_BASE_UK)); |
646 | 0 | if (!ctx->uri) { |
647 | 0 | flb_errno(); |
648 | 0 | flb_chronicle_conf_destroy(ctx); |
649 | 0 | return NULL; |
650 | 0 | } |
651 | 0 | ctx->uri = flb_sds_printf(&ctx->uri, FLB_CHRONICLE_URL_BASE_UK); |
652 | 0 | } |
653 | 0 | else if (strncasecmp(ctx->region, "ASIA", 4) == 0) { |
654 | 0 | ctx->uri = flb_sds_create_size(sizeof(FLB_CHRONICLE_URL_BASE_ASIA)); |
655 | 0 | if (!ctx->uri) { |
656 | 0 | flb_errno(); |
657 | 0 | flb_chronicle_conf_destroy(ctx); |
658 | 0 | return NULL; |
659 | 0 | } |
660 | 0 | ctx->uri = flb_sds_printf(&ctx->uri, FLB_CHRONICLE_URL_BASE_ASIA); |
661 | 0 | } |
662 | 0 | else { |
663 | 0 | flb_plg_error(ctx->ins, "unsupported region"); |
664 | 0 | flb_chronicle_conf_destroy(ctx); |
665 | 0 | return NULL; |
666 | 0 | } |
667 | 0 | flb_plg_info(ctx->ins, "project='%s' custumer_id='%s' region='%s'", |
668 | 0 | ctx->project_id, ctx->customer_id, ctx->region); |
669 | |
|
670 | 0 | return ctx; |
671 | 0 | } |
672 | | |
673 | | |
674 | | int flb_chronicle_oauth_credentials_destroy(struct flb_chronicle_oauth_credentials *creds) |
675 | 0 | { |
676 | 0 | if (!creds) { |
677 | 0 | return -1; |
678 | 0 | } |
679 | 0 | flb_sds_destroy(creds->type); |
680 | 0 | flb_sds_destroy(creds->project_id); |
681 | 0 | flb_sds_destroy(creds->private_key_id); |
682 | 0 | flb_sds_destroy(creds->private_key); |
683 | 0 | flb_sds_destroy(creds->client_email); |
684 | 0 | flb_sds_destroy(creds->client_id); |
685 | 0 | flb_sds_destroy(creds->auth_uri); |
686 | 0 | flb_sds_destroy(creds->token_uri); |
687 | |
|
688 | 0 | flb_free(creds); |
689 | |
|
690 | 0 | return 0; |
691 | 0 | } |
692 | | |
693 | | int flb_chronicle_conf_destroy(struct flb_chronicle *ctx) |
694 | 0 | { |
695 | 0 | if (!ctx) { |
696 | 0 | return -1; |
697 | 0 | } |
698 | | |
699 | 0 | flb_chronicle_oauth_credentials_destroy(ctx->oauth_credentials); |
700 | |
|
701 | 0 | flb_sds_destroy(ctx->endpoint); |
702 | 0 | flb_sds_destroy(ctx->uri); |
703 | 0 | flb_sds_destroy(ctx->location); |
704 | |
|
705 | 0 | if (ctx->o) { |
706 | 0 | flb_oauth2_destroy(ctx->o); |
707 | 0 | } |
708 | |
|
709 | 0 | if (ctx->namespace_ra) { |
710 | 0 | flb_ra_destroy(ctx->namespace_ra); |
711 | 0 | } |
712 | |
|
713 | 0 | chronicle_labels_destroy(ctx); |
714 | |
|
715 | 0 | flb_free(ctx); |
716 | 0 | return 0; |
717 | 0 | } |