Add initial support for OpenNebula contextualization.
Thanks to datacenterlight.ch by ungleich glarus AG for providing access to their OpenNebula-based cloud.
This commit is contained in:
parent
ec87db177d
commit
d9899d488a
8 changed files with 449 additions and 25 deletions
|
@ -35,6 +35,9 @@ Installation is easy, `cloud-agent` detects the cloud type automatically.
|
|||
|
||||
* On OpenStack/VMware, create a file `/etc/hostname.vmx0`
|
||||
|
||||
* On OpenNebula, create a file `/etc/hostname.if`
|
||||
where _if_ is the name of your primary interface.
|
||||
|
||||
* The content of the file is identical for all of them:
|
||||
|
||||
dhcp
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
PROG= cloud-agent
|
||||
SRCS= azure.c cloudinit.c http.c json.c jsmn.c log.c openstack.c main.c xml.c
|
||||
SRCS= http.c json.c jsmn.c log.c main.c xml.c
|
||||
SRCS+= azure.c cloudinit.c opennebula.c openstack.c
|
||||
BINDIR= /usr/local/libexec
|
||||
MANDIR= /usr/local/man/man
|
||||
|
||||
|
@ -15,7 +16,7 @@ CFLAGS+= -Wmissing-declarations
|
|||
CFLAGS+= -Wshadow -Wpointer-arith
|
||||
CFLAGS+= -Wsign-compare -Wcast-qual
|
||||
|
||||
LDADD+= -lexpat -ltls -lssl -lcrypto
|
||||
DPADD+= ${LIBEXPAT} ${LIBTLS} ${LIBSSL} ${LIBCRYPTO}
|
||||
LDADD+= -lexpat -ltls -lssl -lcrypto -lutil
|
||||
DPADD+= ${LIBEXPAT} ${LIBTLS} ${LIBSSL} ${LIBCRYPTO} ${LIBUTIL}
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
|
|
@ -62,13 +62,14 @@ azure(struct system_config *sc)
|
|||
{
|
||||
int ret = -1;
|
||||
|
||||
sc->sc_stack = "azure";
|
||||
|
||||
/* Apply defaults */
|
||||
free(sc->sc_username);
|
||||
if ((sc->sc_username = strdup("azure-user")) == NULL) {
|
||||
log_warnx("failed to set default user");
|
||||
goto fail;
|
||||
}
|
||||
sc->sc_cdrom = "/dev/cd0c";
|
||||
sc->sc_ovfenv = "/var/db/azure-ovf-env.xml";
|
||||
sc->sc_priv = &az_config;
|
||||
|
||||
|
@ -654,36 +655,22 @@ azure_getovfenv(struct system_config *sc)
|
|||
struct xml xml;
|
||||
struct xmlelem *xp, *xe, *xk, *xv;
|
||||
char *sshfp, *sshval, *str;
|
||||
int mount = 0, ret = -1, fd = -1;
|
||||
int ret = -1, fd = -1;
|
||||
FILE *fp;
|
||||
|
||||
/* Silently try to mount the cdrom */
|
||||
fd = disable_output(sc, STDERR_FILENO);
|
||||
ret = shell("mount", "-r", sc->sc_cdrom, "/mnt", NULL);
|
||||
enable_output(sc, STDERR_FILENO, fd);
|
||||
fd = -1;
|
||||
|
||||
if (ret == 0) {
|
||||
log_debug("%s: mounted %s", __func__, sc->sc_cdrom);
|
||||
mount = 1;
|
||||
}
|
||||
ret = -1;
|
||||
|
||||
if (xml_init(&xml) != 0) {
|
||||
log_debug("%s: xml", __func__);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Fallback to and older ovf-env.xml file */
|
||||
/*
|
||||
* Assume that the cdrom is already mounted.
|
||||
* Fallback to and older ovf-env.xml file.
|
||||
*/
|
||||
if (xml_parse(&xml, "/mnt/ovf-env.xml") == -1 &&
|
||||
xml_parse(&xml, sc->sc_ovfenv) == -1)
|
||||
goto done;
|
||||
|
||||
/* unmount if we mounted the cdrom before */
|
||||
if (mount && shell("umount", "/mnt", NULL) == 0) {
|
||||
log_debug("%s: unmounted %s", __func__, sc->sc_cdrom);
|
||||
}
|
||||
|
||||
if ((xp = xml_findl(&xml.ox_root,
|
||||
"Environment", "wa:ProvisioningSection",
|
||||
"LinuxProvisioningConfigurationSet", NULL)) == NULL) {
|
||||
|
|
|
@ -41,6 +41,7 @@ ec2(struct system_config *sc)
|
|||
return (-1);
|
||||
}
|
||||
|
||||
sc->sc_stack = "ec2";
|
||||
return (cloudinit_fetch(sc));
|
||||
}
|
||||
|
||||
|
@ -53,6 +54,7 @@ cloudinit(struct system_config *sc)
|
|||
return (-1);
|
||||
}
|
||||
|
||||
sc->sc_stack = "cloudinit";
|
||||
return (cloudinit_fetch(sc));
|
||||
}
|
||||
|
||||
|
|
188
agent/main.c
188
agent/main.c
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2017 Reyk Floeter <reyk@openbsd.org>
|
||||
* Copyright (c) 2017, 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
|
||||
|
@ -15,19 +15,24 @@
|
|||
*/
|
||||
|
||||
#include <sys/wait.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/if_ether.h>
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <syslog.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <resolv.h>
|
||||
#include <netdb.h>
|
||||
#include <ctype.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
@ -40,6 +45,7 @@
|
|||
__dead void usage(void);
|
||||
static struct system_config *agent_init(const char *, int, int);
|
||||
static int agent_configure(struct system_config *);
|
||||
static int agent_network(struct system_config *);
|
||||
static void agent_free(struct system_config *);
|
||||
static int agent_pf(struct system_config *, int);
|
||||
static int agent_userdata(const unsigned char *, size_t);
|
||||
|
@ -303,14 +309,17 @@ static struct system_config *
|
|||
agent_init(const char *ifname, int dryrun, int timeout)
|
||||
{
|
||||
struct system_config *sc;
|
||||
int fd, ret;
|
||||
|
||||
if ((sc = calloc(1, sizeof(*sc))) == NULL)
|
||||
return (NULL);
|
||||
|
||||
sc->sc_interface = ifname;
|
||||
sc->sc_cdrom = "/dev/cd0c";
|
||||
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_netaddrs);
|
||||
|
||||
if ((sc->sc_nullfd = open("/dev/null", O_RDWR)) == -1) {
|
||||
free(sc);
|
||||
|
@ -322,6 +331,15 @@ agent_init(const char *ifname, int dryrun, int timeout)
|
|||
return (NULL);
|
||||
}
|
||||
|
||||
/* Silently try to mount the cdrom */
|
||||
fd = disable_output(sc, STDERR_FILENO);
|
||||
ret = shell("mount", "-r", sc->sc_cdrom, "/mnt", NULL);
|
||||
enable_output(sc, STDERR_FILENO, fd);
|
||||
if (ret == 0) {
|
||||
log_debug("%s: mounted %s", __func__, sc->sc_cdrom);
|
||||
sc->sc_mount = 1;
|
||||
}
|
||||
|
||||
if (sc->sc_dryrun)
|
||||
return (sc);
|
||||
|
||||
|
@ -337,6 +355,12 @@ static void
|
|||
agent_free(struct system_config *sc)
|
||||
{
|
||||
struct ssh_pubkey *ssh;
|
||||
struct net_addr *net;
|
||||
|
||||
/* unmount if we mounted the cdrom before */
|
||||
if (sc->sc_mount && shell("umount", "/mnt", NULL) == 0) {
|
||||
log_debug("%s: unmounted %s", __func__, sc->sc_cdrom);
|
||||
}
|
||||
|
||||
free(sc->sc_hostname);
|
||||
free(sc->sc_username);
|
||||
|
@ -352,6 +376,12 @@ agent_free(struct system_config *sc)
|
|||
TAILQ_REMOVE(&sc->sc_pubkeys, ssh, ssh_entry);
|
||||
free(ssh);
|
||||
}
|
||||
|
||||
while ((net = TAILQ_FIRST(&sc->sc_netaddrs))) {
|
||||
TAILQ_REMOVE(&sc->sc_netaddrs, net, net_entry);
|
||||
free(net->net_value);
|
||||
free(net);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -405,6 +435,103 @@ agent_setpubkey(struct system_config *sc, const char *sshval, const char *sshfp)
|
|||
return (ret);
|
||||
}
|
||||
|
||||
struct net_addr *
|
||||
agent_getnetaddr(struct system_config *sc, struct net_addr *net)
|
||||
{
|
||||
struct net_addr *na;
|
||||
|
||||
TAILQ_FOREACH(na, &sc->sc_netaddrs, net_entry) {
|
||||
if (na->net_type != net->net_type)
|
||||
continue;
|
||||
if (na->net_ifunit != net->net_ifunit)
|
||||
continue;
|
||||
if (net->net_addr.ss_family != AF_UNSPEC) {
|
||||
if (na->net_addr.ss_family !=
|
||||
net->net_addr.ss_family)
|
||||
continue;
|
||||
if (memcmp(&na->net_addr, &net->net_addr,
|
||||
na->net_addr.ss_len) != 0)
|
||||
continue;
|
||||
}
|
||||
|
||||
return (na);
|
||||
}
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
int
|
||||
agent_addnetaddr(struct system_config *sc, unsigned int unit,
|
||||
const char *value, int af, enum net_type type)
|
||||
{
|
||||
const char *errstr;
|
||||
struct addrinfo hints, *res;
|
||||
struct net_addr *net, *na;
|
||||
|
||||
if ((net = calloc(1, sizeof(*net))) == NULL) {
|
||||
log_debug("%s: calloc", __func__);
|
||||
return (-1);
|
||||
}
|
||||
net->net_ifunit = unit;
|
||||
net->net_type = type;
|
||||
|
||||
switch (type) {
|
||||
case NET_MAC:
|
||||
if (ether_aton(value) == NULL) {
|
||||
log_debug("%s: if%u mac %s", __func__, unit, value);
|
||||
free(net);
|
||||
return (-1);
|
||||
}
|
||||
break;
|
||||
case NET_MTU:
|
||||
case NET_PREFIX:
|
||||
net->net_num = strtonum(value, 0, UINT32_MAX, &errstr);
|
||||
if (errstr != NULL) {
|
||||
log_debug("%s: if%u %s", __func__, unit, value);
|
||||
free(net);
|
||||
return (-1);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = af;
|
||||
hints.ai_socktype = SOCK_DGRAM;
|
||||
hints.ai_flags = AI_NUMERICHOST;
|
||||
if (getaddrinfo(value, "0", &hints, &res) != 0) {
|
||||
log_debug("%s: invalid address %s",
|
||||
__func__, value);
|
||||
free(net);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (res->ai_addrlen > sizeof(net->net_addr)) {
|
||||
log_debug("%s: address too long",
|
||||
__func__);
|
||||
free(net);
|
||||
freeaddrinfo(res);
|
||||
return (-1);
|
||||
}
|
||||
memcpy(&net->net_addr, res->ai_addr, res->ai_addrlen);
|
||||
net->net_addr.ss_len = res->ai_addrlen;
|
||||
net->net_addr.ss_family = res->ai_family;
|
||||
}
|
||||
|
||||
/* Address already exists, ignore new entry */
|
||||
if ((na = agent_getnetaddr(sc, net)) != NULL) {
|
||||
free(net);
|
||||
return (0);
|
||||
}
|
||||
|
||||
if ((net->net_value = strdup(value)) == NULL) {
|
||||
free(net);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
TAILQ_INSERT_TAIL(&sc->sc_netaddrs, net, net_entry);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
fileout(const char *str, const char *mode, const char *fmt, ...)
|
||||
{
|
||||
|
@ -575,6 +702,9 @@ agent_configure(struct system_config *sc)
|
|||
log_warnx("user-data failed");
|
||||
}
|
||||
|
||||
if (agent_network(sc) != 0)
|
||||
log_warnx("network configuration failed");
|
||||
|
||||
log_debug("%s: %s", __func__, "/etc/rc.firsttime");
|
||||
if (fileout("logger -s -t cloud-agent <<EOF\n"
|
||||
"#############################################################\n"
|
||||
|
@ -658,6 +788,55 @@ agent_userdata(const unsigned char *userdata, size_t len)
|
|||
return (ret);
|
||||
}
|
||||
|
||||
static int
|
||||
agent_network(struct system_config *sc)
|
||||
{
|
||||
struct net_addr *net;
|
||||
char ift[16], ifname[16], line[1024], path[PATH_MAX];
|
||||
const char *family;
|
||||
|
||||
if (!sc->sc_network)
|
||||
return (0);
|
||||
|
||||
if (strlcpy(ift, sc->sc_interface, sizeof(ift)) >= sizeof(ift))
|
||||
return (-1);
|
||||
ift[strcspn(ift, "0123456789")] = '\0';
|
||||
|
||||
TAILQ_FOREACH(net, &sc->sc_netaddrs, net_entry) {
|
||||
snprintf(ifname, sizeof(ifname), "%s%u", ift, net->net_ifunit);
|
||||
switch (net->net_type) {
|
||||
case NET_IP:
|
||||
family = net->net_addr.ss_family == AF_INET ?
|
||||
"inet" : "inet6";
|
||||
/* XXX prefix */
|
||||
|
||||
/* hostname.if startup configuration */
|
||||
snprintf(line, sizeof(line), "%s alias %s",
|
||||
family, net->net_value);
|
||||
snprintf(path, sizeof(path),
|
||||
"/etc/hostname.%s", ifname);
|
||||
fileout(line, "a", path);
|
||||
|
||||
/* runtime configuration */
|
||||
(void)shell("ifconfig", ifname, family,
|
||||
"alias", net->net_value, NULL);
|
||||
break;
|
||||
case NET_GATEWAY:
|
||||
fileout(net->net_value, "a", "/etc/mygate");
|
||||
break;
|
||||
case NET_DNS:
|
||||
snprintf(line, sizeof(line), "nameserver %s",
|
||||
net->net_value);
|
||||
fileout(line, "a", "/etc/resolv.conf");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
agent_unconfigure(void)
|
||||
{
|
||||
|
@ -924,13 +1103,18 @@ main(int argc, char *const *argv)
|
|||
* XXX Detect cloud with help from hostctl and sysctl
|
||||
* XXX in addition to the interface name.
|
||||
*/
|
||||
if (strcmp("hvn0", sc->sc_interface) == 0)
|
||||
if (opennebula(sc) == 0)
|
||||
ret = 0;
|
||||
else if (strcmp("hvn0", sc->sc_interface) == 0)
|
||||
ret = azure(sc);
|
||||
else if (strcmp("xnf0", sc->sc_interface) == 0)
|
||||
ret = ec2(sc);
|
||||
else
|
||||
ret = openstack(sc);
|
||||
|
||||
if (sc->sc_stack != NULL)
|
||||
log_debug("%s: %s", __func__, sc->sc_stack);
|
||||
|
||||
if (sc->sc_dryrun) {
|
||||
agent_free(sc);
|
||||
return (0);
|
||||
|
|
36
agent/main.h
36
agent/main.h
|
@ -43,7 +43,31 @@ struct ssh_pubkey {
|
|||
};
|
||||
TAILQ_HEAD(ssh_pubkeys, ssh_pubkey);
|
||||
|
||||
enum net_type {
|
||||
NET_IP,
|
||||
NET_MASK,
|
||||
NET_PREFIX,
|
||||
NET_MAC,
|
||||
NET_MTU,
|
||||
NET_GATEWAY,
|
||||
NET_DNS,
|
||||
NET_MAX
|
||||
};
|
||||
|
||||
struct net_addr {
|
||||
enum net_type net_type;
|
||||
unsigned int net_ifunit;
|
||||
char *net_value;
|
||||
struct sockaddr_storage net_addr;
|
||||
unsigned int net_num;
|
||||
|
||||
TAILQ_ENTRY(net_addr) net_entry;
|
||||
};
|
||||
TAILQ_HEAD(net_addrs, net_addr);
|
||||
|
||||
struct system_config {
|
||||
const char *sc_stack;
|
||||
|
||||
char *sc_hostname;
|
||||
char *sc_username;
|
||||
char *sc_password;
|
||||
|
@ -56,10 +80,15 @@ struct system_config {
|
|||
const char *sc_ovfenv;
|
||||
const char *sc_interface;
|
||||
const char *sc_cdrom;
|
||||
int sc_mount;
|
||||
|
||||
struct source sc_addr;
|
||||
struct ssh_pubkeys sc_pubkeys;
|
||||
|
||||
int sc_network;
|
||||
struct net_addrs sc_netaddrs;
|
||||
unsigned int sc_netmtu;
|
||||
|
||||
int sc_nullfd;
|
||||
int sc_dryrun;
|
||||
void *sc_priv;
|
||||
|
@ -92,6 +121,9 @@ int azure(struct system_config *);
|
|||
int ec2(struct system_config *);
|
||||
int cloudinit(struct system_config *);
|
||||
|
||||
/* opennebula.c */
|
||||
int opennebula(struct system_config *);
|
||||
|
||||
/* openstack.c */
|
||||
int openstack(struct system_config *);
|
||||
|
||||
|
@ -105,6 +137,10 @@ char *get_line(const unsigned char *, size_t);
|
|||
char *get_word(const unsigned char *, size_t);
|
||||
int agent_addpubkey(struct system_config *, const char *, const char *);
|
||||
int agent_setpubkey(struct system_config *, const char *, const char *);
|
||||
struct net_addr *
|
||||
agent_getnetaddr(struct system_config *, struct net_addr *);
|
||||
int agent_addnetaddr(struct system_config *, unsigned int,
|
||||
const char *, int, enum net_type);
|
||||
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);
|
||||
|
|
209
agent/opennebula.c
Normal file
209
agent/opennebula.c
Normal file
|
@ -0,0 +1,209 @@
|
|||
/*
|
||||
* 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fnmatch.h>
|
||||
#include <fcntl.h>
|
||||
#include <ctype.h>
|
||||
#include <sha2.h>
|
||||
#include <err.h>
|
||||
#include <util.h>
|
||||
|
||||
#include "main.h"
|
||||
|
||||
int
|
||||
opennebula(struct system_config *sc)
|
||||
{
|
||||
FILE *fp;
|
||||
const char *delim = "\\\\\0", *errstr;
|
||||
char *line = NULL, *k, *v, *p, q;
|
||||
char *hname = NULL;
|
||||
size_t len, lineno = 0, i;
|
||||
int ret = -1;
|
||||
unsigned int unit;
|
||||
|
||||
/* Return silently without error */
|
||||
if ((fp = fopen("/mnt/context.sh", "r")) == NULL)
|
||||
goto done;
|
||||
|
||||
sc->sc_stack = "opennebula";
|
||||
|
||||
while ((line = fparseln(fp, &len, &lineno,
|
||||
delim, FPARSELN_UNESCALL)) != NULL) {
|
||||
/* key */
|
||||
k = line;
|
||||
|
||||
/* a context always starts with this header */
|
||||
if (lineno == 1) {
|
||||
ret = strcmp(line,
|
||||
"# Context variables generated by OpenNebula");
|
||||
if (ret != 0) {
|
||||
log_debug("%s: unsupported context", __func__);
|
||||
goto done;
|
||||
}
|
||||
free(line);
|
||||
continue;
|
||||
}
|
||||
line[strcspn(line, "#")] = '\0';
|
||||
|
||||
/* value */
|
||||
if ((v = strchr(line, '=')) == NULL || *(v + 1) == '\0') {
|
||||
free(line);
|
||||
continue;
|
||||
}
|
||||
*v++ = '\0';
|
||||
|
||||
/* value is quoted */
|
||||
q = *v;
|
||||
if (strspn(v, "\"'") == 0 || (p = strrchr(v, q)) == v) {
|
||||
free(line);
|
||||
continue;
|
||||
}
|
||||
*v++ = '\0';
|
||||
*p = '\0';
|
||||
|
||||
/* continue if value is empty */
|
||||
if (*v == '\0') {
|
||||
free(line);
|
||||
continue;
|
||||
}
|
||||
|
||||
log_debug("%s: %s = %s", __func__, k, v);
|
||||
|
||||
if (strcasecmp("NETWORK", k) == 0) {
|
||||
if (strcasecmp("YES", v) == 0)
|
||||
sc->sc_network = 1;
|
||||
else if (strcasecmp("YES", v) == 0)
|
||||
sc->sc_network = 0;
|
||||
} else if (fnmatch("ETH*_*", k, 0) != FNM_NOMATCH) {
|
||||
/* Extract interface unit */
|
||||
if ((p = strdup(k + 3)) == NULL) {
|
||||
log_debug("%s: %s", __func__, k);
|
||||
goto done;
|
||||
}
|
||||
p[strcspn(p, "_")] = '\0';
|
||||
unit = strtonum(p, 0, UINT32_MAX, &errstr);
|
||||
free(p);
|
||||
if (errstr != NULL) {
|
||||
log_debug("%s: %s", __func__, k);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Get subkey */
|
||||
k += strcspn(k, "_") + 1;
|
||||
|
||||
if (strcasecmp("DNS", k) == 0) {
|
||||
/* We don't support per-interface DNS */
|
||||
for (p = v; *p != '\0'; v = p) {
|
||||
p = v + strcspn(v, " \t");
|
||||
*p++ = '\0';
|
||||
if ((ret = agent_addnetaddr(sc, 0,
|
||||
v, AF_UNSPEC, NET_DNS)) != 0)
|
||||
break;
|
||||
}
|
||||
} else if (strcasecmp("IP", k) == 0) {
|
||||
ret = agent_addnetaddr(sc, unit,
|
||||
v, AF_INET, NET_IP);
|
||||
} else if (strcasecmp("MASK", k) == 0) {
|
||||
ret = agent_addnetaddr(sc, unit,
|
||||
v, AF_INET, NET_MASK);
|
||||
} else if (strcasecmp("GATEWAY", k) == 0) {
|
||||
ret = agent_addnetaddr(sc, unit,
|
||||
v, AF_INET, NET_GATEWAY);
|
||||
} else if (strcasecmp("IP6", k) == 0) {
|
||||
ret = agent_addnetaddr(sc, unit,
|
||||
v, AF_INET6, NET_IP);
|
||||
} else if (strcasecmp("GATEWAY6", k) == 0) {
|
||||
ret = agent_addnetaddr(sc, unit,
|
||||
v, AF_INET6, NET_GATEWAY);
|
||||
} else if (strcasecmp("PREFIX_LENGTH", k) == 0) {
|
||||
ret = agent_addnetaddr(sc, unit,
|
||||
v, AF_INET6, NET_PREFIX);
|
||||
} else if (strcasecmp("MAC", k) == 0) {
|
||||
if (unit == 0 && hname == NULL) {
|
||||
/* Fake a hostname using the mac */
|
||||
if ((hname = p = calloc(1,
|
||||
strlen(v) + 3)) == NULL) {
|
||||
log_debug("%s: calloc",
|
||||
__func__);
|
||||
goto done;
|
||||
}
|
||||
*p++ = 'v';
|
||||
*p++ = 'm';
|
||||
for (i = 0; i < strlen(v); i++) {
|
||||
if (!isalnum(v[i]))
|
||||
continue;
|
||||
*p++ = v[i];
|
||||
}
|
||||
}
|
||||
|
||||
ret = agent_addnetaddr(sc, unit,
|
||||
v, AF_UNSPEC, NET_MAC);
|
||||
} else if (strcasecmp("MTU", k) == 0) {
|
||||
ret = agent_addnetaddr(sc, unit,
|
||||
v, AF_UNSPEC, NET_MTU);
|
||||
} else
|
||||
ret = 0;
|
||||
if (ret != 0) {
|
||||
log_debug("%s: failed to parse %s",
|
||||
__func__, k);
|
||||
goto done;
|
||||
}
|
||||
} else if (strcasecmp("SSH_PUBLIC_KEY", k) == 0) {
|
||||
if (agent_addpubkey(sc, v, NULL) != 0)
|
||||
log_warnx("failed to ssh pubkey");
|
||||
}
|
||||
|
||||
free(line);
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
fp = NULL;
|
||||
|
||||
/*
|
||||
* OpenNebula doesn't provide an instance id so we
|
||||
* calculate one using the hash of the context file.
|
||||
* This might break if the context is not consistent.
|
||||
*/
|
||||
if ((sc->sc_instance =
|
||||
calloc(1, SHA256_DIGEST_STRING_LENGTH)) == NULL ||
|
||||
SHA256File("/mnt/context.sh", sc->sc_instance) == NULL) {
|
||||
log_debug("%s: failed to calculate instance hash",
|
||||
__func__);
|
||||
goto done;
|
||||
}
|
||||
log_debug("%s: context instance %s", __func__, sc->sc_instance);
|
||||
|
||||
/* Even the hostname is optional */
|
||||
if (hname != NULL) {
|
||||
free(sc->sc_hostname);
|
||||
sc->sc_hostname = hname;
|
||||
log_debug("%s: hostname %s", __func__, hname);
|
||||
}
|
||||
|
||||
line = NULL;
|
||||
ret = 0;
|
||||
|
||||
done:
|
||||
if (fp != NULL)
|
||||
fclose(fp);
|
||||
free(line);
|
||||
return (ret);
|
||||
}
|
|
@ -44,6 +44,7 @@ openstack(struct system_config *sc)
|
|||
free(sc->sc_endpoint);
|
||||
return (cloudinit(sc));
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
@ -62,6 +63,7 @@ openstack_fetch(struct system_config *sc)
|
|||
if ((json = metadata(sc,
|
||||
"/openstack/latest/meta_data.json", TEXT)) == NULL)
|
||||
goto fail;
|
||||
sc->sc_stack = "openstack";
|
||||
|
||||
if ((j = json_parse(json, strlen(json))) == NULL)
|
||||
goto fail;
|
||||
|
|
Loading…
Reference in a new issue