This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project iwhd.git.
The branch, master has been updated
via 0f82ac4e7c2cfbfe18a58f89b5543ca8e64290ba (commit)
from c63dfdc7d21bc0bd221777621a7649552a8aa40f (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
http://repo.or.cz/w/iwhd.git/commit/0f82ac4e7c2cfbfe18a58f89b5543ca8e64290ba
commit 0f82ac4e7c2cfbfe18a58f89b5543ca8e64290ba
Author: Jeff Darcy <jdarcy(a)redhat.com>
Date: Wed Oct 13 10:16:03 2010 -0400
Dynamic config, steps 1-3
(rollup of previous patches to keep commits buildable)
Generate provider_t structures at init instead of on demand
Change non-setup code to use provider_t instead of JSON calls
get_provider in rest.c (provider list/update)
get_provider_value in backend.c (EC2 bundling)
get_provider_value in query.leg (policy eval)
many in proxy.c (replication)
Split proxy.c into setup.c and replica.c
Propagate const changes where needed
Reconcile with autostart changes
diff --git a/Makefile.am b/Makefile.am
index ccf5afc..ac88336 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -35,11 +35,13 @@ iwhd_SOURCES = meta.h mpipe.c mpipe.h - proxy.c - proxy.h +
replica.c + replica.h query.c query.h rest.c + setup.c + setup.h
state_defs.h template.c template.h
diff --git a/auto.c b/auto.c
index b4ff5e9..a0e0b21 100644
--- a/auto.c
+++ b/auto.c
@@ -16,11 +16,9 @@
#include <stdarg.h> /* for microhttpd.h (bug in there) */
#include <stdint.h> /* for microhttpd.h (bug in there) */
-#include <microhttpd.h> /* for proxy.h */
-#include <curl/curl.h> /* for proxy.h */
-#include <glib.h> /* for pfoxy.h */
+#include <jansson.h>
-#include "proxy.h"
+#include "setup.h"
#include "iwh.h"
static char auto_arg_port[10];
@@ -146,8 +144,9 @@ struct server_node {
} a;
};
-static int node_resolve(struct server_node *sn,
- const char *hostname, const char *portstr)
+static int
+node_resolve(struct server_node *sn,
+ const char *hostname, const char *portstr)
{
struct addrinfo hints;
struct addrinfo *res, *res0;
@@ -182,7 +181,8 @@ static int node_resolve(struct server_node *sn,
return -1;
}
-static int auto_test_mongod(void)
+static int
+auto_test_mongod(void)
{
struct server_node snode, *sn = &snode;
int sfd;
diff --git a/backend.c b/backend.c
index 1ad376a..b3551ca 100644
--- a/backend.c
+++ b/backend.c
@@ -41,7 +41,7 @@
#define GLOBALS_IMPL
#include "iwh.h"
#include "meta.h"
-#include "proxy.h"
+#include "setup.h"
#include "template.h"
#include "mpipe.h"
#include "backend.h"
@@ -86,10 +86,10 @@ bad_init (void)
void *
bad_get_child (void * ctx)
{
- my_state *ms = (my_state *)ctx;
+ my_state *ms = (my_state *)ctx;
DPRINTF("*** bad call to %sn",__func__);
- pipe_prod_siginit(&ms->pipe,-1);
+ pipe_prod_siginit(&ms->pipe,-1);
return NULL;
}
@@ -224,8 +224,8 @@ s3_get_child (void * ctx)
{
my_state *ms = ctx;
- /* TBD: check existence before calling siginit */
- pipe_prod_siginit(&ms->pipe,0);
+ /* TBD: check existence before calling siginit */
+ pipe_prod_siginit(&ms->pipe,0);
hstor_get(hstor,ms->bucket,ms->key,http_get_prod,&ms->pipe,0);
/* TBD: check return value */
@@ -294,7 +294,7 @@ s3_bcreate (const char *bucket)
return MHD_HTTP_OK;
}
-char *
+static const char *
s3_init_tmpfile (char *value)
{
char *path;
@@ -344,9 +344,9 @@ s3_register (my_state *ms, const provider_t *prov, const char *next,
char *ramdisk = g_hash_table_lookup(args,"ramdisk");
char *api_key;
char *api_secret;
- char *ami_cert;
- char *ami_key;
- char *ami_uid;
+ const char *ami_cert;
+ const char *ami_key;
+ const char *ami_uid;
const char *argv[12];
int argc = 0;
pid_t pid;
@@ -404,7 +404,7 @@ s3_register (my_state *ms, const provider_t *prov, const char *next,
}
}
else {
- ami_cert = get_provider_value(prov->index,"ami-cert");
+ ami_cert = get_provider_value(prov,"ami-cert");
if (!ami_cert) {
error (0, 0, "missing EC2 AMI cert");
goto cleanup;
@@ -419,7 +419,7 @@ s3_register (my_state *ms, const provider_t *prov, const char *next,
}
}
else {
- ami_key = get_provider_value(prov->index,"ami-key");
+ ami_key = get_provider_value(prov,"ami-key");
if (!ami_key) {
error (0, 0, "missing EC2 AMI key");
goto cleanup;
@@ -428,7 +428,7 @@ s3_register (my_state *ms, const provider_t *prov, const char *next,
ami_uid = g_hash_table_lookup(args,"ami-uid");
if (!ami_uid) {
- ami_uid = get_provider_value(prov->index,"ami-uid");
+ ami_uid = get_provider_value(prov,"ami-uid");
if (!ami_uid) {
error (0, 0, "missing EC2 AMI uid");
goto cleanup;
@@ -538,12 +538,12 @@ cleanup:
*/
if (cval && ami_cert) {
unlink(ami_cert);
- free(ami_cert);
+ free((char *)ami_cert);
}
/* Same reasoning as above, with kval/ami_key. */
if (kval && ami_key) {
unlink(ami_key);
- free(ami_key);
+ free((char *)ami_key);
}
(void)meta_set_value(ms->bucket,ms->key,"ami-id",ami_id_buf);
@@ -566,7 +566,7 @@ curl_get_child (void * ctx)
ms->curl = curl_easy_init();
if (!ms->curl) {
- pipe_prod_siginit(&ms->pipe,-1);
+ pipe_prod_siginit(&ms->pipe,-1);
return NULL; /* TBD: flag error somehow */
}
ms->cleanup |= CLEANUP_CURL;
@@ -582,7 +582,7 @@ curl_get_child (void * ctx)
curl_easy_setopt(ms->curl,CURLOPT_WRITEFUNCTION,
http_get_prod);
curl_easy_setopt(ms->curl,CURLOPT_WRITEDATA,&ms->pipe);
- pipe_prod_siginit(&ms->pipe,0);
+ pipe_prod_siginit(&ms->pipe,0);
curl_easy_perform(ms->curl);
curl_easy_getinfo(ms->curl,CURLINFO_RESPONSE_CODE,&ms->rc);
@@ -796,12 +796,12 @@ fs_get_child (void * ctx)
fd = open(file, O_RDONLY);
if (fd < 0) {
- pipe_prod_siginit(&ms->pipe,-1);
- pipe_prod_finish(&ms->pipe);
+ pipe_prod_siginit(&ms->pipe,-1);
+ pipe_prod_finish(&ms->pipe);
return THREAD_FAILED;
}
- pipe_prod_siginit(&ms->pipe,0);
+ pipe_prod_siginit(&ms->pipe,0);
for (;;) {
bytes = read(fd,buf,sizeof(buf));
diff --git a/iwh.h b/iwh.h
index f3c091e..89d38b2 100644
--- a/iwh.h
+++ b/iwh.h
@@ -38,7 +38,6 @@
*/
GLOBAL(int, verbose, 0);
-GLOBAL(char *, cfg_file, NULL);
GLOBAL(const char *, proxy_host, NULL); /* repod/S3 */
GLOBAL(unsigned short, proxy_port, MY_PORT+1); /* repod/S3 */
GLOBAL(const char *, proxy_key, "foo"); /* S3 only */
@@ -49,7 +48,7 @@ GLOBAL(unsigned int, s3mode, 0); /* repod/S3 */
GLOBAL(const char *, local_path, "/tmp"); /* FS */
GLOBAL(const char *, db_host, "localhost");
GLOBAL(unsigned short, db_port, 0);
-GLOBAL(char *, me, "here");
+GLOBAL(const char *, me, "here");
#define DPRINTF(fmt,args...) do { if (verbose) { diff --git a/meta.cpp b/meta.cpp
index 550e4e4..13abfb2 100644
--- a/meta.cpp
+++ b/meta.cpp
@@ -455,7 +455,7 @@ meta_query_stop (void * qobj)
CLIENT_UNLOCK;
}
-extern "C" char *
+extern "C" const char *
query_getter (void *ctx, const char *id)
{
BSONObj *cur_bo = (BSONObj *)ctx;
diff --git a/proxy.c b/proxy.c
deleted file mode 100644
index 9e50f7c..0000000
--- a/proxy.c
+++ /dev/null
@@ -1,1122 +0,0 @@
-/* Copyright (C) 2010 Red Hat, Inc.
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <
http://www.gnu.org/licenses/>. */
-
-#include <config.h>
-
-#include <errno.h>
-#include <error.h>
-#include <fcntl.h>
-#include <getopt.h>
-#include <poll.h>
-#include <pthread.h>
-#include <semaphore.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <strings.h>
-#include <unistd.h>
-#include <assert.h>
-
-#include <microhttpd.h>
-#include <curl/curl.h>
-#include <hstor.h>
-#include <jansson.h>
-
-#include "iwh.h"
-#include "proxy.h"
-#include "query.h"
-#include "meta.h"
-
-/*
- * A config consists of a JSON array of objects, where each object includes:
- *
- * name string
- * type string "s3" or "cf" or "http" (case insensitive)
- * host string
- * port integer
- * key string S3 key or (optional TBD) HTTP user
- * secret string S3 secret or (optional TBD) HTTP password
- *
- * The above fields are all used to implement replication once we've decided to
- * do it. There may be other fields as well, to help us make that decision.
- * For example, there might be one or more fields to describe geographic
- * location, an array of supported image-format names, etc. This information
- * is deliberately left "schema-free" so that users may add whatever fields
- * they like to both the config and to replication attributes on objects.
- */
-
-/* Sizes for internal string buffers. */
-#define ADDR_SIZE 1024
-#define SVC_ACC_SIZE 128
-#define HEADER_SIZE 64
-
-/* Bitfield for things to check in validate_server */
-#define NEED_NONE 0
-#define NEED_SERVER 0x00000001
-#define NEED_CREDS 0x00000002
-#define NEED_PATH 0x00000004
-#define NEED_ALL ~0
-
-extern backend_func_tbl bad_func_tbl;
-extern backend_func_tbl s3_func_tbl;
-extern backend_func_tbl curl_func_tbl;
-extern backend_func_tbl fs_func_tbl;
-
-typedef enum {
- REPL_PUT, /* store an object */
- REPL_ODELETE, /* delete an object */
- REPL_BCREATE, /* create a bucket */
- /* TBD: bucket deletion, others? */
-} repl_t;
-
-typedef struct _repl_item {
- struct _repl_item *next;
- repl_t type;
- char *path;
- unsigned int server;
- size_t size;
- int pipes[2];
-} repl_item;
-
-typedef struct {
- char *cur_bucket;
- char *cur_key;
- json_t *cur_server;
-} query_ctx_t;
-
-static repl_item *queue_head = NULL;
-static repl_item *queue_tail = NULL;
-static pthread_mutex_t queue_lock;
-static sem_t queue_sema;
-static json_t *config = NULL;
-static int rep_count = 0;
-
-static int
-validate_server (unsigned int i)
-{
- json_t *server;
- json_t *elem;
- const char *name;
- const char *type;
- unsigned int needs = NEED_ALL;
-
- server = json_array_get(config,i);
- if (!json_is_object(server)) {
- error(0,0,"config elem %u: missing object",i);
- return 0;
- }
-
- elem = json_object_get(server,"name");
- if (!json_is_string(elem)) {
- error(0,0,"config elem %u: missing name",i);
- return 0;
- }
- name = json_string_value(elem);
-
- elem = json_object_get(server,"type");
- if (!json_is_string(elem)) {
- error(0,0,"config elem %u (%s): missing type",i,name);
- return 0;
- }
- type = json_string_value(elem);
-
- if (!strcasecmp(type,"s3") || !strcasecmp(type,"cf")) {
- needs = NEED_SERVER | NEED_CREDS;
- }
- else if (!strcasecmp(type,"http")) {
- needs = NEED_SERVER;
- }
- else if (!strcasecmp(type,"fs")) {
- needs = NEED_PATH;
- }
- else {
- error(0,0,"config elem %u (%s): bad type",i,name);
- return 0;
- }
-
- if (needs & NEED_SERVER) {
- elem = json_object_get(server,"host");
- if (!json_is_string(elem)) {
- error(0,0,"config elem %u (%s): missing host",
- i,name);
- return 0;
- }
- elem = json_object_get(server,"port");
- if (!json_is_integer(elem)) {
- error(0,0,"config elem %u (%s): missing port",
- i,name);
- return 0;
- }
- }
-
- if (needs & NEED_CREDS) {
- elem = json_object_get(server,"key");
- if (!json_is_string(elem)) {
- error(0,0,"config elem %u (%s): missing key",
- i, name);
- return 0;
- }
- elem = json_object_get(server,"secret");
- if (!json_is_string(elem)) {
- error(0,0, "config elem %u (%s): missing secret",
- i, name);
- return 0;
- }
- }
-
- if (needs & NEED_PATH) {
- elem = json_object_get(server,"path");
- if (!json_is_string(elem)) {
- error(0,0,"config elem %u (%s): missing path",
- i, name);
- return 0;
- }
- }
-
- return 1;
-}
-
-/* We've already validated, so minimal checking here. */
-char *
-set_config (void)
-{
- json_t *server;
- const char *type;
-
- server = json_array_get(config,0);
- type = json_string_value(json_object_get(server,"type"));
- if (strcasecmp(type,"fs")) {
- proxy_host = json_string_value(
- json_object_get(server,"host"));
- proxy_port = json_integer_value(
- json_object_get(server,"port"));
- if (!strcasecmp(type,"s3")) {
- s3mode = 1;
- proxy_key = json_string_value(
- json_object_get(server,"key"));
- proxy_secret = json_string_value(
- json_object_get(server,"secret"));
- }
- else {
- s3mode = 0;
- }
- }
- else {
- local_path = json_string_value(
- json_object_get(server,"path"));
- }
-
- return (char *)json_string_value(json_object_get(server,"name"));
-}
-
-char *
-parse_config (void)
-{
- json_error_t err;
- unsigned int nservers;
- unsigned int i;
-
- if (access(cfg_file,R_OK) < 0) {
- error(0,errno,"failed to open %s for reading", cfg_file);
- return NULL;
- }
-
- config = json_load_file(cfg_file,&err);
- if (!config) {
- error(0,0,"JSON error on line %d: %s",err.line,err.text);
- return NULL;
- }
-
- if (json_typeof(config) != JSON_ARRAY) {
- error(0,0,"config should be a JSON array");
- goto err;
- }
-
- nservers = json_array_size(config);
- if (!nservers) {
- goto err;
- }
-
- for (i = 0; i < nservers; ++i) {
- if (!validate_server(i)) {
- goto err;
- }
- }
-
- /* Everything looks OK. */
- printf("%u replication servers definedn",nservers-1);
- return set_config();
-
-err:
- json_decref(config);
- config = NULL;
- return 0;
-}
-
-char *
-auto_config(void)
-{
- static const char auto_json[] = {
- "[ {n"
- " "name": "fs_autostart",n"
- " "type": "fs",n"
- " "path": "" AUTO_DIR_FS ""n"
- "} ]n",
- };
- json_error_t err;
-
- if (auto_start(db_port) != 0) {
- return NULL;
- }
-
- config = json_loads(auto_json,&err);
- if (!config) {
- fprintf(stderr,"JSON error on line %d: %sn",err.line,err.text);
- return NULL;
- }
-
- if (json_typeof(config) != JSON_ARRAY) {
- goto out_ie;
- }
-
- if (json_array_size(config) != 1) {
- goto out_ie;
- }
-
- if (!validate_server(0)) {
- goto out_ie;
- }
-
- printf("no replication servers defined, auto-start in effectn");
- return set_config();
-
-out_ie:
- error(0, 0, "invalid autostart configuration (internal error)");
- return NULL;
-}
-
-static size_t
-junk_writer (/* const */ void *ptr, size_t size, size_t nmemb, void *stream)
-{
- size_t n;
-
- n = fwrite(ptr,size,nmemb,stream);
- if (n != nmemb)
- error(0, 0, "warning: write failed");
- if (fflush(stream))
- error(0, 0, "warning: write failed");
- DPRINTF("in %s(%zu,%zu) => %zun",__func__,size,nmemb,n);
-
- return n;
-}
-
-static void *
-proxy_repl_prod_fs (void *ctx)
-{
- repl_item *item = ctx;
- int ifd;
- int ofd;
- char buf[1<<16];
- ssize_t ibytes;
- ssize_t obytes;
- ssize_t offset;
-
- DPRINTF("replicating from %s (FS)n",item->path);
-
- ifd = open(item->path,O_RDONLY);
- if (ifd < 0) {
- error(0,errno,"ifd open");
- return THREAD_FAILED;
- }
- ofd = item->pipes[1];
-
- for (;;) {
- ibytes = read(ifd,buf,sizeof(buf));
- if (ibytes <= 0) {
- if (ibytes < 0) {
- error(0,errno,"%s: read failed", item->path);
- }
- else {
- DPRINTF("EOF on ifdn");
- }
- break;
- }
- offset = 0;
- do {
- obytes = write(ofd,buf+offset,ibytes);
- if (obytes <= 0) {
- if (obytes < 0) {
- error(0,errno,"ofd write");
- }
- else {
- DPRINTF("zero-length write on ofdn");
- }
- break;
- }
- ibytes -= obytes;
- offset += obytes;
- } while (ibytes > 0);
- }
-
- close(ifd);
- close(ofd);
-
- DPRINTF("%s returningn",__func__);
- close(item->pipes[1]);
- return NULL;
-}
-
-static void *
-proxy_repl_prod (void *ctx)
-{
- repl_item *item = ctx;
- FILE *fp = fdopen(item->pipes[1],"w");
- char addr[ADDR_SIZE];
- CURL *curl;
- char svc_acc[SVC_ACC_SIZE];
- struct hstor_client *hstor;
- char *bucket;
- char *key;
- char *stctx;
- char *myurl;
- int chars;
-
- if (fp == NULL) {
- error(0, errno, "%s: fdopen failed", __func__);
- return NULL;
- }
-
- chars = snprintf(addr,ADDR_SIZE,
- "http://%s:%u/%s",proxy_host,proxy_port,item->path);
- if (chars >= ADDR_SIZE) {
- error(0,0,"path too long in %s",__func__);
- goto done;
- }
- DPRINTF("replicating from %sn",addr);
-
- if (s3mode) {
- chars = snprintf(svc_acc,SVC_ACC_SIZE,"%s:%u",
- proxy_host,proxy_port);
- if (chars >= SVC_ACC_SIZE) {
- error(0,0,"svc_acc too long in %s",__func__);
- goto done;
- }
- hstor = hstor_new(svc_acc,proxy_host,
- proxy_key,proxy_secret);
- /* Blech. Can't conflict with consumer, though. */
- myurl = strdup(item->path);
- assert (myurl);
- bucket = strtok_r(myurl,"/",&stctx);
- key = strtok_r(NULL,"/",&stctx);
- hstor_get(hstor,bucket,key,
- junk_writer,fp,0);
- hstor_free(hstor);
- free(myurl);
- }
- else {
- curl = curl_easy_init();
- curl_easy_setopt(curl,CURLOPT_URL,addr);
- curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,junk_writer);
- curl_easy_setopt(curl,CURLOPT_WRITEDATA,fp);
- DPRINTF("%s calling curl_easy_performn",__func__);
- curl_easy_perform(curl);
- curl_easy_cleanup(curl);
- }
-
-done:
- DPRINTF("%s returningn",__func__);
- /* Closing should signal to the consumer that we're finished. */
- fclose(fp);
- return NULL;
-}
-
-static size_t
-junk_reader (void *ptr, size_t size, size_t nmemb, void *stream)
-{
- size_t n;
-
- n = fread(ptr,size,nmemb,stream);
- printf("in %s(%zu,%zu) => %zun",__func__,size,nmemb,n);
- return n;
-}
-
-static size_t
-cf_writer (void *ptr ATTRIBUTE_UNUSED, size_t size, size_t nmemb,
- void *stream ATTRIBUTE_UNUSED)
-{
- return size * nmemb;
-}
-
-static size_t
-cf_header (void *ptr, size_t size, size_t nmemb, void *stream)
-{
- char *next;
- char *sctx;
- json_t *server = (json_t *)stream;
-
- next = strtok_r(ptr,":",&sctx);
- if (next) {
- if (!strcasecmp(next,"X-Storage-Url")) {
- next = strtok_r(NULL," nr",&sctx);
- if (next) {
- DPRINTF("got CF URL %sn",next);
- /* NB: after this, original "host" is gone. */
- json_object_set_new(server,"host",
- json_string(next));
- }
- }
- else if (!strcasecmp(next,"X-Storage-Token")) {
- next = strtok_r(NULL," nr",&sctx);
- if (next) {
- DPRINTF("got CF token %sn",next);
- json_object_set_new(server,"token",
- json_string(next));
- }
- }
- }
- return size * nmemb;
-}
-
-static const char *
-get_cloudfiles_token (json_t *server, const char *host, unsigned int port,
- const char * user, const char * key)
-{
- CURL *curl;
- char addr[ADDR_SIZE];
- char auth_user[HEADER_SIZE];
- char auth_key[HEADER_SIZE];
- json_t *token_obj;
- struct curl_slist *slist;
- int chars;
-
- token_obj = json_object_get(server,"token");
- if (token_obj) {
- return json_string_value(token_obj);
- }
-
- chars = snprintf(addr,ADDR_SIZE,"https://%s:%u/v1.0",host,port);
- if (chars >= ADDR_SIZE) {
- error(0,0,"API URL too long in %s",__func__);
- return NULL;
- }
-
- chars = snprintf(auth_user,HEADER_SIZE,"X-Auth-User: %s",user);
- if (chars >= HEADER_SIZE) {
- error(0,0,"auth_user too long in %s",__func__);
- return NULL;
- }
-
- chars = snprintf(auth_key,HEADER_SIZE,"X-Auth-Key: %s",key);
- if (chars >= HEADER_SIZE) {
- error(0,0,"auth_key too long in %s",__func__);
- return NULL;
- }
-
- curl = curl_easy_init();
- curl_easy_setopt(curl,CURLOPT_URL,addr);
- curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,cf_writer);
- curl_easy_setopt(curl,CURLOPT_HEADERFUNCTION,cf_header);
- curl_easy_setopt(curl,CURLOPT_WRITEHEADER,server);
- slist = curl_slist_append(NULL,auth_user);
- slist = curl_slist_append(slist,auth_key);
- curl_easy_setopt(curl,CURLOPT_HTTPHEADER,slist);
- curl_easy_perform(curl);
- curl_easy_cleanup(curl);
- curl_slist_free_all(slist);
-
- token_obj = json_object_get(server,"token");
- return token_obj ? json_string_value(token_obj) : NULL;
-}
-
-static void *
-proxy_repl_cons (void *ctx)
-{
- repl_item *item = ctx;
- FILE *fp = fdopen(item->pipes[0],"r");
- char addr[ADDR_SIZE];
- CURL *curl;
- json_t *server;
- char svc_acc[SVC_ACC_SIZE];
- char auth_hdr[HEADER_SIZE];
- struct hstor_client *hstor;
- char *bucket;
- char *key;
- char *stctx;
- const char *s_host;
- unsigned int s_port;
- const char *s_key;
- const char *s_secret;
- const char *s_type;
- const char *s_name;
- struct curl_slist *slist;
- char *myurl;
- int chars;
-
- if (fp == NULL) {
- error(0, errno, "%s: fdopen failed", __func__);
- return THREAD_FAILED;
- }
-
- server = json_array_get(config,item->server);
- s_host = json_string_value(json_object_get(server,"host"));
- s_port = json_integer_value(json_object_get(server,"port"));
- s_key = json_string_value(json_object_get(server,"key"));
- s_secret = json_string_value(json_object_get(server,"secret"));
- s_type = json_string_value(json_object_get(server,"type"));
- s_name = json_string_value(json_object_get(server,"name"));
-
- myurl = strdup(item->path);
- assert (myurl);
- bucket = strtok_r(myurl,"/",&stctx);
- key = strtok_r(NULL,"/",&stctx);
-
- if (!strcasecmp(s_type,"s3")) {
- DPRINTF("replicating %zu to %s/%s (S3)n",item->size,s_host,
- item->path);
- chars = snprintf(svc_acc,SVC_ACC_SIZE,"%s:%u",s_host,s_port);
- if (chars >= SVC_ACC_SIZE) {
- error(0,0,"svc_acc too long in %s",__func__);
- return THREAD_FAILED;
- }
- hstor = hstor_new(svc_acc,s_host,s_key,s_secret);
- /* Blech. Can't conflict with producer, though. */
- hstor_put(hstor,bucket,key,
- junk_reader,item->size,fp,NULL);
- hstor_free(hstor);
- }
- else {
- const char *token_str = NULL;
- if (!strcasecmp(s_type,"cf")) {
- token_str = get_cloudfiles_token(server,s_host,s_port,
- s_key, s_secret);
- if (!token_str) {
- DPRINTF("could not get CF tokenn");
- return THREAD_FAILED;
- }
- /* Re-fetch as this might have changed. */
- s_host = json_string_value(json_object_get(server,
- "host"));
- chars = snprintf(addr,ADDR_SIZE,"%s/%s",
- s_host,item->path);
- if (chars >= ADDR_SIZE) {
- error(0,0,"CF path too long in %s",__func__);
- return THREAD_FAILED;
- }
- DPRINTF("replicating %zu to %s (CF)n",item->size,
- addr);
- }
- else {
- chars = snprintf(addr,ADDR_SIZE,"http://%s:%u/%s",
- s_host,s_port,item->path);
- if (chars >= ADDR_SIZE) {
- error(0,0,"HTTP path too long in %s",
- __func__);
- return THREAD_FAILED;
- }
- DPRINTF("replicating %zu to %s (repod)n",item->size,
- addr);
- }
- curl = curl_easy_init();
- curl_easy_setopt(curl,CURLOPT_URL,addr);
- curl_easy_setopt(curl,CURLOPT_UPLOAD,1);
- curl_easy_setopt(curl,CURLOPT_INFILESIZE_LARGE,
- (curl_off_t)item->size);
- curl_easy_setopt(curl,CURLOPT_READFUNCTION,junk_reader);
- if (!strcasecmp(s_type,"cf")) {
- chars = snprintf(auth_hdr,HEADER_SIZE,
- "X-Auth-Token: %s",token_str);
- if (chars >= HEADER_SIZE) {
- error(0,0,"auth_token too long in %s",
- __func__);
- return THREAD_FAILED;
- }
- slist = curl_slist_append(NULL,auth_hdr);
- /*
- * Rackspace doesn't clearly document that you'll get
- * 412 (Precondition Failed) if you omit this.
- */
- slist = curl_slist_append(slist,
- "Content-Type: binary/octet-stream");
- }
- else {
- slist = curl_slist_append(NULL,"X-redhat-role: master");
- }
- curl_easy_setopt(curl,CURLOPT_HTTPHEADER,slist);
- curl_easy_setopt(curl,CURLOPT_READDATA,fp);
- DPRINTF("%s calling curl_easy_performn",__func__);
- curl_easy_perform(curl);
- curl_easy_cleanup(curl);
- curl_slist_free_all(slist);
- }
-
- DPRINTF("%s returningn",__func__);
- fclose(fp);
- meta_got_copy(bucket,key,s_name);
- free(myurl);
- return NULL;
-}
-
-static void
-repl_worker_del (const repl_item *item)
-{
- json_t *server;
- const char *s_host;
- unsigned int s_port;
- const char *s_key;
- const char *s_secret;
- const char *s_type;
- char svc_acc[SVC_ACC_SIZE];
- struct hstor_client *hstor;
- char addr[ADDR_SIZE];
- CURL *curl;
- char *bucket;
- char *key;
- char *stctx;
- int chars;
-
- server = json_array_get(config,item->server);
- s_host = json_string_value(json_object_get(server,"host"));
- s_port = json_integer_value(json_object_get(server,"port"));
- s_key = json_string_value(json_object_get(server,"key"));
- s_secret = json_string_value(json_object_get(server,"secret"));
- s_type = json_string_value(json_object_get(server,"type"));
-
- if (!strcasecmp(s_type,"s3")) {
- DPRINTF("%s replicating delete of %s on %s:%u (S3)n",__func__,
- item->path, s_host, s_port);
- chars = snprintf(svc_acc,SVC_ACC_SIZE,"%s:%u",s_host,s_port);
- if (chars >= SVC_ACC_SIZE) {
- error(0,0,"svc_acc too long in %s",__func__);
- return;
- }
- /* TBD: check return */
- hstor = hstor_new(svc_acc,s_host,s_key,s_secret);
- assert (item->path);
- bucket = strtok_r(item->path,"/",&stctx);
- key = strtok_r(NULL,"/",&stctx);
- (void)hstor_del(hstor,bucket,key);
- hstor_free(hstor);
- }
- else {
- DPRINTF("%s replicating delete of %s on %s:%u (HTTP)n",
- __func__, item->path, s_host, s_port);
- chars = snprintf(addr,ADDR_SIZE,"http://%s:%d%s",
- s_host,s_port,item->path);
- if (chars >= ADDR_SIZE) {
- error(0,0,"path too long in %s",__func__);
- return;
- }
- curl = curl_easy_init();
- curl_easy_setopt(curl,CURLOPT_URL,addr);
- curl_easy_setopt(curl,CURLOPT_CUSTOMREQUEST,"DELETE");
- curl_easy_perform(curl);
- curl_easy_cleanup(curl);
- }
-
- DPRINTF("%s returningn",__func__);
-}
-
-static void
-repl_worker_bcreate (repl_item *item)
-{
- json_t *server;
- const char *s_host;
- unsigned int s_port;
- const char *s_key;
- const char *s_secret;
- const char *s_type;
- char svc_acc[SVC_ACC_SIZE];
- struct hstor_client *hstor;
- char addr[ADDR_SIZE];
- CURL *curl;
- int chars;
-
- server = json_array_get(config,item->server);
- s_host = json_string_value(json_object_get(server,"host"));
- s_port = json_integer_value(json_object_get(server,"port"));
- s_key = json_string_value(json_object_get(server,"key"));
- s_secret = json_string_value(json_object_get(server,"secret"));
- s_type = json_string_value(json_object_get(server,"type"));
-
- if (!strcasecmp(s_type,"s3")) {
- DPRINTF("%s replicating create of bucket %s on %s:%u (S3)n",
- __func__, item->path, s_host, s_port);
- chars = snprintf(svc_acc,SVC_ACC_SIZE,"%s:%u",s_host,s_port);
- if (chars >= SVC_ACC_SIZE) {
- error(0,0,"svc_acc too long in %s",__func__);
- return;
- }
- /* TBD: check return */
- hstor = hstor_new(svc_acc,s_host,s_key,s_secret);
- assert (item->path);
- if (!hstor_add_bucket(hstor,item->path)) {
- error(0,0,"bucket create failed for %s",
- item->path);
- }
- hstor_free(hstor);
- }
- else {
- DPRINTF("%s replicating create of bucket %s on %s:%u (HTTP)n",
- __func__, item->path, s_host, s_port);
- chars = snprintf(addr,ADDR_SIZE,"http://%s:%d/%s",
- s_host,s_port,item->path);
- if (chars >= ADDR_SIZE) {
- error(0,0,"path too long in %s",__func__);
- return;
- }
- curl = curl_easy_init();
- curl_easy_setopt(curl,CURLOPT_URL,addr);
- curl_easy_setopt(curl,CURLOPT_CUSTOMREQUEST,"PUT");
- curl_easy_perform(curl);
- curl_easy_cleanup(curl);
- }
-
- DPRINTF("%s returningn",__func__);
-}
-
-/* Use this to diagnose failed thread creation. */
-#define xpthread_create(thread, start_routine, item, msg) - do { - int err =
pthread_create (thread, NULL, start_routine, item); - if (err) { - error
(0, err, msg); - return NULL; - } - } while (0)
-
-static void *
-repl_worker (void *notused ATTRIBUTE_UNUSED)
-{
- repl_item *item;
- pthread_t cons;
- pthread_t prod;
-
- for (;;) {
- sem_wait(&queue_sema);
- pthread_mutex_lock(&queue_lock);
- item = queue_head;
- queue_head = item->next;
- if (!queue_head) {
- queue_tail = NULL;
- }
- pthread_mutex_unlock(&queue_lock);
-
- switch (item->type) {
- case REPL_PUT:
- if (pipe(item->pipes) >= 0) {
- xpthread_create(&prod, (proxy_host
- ? proxy_repl_prod
- : proxy_repl_prod_fs),
- item,
- "failed to start producer thread");
- xpthread_create(&cons,proxy_repl_cons,item,
- "failed to start consumer thread");
- pthread_join(prod,NULL);
- pthread_join(cons,NULL);
- }
- else {
- error(0,errno,"pipe");
- }
- break;
- case REPL_ODELETE:
- repl_worker_del(item);
- break;
- case REPL_BCREATE:
- repl_worker_bcreate(item);
- break;
- default:
- error(0,0,"bad repl type %d (url=%s) skipped",
- item->type, item->path);
- }
- free(item->path);
- free(item);
- /* No atomic dec without test? Lame. */
- (void)g_atomic_int_dec_and_test(&rep_count);
- }
-}
-
-void
-repl_init (void)
-{
- pthread_t tid;
-
- sem_init(&queue_sema,0,0);
- pthread_mutex_init(&queue_lock,NULL);
- pthread_create(&tid,NULL,repl_worker,NULL);
-}
-
-static char *
-repl_oget (void *ctx, const char *id)
-{
- query_ctx_t *qctx = ctx;
- char *cur_value = NULL;
-
- (void)meta_get_value(qctx->cur_bucket,qctx->cur_key,id,&cur_value);
-
- return cur_value;
-}
-
-static char *
-repl_sget (void *ctx, const char *id)
-{
- query_ctx_t *qctx = ctx;
- json_t *elem = json_object_get(qctx->cur_server,id);
-
- return elem ? (char *)json_string_value(elem) : NULL;
-}
-
-void
-replicate (const char *url, size_t size, const char *policy)
-{
- unsigned int i;
- repl_item *item;
- value_t *expr;
- int res;
- char *url2;
- char *stctx;
- query_ctx_t qctx;
- getter_t oget;
- getter_t sget;
-
- url2 = strdup(url);
- if (!url2) {
- error(0,0,"could not parse url %s",url);
- return;
- }
- qctx.cur_bucket = strtok_r(url2,"/",&stctx);
- qctx.cur_key = strtok_r(NULL,"/",&stctx);
-
- if (!size) {
- size = meta_get_size(qctx.cur_bucket,qctx.cur_key);
- DPRINTF("fetched size %zu for %sn",size,url);
- }
-
- if (policy) {
- DPRINTF("--- policy = %sn",policy);
- expr = parse(policy);
- }
- else {
- expr = NULL;
- }
-
- oget.func = repl_oget;
- oget.ctx = &qctx;
- sget.func = repl_sget;
- sget.ctx = &qctx;
-
- for (i = 1; i < json_array_size(config); ++i) {
- if (expr) {
- qctx.cur_server = json_array_get(config,i);
- res = eval(expr,&oget,&sget);
- }
- else {
- res = 0;
- }
- if (res <= 0) {
- DPRINTF("skipping %u for %sn",i,url);
- continue;
- }
- DPRINTF("REPLICATING %s to %un",url,i);
- item = malloc(sizeof(*item));
- if (!item) {
- error(0,errno,"could not create repl_item for %s",
- url);
- break;
- }
- item->type = REPL_PUT;
- item->path = strdup(url);
- if (!item->path) {
- error(0,errno,"could not create repl_item for %s",
- url);
- break;
- }
- item->server = i;
- item->size = size;
- pthread_mutex_lock(&queue_lock);
- if (queue_tail) {
- item->next = queue_tail->next;
- queue_tail->next = item;
- }
- else {
- item->next = NULL;
- queue_head = item;
- }
- queue_tail = item;
- pthread_mutex_unlock(&queue_lock);
- g_atomic_int_inc(&rep_count);
- sem_post(&queue_sema);
- }
-
- if (expr) {
- free_value(expr);
- }
- free(url2);
-}
-
-static void
-replicate_namespace_action (const char *name, repl_t action)
-{
- unsigned int i;
- repl_item *item;
-
- for (i = 1; i < json_array_size(config); ++i) {
- DPRINTF("replicating delete(%s) on %un",name,i);
- item = malloc(sizeof(*item));
- if (!item) {
- error(0,errno,"could not create repl_item for %s",
- name);
- return;
- }
- item->type = action;
- item->path = strdup(name);
- if (!item->path) {
- free(item);
- return;
- }
- item->server = i;
- pthread_mutex_lock(&queue_lock);
- if (queue_tail) {
- item->next = queue_tail->next;
- queue_tail->next = item;
- }
- else {
- item->next = NULL;
- queue_head = item;
- }
- queue_tail = item;
- pthread_mutex_unlock(&queue_lock);
- g_atomic_int_inc(&rep_count);
- sem_post(&queue_sema);
- }
-}
-
-void
-replicate_delete (const char *name)
-{
- replicate_namespace_action(name,REPL_ODELETE);
-}
-
-void
-replicate_bcreate (const char *name)
-{
- replicate_namespace_action(name,REPL_BCREATE);
-}
-
-int
-get_provider (int i, provider_t *out)
-{
- json_t *server;
-
- server = json_array_get(config,i);
- if (!server) {
- DPRINTF("no such entry %dn",i);
- return 0;
- }
-
- out->index = i;
- out->name = json_string_value(json_object_get(server,"name"));
- out->type = json_string_value(json_object_get(server,"type"));
- out->host = json_string_value(json_object_get(server,"host"));
- out->port = json_integer_value(json_object_get(server,"port"));
- /* TBD: change key/secret field names to username/password */
- out->username = json_string_value(json_object_get(server,"key"));
- out->password = json_string_value(json_object_get(server,"secret"));
- out->path = json_string_value(json_object_get(server,"path"));
-
- /* Use empty strings instead of NULL. */
- if (!out->username) out->username = "";
- if (!out->password) out->password = "";
-
- /* TBD: do this a cleaner way. */
- if (!strcasecmp(out->type,"s3")) {
- out->func_tbl = &s3_func_tbl;
- }
- else if (!strcasecmp(out->type,"http")) {
- out->func_tbl = &curl_func_tbl;
- }
- else if (!strcasecmp(out->type,"fs")) {
- out->func_tbl = &fs_func_tbl;
- }
- else {
- out->func_tbl = &bad_func_tbl;
- }
-
- return 1;
-}
-
-char *
-get_provider_value (int i, const char *fname)
-{
- json_t *server;
- json_t *field;
-
- server = json_array_get(config,i);
- if (!server) {
- DPRINTF("no such entry %dn",i);
- return NULL;
- }
-
- field = json_object_get(server,fname);
- if (!field) {
- DPRINTF("no such field %s on server %dn",fname,i);
- return NULL;
- }
-
- return (char *)json_string_value(field);
-}
-
-void
-update_provider (const char *provider, const char *username, const char *password)
-{
- int i;
- json_t *server;
- const char *s_name;
-
- DPRINTF("updating %s username=%s password=%sn",
- provider, username, password);
-
- for (i = 0; ; ++i) {
- server = json_array_get(config,i);
- if (!server) {
- DPRINTF(" could not find provider %sn",provider);
- break;
- }
- s_name = json_string_value(json_object_get(server,"name"));
- DPRINTF(" checking %sn",s_name);
- if (s_name && !strcmp(s_name,provider)) {
- json_object_set_new(server,"key",json_string(username));
- json_object_set_new(server,"secret",
- json_string(password));
- break;
- }
- }
-}
-
-/* Part of our API to the query module. */
-char *
-follow_link (char *object, char *key)
-{
- (void)object;
- (void)key;
-
- return "no_such_object";
-}
-
-int
-get_rep_count (void)
-{
- return g_atomic_int_get(&rep_count);
-}
diff --git a/proxy.h b/proxy.h
deleted file mode 100644
index e09cfa4..0000000
--- a/proxy.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/* Copyright (C) 2010 Red Hat, Inc.
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <
http://www.gnu.org/licenses/>. */
-
-#if !defined(_PROXY_H)
-#define _PROXY_H
-
-#include "backend.h"
-
-typedef struct _provider {
- int index;
- const char *name;
- const char *type;
- const char *host;
- int port;
- const char *username;
- const char *password;
- const char *path;
- backend_func_tbl *func_tbl;
-} provider_t;
-
-char *parse_config (void);
-char *auto_config (void);
-void repl_init (void);
-void replicate (const char *url, size_t size,
- const char *policy);
-void replicate_delete (const char *url);
-void replicate_bcreate (const char *bucket);
-int get_provider (int i, provider_t *out);
-void update_provider (const char *provider,
- const char *username, const char *password);
-char *get_provider_value (int i, const char *fname);
-int get_rep_count (void);
-
-int auto_start (int dbport);
-void auto_stop (void);
-
-#endif
diff --git a/query.h b/query.h
index d541dd7..8189633 100644
--- a/query.h
+++ b/query.h
@@ -41,12 +41,12 @@ typedef struct _value {
struct _value *right;
} as_tree;
};
- char *resolved; /* saved result for T_OFIELD/T_SFIELD/T_LINK */
+ const char *resolved; /* saved result for T_OFIELD/T_SFIELD/T_LINK */
} value_t;
typedef struct {
- char *(*func) (void *, const char *);
- void *ctx;
+ const char *(*func) (void *, const char *);
+ void *ctx;
} getter_t;
#define CALL_GETTER(g,x) g->func(g->ctx,x)
diff --git a/query.leg b/query.leg
index 1c85e8b..2b9cf59 100644
--- a/query.leg
+++ b/query.leg
@@ -154,7 +154,7 @@ struct { char *name; char *value; } hacked_obj_fields[] = {
};
/* Fake out the eval code for unit testing. */
-char *
+const char *
unit_oget_func (void * notused, const char *text)
{
int i;
@@ -173,7 +173,7 @@ getter_t unit_oget = { unit_oget_func };
* Same as above, but the site-field stuff is so similar to the object-field
* stuff that it's not worth exercising too much separately.
*/
-char *
+const char *
unit_sget_func (void * notused, const char *text)
{
return "never";
@@ -213,17 +213,18 @@ extern char *follow_link (const char *object, const char *key);
* all component parts are string-valued themselves. That excludes numbers
* and booleans.
*/
-char *
+const char *
string_value (value_t *v, getter_t *oget, getter_t *sget)
{
- char *left;
+ const char *left;
switch (v->type) {
case T_STRING:
return v->as_str;
case T_OFIELD:
if (!v->resolved) {
- v->resolved = oget ? CALL_GETTER(oget,v->as_str) : NULL;
+ v->resolved = oget
+ ? CALL_GETTER(oget,v->as_str) : NULL;
}
return v->resolved;
case T_SFIELD:
@@ -274,11 +275,11 @@ int
compare (value_t *left, comp_t op, value_t *right,
getter_t *oget, getter_t *sget)
{
- char *lstr;
- char *rstr;
- int lval = 0; // solely to placate gcc
- int rval;
- int num_ok = 1;
+ const char *lstr;
+ const char *rstr;
+ int lval = 0; // solely to placate gcc
+ int rval;
+ int num_ok = 1;
lstr = string_value(left,oget,sget);
rstr = string_value(right,oget,sget);
@@ -420,11 +421,7 @@ free_value (value_t *v)
return;
}
- if (v->resolved) {
- printf("freeing resolved string "%s" (%p)n",
- v->resolved, v->resolved);
- }
- free(v->resolved);
+ free((char *)v->resolved);
switch (v->type) {
case T_STRING:
@@ -466,8 +463,8 @@ free_value (value_t *v)
int
eval (const value_t *v, getter_t *oget, getter_t *sget)
{
- int res;
- char *str;
+ int res;
+ const char *str;
switch (v->type) {
case T_NUMBER:
@@ -590,10 +587,10 @@ parse (const char *text)
int
main (int argc, char **argv)
{
- int i;
- value_t *expr;
- int res;
- char *str;
+ int i;
+ value_t *expr;
+ int res;
+ const char *str;
for (i = 1; i < argc; ++i) {
expr = parse(argv[i]);
diff --git a/rest.c b/rest.c
index 070c4eb..91b3552 100644
--- a/rest.c
+++ b/rest.c
@@ -38,7 +38,8 @@
#include "iwh.h"
#include "meta.h"
#include "backend.h"
-#include "proxy.h"
+#include "setup.h"
+#include "replica.h"
#include "template.h"
#include "mpipe.h"
#include "state_defs.h"
@@ -69,10 +70,10 @@ typedef struct {
MHD_AccessHandlerCallback handler;
} rule;
-static int fs_mode = 0;
static unsigned short my_port = MY_PORT;
static int autostart = 0;
-const char *program_name;
+const char *program_name;
+char *cfg_file = NULL;
static char *(reserved_name[]) = { "_default", "_query",
"_new", NULL };
static char *(reserved_attr[]) = { "bucket", "key", "date",
"etag", "loc", NULL };
@@ -247,8 +248,8 @@ proxy_get_cons (void *ctx, uint64_t pos, char *buf, int max)
child_res = NULL;
pthread_join(ms->backend_th,&child_res);
if (child_res == THREAD_FAILED) {
- DPRINTF("GET producer failedn");
- /* Nothing we can do; already sent status. */
+ DPRINTF("GET producer failedn");
+ /* Nothing we can do; already sent status. */
}
if (ms->from_master) {
pthread_join(ms->cache_th,NULL);
@@ -271,7 +272,7 @@ proxy_get_data (void *cctx, struct MHD_Connection *conn, const char
*url,
pipe_private *pp2;
char *my_etag;
const char *user_etag;
- int rc;
+ int rc;
(void)cctx;
(void)method;
@@ -288,10 +289,10 @@ proxy_get_data (void *cctx, struct MHD_Connection *conn, const char
*url,
ms->cleanup |= CLEANUP_URL;
my_etag = meta_has_copy(ms->bucket,ms->key,me);
- if (!my_etag) {
- DPRINTF("falling back to local for
%s/%sn",ms->bucket,ms->key);
- ms->from_master = 0;
- }
+ if (!my_etag) {
+ DPRINTF("falling back to local for %s/%sn",ms->bucket,ms->key);
+ ms->from_master = 0;
+ }
else if (*my_etag) {
user_etag = MHD_lookup_connection_value(
conn, MHD_HEADER_KIND, "If-None-Match");
@@ -351,8 +352,8 @@ proxy_get_data (void *cctx, struct MHD_Connection *conn, const char
*url,
pp2 = NULL;
}
- rc = pipe_cons_wait_init(&ms->pipe);
- ms->rc = (rc == 0) ? MHD_HTTP_OK : MHD_HTTP_INTERNAL_SERVER_ERROR;
+ rc = pipe_cons_wait_init(&ms->pipe);
+ ms->rc = (rc == 0) ? MHD_HTTP_OK : MHD_HTTP_INTERNAL_SERVER_ERROR;
resp = MHD_create_response_from_callback(
MHD_SIZE_UNKNOWN, 65536, proxy_get_cons, pp, child_closer);
@@ -1303,10 +1304,9 @@ check_location (my_state *ms)
static int
register_image (my_state *ms)
{
- char *site;
- provider_t prov;
- int i;
- char *next;
+ const char *site;
+ const provider_t *prov;
+ char *next;
site = g_hash_table_lookup(ms->dict,"site");
if (!site) {
@@ -1319,15 +1319,14 @@ register_image (my_state *ms)
*(next++) = '0';
}
- for (i = 0; get_provider(i,&prov); ++i) {
- if (strcmp(prov.name,site)) {
- continue;
- }
- return prov.func_tbl->register_func(ms,&prov,next,ms->dict);
+ prov = get_provider(site);
+ if (!prov) {
+ DPRINTF("site %s not foundn",site);
+ return MHD_HTTP_BAD_REQUEST;
}
- DPRINTF("site %s not foundn",site);
- return MHD_HTTP_BAD_REQUEST;
+ return prov->func_tbl->register_func(ms,prov,next,ms->dict);
+
}
static int
@@ -1406,9 +1405,6 @@ static int
show_parts (struct MHD_Connection *conn, my_state *ms)
{
struct MHD_Response *resp;
- void *ctx;
- const char *name;
- const char *value;
ms->aquery = meta_get_attrs(ms->bucket,ms->key);
if (!ms->aquery) {
@@ -1512,10 +1508,11 @@ proxy_object_post (void *cctx, struct MHD_Connection *conn, const
char *url,
static int
prov_list_generator (void *ctx, uint64_t pos, char *buf, int max)
{
- my_state *ms = ctx;
- int len;
- provider_t prov;
- const char *accept_hdr;
+ my_state *ms = ctx;
+ int len;
+ gpointer key;
+ const provider_t *prov;
+ const char *accept_hdr;
(void)pos;
@@ -1528,6 +1525,7 @@ prov_list_generator (void *ctx, uint64_t pos, char *buf, int max)
return -1;
}
ms->cleanup |= CLEANUP_TMPL;
+ init_prov_iter(&ms->prov_iter);
len = tmpl_prov_header(ms->gen_ctx);
if (!len) {
return -1;
@@ -1543,9 +1541,9 @@ prov_list_generator (void *ctx, uint64_t pos, char *buf, int max)
return -1;
}
- if (get_provider(ms->gen_ctx->index,&prov)) {
- len = tmpl_prov_entry(ms->gen_ctx,prov.name,prov.type,
- prov.host, prov.port, prov.username, prov.password);
+ if (g_hash_table_iter_next(&ms->prov_iter,&key,(gpointer *)&prov)) {
+ len = tmpl_prov_entry(ms->gen_ctx,prov->name,prov->type,
+ prov->host, prov->port, prov->username, prov->password);
if (!len) {
return -1;
}
@@ -1875,13 +1873,13 @@ usage (int status)
{
if (status != EXIT_SUCCESS)
fprintf (stderr, _("Try `%s --help' for more information.n"),
- program_name);
+ program_name);
else
{
printf (_(" Usage: %s [OPTION]n "),
- program_name);
+ program_name);
fputs (_(" Deltacloud image-warehouse daemon.n A configuration file must be
specified.n@@ -1900,7 +1898,7 @@ A configuration file must be specified.n n Report %s bugs
to %s.n "),
- program_name, PACKAGE_BUGREPORT);
+ program_name, PACKAGE_BUGREPORT);
}
exit (status);
}
@@ -1977,7 +1975,7 @@ args_done:
}
}
else if (!autostart && cfg_file) {
- me = parse_config();
+ me = parse_config(cfg_file);
if (!me) {
error(0,0,"could not parse %s",cfg_file);
return !0;
diff --git a/state_defs.h b/state_defs.h
index f13c043..0460a00 100644
--- a/state_defs.h
+++ b/state_defs.h
@@ -58,6 +58,7 @@ typedef struct {
pthread_t cache_th;
/* for bucket/object/provider list generators */
tmpl_ctx_t *gen_ctx;
+ GHashTableIter prov_iter;
} my_state;
#define CLEANUP_CURL 0x01
diff --git a/t/basic b/t/basic
index 0f409a4..4dac5e9 100644
--- a/t/basic
+++ b/t/basic
@@ -48,9 +48,10 @@ EOF
emit_provider()
{
local xml_or_json=$1
- case $# in 7);; *) echo "emit_provider: wrong # args" 1>&2; exit 1;;
esac
+ shift 1
case $xml_or_json in xml|json);;
*) echo "invalid xml_or_json $xml_or_json" 1>&2; exit 1;; esac
+ case $# in 6);; *) echo "emit_provider: wrong # args" 1>&2; exit 1;;
esac
if test $xml_or_json = xml; then
printf @@ -63,7 +64,7 @@ emit_provider()
tt<password>%s</password>
t</provider>
</providers>
-' $2 $3 $4 $5 $6 $7
+' "$@"
else
printf '[
@@ -76,7 +77,7 @@ emit_provider()
tt"password": "%s"
t}
]
-' $2 $3 $4 $5 $6 $7
+' "$@"
fi
}
@@ -178,11 +179,10 @@ grep ' 404$' del_nosuch.err || fail=1
# ################## Providers
p_name=primary
-host='(null)'
# Verify that default providers information is as expected.
curl
http://localhost:$port/_providers > p || fail=1
-emit_provider xml "$p_name" fs "$host" 0 '' '' >
p.exp || fail=1
+emit_provider xml "$p_name" fs '' 0 '' '' > p.exp ||
fail=1
compare p.exp p || fail=1
for i in xml json; do
@@ -193,7 +193,7 @@ for i in xml json; do
curl_H -d provider="$p_name" -d username=u -d password=p
http://localhost:$port/_providers || fail=1
curl_H
http://localhost:$port/_providers > p || fail=1
- emit_provider $i "$p_name" fs "$host" 0 u p > p.xml || fail=1
+ emit_provider $i "$p_name" fs '' 0 u p > p.xml || fail=1
compare p.xml p || fail=1
# Attempt to modify some other attribute; should fail (but curl won't)
@@ -209,20 +209,20 @@ for i in xml json; do
curl_H -d provider="$p_name" -d username=u
http://localhost:$port/_providers || fail=1
curl_H
http://localhost:$port/_providers > p || fail=1
- emit_provider $i "$p_name" fs "$host" 0 u p > p.exp || fail=1
+ emit_provider $i "$p_name" fs '' 0 u p > p.exp || fail=1
compare p.exp p || fail=1
curl_H -d provider="$p_name" -d password=p
http://localhost:$port/_providers || fail=1
curl_H
http://localhost:$port/_providers > p || fail=1
- emit_provider $i "$p_name" fs "$host" 0 u p > p.exp || fail=1
+ emit_provider $i "$p_name" fs '' 0 u p > p.exp || fail=1
compare p.exp p || fail=1
# Try to change both username and password. Now, it must succeed.
curl_H -d provider="$p_name" -d username=v -d password=q
http://localhost:$port/_providers || fail=1
curl_H
http://localhost:$port/_providers > p || fail=1
- emit_provider $i "$p_name" fs "$host" 0 v q > p.exp || fail=1
+ emit_provider $i "$p_name" fs '' 0 v q > p.exp || fail=1
compare p.exp p || fail=1
# List an empty bucket.
diff --git a/template.c b/template.c
index a7f1cca..b66bc1d 100644
--- a/template.c
+++ b/template.c
@@ -273,6 +273,12 @@ tmpl_prov_entry (tmpl_ctx_t *ctx,
int size;
const tmpl_format_t *fmt = ctx->format;
+ if (!name) name = "";
+ if (!type) type = "";
+ if (!host) host = "";
+ if (!user) user = "";
+ if (!pass) pass = "";
+
size = snprintf(ctx->raw_buf,TMPL_BUF_SIZE,fmt->prov_entry,
name, type, host, port, user, pass);
if (size >= TMPL_BUF_SIZE) {
-----------------------------------------------------------------------
Summary of changes:
Makefile.am | 6 +-
auto.c | 14 +-
backend.c | 38 +-
iwh.h | 3 +-
meta.cpp | 2 +-
proxy.c | 1122 ----------------------------------------------------------
proxy.h | 49 ---
query.h | 6 +-
query.leg | 39 +--
rest.c | 72 ++--
state_defs.h | 1 +
t/basic | 18 +-
template.c | 6 +
13 files changed, 104 insertions(+), 1272 deletions(-)
delete mode 100644 proxy.c
delete mode 100644 proxy.h
repo.or.cz automatic notification. Contact project admin jim(a)meyering.net
if you want to unsubscribe, or site admin admin(a)repo.or.cz if you receive
no reply.
--
iwhd.git ("image warehouse daemon")