MEDIUM: da: new optional data file download scheduler service.

New specialized service to daily handle the update of download file without
interruption of service and to be preemptively started before HAProxy.
It consists on a standalone utility which shared a memory block with
the DeviceAtlas module which handles the JSON data file update on
a daily basis.

Signed-off-by: David Carlier <dcarlier@deviceatlas.com>
This commit is contained in:
David Carlier 2022-01-21 20:46:40 +00:00 committed by Willy Tarreau
parent 74904a4792
commit e9cff619c1
2 changed files with 243 additions and 0 deletions

View File

@ -0,0 +1,48 @@
# DEVICEATLAS_SRC : DeviceAtlas API source root path
OS := $(shell uname -s)
OBJS := dadwsch.o
CFLAGS := -g -O2
LDFLAGS :=
CURL_CONFIG := curl-config
CURLDIR := $(shell $(CURL_CONFIG) --prefix 2>/dev/null || echo /usr/local)
CURL_INC := $(CURLDIR)/include
CURL_LIB := $(CURLDIR)/lib
CURL_LDFLAGS := $(shell $(CURL_CONFIG) --libs 2>/dev/null || echo -L /usr/local/lib -lcurl)
PCRE2_CONFIG := pcre2-config
PCRE2DIR := $(shell $(PCRE2_CONFIG) --prefix 2>/dev/null || echo /usr/local)
PCRE2_INC := $(PCRE2DIR)/include
PCRE2_LIB := $(PCRE2DIR)/lib
PCRE2_LDFLAGS := $(shell $(PCRE2_CONFIG) --libs8 2>/dev/null || echo /usr/local)
ifeq ($(DEVICEATLAS_SRC),)
dadwsch: dadwsch.c
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
LDFLAGS += -lda
else
DEVICEATLAS_INC = $(DEVICEATLAS_SRC)
DEVICEATLAS_LIB = $(DEVICEATLAS_SRC)
CFLAGS += -DDA_REGEX_HDR=\"dac_pcre2.c\" -DDA_REGEX_TAG=2
CFLAGS += -DMOBI_CURL -DMOBI_CURLSSET -DMOBI_GZ -DMOBI_ZIP
CFLAGS += -I$(DEVICEATLAS_INC) -I$(CURL_INC) -I$(PCRE2DIR)
LDFLAGS += $(CURL_LDFLAGS) $(PCRE2_LDFLAGS) -lz -lzip -lpthread
dadwsch: dadwsch.c $(DEVICEATLAS_SRC)/dac.c $(DEVICEATLAS_SRC)/dasch.c $(DEVICEATLAS_SRC)/dadwarc.c $(DEVICEATLAS_SRC)/dadwcom.c $(DEVICEATLAS_SRC)/dadwcurl.c $(DEVICEATLAS_SRC)/json.c $(DEVICEATLAS_SRC)/Os/daunix.c
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
endif
ifeq ($(OS), Linux)
LDFLAGS += -lrt
endif
ifeq ($(OS), SunOS)
LDFLAGS += -lrt
endif
clean:
rm -f *.o
rm -f $(DEVICEATLAS_LIB)*.o
rm -f dadwsch

View File

