Support for openstack meta_data.json, connect timeout, other fixes.
This commit is contained in:
parent
eb9d5b440c
commit
ac66f160e0
7 changed files with 279 additions and 55 deletions
|
@ -1,5 +1,5 @@
|
||||||
PROG= cloud-agent
|
PROG= cloud-agent
|
||||||
SRCS= main.c xml.c azure.c cloudinit.c http.c log.c
|
SRCS= azure.c cloudinit.c http.c json.c jsmn.c log.c openstack.c main.c xml.c
|
||||||
BINDIR= /usr/local/libexec
|
BINDIR= /usr/local/libexec
|
||||||
MANDIR= /usr/local/man/man
|
MANDIR= /usr/local/man/man
|
||||||
|
|
||||||
|
|
|
@ -64,6 +64,7 @@ azure(struct system_config *sc)
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
|
|
||||||
/* Apply defaults */
|
/* Apply defaults */
|
||||||
|
free(sc->sc_username);
|
||||||
if ((sc->sc_username = strdup("azure-user")) == NULL) {
|
if ((sc->sc_username = strdup("azure-user")) == NULL) {
|
||||||
log_warnx("failed to set default user");
|
log_warnx("failed to set default user");
|
||||||
goto done;
|
goto done;
|
||||||
|
|
|
@ -30,12 +30,11 @@
|
||||||
#include "xml.h"
|
#include "xml.h"
|
||||||
|
|
||||||
static int cloudinit_fetch(struct system_config *);
|
static int cloudinit_fetch(struct system_config *);
|
||||||
static char *cloudinit_get(struct system_config *, const char *,
|
|
||||||
enum strtype);
|
|
||||||
|
|
||||||
int
|
int
|
||||||
ec2(struct system_config *sc)
|
ec2(struct system_config *sc)
|
||||||
{
|
{
|
||||||
|
free(sc->sc_username);
|
||||||
if ((sc->sc_username = strdup("ec2-user")) == NULL ||
|
if ((sc->sc_username = strdup("ec2-user")) == NULL ||
|
||||||
(sc->sc_endpoint = strdup("169.254.169.254")) == NULL) {
|
(sc->sc_endpoint = strdup("169.254.169.254")) == NULL) {
|
||||||
log_warnx("failed to set defaults");
|
log_warnx("failed to set defaults");
|
||||||
|
@ -49,8 +48,7 @@ int
|
||||||
cloudinit(struct system_config *sc)
|
cloudinit(struct system_config *sc)
|
||||||
{
|
{
|
||||||
/* XXX get endpoint from DHCP lease file */
|
/* XXX get endpoint from DHCP lease file */
|
||||||
if ((sc->sc_username = strdup("puffy")) == NULL ||
|
if ((sc->sc_endpoint = strdup("169.254.169.254")) == NULL) {
|
||||||
(sc->sc_endpoint = strdup("169.254.169.254")) == NULL) {
|
|
||||||
log_warnx("failed to set defaults");
|
log_warnx("failed to set defaults");
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
@ -58,35 +56,6 @@ cloudinit(struct system_config *sc)
|
||||||
return (cloudinit_fetch(sc));
|
return (cloudinit_fetch(sc));
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *
|
|
||||||
cloudinit_get(struct system_config *sc, const char *path, enum strtype type)
|
|
||||||
{
|
|
||||||
struct httpget *g = NULL;
|
|
||||||
char *str = NULL;
|
|
||||||
|
|
||||||
log_debug("%s: %s", __func__, path);
|
|
||||||
|
|
||||||
g = http_get(&sc->sc_addr, 1,
|
|
||||||
sc->sc_endpoint, 80, path, NULL, 0, NULL);
|
|
||||||
if (g != NULL && g->code == 200 && g->bodypartsz > 0) {
|
|
||||||
switch (type) {
|
|
||||||
case TEXT:
|
|
||||||
/* multi-line string, always printable */
|
|
||||||
str = get_string(g->bodypart, g->bodypartsz);
|
|
||||||
break;
|
|
||||||
case LINE:
|
|
||||||
str = get_line(g->bodypart, g->bodypartsz);
|
|
||||||
break;
|
|
||||||
case WORD:
|
|
||||||
str = get_word(g->bodypart, g->bodypartsz);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
http_get_free(g);
|
|
||||||
|
|
||||||
return (str);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
cloudinit_fetch(struct system_config *sc)
|
cloudinit_fetch(struct system_config *sc)
|
||||||
{
|
{
|
||||||
|
@ -96,37 +65,32 @@ cloudinit_fetch(struct system_config *sc)
|
||||||
sc->sc_addr.ip = sc->sc_endpoint;
|
sc->sc_addr.ip = sc->sc_endpoint;
|
||||||
sc->sc_addr.family = 4;
|
sc->sc_addr.family = 4;
|
||||||
|
|
||||||
if (sc->sc_dryrun)
|
|
||||||
return (0);
|
|
||||||
|
|
||||||
/* instance-id */
|
/* instance-id */
|
||||||
if ((sc->sc_instance = cloudinit_get(sc,
|
if ((sc->sc_instance = metadata(sc,
|
||||||
"/latest/meta-data/instance-id", WORD)) == NULL)
|
"/latest/meta-data/instance-id", WORD)) == NULL)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
/* hostname */
|
/* hostname */
|
||||||
if ((sc->sc_hostname = cloudinit_get(sc,
|
if ((sc->sc_hostname = metadata(sc,
|
||||||
"/latest/meta-data/local-hostname", WORD)) == NULL)
|
"/latest/meta-data/local-hostname", WORD)) == NULL)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
/* pubkey */
|
/* pubkey */
|
||||||
if ((str = cloudinit_get(sc,
|
if ((str = metadata(sc,
|
||||||
"/latest/meta-data/public-keys/0/openssh-key", LINE)) == NULL)
|
"/latest/meta-data/public-keys/0/openssh-key", LINE)) == NULL)
|
||||||
goto fail;
|
goto fail;
|
||||||
if (agent_addpubkey(sc, str, NULL) != 0)
|
if (agent_addpubkey(sc, str, NULL) != 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
/* optional username - this is an extension by meta-data(8) */
|
/* optional username - this is an extension by meta-data(8) */
|
||||||
if ((str = cloudinit_get(sc,
|
if ((str = metadata(sc, "/latest/meta-data/username", WORD)) != NULL) {
|
||||||
"/latest/meta-data/username", WORD)) != NULL) {
|
|
||||||
free(sc->sc_username);
|
free(sc->sc_username);
|
||||||
sc->sc_username = str;
|
sc->sc_username = str;
|
||||||
str = NULL;
|
str = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* userdata */
|
/* userdata */
|
||||||
if ((sc->sc_userdata = cloudinit_get(sc,
|
if ((sc->sc_userdata = metadata(sc, "/latest/user-data", TEXT)) == NULL)
|
||||||
"/latest/user-data", TEXT)) == NULL)
|
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
|
@ -277,8 +277,8 @@ again:
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
warn("%s: socket", addrs[cur].ip);
|
warn("%s: socket", addrs[cur].ip);
|
||||||
goto again;
|
goto again;
|
||||||
} else if (connect(fd, (struct sockaddr *)&ss, len) == -1) {
|
} else if (connect_wait(fd, (struct sockaddr *)&ss, len) == -1) {
|
||||||
warn("%s: connect", addrs[cur].ip);
|
warn("http://%s%s", addrs[cur].ip, path);
|
||||||
close(fd);
|
close(fd);
|
||||||
goto again;
|
goto again;
|
||||||
}
|
}
|
||||||
|
|
145
agent/main.c
145
agent/main.c
|
@ -26,16 +26,20 @@
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <poll.h>
|
||||||
|
#include <err.h>
|
||||||
|
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "xml.h"
|
#include "xml.h"
|
||||||
|
|
||||||
__dead void usage(void);
|
__dead void usage(void);
|
||||||
static struct system_config *agent_init(const char *, int);
|
static struct system_config *agent_init(const char *, int, int);
|
||||||
static int agent_configure(struct system_config *);
|
static int agent_configure(struct system_config *);
|
||||||
static void agent_free(struct system_config *);
|
static void agent_free(struct system_config *);
|
||||||
static int agent_pf(struct system_config *, int);
|
static int agent_pf(struct system_config *, int);
|
||||||
static void agent_unconfigure(void);
|
static void agent_unconfigure(void);
|
||||||
|
static char *metadata_parse(char *, size_t, enum strtype);
|
||||||
|
static int agent_timeout;
|
||||||
|
|
||||||
int
|
int
|
||||||
shell(const char *arg, ...)
|
shell(const char *arg, ...)
|
||||||
|
@ -289,7 +293,7 @@ get_word(u_int8_t *ptr, size_t len)
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct system_config *
|
static struct system_config *
|
||||||
agent_init(const char *ifname, int dryrun)
|
agent_init(const char *ifname, int dryrun, int timeout)
|
||||||
{
|
{
|
||||||
struct system_config *sc;
|
struct system_config *sc;
|
||||||
|
|
||||||
|
@ -298,12 +302,18 @@ agent_init(const char *ifname, int dryrun)
|
||||||
|
|
||||||
sc->sc_interface = ifname;
|
sc->sc_interface = ifname;
|
||||||
sc->sc_dryrun = dryrun ? 1 : 0;
|
sc->sc_dryrun = dryrun ? 1 : 0;
|
||||||
|
sc->sc_timeout = agent_timeout = timeout < 1 ? -1 : timeout * 1000;
|
||||||
TAILQ_INIT(&sc->sc_pubkeys);
|
TAILQ_INIT(&sc->sc_pubkeys);
|
||||||
|
|
||||||
if ((sc->sc_nullfd = open("/dev/null", O_RDWR)) == -1) {
|
if ((sc->sc_nullfd = open("/dev/null", O_RDWR)) == -1) {
|
||||||
free(sc);
|
free(sc);
|
||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
if ((sc->sc_username = strdup("puffy")) == NULL) {
|
||||||
|
free(sc);
|
||||||
|
close(sc->sc_nullfd);
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
if (sc->sc_dryrun)
|
if (sc->sc_dryrun)
|
||||||
return (sc);
|
return (sc);
|
||||||
|
@ -599,12 +609,125 @@ agent_unconfigure(void)
|
||||||
"permit keepenv nopass root\n", "w", "/etc/doas.conf");
|
"permit keepenv nopass root\n", "w", "/etc/doas.conf");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static char *
|
||||||
|
metadata_parse(char *s, size_t sz, enum strtype type)
|
||||||
|
{
|
||||||
|
char *str;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case TEXT:
|
||||||
|
/* multi-line string, always printable */
|
||||||
|
str = get_string(s, sz);
|
||||||
|
break;
|
||||||
|
case LINE:
|
||||||
|
str = get_line(s, sz);
|
||||||
|
break;
|
||||||
|
case WORD:
|
||||||
|
str = get_word(s, sz);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (str);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
metadata(struct system_config *sc, const char *path, enum strtype type)
|
||||||
|
{
|
||||||
|
struct httpget *g = NULL;
|
||||||
|
char *str = NULL;
|
||||||
|
|
||||||
|
log_debug("%s: %s", __func__, path);
|
||||||
|
|
||||||
|
g = http_get(&sc->sc_addr, 1,
|
||||||
|
sc->sc_endpoint, 80, path, NULL, 0, NULL);
|
||||||
|
if (g != NULL && g->code == 200 && g->bodypartsz > 0)
|
||||||
|
str = metadata_parse(g->bodypart, g->bodypartsz, type);
|
||||||
|
http_get_free(g);
|
||||||
|
|
||||||
|
return (str);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
metadata_file(struct system_config *sc, const char *name, enum strtype type)
|
||||||
|
{
|
||||||
|
FILE *fp, *mfp;
|
||||||
|
char buf[BUFSIZ], *mbuf, *str;
|
||||||
|
size_t sz, msz;
|
||||||
|
|
||||||
|
if ((fp = fopen(name, "r")) == NULL) {
|
||||||
|
log_warn("%s: could not open %s", __func__, name);
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((mfp = open_memstream(&mbuf, &msz)) == NULL) {
|
||||||
|
log_warn("%s: open_memstream", __func__);
|
||||||
|
fclose(fp);
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
if ((sz = fread(buf, 1, sizeof(buf), fp)) < 1)
|
||||||
|
break;
|
||||||
|
if (fwrite(buf, sz, 1, mfp) != 1)
|
||||||
|
break;
|
||||||
|
} while (sz == sizeof(buf));
|
||||||
|
|
||||||
|
fclose(mfp);
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
str = metadata_parse(mbuf, msz, type);
|
||||||
|
free(mbuf);
|
||||||
|
|
||||||
|
return (str);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
connect_wait(int s, const struct sockaddr *name, socklen_t namelen)
|
||||||
|
{
|
||||||
|
struct pollfd pfd[1];
|
||||||
|
int error = 0, flag;
|
||||||
|
socklen_t errlen = sizeof(error);
|
||||||
|
|
||||||
|
if ((flag = fcntl(s, F_GETFL, 0)) == -1 ||
|
||||||
|
(fcntl(s, F_SETFL, flag | O_NONBLOCK)) == -1)
|
||||||
|
return (-1);
|
||||||
|
|
||||||
|
error = connect(s, name, namelen);
|
||||||
|
do {
|
||||||
|
pfd[0].fd = s;
|
||||||
|
pfd[0].events = POLLOUT;
|
||||||
|
|
||||||
|
if ((error = poll(pfd, 1, agent_timeout)) == -1)
|
||||||
|
continue;
|
||||||
|
if (error == 0) {
|
||||||
|
error = ETIMEDOUT;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (getsockopt(s, SOL_SOCKET, SO_ERROR, &error, &errlen) == -1)
|
||||||
|
continue;
|
||||||
|
} while (error != 0 && error == EINTR);
|
||||||
|
|
||||||
|
done:
|
||||||
|
if (fcntl(s, F_SETFL, flag & ~O_NONBLOCK) == -1)
|
||||||
|
return (-1);
|
||||||
|
|
||||||
|
if (error != 0) {
|
||||||
|
errno = error;
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
log_debug("%s:%d error %d", __func__, __LINE__, error);
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
__dead void
|
__dead void
|
||||||
usage(void)
|
usage(void)
|
||||||
{
|
{
|
||||||
extern char *__progname;
|
extern char *__progname;
|
||||||
|
|
||||||
fprintf(stderr, "usage: %s [-nuv] interface\n",
|
fprintf(stderr, "usage: %s [-nuv] [-t 3] interface\n",
|
||||||
__progname);
|
__progname);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
@ -614,9 +737,10 @@ main(int argc, char *const *argv)
|
||||||
{
|
{
|
||||||
struct system_config *sc;
|
struct system_config *sc;
|
||||||
int verbose = 0, dryrun = 0, unconfigure = 0;
|
int verbose = 0, dryrun = 0, unconfigure = 0;
|
||||||
int ch, ret;
|
int ch, ret, timeout = CONNECT_TIMEOUT;
|
||||||
|
const char *error = NULL;
|
||||||
|
|
||||||
while ((ch = getopt(argc, argv, "nvu")) != -1) {
|
while ((ch = getopt(argc, argv, "nvt:u")) != -1) {
|
||||||
switch (ch) {
|
switch (ch) {
|
||||||
case 'n':
|
case 'n':
|
||||||
dryrun = 1;
|
dryrun = 1;
|
||||||
|
@ -624,6 +748,11 @@ main(int argc, char *const *argv)
|
||||||
case 'v':
|
case 'v':
|
||||||
verbose += 2;
|
verbose += 2;
|
||||||
break;
|
break;
|
||||||
|
case 't':
|
||||||
|
timeout = strtonum(optarg, -1, 86400, &error);
|
||||||
|
if (error != NULL)
|
||||||
|
fatalx("invalid timeout: %s", error);
|
||||||
|
break;
|
||||||
case 'u':
|
case 'u':
|
||||||
unconfigure = 1;
|
unconfigure = 1;
|
||||||
break;
|
break;
|
||||||
|
@ -650,7 +779,7 @@ main(int argc, char *const *argv)
|
||||||
if (pledge("stdio cpath rpath wpath exec proc dns inet", NULL) == -1)
|
if (pledge("stdio cpath rpath wpath exec proc dns inet", NULL) == -1)
|
||||||
fatal("pledge");
|
fatal("pledge");
|
||||||
|
|
||||||
if ((sc = agent_init(argv[0], dryrun)) == NULL)
|
if ((sc = agent_init(argv[0], dryrun, timeout)) == NULL)
|
||||||
fatalx("agent");
|
fatalx("agent");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -661,10 +790,8 @@ main(int argc, char *const *argv)
|
||||||
ret = azure(sc);
|
ret = azure(sc);
|
||||||
else if (strcmp("xnf0", sc->sc_interface) == 0)
|
else if (strcmp("xnf0", sc->sc_interface) == 0)
|
||||||
ret = ec2(sc);
|
ret = ec2(sc);
|
||||||
else if (strcmp("vio0", sc->sc_interface) == 0)
|
|
||||||
ret = cloudinit(sc);
|
|
||||||
else
|
else
|
||||||
fatal("unsupported cloud interface %s", sc->sc_interface);
|
ret = openstack(sc);
|
||||||
|
|
||||||
if (sc->sc_dryrun) {
|
if (sc->sc_dryrun) {
|
||||||
agent_free(sc);
|
agent_free(sc);
|
||||||
|
|
31
agent/main.h
31
agent/main.h
|
@ -19,10 +19,14 @@
|
||||||
|
|
||||||
#include <sys/queue.h>
|
#include <sys/queue.h>
|
||||||
#include <sys/cdefs.h>
|
#include <sys/cdefs.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
#include "http.h"
|
#include "http.h"
|
||||||
|
#include "jsmn.h"
|
||||||
|
|
||||||
|
#define CONNECT_TIMEOUT 10 /* in seconds */
|
||||||
|
|
||||||
enum strtype {
|
enum strtype {
|
||||||
WORD,
|
WORD,
|
||||||
|
@ -46,6 +50,7 @@ struct system_config {
|
||||||
char *sc_userdata;
|
char *sc_userdata;
|
||||||
char *sc_endpoint;
|
char *sc_endpoint;
|
||||||
char *sc_instance;
|
char *sc_instance;
|
||||||
|
int sc_timeout;
|
||||||
|
|
||||||
const char *sc_ovfenv;
|
const char *sc_ovfenv;
|
||||||
const char *sc_interface;
|
const char *sc_interface;
|
||||||
|
@ -59,6 +64,26 @@ struct system_config {
|
||||||
void *sc_priv;
|
void *sc_priv;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct jsmnp;
|
||||||
|
struct jsmnn {
|
||||||
|
struct parse *p;
|
||||||
|
union {
|
||||||
|
char *str;
|
||||||
|
struct jsmnp *obj;
|
||||||
|
struct jsmnn **array;
|
||||||
|
} d;
|
||||||
|
size_t fields;
|
||||||
|
jsmntype_t type;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* json.c */
|
||||||
|
struct jsmnn *json_parse(const char *, size_t);
|
||||||
|
void json_free(struct jsmnn *);
|
||||||
|
struct jsmnn *json_getarrayobj(struct jsmnn *);
|
||||||
|
struct jsmnn *json_getarray(struct jsmnn *, const char *);
|
||||||
|
struct jsmnn *json_getobj(struct jsmnn *, const char *);
|
||||||
|
char *json_getstr(struct jsmnn *, const char *);
|
||||||
|
|
||||||
/* azure.c */
|
/* azure.c */
|
||||||
int azure(struct system_config *);
|
int azure(struct system_config *);
|
||||||
|
|
||||||
|
@ -66,6 +91,9 @@ int azure(struct system_config *);
|
||||||
int ec2(struct system_config *);
|
int ec2(struct system_config *);
|
||||||
int cloudinit(struct system_config *);
|
int cloudinit(struct system_config *);
|
||||||
|
|
||||||
|
/* openstack.c */
|
||||||
|
int openstack(struct system_config *);
|
||||||
|
|
||||||
/* main.c */
|
/* main.c */
|
||||||
int shell(const char *, ...);
|
int shell(const char *, ...);
|
||||||
int shellout(const char *, char **, const char *, ...);
|
int shellout(const char *, char **, const char *, ...);
|
||||||
|
@ -76,6 +104,9 @@ char *get_line(u_int8_t *, size_t);
|
||||||
char *get_word(u_int8_t *, size_t);
|
char *get_word(u_int8_t *, size_t);
|
||||||
int agent_addpubkey(struct system_config *, const char *, const char *);
|
int agent_addpubkey(struct system_config *, const char *, const char *);
|
||||||
int agent_setpubkey(struct system_config *, const char *, const char *);
|
int agent_setpubkey(struct system_config *, const char *, const char *);
|
||||||
|
char *metadata(struct system_config *, const char *, enum strtype);
|
||||||
|
char *metadata_file(struct system_config *, const char *, enum strtype);
|
||||||
|
int connect_wait(int, const struct sockaddr *, socklen_t);
|
||||||
|
|
||||||
/* log.c */
|
/* log.c */
|
||||||
void log_init(int, int);
|
void log_init(int, int);
|
||||||
|
|
101
agent/openstack.c
Normal file
101
agent/openstack.c
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018 Reyk Floeter <reyk@openbsd.org>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/queue.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <err.h>
|
||||||
|
|
||||||
|
#include "main.h"
|
||||||
|
#include "http.h"
|
||||||
|
#include "xml.h"
|
||||||
|
|
||||||
|
static int openstack_fetch(struct system_config *);
|
||||||
|
|
||||||
|
int
|
||||||
|
openstack(struct system_config *sc)
|
||||||
|
{
|
||||||
|
if ((sc->sc_endpoint = strdup("169.254.169.254")) == NULL) {
|
||||||
|
log_warnx("failed to set defaults");
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (openstack_fetch(sc) != 0) {
|
||||||
|
free(sc->sc_endpoint);
|
||||||
|
return (cloudinit(sc));
|
||||||
|
}
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
openstack_fetch(struct system_config *sc)
|
||||||
|
{
|
||||||
|
int ret = -1;
|
||||||
|
char *json = NULL, *str;
|
||||||
|
struct jsmnn *j = NULL, *o, *f;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
sc->sc_addr.ip = sc->sc_endpoint;
|
||||||
|
sc->sc_addr.family = 4;
|
||||||
|
|
||||||
|
/* meta_data, we don't handle vendor_data */
|
||||||
|
if ((json = metadata(sc,
|
||||||
|
"/openstack/latest/meta_data.json", TEXT)) == NULL)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
if ((j = json_parse(json, strlen(json))) == NULL)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
/* instance-id */
|
||||||
|
if ((sc->sc_instance = json_getstr(j, "uuid")) == NULL)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
/* hostname */
|
||||||
|
if ((sc->sc_hostname = json_getstr(j, "hostname")) == NULL)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
/* public keys */
|
||||||
|
if ((o = json_getarray(j, "keys")) == NULL)
|
||||||
|
goto fail;
|
||||||
|
for (i = 0; i < o->fields; i++) {
|
||||||
|
if ((f = json_getarrayobj(o->d.array[i])) == NULL)
|
||||||
|
continue;
|
||||||
|
if ((str = json_getstr(f, "data")) == NULL)
|
||||||
|
continue;
|
||||||
|
if (agent_addpubkey(sc, str, NULL) != 0) {
|
||||||
|
free(str);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
free(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* userdata */
|
||||||
|
if ((sc->sc_userdata =
|
||||||
|
metadata(sc, "/openstack/latest/user-data", TEXT)) == NULL)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
fail:
|
||||||
|
json_free(j);
|
||||||
|
free(json);
|
||||||
|
return (ret);
|
||||||
|
}
|
Loading…
Reference in a new issue