Commit 7700c6cf authored by Mike Hibler's avatar Mike Hibler
Browse files

Respect the uploader_path field in image_versions.

The "Emulab configuration" of the mserver will now use uploader_path
if set rather than path.

A slight semantic change goes along with this. If the uploader_path is
set, we assume that it is a temporary file to upload to and we (the mserver)
do not do the dance of uploading to our own temporary and moving it into place.
parent 1782fc9b
......@@ -434,6 +434,7 @@ set_put_values(struct config_host_authinfo *ai, int ix)
ii->put_itimeout = put_maxiwait;
/* put_oldversion */
#if 0
/*
* For standard images, we keep ALL old versions as:
* <path>.<timestamp>, just because we are extra paranoid about those.
......@@ -449,7 +450,12 @@ set_put_values(struct config_host_authinfo *ai, int ix)
snprintf(str, len, "%s.%09u", ii->path, (unsigned)curtime);
ii->put_oldversion = str;
} else
ii->put_oldversion = NULL;
#endif
{
int len = strlen(ii->path) + 5;
ii->put_oldversion = mymalloc(len);
snprintf(ii->put_oldversion, len, "%s.bak", ii->path);
}
/* put_options */
ii->put_options = NULL;
......@@ -1480,7 +1486,8 @@ emulab_get_host_authinfo(struct in_addr *req, struct in_addr *host,
if (wantvers) {
res = mydb_query("SELECT i.pid,i.gid,"
"i.imagename,v.path,"
"i.imageid,v.version"
"i.imageid,v.version,"
"v.uploader_path"
" FROM images as i "
" LEFT JOIN image_versions "
" as v on "
......@@ -1488,12 +1495,13 @@ emulab_get_host_authinfo(struct in_addr *req, struct in_addr *host,
" v.version='%s' "
"WHERE i.pid='%s'"
" AND i.imagename='%s'",
6, wantvers, wantpid, wantname);
7, wantvers, wantpid, wantname);
}
else {
res = mydb_query("SELECT i.pid,i.gid,"
"i.imagename,v.path,"
"i.imageid,v.version"
"i.imageid,v.version,"
"v.uploader_path"
" FROM images as i "
" LEFT JOIN image_versions "
" as v on "
......@@ -1501,7 +1509,7 @@ emulab_get_host_authinfo(struct in_addr *req, struct in_addr *host,
" v.version=i.version "
"WHERE i.pid='%s'"
" AND i.imagename='%s'",
6, wantpid, wantname);
7, wantpid, wantname);
}
} else {
/*
......@@ -1511,7 +1519,8 @@ emulab_get_host_authinfo(struct in_addr *req, struct in_addr *host,
if (wantvers) {
res = mydb_query("SELECT i.pid,i.gid,"
"i.imagename,v.path,"
"i.imageid,v.version"
"i.imageid,v.version,"
"v.uploader_path"
" FROM images as i"
" LEFT JOIN image_versions "
" as v on "
......@@ -1523,13 +1532,14 @@ emulab_get_host_authinfo(struct in_addr *req, struct in_addr *host,
" AND (i.gid='%s' OR"
" (i.gid=i.pid AND "
" v.shared=1))",
6, wantvers, wantpid, wantname,
7, wantvers, wantpid, wantname,
ei->pid, ei->gid);
}
else {
res = mydb_query("SELECT i.pid,i.gid,"
"i.imagename,v.path,"
"i.imageid,v.version"
"i.imageid,v.version,"
"v.uploader_path"
" FROM images as i"
" LEFT JOIN image_versions "
" as v on "
......@@ -1572,11 +1582,12 @@ emulab_get_host_authinfo(struct in_addr *req, struct in_addr *host,
struct emulab_ii_extra_info *ii;
struct config_imageinfo *ci;
struct stat sb;
char *iid;
int iidx;
char *iid, *targetpath;
int iidx, hasuploadpath = 0;
row = mysql_fetch_row(res);
/* XXX ignore rows with null or empty info */
/* XXX row[6] (uploader_path) can be NULL */
if (!row[0] || !row[0][0] ||
!row[1] || !row[1][0] ||
!row[2] || !row[2][0] ||
......@@ -1585,6 +1596,16 @@ emulab_get_host_authinfo(struct in_addr *req, struct in_addr *host,
!row[5] || !row[5][0])
continue;
/*
* If an uploader_path was specified, use that.
* Otherwise use the path.
*/
if (row[6] && row[6][0]) {
targetpath = row[6];
hasuploadpath = 1;
} else
targetpath = row[3];
/*
* XXX if image is in the standard image directory,
* disallow PUTs.
......@@ -1597,9 +1618,9 @@ emulab_get_host_authinfo(struct in_addr *req, struct in_addr *host,
* hwdown and other special experiments possibly
* without revoking the access of the previous user.
*/
if (isindir(STDIMAGEDIR, row[3])) {
FrisError("%s: cannot update standard images "
"right now", row[3]);
if (isindir(STDIMAGEDIR, targetpath)) {
FrisError("%s: cannot update image using "
"path '%s'", targetpath);
continue;
}
......@@ -1608,12 +1629,12 @@ emulab_get_host_authinfo(struct in_addr *req, struct in_addr *host,
ci->imageid = iid;
ci->dir = NULL;
if (wantmeta && strcmp(wantmeta, "sig") == 0) {
ci->path = mymalloc(strlen(row[3]) + 4);
strcpy(ci->path, row[3]);
ci->path = mymalloc(strlen(targetpath) + 4);
strcpy(ci->path, targetpath);
strcat(ci->path, ".sig");
ci->flags = CONFIG_PATH_ISSIGFILE;
} else {
ci->path = mystrdup(row[3]);
ci->path = mystrdup(targetpath);
ci->flags = CONFIG_PATH_ISFILE;
}
if (stat(ci->path, &sb) == 0) {
......@@ -1646,6 +1667,16 @@ emulab_get_host_authinfo(struct in_addr *req, struct in_addr *host,
}
set_put_values(put, put->numimages);
/*
* XXX if we have an explict uploader path we are
* under control of image_create and don't need to
* worry about backups.
*/
if (hasuploadpath && ci->put_oldversion) {
free(ci->put_oldversion);
ci->put_oldversion = NULL;
}
ii = mymalloc(sizeof *ii);
ii->DB_imageid = iidx;
ci->extra = ii;
......
......@@ -187,23 +187,28 @@ set_get_values(struct config_host_authinfo *ai, int ix)
static void
set_put_values(struct config_host_authinfo *ai, int ix)
{
struct config_imageinfo *ii = &ai->imageinfo[ix];
int len;
/* put_maxsize */
ai->imageinfo[ix].put_maxsize = 10000000000ULL; /* XXX 10GB */
ii->put_maxsize = 20000000000ULL; /* XXX 20GB */
/* put_timeout */
ai->imageinfo[ix].put_timeout = 900;
ai->imageinfo[ix].put_itimeout = 120;
ii->put_timeout = 1200;
ii->put_itimeout = 120;
/* put_oldversion */
ai->imageinfo[ix].put_oldversion = NULL;
/* put_oldversion -- setting to NULL means no tmpfile during upload */
len = strlen(ii->path) + 5;
ii->put_oldversion = mymalloc(len);
snprintf(ii->put_oldversion, len, "%s.bak", ii->path);
/* put_options */
ai->imageinfo[ix].put_options = NULL;
ii->put_options = NULL;
/* and whack the get_* fields */
ai->imageinfo[ix].get_methods = 0;
ai->imageinfo[ix].get_timeout = 0;
ai->imageinfo[ix].get_options = NULL;
ii->get_methods = 0;
ii->get_timeout = 0;
ii->get_options = NULL;
}
#define FREE(p) { if (p) free(p); }
......
......@@ -2009,7 +2009,7 @@ static void
finishupload(struct childinfo *ci, int status)
{
char *bakname, *tmpname, *realname;
int len, didbackup;
int didbackup;
struct uploadextra *ue;
time_t mtime;
......@@ -2019,14 +2019,28 @@ finishupload(struct childinfo *ci, int status)
mtime = (time_t)ue->mtime;
free(ci->extra);
ci->extra = NULL;
tmpname = ci->imageinfo->path;
ci->imageinfo->path = realname;
if (realname) {
tmpname = ci->imageinfo->path;
assert(tmpname != NULL);
ci->imageinfo->path = realname;
bakname = ci->imageinfo->put_oldversion;
assert(bakname != NULL);
} else {
tmpname = bakname = NULL;
realname = ci->imageinfo->path;
}
if (status != 0) {
FrisError("%s: upload failed, removing tmpfile %s",
realname, tmpname);
unlink(tmpname);
free(tmpname);
if (tmpname) {
FrisError("%s: upload failed, removing tmpfile %s",
realname, tmpname);
unlink(tmpname);
free(tmpname);
} else {
FrisError("%s: upload failed, removing", realname);
unlink(realname);
}
return;
}
......@@ -2035,35 +2049,30 @@ finishupload(struct childinfo *ci, int status)
gettimeofday(&tv[0], NULL);
tv[1].tv_sec = mtime;
tv[1].tv_usec = 0;
if (utimes(tmpname, tv) < 0)
FrisWarning("%s: failed to set mtime", tmpname);
if (utimes(tmpname ? tmpname : realname, tv) < 0)
FrisWarning("%s: failed to set mtime",
tmpname ? tmpname : realname);
}
/*
* If the configuration specified an explicit place for the
* old version, move it there now. Otherwise just save it as
* <realname>.bak
* old version, move it there now. Otherwise, we were saving
* directly to the specified path and there is nothing to backup.
*/
if (ci->imageinfo->put_oldversion)
bakname = ci->imageinfo->put_oldversion;
else {
len = strlen(realname) + 5;
bakname = malloc(len);
snprintf(bakname, len, "%s.bak", realname);
}
didbackup = 1;
if (rename(realname, bakname) < 0)
didbackup = 0;
if ((!didbackup && errno != ENOENT) || rename(tmpname, realname) < 0) {
FrisError("%s: failed to install new version (%d), leaving as %s",
realname, errno, tmpname);
if (didbackup)
rename(bakname, realname);
if (bakname) {
didbackup = 1;
if (rename(realname, bakname) < 0)
didbackup = 0;
if ((!didbackup && errno != ENOENT) ||
rename(tmpname, realname) < 0) {
FrisError("%s: failed to install new version (%d),"
"leaving as %s", realname, errno, tmpname);
if (didbackup)
rename(bakname, realname);
}
free(tmpname);
}
free(tmpname);
if (ci->imageinfo->put_oldversion == NULL)
free(bakname);
FrisLog("%s: upload complete", realname);
}
......@@ -2076,8 +2085,7 @@ startuploader(struct config_imageinfo *ii, in_addr_t meaddr, in_addr_t youaddr,
{
struct childinfo *ci;
struct uploadextra *ue;
char *tmpname;
int len, itimo = 0;
int itimo = 0;
assert(findchild(ii->imageid, PTYPE_UPLOADER, MS_METHOD_ANY) == NULL);
assert(errorp != NULL);
......@@ -2158,14 +2166,21 @@ startuploader(struct config_imageinfo *ii, in_addr_t meaddr, in_addr_t youaddr,
/*
* Arrange to upload the image as <path>.tmp and then
* rename it into place when done.
*
* XXX if put_oldversion is NULL, we assume that we are
* uploading to a temporary file in the first place.
* See config_emulab.c.
*/
len = strlen(ci->imageinfo->path) + 5;
if ((tmpname = malloc(len)) != NULL) {
ue->realname = ci->imageinfo->path;
snprintf(tmpname, len, "%s.tmp", ci->imageinfo->path);
ci->imageinfo->path = tmpname;
ci->done = finishupload;
if (ci->imageinfo->put_oldversion) {
int len = strlen(ci->imageinfo->path) + 5;
char *tmpname = malloc(len);
if (tmpname != NULL) {
ue->realname = ci->imageinfo->path;
snprintf(tmpname, len, "%s.tmp", ci->imageinfo->path);
ci->imageinfo->path = tmpname;
}
}
ci->done = finishupload;
if ((*errorp = startchild(ci)) != 0) {
free_imageinfo(ci->imageinfo);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment