Add "-r rootdisk" growdisk support

This commit is contained in:
reykfloeter 2019-06-01 23:41:32 +02:00
parent a8490a757f
commit 8dfa3c843a
5 changed files with 193 additions and 21 deletions

View file

@ -1,6 +1,7 @@
PROG= cloud-agent
SRCS= http.c json.c jsmn.c log.c main.c xml.c
SRCS+= azure.c cloudinit.c opennebula.c openstack.c
SRCS+= growdisk.c
BINDIR= /usr/local/libexec
MANDIR= /usr/local/man/man

View file

@ -23,6 +23,7 @@
.Sh SYNOPSIS
.Nm cloud-agent
.Op Fl nuv
.Op Fl r Ar rootdisk
.Op Fl t Ar timeout
.Op Fl U Ar username
.Ar interface
@ -53,6 +54,10 @@ configuration.
Using
.Dq root
is supported, but not recommended.
.It Fl r Ar rootdisk
Automatically grow the last
.Ox
FFS partition of the root disk to use all the available space.
.It Fl u
Deprovision and unconfigure the system.
This deletes keys, passwords, and logs files without asking for permission.
@ -64,11 +69,12 @@ Enable
.Nm
in the
.Xr hostname.if 5
of the VM's primary networking interface:
of the VM's primary networking interface and automatically the last
partition of the root disk:
.Bd -literal -offset indent
# cat /etc/hostname.hvn0
dhcp
!/usr/local/libexec/cloud-agent "\e$if"
!/usr/local/libexec/cloud-agent -r sd0 "\e$if"
.Ed
.Sh FILES
.Bl -tag -width "/usr/local/libexec/cloud-agentX" -compact

149
agent/growdisk.c Normal file
View file

@ -0,0 +1,149 @@
/*
* Copyright (c) 2019 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/param.h> /* DEV_BSIZE */
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/dkio.h>
#define DKTYPENAMES
#include <sys/disklabel.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <util.h>
#include <err.h>
#include "main.h"
static uint16_t dkcksum(struct disklabel *);
static uint16_t
dkcksum(struct disklabel *lp)
{
uint16_t *start, *end, sum;
start = (uint16_t *)lp;
end = (uint16_t *)&lp->d_partitions[lp->d_npartitions];
for (sum = 0; start < end;)
sum ^= *start++;
return (sum);
}
int
growdisk(struct system_config *sc)
{
char c, last_part = 0, *out, *path = NULL;
int ret = -1, i, errfd, outfd;
struct partition *pp, *p = NULL;
struct disklabel lp;
int fd;
uint16_t cksum;
/*
* Grow the OpenBSD MBR partition
*/
/* XXX this is a bit ugly but easier to do */
if (shellout("e 3\n\n\n\n*\nw\nq\n", &out,
"fdisk", "-e", sc->sc_rootdisk, NULL) != 0) {
log_warnx("failed to grow OpenBSD partition");
return (-1);
}
free(out);
/*
* Grow the last partition in the disklabel
*/
if ((fd = opendev(sc->sc_rootdisk,
O_RDWR, OPENDEV_PART, NULL)) == -1) {
log_warn("failed to open %s", sc->sc_rootdisk);
return (-1);
}
if (ioctl(fd, DIOCGDINFO, &lp) == -1) {
log_warn("failed to get disklabel");
goto done;
}
if (lp.d_magic != DISKMAGIC || lp.d_magic2 != DISKMAGIC) {
log_warnx("invalid disklabel magic bytes");
goto done;
}
cksum = lp.d_checksum;
lp.d_checksum = 0;
if (dkcksum(&lp) != cksum) {
log_warnx("invalid disklabel checksum");
goto done;
}
pp = lp.d_partitions;
for (i = 0, pp = lp.d_partitions; i < lp.d_npartitions; i++, pp++) {
if (!DL_GETPSIZE(pp))
continue;
c = 'a' + i;
if (pp->p_fstype == FS_BSDFFS) {
last_part = c;
p = pp;
}
}
if (last_part == 0) {
log_warnx("last BSD partition not found");
goto done;
}
/* Update OpenBSD boundaries */
DL_SETBEND(&lp, DL_GETDSIZE(&lp) - DL_GETBSTART(&lp));
/* Update the size of the last partition */
DL_SETPSIZE(p, DL_GETBEND(&lp) - DL_GETPOFFSET(p));
lp.d_checksum = dkcksum(&lp);
if (ioctl(fd, DIOCWDINFO, &lp) == -1) {
log_warn("failed to write disklabel");
goto done;
}
/*
* Grow the filesystem
*/
if (asprintf(&path, "/dev/%s%c", sc->sc_rootdisk, last_part) == -1)
goto done;
errfd = disable_output(sc, STDERR_FILENO);
outfd = disable_output(sc, STDOUT_FILENO);
(void)shell("umount", "-f", path, NULL);
(void)shell("growfs", "-yq", path, NULL);
if ((ret = shell("fsck", "-y", path, NULL)) != 0)
ret = -1;
enable_output(sc, STDERR_FILENO, errfd);
enable_output(sc, STDOUT_FILENO, outfd);
ret = 0;
done:
free(path);
close(fd);
return (ret);
}

