Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add equinix support #56

Merged
merged 10 commits into from
Oct 21, 2022
Merged
6 changes: 2 additions & 4 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ EXTRA_DIST = \
LICENSE \
COPYING \
data/ucd.service.in \
data/ucd@.service.in \
docs/ucd.1.md \
docs/ucd-data-fetch.1.md \
docs/cloud-config.5.md
Expand Down Expand Up @@ -87,10 +88,7 @@ ucd_data_fetch_CFLAGS = $(AM_CFLAGS)
SYSTEMD_DIR=$(prefix)/lib/systemd/system/
systemdsystemunitdir = @SYSTEMD_SYSTEMUNITDIR@
systemdsystemunit_DATA = data/ucd.service \
data/ucd-aws.service \
data/ucd-oci.service \
data/ucd-tencent.service \
data/ucd-aliyun.service
data/ucd@.service
bwarden marked this conversation as resolved.
Show resolved Hide resolved

systemdsystemunit-install-local:
mkdir -p $(DESTDIR)$(systemdsystemunitdir)/multi-user.target.wants/
Expand Down
5 changes: 1 addition & 4 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,7 @@ AC_CONFIG_SRCDIR([src/main.c])
AC_CONFIG_FILES([Makefile
tests/Makefile
data/ucd.service
data/ucd-aws.service
data/ucd-oci.service
data/ucd-tencent.service
data/ucd-aliyun.service])
data/ucd@.service])
AC_CONFIG_HEADERS([config.h])

LT_INIT
Expand Down
17 changes: 0 additions & 17 deletions data/ucd-aliyun.service.in

This file was deleted.

17 changes: 0 additions & 17 deletions data/ucd-oci.service.in

This file was deleted.

17 changes: 0 additions & 17 deletions data/ucd-tencent.service.in

This file was deleted.

6 changes: 3 additions & 3 deletions data/ucd-aws.service.in → data/ucd@.service.in
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
[Unit]
Description=micro-config-drive job for AWS
Description=micro-config-drive job for %I
After=network.target systemd-networkd.service
Wants=local-fs.target sshd.service sshd-keygen.service
ConditionPathExists=!/var/lib/cloud/aws-user-data
ConditionPathExists=!/var/lib/cloud/%I-user-data

[Service]
Type=oneshot
ExecStart=@prefix@/bin/ucd-data-fetch aws
ExecStart=@prefix@/bin/ucd-data-fetch %I
RemainAfterExit=yes
TimeoutSec=0

Expand Down
144 changes: 115 additions & 29 deletions src/ucd-data-fetch.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
#include <stdbool.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/stat.h>
#include <sys/types.h>
Expand All @@ -60,61 +61,86 @@
struct cloud_struct {
char *name;
char *ip;
uint16_t port;
char *request_sshkey_path;
char *request_userdata_path;
char *cloud_config_header;
};

#define MAX_CONFIGS 4
#define MAX_CONFIGS 6
static struct cloud_struct config[MAX_CONFIGS] = {
{
"aws",
"169.254.169.254",
80,
"/latest/meta-data/public-keys/0/openssh-key",
"/latest/user-data",
"#cloud-config\n" \
"users:\n" \
" - name: clear\n" \
" groups: wheelnopw\n" \
"ssh_authorized_keys:\n" \
" - "
"ssh_authorized_keys:\n"
},
{
"oci",
"169.254.169.254",
80,
"/opc/v1/instance/metadata/ssh_authorized_keys",
NULL,
"#cloud-config\n" \
"users:\n" \
" - name: opc\n" \
" groups: wheelnopw\n" \
" gecos: Oracle Public Cloud User\n" \
"ssh_authorized_keys:\n" \
" - "
"ssh_authorized_keys:\n"
},
{
"tencent",
"169.254.0.23",
80,
"/latest/meta-data/public-keys/0/openssh-key",
NULL,
"#cloud-config\n" \
"users:\n" \
" - name: tencent\n" \
" groups: wheelnopw\n" \
"ssh_authorized_keys:\n" \
" - "
"ssh_authorized_keys:\n"
},
{
"aliyun",
"100.100.100.200",
80,
"/latest/meta-data/public-keys/0/openssh-key",
NULL,
"#cloud-config\n" \
"users:\n" \
" - name: aliyun\n" \
" groups: wheelnopw\n" \
"ssh_authorized_keys:\n" \
" - "
"ssh_authorized_keys:\n"
},
{
"equinix",
"metadata.platformequinix.com",
80,
"/2009-04-04/meta-data/public-keys",
"/userdata",
"#cloud-config\n" \
"users:\n" \
" - name: clear\n" \
" groups: wheelnopw\n" \
"ssh_authorized_keys:\n"
},
{
"test",
"127.0.0.254",
8123,
"/public-keys",
"/user-data",
"#cloud-config\n" \
"users:\n" \
" - name: clear\n" \
" groups: wheelnopw\n" \
"ssh_authorized_keys:\n"
}
};

Expand Down Expand Up @@ -162,31 +188,36 @@ static int parse_headers(FILE *f, size_t *cl)
}

