commit 082b76a78c099283ef9f29255cb9b9679f8e14d3
Author: Pete Zaitcev <zaitcev(a)yahoo.com>
Date: Mon Jul 11 16:31:06 2011 -0600
use POST body for ID and messages
This patch addresses two issues. First, RHEV-M sometimes throws some
diagnostics at us, which are far too long to stuff into a 64-byte
attribute, but which are desirable to see. Second, we now allow
multiple registrations for clouds that allow that. Requested by
Ian McLeod.
So, this patch adds a body to POST reply. Its first line is ID,
in same format as ami-id was, only longer, and the rest is the
diagnostic messages.
https://www.aeolusproject.org/redmine/issues/1253
https://www.aeolusproject.org/redmine/issues/1886
NEWS | 8 +++++
backend.c | 48 ++++++++++++++++++++++++++++++
dc-rhev-image.c | 78 ++++++++++++++++++++++++++++++++++---------------
doc/registrations.md | 16 ++++++++--
state_defs.h | 2 +-
5 files changed, 124 insertions(+), 28 deletions(-)
---
diff --git a/NEWS b/NEWS
index 63bbec9..d3da617 100644
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,14 @@ iwhd NEWS -*- outline
-*-
* Noteworthy changes in release ?.? (????-??-??) [?]
+** New features
+
+ A registration to RHEV-M now returns the ID and diagnostic messages
+ in the body of reply to POST request. This permits to register the
+ same image several times, and helps triaging any problems. The old
+ "ami-id" attribute is retained and remains the same across registration
+ back-end types.
+
** Bug fixes
On Fedora systems, /etc/iwhd/conf.js is not overwritten anymore when
diff --git a/backend.c b/backend.c
index 4102a00..62cb42b 100644
--- a/backend.c
+++ b/backend.c
@@ -62,6 +62,7 @@ static struct hstor_client *hstor;
#define ADDR_SIZE 256
#define LINE_SIZE 500
#define HEADER_SIZE 64
+#define ERR_SIZE 2000
#define S3_IMAGE_PATTERN "^IMAGE[[:blank:]]+([^[:space:]]+)"
#define S3_ERROR_PATTERN "^ERROR[[:blank:]]+([^[:space:]]+)"
@@ -1450,6 +1451,12 @@ fs_rhevm_register (my_state *ms, const provider_t *prov, const char
*next,
char ami_id_buf[64];
regmatch_t match[2];
+ struct MHD_Response *resp;
+ char res_buf[LINE_SIZE];
+ char msg_buf[ERR_SIZE+1];
+ char *msg_ptr;
+ int rc;
+
strcpy(ami_id_buf, "none");
if (!regex_ok) {
@@ -1583,14 +1590,27 @@ fs_rhevm_register (my_state *ms, const provider_t *prov, const
char *next,
strcpy(ami_id_buf,"failed (fdopen)");
goto cleanup;
}
+ res_buf[0] = 0;
+ msg_ptr = msg_buf;
while (fgets(buf,sizeof(buf)-1,fp)) {
if ((s = strchr(buf, '\n')) != NULL)
*s = '\0';
+
+ if (msg_ptr < &msg_buf[ERR_SIZE]) {
+ rc = snprintf(msg_ptr,&msg_buf[ERR_SIZE]-msg_ptr,
+ "%s\r\n",buf);
+ if (msg_ptr + rc >= &msg_buf[ERR_SIZE])
+ msg_ptr = &msg_buf[ERR_SIZE];
+ else
+ msg_ptr += rc;
+ }
+
if (regexec(&s3_success_pat,buf,2,match,0) == 0) {
buf[match[1].rm_eo] = '\0';
s = buf+match[1].rm_so;
DPRINTF("found image UUID: %s\n",s);
snprintf(ami_id_buf,sizeof(ami_id_buf),"OK %s",s);
+ snprintf(res_buf,LINE_SIZE,"OK %s\r\n",s);
ret = MHD_HTTP_OK;
}
else if (strncmp(buf,"ERROR",sizeof("ERROR")-1) == 0) {
@@ -1599,11 +1619,13 @@ fs_rhevm_register (my_state *ms, const provider_t *prov, const
char *next,
s++;
DPRINTF("found err marker: %s\n",s);
snprintf(ami_id_buf,sizeof(ami_id_buf),"failed %s",s);
+ snprintf(res_buf,LINE_SIZE,"failed\r\n");
}
else {
DPRINTF("<%s>\n",buf);
}
}
+ *msg_ptr = 0;
fclose(fp);
DPRINTF("waiting for child...\n");
@@ -1623,6 +1645,32 @@ fs_rhevm_register (my_state *ms, const provider_t *prov, const char
*next,
DPRINTF("...child exited\n");
}
+ /*
+ * TBD: Ian requested JSON output, so we should invoke
+ * MHD_lookup_connection_value(,,"Accept") here and negotiate
+ * JSON or plain text (or maybe XML). However, JSON requires
+ * escaping, which is kinda bothersome, so do it later.
+ */
+ rc = asprintf(&msg_ptr, "%s%s", res_buf, msg_buf);
+ if (rc < 0) {
+ ret = MHD_HTTP_INTERNAL_SERVER_ERROR;
+ strcpy(ami_id_buf,"failed (no core)");
+ goto cleanup;
+ }
+
+ resp = MHD_create_response_from_data(strlen(msg_ptr),msg_ptr,
+ MHD_YES,MHD_NO);
+ if (!resp) {
+ fprintf(stderr,"MHD_crfd failed\n");
+ ret = MHD_HTTP_INTERNAL_SERVER_ERROR;
+ strcpy(ami_id_buf,"failed (MHD_cfgd)");
+ goto cleanup;
+ }
+ MHD_queue_response(ms->conn,ret,resp);
+ MHD_destroy_response(resp);
+
+ ret = MHD_HTTP_PROCESSING;
+
if (strncmp(ami_id_buf,"pending",sizeof("pending")-1)==0) {
/*
* Unfortunately "pending" may get stuck if dc-rhev-image
diff --git a/dc-rhev-image.c b/dc-rhev-image.c
index c768445..00ee16c 100644
--- a/dc-rhev-image.c
+++ b/dc-rhev-image.c
@@ -1912,16 +1912,13 @@ static void copyimage(const struct config *cfg, const struct
id_pack *idp,
static char *import_get_status(xmlNode *etparent)
{
- char *status;
+ char *status, *p;
+ const char *error;
xmlNode *et;
xmlNode *ettext;
+ int rc;
- for (et = etparent->children; et; et = et->next) {
- if (et->type != XML_ELEMENT_NODE)
- continue;
- if (strcmp((const char *)et->name, "status") == 0)
- break;
- }
+ et = xmlGetChild(etparent, "status");
if (!et) {
fprintf(stderr, "ERROR No import status\n");
exit(EXIT_FAILURE);
@@ -1933,10 +1930,56 @@ static char *import_get_status(xmlNode *etparent)
exit(EXIT_FAILURE);
}
- status = strdup((char *)ettext->content);
- if (!status)
+ status = (char *)ettext->content;
+ if (c_strcasecmp(status, "COMPLETE") == 0 ||
+ c_strcasecmp(status, "IN_PROGRESS") == 0 ||
+ c_strcasecmp(status, "PENDING") == 0)
+ {
+ status = strdup(status);
+ if (!status)
+ goto err_alloc;
+ return status;
+ }
+
+ /*
+ * The status is most likely "FAILED". Try to find out the reason.
+ * Actually, <reason> is usually inane, so just go for <detail>.
+ *
+ * <action>
+ * <storage_domain id="af096e18-4b05-4a04-bc60-5a4148d73b9c"/>
+ * <cluster id="2ffa21f2-0d68-4c6b-98e3-0ef6ec5003e7"/>
+ * <status>FAILED</status>
+ * <fault>
+ * <reason>RHEVM operation failed</reason>
+ * <detail>[vm cannot import template name exists, var action import,
var type vm template]</detail>
+ * </fault>
+ * </action>
+ */
+ error = "-";
+ et = xmlGetChild(etparent, "fault");
+ if (et) {
+ et = xmlGetChild(et, "detail");
+ if (et) {
+ ettext = et->children;
+ if (ettext &&
+ ettext->type == XML_TEXT_NODE &&
+ ettext->content)
+ {
+ error = (const char *)ettext->content;
+ }
+ }
+ }
+
+ rc = asprintf(&status, "%s %s", status, error);
+ if (rc < 0)
goto err_alloc;
+ /* This special-casing helps to unravel Java tracebacks. */
+ for (p = status; *p != 0; p++) {
+ if (*p == '\r')
+ *p = ' ';
+ }
+
return status;
err_alloc:
@@ -2078,20 +2121,7 @@ static xmlChar *import_start(struct config *cfg, struct api_conn
*connection,
c_strcasecmp(status, "IN_PROGRESS") == 0) {
;
} else {
- fprintf(stderr, "ERROR Bad import status `%s'\n", status);
- /*
- * XXX process "FAILED" status, report meaningful error
- *
- * <action>
- * <storage_domain id="af096e18-4b05-4a04-bc60-5a4148d73b9c"/>
- * <cluster id="2ffa21f2-0d68-4c6b-98e3-0ef6ec5003e7"/>
- * <status>FAILED</status>
- * <fault>
- * <reason>RHEVM operation failed</reason>
- * <detail>[vm cannot import template name exists, var action import,
var type vm template]</detail>
- * </fault>
- * </action>
- */
+ fprintf(stderr, "ERROR import `%s'\n", status);
exit(EXIT_FAILURE);
}
@@ -2215,7 +2245,7 @@ static void import_tpl(struct config *cfg, struct api_conn
*connection,
exit(EXIT_FAILURE);
}
} else {
- fprintf(stderr, "ERROR Unknown import status `%s'\n",
+ fprintf(stderr, "ERROR import `%s'\n",
status);
exit(EXIT_FAILURE);
}
diff --git a/doc/registrations.md b/doc/registrations.md
index b063ba0..1fc09c5 100644
--- a/doc/registrations.md
+++ b/doc/registrations.md
@@ -11,13 +11,23 @@ server M, the registration involves:
- notifying M with an API call
The registration is triggered with "op=register" posted to iwhd image.
-Unfortunately, paramteres are cloud-specific (see examples).
+Unfortunately, parameters are cloud-specific (see examples).
-When registrarion completes with code 200, application is supposed to
-extract a cloud ID from the "ami-id" attribute, and verify that it starts
+When registration completes with code 200, legacy applications extract
+a cloud ID from the "ami-id" attribute, and verify that it starts
with "OK". For example:
curl
http://iwhdhost.eng.example.com:9090/buk1/test_img/ami-id
+Newer applications receive the "OK" tag and the ID in the first line of
+the body of the POST reply. This permits several registrations for the
+same object (obviously only for clouds that support such a concept).
+The rest of the reply consists of diagnostic messages from the registration
+back-end, which help to diagnose issues.
+
+The iwhd 0.96 and prior return an empty reply body (version is available
+in the GET /). Later versions continue to set "ami-id" attribute for
+compatibility.
+
Another unfortunate implementation limitation is that registrations are
going to fail unless iwhd uses a filesystem-type back-end. A work is ongoing
to lift this restriction.
diff --git a/state_defs.h b/state_defs.h
index 6a3fd0b..30bebb9 100644
--- a/state_defs.h
+++ b/state_defs.h
@@ -56,7 +56,7 @@ typedef struct _my_state {
long rc;
/* for proxy puts */
size_t size;
- /* for proxy puts and queries */
+ /* for proxy puts, queries, and registrations */
struct MHD_Connection *conn;
/* for proxy queries */
struct MHD_PostProcessor *post;