|
Packit |
c22fc9 |
/*
|
|
Packit |
c22fc9 |
* Soft: Vrrpd is an implementation of VRRPv2 as specified in rfc2338.
|
|
Packit |
c22fc9 |
* VRRP is a protocol which elect a master server on a LAN. If the
|
|
Packit |
c22fc9 |
* master fails, a backup server takes over.
|
|
Packit |
c22fc9 |
* The original implementation has been made by jerome etienne.
|
|
Packit |
c22fc9 |
*
|
|
Packit |
c22fc9 |
* Part: Output running VRRP state information in JSON format
|
|
Packit |
c22fc9 |
*
|
|
Packit |
c22fc9 |
* Author: Damien Clabaut, <Damien.Clabaut@corp.ovh.com>
|
|
Packit |
c22fc9 |
*
|
|
Packit |
c22fc9 |
* This program is distributed in the hope that it will be useful,
|
|
Packit |
c22fc9 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
c22fc9 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
Packit |
c22fc9 |
* See the GNU General Public License for more details.
|
|
Packit |
c22fc9 |
*
|
|
Packit |
c22fc9 |
* This program is free software; you can redistribute it and/or
|
|
Packit |
c22fc9 |
* modify it under the terms of the GNU General Public License
|
|
Packit |
c22fc9 |
* as published by the Free Software Foundation; either version
|
|
Packit |
c22fc9 |
* 2 of the License, or (at your option) any later version.
|
|
Packit |
c22fc9 |
*
|
|
Packit |
c22fc9 |
* Copyright (C) 2017 Damien Clabaut, <Damien.Clabaut@corp.ovh.com>
|
|
Packit |
c22fc9 |
* Copyright (C) 2017-2017 Alexandre Cassen, <acassen@gmail.com>
|
|
Packit |
c22fc9 |
*/
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
#include "config.h"
|
|
Packit |
c22fc9 |
#include "vrrp_json.h"
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
#include <errno.h>
|
|
Packit |
c22fc9 |
#include <stdio.h>
|
|
Packit |
c22fc9 |
#include <json.h>
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
#include "vrrp.h"
|
|
Packit |
c22fc9 |
#include "vrrp_track.h"
|
|
Packit |
c22fc9 |
#include "list.h"
|
|
Packit |
c22fc9 |
#include "vrrp_data.h"
|
|
Packit |
c22fc9 |
#include "vrrp_iproute.h"
|
|
Packit |
c22fc9 |
#include "vrrp_iprule.h"
|
|
Packit |
c22fc9 |
#include "logger.h"
|
|
Packit |
c22fc9 |
#include "timer.h"
|
|
Packit |
c22fc9 |
#include "utils.h"
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
static inline double
|
|
Packit |
c22fc9 |
timeval_to_double(const timeval_t *t)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
/* The casts are necessary to avoid conversion warnings */
|
|
Packit |
c22fc9 |
return (double)t->tv_sec + (double)t->tv_usec / TIMER_HZ_FLOAT;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
void
|
|
Packit |
c22fc9 |
vrrp_print_json(void)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
FILE *file;
|
|
Packit |
c22fc9 |
element e;
|
|
Packit |
c22fc9 |
struct json_object *array;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (LIST_ISEMPTY(vrrp_data->vrrp))
|
|
Packit |
c22fc9 |
return;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
file = fopen_safe("/tmp/keepalived.json", "w");
|
|
Packit |
c22fc9 |
if (!file) {
|
|
Packit |
c22fc9 |
log_message(LOG_INFO, "Can't open /tmp/keepalived.json (%d: %s)",
|
|
Packit |
c22fc9 |
errno, strerror(errno));
|
|
Packit |
c22fc9 |
return;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
array = json_object_new_array();
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
for (e = LIST_HEAD(vrrp_data->vrrp); e; ELEMENT_NEXT(e)) {
|
|
Packit |
c22fc9 |
struct json_object *instance_json, *json_stats, *json_data,
|
|
Packit |
c22fc9 |
*vips, *evips, *track_ifp, *track_script;
|
|
Packit |
c22fc9 |
#ifdef _HAVE_FIB_ROUTING_
|
|
Packit |
c22fc9 |
struct json_object *vroutes, *vrules;
|
|
Packit |
c22fc9 |
#endif
|
|
Packit |
c22fc9 |
element f;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
vrrp_t *vrrp = ELEMENT_DATA(e);
|
|
Packit |
c22fc9 |
instance_json = json_object_new_object();
|
|
Packit |
c22fc9 |
json_stats = json_object_new_object();
|
|
Packit |
c22fc9 |
json_data = json_object_new_object();
|
|
Packit |
c22fc9 |
vips = json_object_new_array();
|
|
Packit |
c22fc9 |
evips = json_object_new_array();
|
|
Packit |
c22fc9 |
track_ifp = json_object_new_array();
|
|
Packit |
c22fc9 |
track_script = json_object_new_array();
|
|
Packit |
c22fc9 |
#ifdef _HAVE_FIB_ROUTING_
|
|
Packit |
c22fc9 |
vroutes = json_object_new_array();
|
|
Packit |
c22fc9 |
vrules = json_object_new_array();
|
|
Packit |
c22fc9 |
#endif
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
// Dump data to json
|
|
Packit |
c22fc9 |
json_object_object_add(json_data, "iname",
|
|
Packit |
c22fc9 |
json_object_new_string(vrrp->iname));
|
|
Packit |
c22fc9 |
json_object_object_add(json_data, "dont_track_primary",
|
|
Packit |
c22fc9 |
json_object_new_int(vrrp->dont_track_primary));
|
|
Packit |
c22fc9 |
json_object_object_add(json_data, "skip_check_adv_addr",
|
|
Packit |
c22fc9 |
json_object_new_int(vrrp->skip_check_adv_addr));
|
|
Packit |
c22fc9 |
json_object_object_add(json_data, "strict_mode",
|
|
Packit |
c22fc9 |
json_object_new_int((int)vrrp->strict_mode));
|
|
Packit |
c22fc9 |
#ifdef _HAVE_VRRP_VMAC_
|
|
Packit |
c22fc9 |
json_object_object_add(json_data, "vmac_ifname",
|
|
Packit |
c22fc9 |
json_object_new_string(vrrp->vmac_ifname));
|
|
Packit |
c22fc9 |
#endif
|
|
Packit |
c22fc9 |
// Tracked interfaces are stored in a list
|
|
Packit |
c22fc9 |
if (!LIST_ISEMPTY(vrrp->track_ifp)) {
|
|
Packit |
c22fc9 |
for (f = LIST_HEAD(vrrp->track_ifp); f; ELEMENT_NEXT(f)) {
|
|
Packit |
c22fc9 |
interface_t *ifp = ELEMENT_DATA(f);
|
|
Packit |
c22fc9 |
json_object_array_add(track_ifp,
|
|
Packit |
c22fc9 |
json_object_new_string(ifp->ifname));
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
json_object_object_add(json_data, "track_ifp", track_ifp);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
// Tracked scripts also
|
|
Packit |
c22fc9 |
if (!LIST_ISEMPTY(vrrp->track_script)) {
|
|
Packit |
c22fc9 |
for (f = LIST_HEAD(vrrp->track_script); f; ELEMENT_NEXT(f)) {
|
|
Packit |
c22fc9 |
tracked_sc_t *tsc = ELEMENT_DATA(f);
|
|
Packit |
c22fc9 |
vrrp_script_t *vscript = tsc->scr;
|
|
Packit |
c22fc9 |
json_object_array_add(track_script,
|
|
Packit |
c22fc9 |
json_object_new_string(cmd_str(&vscript->script)));
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
json_object_object_add(json_data, "track_script", track_script);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
json_object_object_add(json_data, "ifp_ifname",
|
|
Packit |
c22fc9 |
json_object_new_string(vrrp->ifp->ifname));
|
|
Packit |
c22fc9 |
json_object_object_add(json_data, "master_priority",
|
|
Packit |
c22fc9 |
json_object_new_int(vrrp->master_priority));
|
|
Packit |
c22fc9 |
json_object_object_add(json_data, "last_transition",
|
|
Packit |
c22fc9 |
json_object_new_double(timeval_to_double(&vrrp->last_transition)));
|
|
Packit |
c22fc9 |
json_object_object_add(json_data, "garp_delay",
|
|
Packit |
c22fc9 |
json_object_new_double(vrrp->garp_delay / TIMER_HZ_FLOAT));
|
|
Packit |
c22fc9 |
json_object_object_add(json_data, "garp_refresh",
|
|
Packit |
c22fc9 |
json_object_new_int((int)vrrp->garp_refresh.tv_sec));
|
|
Packit |
c22fc9 |
json_object_object_add(json_data, "garp_rep",
|
|
Packit |
c22fc9 |
json_object_new_int((int)vrrp->garp_rep));
|
|
Packit |
c22fc9 |
json_object_object_add(json_data, "garp_refresh_rep",
|
|
Packit |
c22fc9 |
json_object_new_int((int)vrrp->garp_refresh_rep));
|
|
Packit |
c22fc9 |
json_object_object_add(json_data, "garp_lower_prio_delay",
|
|
Packit |
c22fc9 |
json_object_new_int((int)(vrrp->garp_lower_prio_delay / TIMER_HZ)));
|
|
Packit |
c22fc9 |
json_object_object_add(json_data, "garp_lower_prio_rep",
|
|
Packit |
c22fc9 |
json_object_new_int((int)vrrp->garp_lower_prio_rep));
|
|
Packit |
c22fc9 |
json_object_object_add(json_data, "lower_prio_no_advert",
|
|
Packit |
c22fc9 |
json_object_new_int((int)vrrp->lower_prio_no_advert));
|
|
Packit |
c22fc9 |
json_object_object_add(json_data, "higher_prio_send_advert",
|
|
Packit |
c22fc9 |
json_object_new_int((int)vrrp->higher_prio_send_advert));
|
|
Packit |
c22fc9 |
json_object_object_add(json_data, "vrid",
|
|
Packit |
c22fc9 |
json_object_new_int(vrrp->vrid));
|
|
Packit |
c22fc9 |
json_object_object_add(json_data, "base_priority",
|
|
Packit |
c22fc9 |
json_object_new_int(vrrp->base_priority));
|
|
Packit |
c22fc9 |
json_object_object_add(json_data, "effective_priority",
|
|
Packit |
c22fc9 |
json_object_new_int(vrrp->effective_priority));
|
|
Packit |
c22fc9 |
json_object_object_add(json_data, "vipset",
|
|
Packit |
c22fc9 |
json_object_new_boolean(vrrp->vipset));
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
//Virtual IPs are stored in a list
|
|
Packit |
c22fc9 |
if (!LIST_ISEMPTY(vrrp->vip)) {
|
|
Packit |
c22fc9 |
for (f = LIST_HEAD(vrrp->vip); f; ELEMENT_NEXT(f)) {
|
|
Packit |
c22fc9 |
ip_address_t *vip = ELEMENT_DATA(f);
|
|
Packit |
c22fc9 |
char ipaddr[INET6_ADDRSTRLEN];
|
|
Packit |
c22fc9 |
inet_ntop(vrrp->family, &(vip->u.sin.sin_addr.s_addr),
|
|
Packit |
c22fc9 |
ipaddr, INET6_ADDRSTRLEN);
|
|
Packit |
c22fc9 |
json_object_array_add(vips,
|
|
Packit |
c22fc9 |
json_object_new_string(ipaddr));
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
json_object_object_add(json_data, "vips", vips);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
//External VIPs are also stored in a list
|
|
Packit |
c22fc9 |
if (!LIST_ISEMPTY(vrrp->evip)) {
|
|
Packit |
c22fc9 |
for (f = LIST_HEAD(vrrp->evip); f; ELEMENT_NEXT(f)) {
|
|
Packit |
c22fc9 |
ip_address_t *evip = ELEMENT_DATA(f);
|
|
Packit |
c22fc9 |
char ipaddr[INET6_ADDRSTRLEN];
|
|
Packit |
c22fc9 |
inet_ntop(vrrp->family, &(evip->u.sin.sin_addr.s_addr),
|
|
Packit |
c22fc9 |
ipaddr, INET6_ADDRSTRLEN);
|
|
Packit |
c22fc9 |
json_object_array_add(evips,
|
|
Packit |
c22fc9 |
json_object_new_string(ipaddr));
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
json_object_object_add(json_data, "evips", evips);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
json_object_object_add(json_data, "promote_secondaries",
|
|
Packit |
c22fc9 |
json_object_new_boolean(vrrp->promote_secondaries));
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
#ifdef _HAVE_FIB_ROUTING_
|
|
Packit |
c22fc9 |
// Dump vroutes
|
|
Packit |
c22fc9 |
if (!LIST_ISEMPTY(vrrp->vroutes)) {
|
|
Packit |
c22fc9 |
for (f = LIST_HEAD(vrrp->vroutes); f; ELEMENT_NEXT(f)) {
|
|
Packit |
c22fc9 |
ip_route_t *route = ELEMENT_DATA(f);
|
|
Packit |
c22fc9 |
char *buf = MALLOC(ROUTE_BUF_SIZE);
|
|
Packit |
c22fc9 |
format_iproute(route, buf, ROUTE_BUF_SIZE);
|
|
Packit |
c22fc9 |
json_object_array_add(vroutes,
|
|
Packit |
c22fc9 |
json_object_new_string(buf));
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
json_object_object_add(json_data, "vroutes", vroutes);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
// Dump vrules
|
|
Packit |
c22fc9 |
if (!LIST_ISEMPTY(vrrp->vrules)) {
|
|
Packit |
c22fc9 |
for (f = LIST_HEAD(vrrp->vrules); f; ELEMENT_NEXT(f)) {
|
|
Packit |
c22fc9 |
ip_rule_t *rule = ELEMENT_DATA(f);
|
|
Packit |
c22fc9 |
char *buf = MALLOC(RULE_BUF_SIZE);
|
|
Packit |
c22fc9 |
format_iprule(rule, buf, RULE_BUF_SIZE);
|
|
Packit |
c22fc9 |
json_object_array_add(vrules,
|
|
Packit |
c22fc9 |
json_object_new_string(buf));
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
json_object_object_add(json_data, "vrules", vrules);
|
|
Packit |
c22fc9 |
#endif
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
json_object_object_add(json_data, "adver_int",
|
|
Packit |
c22fc9 |
json_object_new_double(vrrp->adver_int / TIMER_HZ_FLOAT));
|
|
Packit |
c22fc9 |
json_object_object_add(json_data, "master_adver_int",
|
|
Packit |
c22fc9 |
json_object_new_double(vrrp->master_adver_int / TIMER_HZ_FLOAT));
|
|
Packit |
c22fc9 |
json_object_object_add(json_data, "accept",
|
|
Packit |
c22fc9 |
json_object_new_int((int)vrrp->accept));
|
|
Packit |
c22fc9 |
json_object_object_add(json_data, "nopreempt",
|
|
Packit |
c22fc9 |
json_object_new_boolean(vrrp->nopreempt));
|
|
Packit |
c22fc9 |
json_object_object_add(json_data, "preempt_delay",
|
|
Packit |
c22fc9 |
json_object_new_int((int)(vrrp->preempt_delay / TIMER_HZ)));
|
|
Packit |
c22fc9 |
json_object_object_add(json_data, "state",
|
|
Packit |
c22fc9 |
json_object_new_int(vrrp->state));
|
|
Packit |
c22fc9 |
json_object_object_add(json_data, "wantstate",
|
|
Packit |
c22fc9 |
json_object_new_int(vrrp->wantstate));
|
|
Packit |
c22fc9 |
json_object_object_add(json_data, "version",
|
|
Packit |
c22fc9 |
json_object_new_int(vrrp->version));
|
|
Packit |
c22fc9 |
if (vrrp->script_backup)
|
|
Packit |
c22fc9 |
json_object_object_add(json_data, "script_backup",
|
|
Packit |
c22fc9 |
json_object_new_string(cmd_str(vrrp->script_backup)));
|
|
Packit |
c22fc9 |
if (vrrp->script_master)
|
|
Packit |
c22fc9 |
json_object_object_add(json_data, "script_master",
|
|
Packit |
c22fc9 |
json_object_new_string(cmd_str(vrrp->script_master)));
|
|
Packit |
c22fc9 |
if (vrrp->script_fault)
|
|
Packit |
c22fc9 |
json_object_object_add(json_data, "script_fault",
|
|
Packit |
c22fc9 |
json_object_new_string(cmd_str(vrrp->script_fault)));
|
|
Packit |
c22fc9 |
if (vrrp->script_stop)
|
|
Packit |
c22fc9 |
json_object_object_add(json_data, "script_stop",
|
|
Packit |
c22fc9 |
json_object_new_string(cmd_str(vrrp->script_stop)));
|
|
Packit |
c22fc9 |
if (vrrp->script)
|
|
Packit |
c22fc9 |
json_object_object_add(json_data, "script",
|
|
Packit |
c22fc9 |
json_object_new_string(cmd_str(vrrp->script)));
|
|
Packit |
c22fc9 |
if (vrrp->script_master_rx_lower_pri)
|
|
Packit |
c22fc9 |
json_object_object_add(json_data, "script_master_rx_lower_pri",
|
|
Packit |
c22fc9 |
json_object_new_string(cmd_str(vrrp->script_master_rx_lower_pri)));
|
|
Packit |
c22fc9 |
json_object_object_add(json_data, "smtp_alert",
|
|
Packit |
c22fc9 |
json_object_new_boolean(vrrp->smtp_alert));
|
|
Packit |
c22fc9 |
#ifdef _WITH_VRRP_AUTH_
|
|
Packit |
c22fc9 |
if (vrrp->auth_type) {
|
|
Packit |
c22fc9 |
json_object_object_add(json_data, "auth_type",
|
|
Packit |
c22fc9 |
json_object_new_int(vrrp->auth_type));
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (vrrp->auth_type != VRRP_AUTH_AH) {
|
|
Packit |
c22fc9 |
char auth_data[sizeof(vrrp->auth_data) + 1];
|
|
Packit |
c22fc9 |
memcpy(auth_data, vrrp->auth_data, sizeof(vrrp->auth_data));
|
|
Packit |
c22fc9 |
auth_data[sizeof(vrrp->auth_data)] = '\0';
|
|
Packit |
c22fc9 |
json_object_object_add(json_data, "auth_data",
|
|
Packit |
c22fc9 |
json_object_new_string(auth_data));
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
else
|
|
Packit |
c22fc9 |
json_object_object_add(json_data, "auth_type",
|
|
Packit |
c22fc9 |
json_object_new_int(0));
|
|
Packit |
c22fc9 |
#endif
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
// Dump stats to json
|
|
Packit |
c22fc9 |
json_object_object_add(json_stats, "advert_rcvd",
|
|
Packit |
c22fc9 |
json_object_new_int64((int64_t)vrrp->stats->advert_rcvd));
|
|
Packit |
c22fc9 |
json_object_object_add(json_stats, "advert_sent",
|
|
Packit |
c22fc9 |
json_object_new_int64(vrrp->stats->advert_sent));
|
|
Packit |
c22fc9 |
json_object_object_add(json_stats, "become_master",
|
|
Packit |
c22fc9 |
json_object_new_int64(vrrp->stats->become_master));
|
|
Packit |
c22fc9 |
json_object_object_add(json_stats, "release_master",
|
|
Packit |
c22fc9 |
json_object_new_int64(vrrp->stats->release_master));
|
|
Packit |
c22fc9 |
json_object_object_add(json_stats, "packet_len_err",
|
|
Packit |
c22fc9 |
json_object_new_int64((int64_t)vrrp->stats->packet_len_err));
|
|
Packit |
c22fc9 |
json_object_object_add(json_stats, "advert_interval_err",
|
|
Packit |
c22fc9 |
json_object_new_int64((int64_t)vrrp->stats->advert_interval_err));
|
|
Packit |
c22fc9 |
json_object_object_add(json_stats, "ip_ttl_err",
|
|
Packit |
c22fc9 |
json_object_new_int64((int64_t)vrrp->stats->ip_ttl_err));
|
|
Packit |
c22fc9 |
json_object_object_add(json_stats, "invalid_type_rcvd",
|
|
Packit |
c22fc9 |
json_object_new_int64((int64_t)vrrp->stats->invalid_type_rcvd));
|
|
Packit |
c22fc9 |
json_object_object_add(json_stats, "addr_list_err",
|
|
Packit |
c22fc9 |
json_object_new_int64((int64_t)vrrp->stats->addr_list_err));
|
|
Packit |
c22fc9 |
json_object_object_add(json_stats, "invalid_authtype",
|
|
Packit |
c22fc9 |
json_object_new_int64(vrrp->stats->invalid_authtype));
|
|
Packit |
c22fc9 |
#ifdef _WITH_VRRP_AUTH_
|
|
Packit |
c22fc9 |
json_object_object_add(json_stats, "authtype_mismatch",
|
|
Packit |
c22fc9 |
json_object_new_int64(vrrp->stats->authtype_mismatch));
|
|
Packit |
c22fc9 |
json_object_object_add(json_stats, "auth_failure",
|
|
Packit |
c22fc9 |
json_object_new_int64(vrrp->stats->auth_failure));
|
|
Packit |
c22fc9 |
#endif
|
|
Packit |
c22fc9 |
json_object_object_add(json_stats, "pri_zero_rcvd",
|
|
Packit |
c22fc9 |
json_object_new_int64((int64_t)vrrp->stats->pri_zero_rcvd));
|
|
Packit |
c22fc9 |
json_object_object_add(json_stats, "pri_zero_sent",
|
|
Packit |
c22fc9 |
json_object_new_int64((int64_t)vrrp->stats->pri_zero_sent));
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
// Add both json_data and json_stats to main instance_json
|
|
Packit |
c22fc9 |
json_object_object_add(instance_json, "data", json_data);
|
|
Packit |
c22fc9 |
json_object_object_add(instance_json, "stats", json_stats);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
// Add instance_json to main array
|
|
Packit |
c22fc9 |
json_object_array_add(array, instance_json);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
fprintf(file, "%s", json_object_to_json_string(array));
|
|
Packit |
c22fc9 |
fclose(file);
|
|
Packit |
c22fc9 |
}
|