View file

@ -43,7 +43,8 @@
#include "xml.h"
__dead void usage(void);
static struct system_config *agent_init(const char *, int, int);
static struct system_config
*agent_init(const char *, 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 *);
@ -306,7 +307,7 @@ get_word(const unsigned char *ptr, size_t len)
}
static struct system_config *
agent_init(const char *ifname, int dryrun, int timeout)
agent_init(const char *ifname, const char *rootdisk, int dryrun, int timeout)
{
struct system_config *sc;
int fd, ret;
@ -318,6 +319,7 @@ agent_init(const char *ifname, int dryrun, int timeout)
sc->sc_cdrom = "/dev/cd0c";
sc->sc_dryrun = dryrun ? 1 : 0;
sc->sc_timeout = agent_timeout = timeout < 1 ? -1 : timeout * 1000;
sc->sc_rootdisk = rootdisk;
TAILQ_INIT(&sc->sc_pubkeys);
TAILQ_INIT(&sc->sc_netaddrs);
@ -1089,8 +1091,8 @@ usage(void)
{
extern char *__progname;
fprintf(stderr, "usage: %s [-nuv] [-t 3] [-U puffy] interface\n",
__progname);
fprintf(stderr, "usage: %s [-nuv] [-r rootdisk] [-t 3] [-U puffy] "
"interface\n", __progname);
exit(1);
}
@ -1130,19 +1132,19 @@ main(int argc, char *const *argv)
struct system_config *sc;
int verbose = 0, dryrun = 0, unconfigure = 0;
int ch, ret, timeout = CONNECT_TIMEOUT;
const char *error = NULL;
const char *error = NULL, *rootdisk = NULL;
char *args, *username = NULL;
if ((args = get_args(argc, argv)) == NULL)
fatalx("failed to save args");
while ((ch = getopt(argc, argv, "nvt:U:u")) != -1) {
while ((ch = getopt(argc, argv, "nr:t:U:uv")) != -1) {
switch (ch) {
case 'n':
dryrun = 1;
break;
case 'v':
verbose += 2;
case 'r':
rootdisk = optarg;
break;
case 't':
timeout = strtonum(optarg, -1, 86400, &error);
@ -1156,6 +1158,9 @@ main(int argc, char *const *argv)
case 'u':
unconfigure = 1;
break;
case 'v':
verbose += 2;
break;
default:
usage();
}
@ -1176,11 +1181,18 @@ main(int argc, char *const *argv)
if (argc != 1)
usage();
if (pledge("stdio cpath rpath wpath exec proc dns inet", NULL) == -1)
if (pledge(rootdisk == NULL ?
"stdio cpath rpath wpath exec proc dns inet" :
"stdio cpath rpath wpath exec proc dns inet disklabel",
NULL) == -1)
fatal("pledge");
if ((sc = agent_init(argv[0], dryrun, timeout)) == NULL)
if ((sc = agent_init(argv[0], rootdisk, dryrun, timeout)) == NULL)
fatalx("agent");
if (rootdisk != NULL && growdisk(sc) == -1)
fatalx("failed to grow %s", rootdisk);
sc->sc_args = args;
if (username != NULL) {
free(sc->sc_username);

View file

@ -82,6 +82,7 @@ struct system_config {
const char *sc_ovfenv;
const char *sc_interface;
const char *sc_cdrom;
const char *sc_rootdisk;
int sc_mount;
struct source sc_addr;
@ -129,6 +130,9 @@ int opennebula(struct system_config *);
/* openstack.c */
int openstack(struct system_config *);
/* growdisk.c */
int growdisk(struct system_config *);
/* main.c */
int shell(const char *, ...);
int shellout(const char *, char **, const char *, ...);