/**
* write_lines() - write remaining data from stream f into out, while minding cl length
* write_lines() - write remaining lines from stream f into out, while minding cl length
* - if prefix != NULL, each line written is prefixed with the prefix.
* - returns 0 on success, 1 on failure
* - after this call, the calue of `cl` outside the function is invalid.
* - after this call, the value of `cl` outside the function is invalid.
*/
static int write_lines(int out, FILE *f, size_t cl)
static int write_lines(int out, FILE *f, size_t cl, const char *prefix)
{
for (;;) {
if (cl == 0) {
return 0;
}

size_t len;
char buf[512] = {0};
char buf[2048] = {0};

len = (cl > sizeof(buf)) ? sizeof(buf) : cl;

size_t r = fread(buf, 1, len, f);
char *r = fgets(buf, sizeof(buf), f);
if (ferror(f)) {
return 1;
} else if (r == 0) {
} else if (!r) {
return 0;
}

cl -= r;
if (write(out, buf, r) < (ssize_t)r) {
size_t len = strlen(r);
cl -= len;

if (prefix) {
if (write(out, prefix, strlen(prefix)) < (ssize_t)strlen(prefix))
return 1;
}

if (write(out, buf, len) < (ssize_t)len) {
return 1;
}
}
Expand Down Expand Up @@ -233,12 +264,42 @@ int main(int argc, char *argv[]) {
memset(&server, 0, sizeof(struct sockaddr_in));
server.sin_family = AF_INET;
server.sin_addr.s_addr = inet_addr(config[conf].ip);
server.sin_port = htons(80);
server.sin_port = htons(config[conf].port);

struct timespec ts;
ts.tv_sec = 0;
ts.tv_nsec = 50000000;

/* Do we need to look up a hostname? */
if ((int) server.sin_addr.s_addr == -1) {
n = 0;
for (;;) {
struct hostent *hp = gethostbyname(config[conf].ip);
if (hp != NULL) {
if (hp->h_length > 0) {
/* Got it; use the resulting IP address */
server.sin_family = (short unsigned int) (hp->h_addrtype & 0xFFFF);
memcpy(&(server.sin_addr.s_addr), hp->h_addr, (size_t) hp->h_length);
break;
}
else {
fprintf(stderr, "gethostbyname(): empty response");
exit(EXIT_FAILURE);
}
}

if ((h_errno != TRY_AGAIN) && (h_errno != NO_RECOVERY)) {
herror("gethostbyname()");
exit(EXIT_FAILURE);
}
nanosleep(&ts, NULL);
if (++n > 2000) { /* 100 secs */
herror("gethostbyname()");
exit(EXIT_FAILURE);
}
}
}

for (;;) {
int r = connect(sockfd, (struct sockaddr *)&server, sizeof(server));
if (r == 0) {
Expand All @@ -248,7 +309,7 @@ int main(int argc, char *argv[]) {
FAIL("connect()");
}
nanosleep(&ts, NULL);
if (++n > 200) { /* 10 secs */
if (++n > 2400) { /* 120 secs - any used up in gethostbyname */
FAIL("timeout in connect()");
}
}
Expand All @@ -275,36 +336,56 @@ int main(int argc, char *argv[]) {
size_t cl;
int result = parse_headers(f, &cl);
if (result != 1) {
close(sockfd);
fclose(f);
FAIL("parse_headers()");
}

close(sockfd);

int out;
(void) mkdir(USER_DATA_PATH, 0);
if (asprintf(&outpath, "%s/%s-user-data", USER_DATA_PATH, config[conf].name) < 0) {
fclose(f);
FAIL("asprintf()");
}
/* Special case for testing -- can't use/don't need privileged directory */
if (0 == strcmp(config[conf].name, "test")) {
if (asprintf(&outpath, "%s-user-data", config[conf].name) < 0) {
fclose(f);
FAIL("asprintf()");
}
}
(void) unlink(outpath);
out = open(outpath, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
if (out < 0) {
fclose(f);
FAIL("open()");
}

/* Insert cloud-config header above SSH key. */
len = strlen(config[conf].cloud_config_header);
if (write(out, config[conf].cloud_config_header, len) < (ssize_t)len) {
close(out);
fclose(f);
unlink(outpath);
FAIL("write()");
}

if (write_lines(out, f, cl) != 0) {
/* Write out SSH keys */
if (write_lines(out, f, cl, " - ") != 0) {
close(out);
fclose(f);
unlink(outpath);
FAIL("write_lines()");
}

/* Write an extra linefeed in case this didn't end with one */
if (write(out, "\n", 1) < (ssize_t) 1) {
close(out);
fclose(f);
unlink(outpath);
FAIL("write()");
}
close(sockfd);

/* reopen socket */
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
Expand Down Expand Up @@ -357,7 +438,7 @@ int main(int argc, char *argv[]) {
}

/* don't write part #2 if 404 or some non-error */
if ((result != 2) && (write_lines(out, f, cl) != 0)) {
if ((result != 2) && (write_lines(out, f, cl, NULL) != 0)) {
close(out);
fclose(f);
unlink(outpath);
Expand All @@ -370,6 +451,11 @@ int main(int argc, char *argv[]) {

finish:

(void) execl(BINDIR "/ucd", BINDIR "/ucd", "-u", outpath, (char *)NULL);
FAIL("exec()");
/* Don't run ucd for the test template */
if (strcmp(config[conf].name, "test") != 0) {
(void) execl(BINDIR "/ucd", BINDIR "/ucd", "-u", outpath, (char *)NULL);
FAIL("exec()");
}
bwarden marked this conversation as resolved.
Show resolved Hide resolved

return 0;
}
Loading