@ -0,0 +1,195 @@
#define _GNU_SOURCE
#include <dac.h>
#include <dadwcurl.h>
#include <dadwarc.h>
#include <getopt.h>
#include <stdlib.h>
#include <signal.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/mman.h>
#define ATLASTOKSZ PATH_MAX
#define ATLASMAPNM "/hapdeviceatlas"
const char *__pgname;
static struct {
da_dwatlas_t o;
int ofd;
void* atlasmap;
} global_deviceatlassch = {
.ofd = -1,
.atlasmap = NULL
};
void usage(void)
{
fprintf(stderr, "%s -u download URL [-d hour (in H:M:S format) current hour by default] [-p path for the downloaded file, /tmp by default]\n", __pgname);
exit(EXIT_FAILURE);
}
static size_t jsonread(void *ctx, size_t count, char *buf)
{
return fread(buf, 1, count, ctx);
}
static da_status_t jsonseek(void *ctx, off_t pos)
{
return fseek(ctx, pos, SEEK_SET) != -1 ? DA_OK : DA_SYS;
}
static void dadwlog(dw_config_t cfg, const char* msg)
{
time_t now = time(NULL);
char buf[26] = {0};
ctime_r(&now, buf);
buf[24] = 0;
fprintf(stderr, "%s: %s\n", buf, msg);
}
static dw_status_t dadwnot(void *a, dw_config_t *cfg)
{
da_dwatlas_t *o = (da_dwatlas_t *)a;
if (!o)
return DW_ERR;
char *e;
char jsondbuf[26] = {0}, buf[26] = {0}, atlasp[ATLASTOKSZ] = {0};
time_t now = time(NULL);
time_t jsond;
int fd = -1;
(void)a;
jsond = da_getdatacreation(&o->atlas);
dwgetfinalp(o->dcfg.info, atlasp, sizeof(atlasp));
ctime_r(&jsond, jsondbuf);
ctime_r(&now, buf);
jsondbuf[24] = 0;
buf[24] = 0;
printf("%s: data file generated on `%s`\n", buf, jsondbuf);
int val = 1;
unsigned char *ptr = (unsigned char *)global_deviceatlassch.atlasmap;
memset(ptr, 0, sizeof(atlasp));
strcpy(ptr, atlasp);
return DW_OK;
}
static da_status_t dadwinit(void)
{
if ((global_deviceatlassch.ofd = shm_open(ATLASMAPNM, O_RDWR | O_CREAT, 0660)) == -1) {
fprintf(stderr, "%s\n", strerror(errno));
return DA_SYS;
}
if (ftruncate(global_deviceatlassch.ofd, ATLASTOKSZ) == -1) {
close(global_deviceatlassch.ofd);
return DA_SYS;
}
lseek(global_deviceatlassch.ofd, 0, SEEK_SET);
global_deviceatlassch.atlasmap = mmap(0, ATLASTOKSZ, PROT_READ | PROT_WRITE, MAP_SHARED, global_deviceatlassch.ofd, 0);
if (global_deviceatlassch.atlasmap == MAP_FAILED) {
fprintf(stderr, "%s\n", strerror(errno));
return DA_SYS;
} else {
memset(global_deviceatlassch.atlasmap, 0, ATLASTOKSZ);
return DA_OK;
}
}
static void dadwexit(int sig __attribute__((unused)), siginfo_t *s __attribute__((unused)), void *ctx __attribute__((unused)))
{
ssize_t w;
fprintf(stderr, "%s: exit\n", __pgname);
dw_daatlas_close(&global_deviceatlassch.o);
da_fini();
munmap(global_deviceatlassch.atlasmap, ATLASTOKSZ);
close(global_deviceatlassch.ofd);
shm_unlink(ATLASMAPNM);
exit(EXIT_SUCCESS);
}
int main(int argc, char **argv)
{
const char *opts = "u:p:d:h";
bool dset = false;
size_t i;
int ch;
da_property_decl_t extraprops[1] = {
{ 0, 0 }
};
__pgname = argv[0];
dw_df_dainit_fn = curldwinit;
dw_df_dacleanup_fn = curldwcleanup;
da_init();
memset(&global_deviceatlassch.o.dcfg, 0, sizeof(global_deviceatlassch.o.dcfg));
while ((ch = getopt(argc, argv, opts)) != -1) {
switch (ch) {
case 'u':
global_deviceatlassch.o.dcfg.info.url = strdup(optarg);
break;
case 'p':
global_deviceatlassch.o.dcfg.info.path = strdup(optarg);
break;
case 'd':
if (strptime(optarg, "%H:%M:%S", &global_deviceatlassch.o.dcfg.info.rtm) != NULL)
dset = true;
else
usage();
break;
case 'h':
default:
usage();
}
}
if (!dset) {
time_t now = time(NULL);
struct tm *cnow = gmtime(&now);
memcpy(&global_deviceatlassch.o.dcfg.info.rtm, cnow, offsetof(struct tm, tm_mday));
}
if (!global_deviceatlassch.o.dcfg.info.url)
usage();
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_flags = SA_SIGINFO | SA_RESTART;
sa.sa_sigaction = dadwexit;
global_deviceatlassch.o.dcfg.info.datatm = 1;
global_deviceatlassch.o.dcfg.info.chksum = 1;
global_deviceatlassch.o.dcfg.info.reload = 1;
global_deviceatlassch.o.dcfg.info.tobin = 1;
global_deviceatlassch.o.dcfg.ep = extraprops;
global_deviceatlassch.o.dcfg.dwproc = curldwproc;
global_deviceatlassch.o.dcfg.dwextract = dadwextract;
global_deviceatlassch.o.dcfg.lptr = (void *)stderr;
global_deviceatlassch.o.dcfg.dwlog = &dadwlog;
global_deviceatlassch.o.dcfg.dwnotify_n = &dadwnot;
global_deviceatlassch.o.rfn = jsonread;
global_deviceatlassch.o.posfn = jsonseek;
if (dadwinit() != DA_OK) {
fprintf(stderr, "%s init failed\n", __pgname);
exit(EXIT_FAILURE);
}
if (da_atlas_open_schedule(&global_deviceatlassch.o) != DA_OK) {
fprintf(stderr, "%s scheduling failed\n", __pgname);
exit(EXIT_FAILURE);
}
sigaction(SIGINT, &sa, NULL);
sigaction(SIGQUIT, &sa, NULL);
sigaction(SIGTERM, &sa, NULL);
while (true) sleep(1);
return 0;
}