ERL_NIF_TERM x_conf_set(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { const char * func_name = "x_conf_set()"; logger.debug(MOD_NAME, func_name, "Entered"); uint64_t id; char option[MAX_NAME_LEN]; memset(option, 0, MAX_NAME_LEN); char value[MAX_NAME_LEN]; memset(value, 0, MAX_NAME_LEN); if (!enif_get_uint64(env, argv[0], &id) || !enif_get_string(env, argv[1], option, MAX_NAME_LEN, ERL_NIF_LATIN1) || !enif_get_string(env, argv[1], option, MAX_NAME_LEN, ERL_NIF_LATIN1)) { logger.error(MOD_NAME, func_name, "enif get params failed"); return enif_make_badarg(env); } logger.debug(MOD_NAME, func_name, "cluster : %ld", id); rados_t cluster = map_cluster_get(id); if (cluster == NULL) { logger.error(MOD_NAME, func_name, "cluster non-existing : %ld", id); return enif_make_badarg(env); } int err = rados_conf_set(cluster, option, value); if (err < 0) { return make_error_tuple(env, -err); } return enif_make_atom(env, "ok"); }
static int qemu_rbd_set_keypairs(rados_t cluster, const char *keypairs, Error **errp) { char *p, *buf; char *name; char *value; int ret = 0; buf = g_strdup(keypairs); p = buf; while (p) { name = qemu_rbd_next_tok(p, '=', &p); if (!p) { error_setg(errp, "conf option %s has no value", name); ret = -EINVAL; break; } value = qemu_rbd_next_tok(p, ':', &p); ret = rados_conf_set(cluster, name, value); if (ret < 0) { error_setg_errno(errp, -ret, "invalid conf option %s", name); ret = -EINVAL; break; } } g_free(buf); return ret; }
static int qemu_rbd_set_conf(rados_t cluster, const char *conf, bool only_read_conf_file, Error **errp) { char *p, *buf; char name[RBD_MAX_CONF_NAME_SIZE]; char value[RBD_MAX_CONF_VAL_SIZE]; int ret = 0; buf = g_strdup(conf); p = buf; while (p) { ret = qemu_rbd_next_tok(name, sizeof(name), p, '=', "conf option name", &p, errp); if (ret < 0) { break; } qemu_rbd_unescape(name); if (!p) { error_setg(errp, "conf option %s has no value", name); ret = -EINVAL; break; } ret = qemu_rbd_next_tok(value, sizeof(value), p, ':', "conf option value", &p, errp); if (ret < 0) { break; } qemu_rbd_unescape(value); if (strcmp(name, "conf") == 0) { /* read the conf file alone, so it doesn't override more specific settings for a particular device */ if (only_read_conf_file) { ret = rados_conf_read_file(cluster, value); if (ret < 0) { error_setg_errno(errp, -ret, "error reading conf file %s", value); break; } } } else if (strcmp(name, "id") == 0) { /* ignore, this is parsed by qemu_rbd_parse_clientname() */ } else if (!only_read_conf_file) { ret = rados_conf_set(cluster, name, value); if (ret < 0) { error_setg_errno(errp, -ret, "invalid conf option %s", name); ret = -EINVAL; break; } } } g_free(buf); return ret; }
static int conf_set(const char *key, const char *value) { int r; r = rados_conf_set(cluster, key, value); if (r < 0) { fprintf(stderr, "invalid conf option: %s\n", key); } return r; }
static int qemu_rbd_set_auth(rados_t cluster, BlockdevOptionsRbd *opts, Error **errp) { char *key, *acr; int r; GString *accu; RbdAuthModeList *auth; if (opts->key_secret) { key = qcrypto_secret_lookup_as_base64(opts->key_secret, errp); if (!key) { return -EIO; } r = rados_conf_set(cluster, "key", key); g_free(key); if (r < 0) { error_setg_errno(errp, -r, "Could not set 'key'"); return r; } } if (opts->has_auth_client_required) { accu = g_string_new(""); for (auth = opts->auth_client_required; auth; auth = auth->next) { if (accu->str[0]) { g_string_append_c(accu, ';'); } g_string_append(accu, RbdAuthMode_str(auth->value)); } acr = g_string_free(accu, FALSE); r = rados_conf_set(cluster, "auth_client_required", acr); g_free(acr); if (r < 0) { error_setg_errno(errp, -r, "Could not set 'auth_client_required'"); return r; } } return 0; }
static int qemu_rbd_set_conf(rados_t cluster, const char *conf) { char *p, *buf; char name[RBD_MAX_CONF_NAME_SIZE]; char value[RBD_MAX_CONF_VAL_SIZE]; int ret = 0; buf = g_strdup(conf); p = buf; while (p) { ret = qemu_rbd_next_tok(name, sizeof(name), p, '=', "conf option name", &p); if (ret < 0) { break; } qemu_rbd_unescape(name); if (!p) { error_report("conf option %s has no value", name); ret = -EINVAL; break; } ret = qemu_rbd_next_tok(value, sizeof(value), p, ':', "conf option value", &p); if (ret < 0) { break; } qemu_rbd_unescape(value); if (strcmp(name, "conf") == 0) { ret = rados_conf_read_file(cluster, value); if (ret < 0) { error_report("error reading conf file %s", value); break; } } else if (strcmp(name, "id") == 0) { /* ignore, this is parsed by qemu_rbd_parse_clientname() */ } else { ret = rados_conf_set(cluster, name, value); if (ret < 0) { error_report("invalid conf option %s", name); ret = -EINVAL; break; } } } g_free(buf); return ret; }
static int qemu_rbd_set_auth(rados_t cluster, const char *secretid, Error **errp) { if (secretid == 0) { return 0; } gchar *secret = qcrypto_secret_lookup_as_base64(secretid, errp); if (!secret) { return -1; } rados_conf_set(cluster, "key", secret); g_free(secret); return 0; }
static int qemu_rbd_set_keypairs(rados_t cluster, const char *keypairs_json, Error **errp) { QList *keypairs; QString *name; QString *value; const char *key; size_t remaining; int ret = 0; if (!keypairs_json) { return ret; } keypairs = qobject_to(QList, qobject_from_json(keypairs_json, &error_abort)); remaining = qlist_size(keypairs) / 2; assert(remaining); while (remaining--) { name = qobject_to(QString, qlist_pop(keypairs)); value = qobject_to(QString, qlist_pop(keypairs)); assert(name && value); key = qstring_get_str(name); ret = rados_conf_set(cluster, key, qstring_get_str(value)); qobject_unref(value); if (ret < 0) { error_setg_errno(errp, -ret, "invalid conf option %s", key); qobject_unref(name); ret = -EINVAL; break; } qobject_unref(name); } qobject_unref(keypairs); return ret; }
static int virStorageBackendRBDOpenRADOSConn(virStorageBackendRBDStatePtr *ptr, virConnectPtr conn, virStoragePoolObjPtr pool) { int ret = -1; unsigned char *secret_value = NULL; size_t secret_value_size; char *rados_key = NULL; virBuffer mon_host = VIR_BUFFER_INITIALIZER; virSecretPtr secret = NULL; char secretUuid[VIR_UUID_STRING_BUFLEN]; int i; char *mon_buff = NULL; VIR_DEBUG("Found Cephx username: %s", pool->def->source.auth.cephx.username); if (pool->def->source.auth.cephx.username != NULL) { VIR_DEBUG("Using cephx authorization"); if (rados_create(&ptr->cluster, pool->def->source.auth.cephx.username) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("failed to initialize RADOS")); goto cleanup; } if (pool->def->source.auth.cephx.secret.uuidUsable) { virUUIDFormat(pool->def->source.auth.cephx.secret.uuid, secretUuid); VIR_DEBUG("Looking up secret by UUID: %s", secretUuid); secret = virSecretLookupByUUIDString(conn, secretUuid); } else if (pool->def->source.auth.cephx.secret.usage != NULL) { VIR_DEBUG("Looking up secret by usage: %s", pool->def->source.auth.cephx.secret.usage); secret = virSecretLookupByUsage(conn, VIR_SECRET_USAGE_TYPE_CEPH, pool->def->source.auth.cephx.secret.usage); } if (secret == NULL) { virReportError(VIR_ERR_NO_SECRET, "%s", _("failed to find the secret")); goto cleanup; } secret_value = virSecretGetValue(secret, &secret_value_size, 0); base64_encode_alloc((char *)secret_value, secret_value_size, &rados_key); memset(secret_value, 0, secret_value_size); if (rados_key == NULL) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("failed to decode the RADOS key")); goto cleanup; } VIR_DEBUG("Found cephx key: %s", rados_key); if (rados_conf_set(ptr->cluster, "key", rados_key) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("failed to set RADOS option: %s"), "rados_key"); goto cleanup; } memset(rados_key, 0, strlen(rados_key)); if (rados_conf_set(ptr->cluster, "auth_supported", "cephx") < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("failed to set RADOS option: %s"), "auth_supported"); goto cleanup; } } else { VIR_DEBUG("Not using cephx authorization"); if (rados_create(&ptr->cluster, NULL) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("failed to create the RADOS cluster")); goto cleanup; } if (rados_conf_set(ptr->cluster, "auth_supported", "none") < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("failed to set RADOS option: %s"), "auth_supported"); goto cleanup; } } VIR_DEBUG("Found %zu RADOS cluster monitors in the pool configuration", pool->def->source.nhost); for (i = 0; i < pool->def->source.nhost; i++) { if (pool->def->source.hosts[i].name != NULL && !pool->def->source.hosts[i].port) { virBufferAsprintf(&mon_host, "%s:6789,", pool->def->source.hosts[i].name); } else if (pool->def->source.hosts[i].name != NULL && pool->def->source.hosts[i].port) { virBufferAsprintf(&mon_host, "%s:%d,", pool->def->source.hosts[i].name, pool->def->source.hosts[i].port); } else { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("received malformed monitor, check the XML definition")); } } if (virBufferError(&mon_host)) { virReportOOMError(); goto cleanup; } mon_buff = virBufferContentAndReset(&mon_host); VIR_DEBUG("RADOS mon_host has been set to: %s", mon_buff); if (rados_conf_set(ptr->cluster, "mon_host", mon_buff) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("failed to set RADOS option: %s"), "mon_host"); goto cleanup; } ptr->starttime = time(0); if (rados_connect(ptr->cluster) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("failed to connect to the RADOS monitor on: %s"), mon_buff); goto cleanup; } ret = 0; cleanup: VIR_FREE(secret_value); VIR_FREE(rados_key); virSecretFree(secret); virBufferFreeAndReset(&mon_host); VIR_FREE(mon_buff); return ret; }
static int testrados(void) { char tmp[32]; int i, r; rados_t cl; if (rados_create(&cl, NULL) < 0) { printf("error initializing\n"); return 1; } if (rados_conf_read_file(cl, NULL)) { printf("error reading configuration file\n"); return 1; } // Try to set a configuration option that doesn't exist. // This should fail. if (!rados_conf_set(cl, "config option that doesn't exist", "some random value")) { printf("error: succeeded in setting nonexistent config option\n"); return 1; } if (rados_conf_get(cl, "log to stderr", tmp, sizeof(tmp))) { printf("error: failed to read log_to_stderr from config\n"); return 1; } // Can we change it? if (rados_conf_set(cl, "log to stderr", "2")) { printf("error: error setting log_to_stderr\n"); return 1; } if (rados_conf_get(cl, "log to stderr", tmp, sizeof(tmp))) { printf("error: failed to read log_to_stderr from config\n"); return 1; } if (tmp[0] != '2') { printf("error: new setting for log_to_stderr failed to take effect.\n"); return 1; } if (rados_connect(cl)) { printf("error connecting\n"); return 1; } if (rados_connect(cl) == 0) { printf("second connect attempt didn't return an error\n"); return 1; } /* create an io_ctx */ r = rados_pool_create(cl, "foo"); printf("rados_pool_create = %d\n", r); rados_ioctx_t io_ctx; r = rados_ioctx_create(cl, "foo", &io_ctx); printf("rados_ioctx_create = %d, io_ctx = %p\n", r, io_ctx); /* list all pools */ { int buf_sz = rados_pool_list(cl, NULL, 0); printf("need buffer size of %d\n", buf_sz); char buf[buf_sz]; int r = rados_pool_list(cl, buf, buf_sz); if (r != buf_sz) { printf("buffer size mismatch: got %d the first time, but %d " "the second.\n", buf_sz, r); return 1; } const char *b = buf; printf("begin pools.\n"); while (1) { if (b[0] == '\0') break; printf(" pool: '%s'\n", b); b += strlen(b) + 1; }; printf("end pools.\n"); } /* stat */ struct rados_pool_stat_t st; r = rados_ioctx_pool_stat(io_ctx, &st); printf("rados_ioctx_pool_stat = %d, %lld KB, %lld objects\n", r, (long long)st.num_kb, (long long)st.num_objects); /* snapshots */ r = rados_ioctx_snap_create(io_ctx, "snap1"); printf("rados_ioctx_snap_create snap1 = %d\n", r); rados_snap_t snaps[10]; r = rados_ioctx_snap_list(io_ctx, snaps, 10); for (i=0; i<r; i++) { char name[100]; rados_ioctx_snap_get_name(io_ctx, snaps[i], name, sizeof(name)); printf("rados_ioctx_snap_list got snap %lld %s\n", (long long)snaps[i], name); } rados_snap_t snapid; r = rados_ioctx_snap_lookup(io_ctx, "snap1", &snapid); printf("rados_ioctx_snap_lookup snap1 got %lld, result %d\n", (long long)snapid, r); r = rados_ioctx_snap_remove(io_ctx, "snap1"); printf("rados_ioctx_snap_remove snap1 = %d\n", r); /* sync io */ time_t tm; char buf[128], buf2[128]; time(&tm); snprintf(buf, 128, "%s", ctime(&tm)); const char *oid = "foo_object"; r = rados_write(io_ctx, oid, buf, strlen(buf) + 1, 0); printf("rados_write = %d\n", r); r = rados_read(io_ctx, oid, buf2, sizeof(buf2), 0); printf("rados_read = %d\n", r); if (memcmp(buf, buf2, r)) printf("*** content mismatch ***\n"); /* attrs */ if (do_rados_setxattr(io_ctx, oid, "b", "2")) return 1; if (do_rados_setxattr(io_ctx, oid, "a", "1")) return 1; if (do_rados_setxattr(io_ctx, oid, "c", "3")) return 1; if (do_rados_getxattr(io_ctx, oid, "a", "1")) return 1; if (do_rados_getxattr(io_ctx, oid, "b", "2")) return 1; if (do_rados_getxattr(io_ctx, oid, "c", "3")) return 1; const char *exkeys[] = { "a", "b", "c", NULL }; const char *exvals[] = { "1", "2", "3", NULL }; if (do_rados_getxattrs(io_ctx, oid, exkeys, exvals)) return 1; uint64_t size; time_t mtime; r = rados_stat(io_ctx, oid, &size, &mtime); printf("rados_stat size = %lld mtime = %d = %d\n", (long long)size, (int)mtime, r); r = rados_stat(io_ctx, "does_not_exist", NULL, NULL); printf("rados_stat(does_not_exist) = %d\n", r); /* exec */ rados_exec(io_ctx, oid, "crypto", "md5", buf, strlen(buf) + 1, buf, 128); printf("exec result=%s\n", buf); r = rados_read(io_ctx, oid, buf2, 128, 0); printf("read result=%s\n", buf2); printf("size=%d\n", r); /* aio */ rados_completion_t a, b; rados_aio_create_completion(0, 0, 0, &a); rados_aio_create_completion(0, 0, 0, &b); rados_aio_write(io_ctx, "a", a, buf, 100, 0); rados_aio_write(io_ctx, "../b/bb_bb_bb\\foo\\bar", b, buf, 100, 0); rados_aio_wait_for_safe(a); printf("a safe\n"); rados_aio_wait_for_safe(b); printf("b safe\n"); rados_aio_release(a); rados_aio_release(b); /* test flush */ printf("testing aio flush\n"); rados_completion_t c; rados_aio_create_completion(0, 0, 0, &c); rados_aio_write(io_ctx, "c", c, buf, 100, 0); int safe = rados_aio_is_safe(c); printf("a should not yet be safe and ... %s\n", safe ? "is":"is not"); assert(!safe); rados_aio_flush(io_ctx); safe = rados_aio_is_safe(c); printf("a should be safe and ... %s\n", safe ? "is":"is not"); assert(safe); rados_aio_release(c); rados_read(io_ctx, "../b/bb_bb_bb\\foo\\bar", buf2, 128, 0); /* list objects */ rados_list_ctx_t h; r = rados_objects_list_open(io_ctx, &h); printf("rados_list_objects_open = %d, h = %p\n", r, h); const char *poolname; while (rados_objects_list_next(h, &poolname) == 0) printf("rados_list_objects_next got object '%s'\n", poolname); rados_objects_list_close(h); /* stat */ r = rados_ioctx_pool_stat(io_ctx, &st); printf("rados_stat_pool = %d, %lld KB, %lld objects\n", r, (long long)st.num_kb, (long long)st.num_objects); /* delete a pool */ printf("rados_delete_pool = %d\n", r); rados_ioctx_destroy(io_ctx); r = rados_pool_delete(cl, "foo"); printf("rados_ioctx_pool_delete = %d\n", r); rados_shutdown(cl); return 0; }
static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags, Error **errp) { BDRVRBDState *s = bs->opaque; const char *pool, *snap, *conf, *user, *image_name, *keypairs; const char *secretid, *filename; QemuOpts *opts; Error *local_err = NULL; char *mon_host = NULL; int r; /* If we are given a filename, parse the filename, with precedence given to * filename encoded options */ filename = qdict_get_try_str(options, "filename"); if (filename) { warn_report("'filename' option specified. " "This is an unsupported option, and may be deprecated " "in the future"); qemu_rbd_parse_filename(filename, options, &local_err); if (local_err) { r = -EINVAL; error_propagate(errp, local_err); goto exit; } } opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort); qemu_opts_absorb_qdict(opts, options, &local_err); if (local_err) { error_propagate(errp, local_err); r = -EINVAL; goto failed_opts; } mon_host = qemu_rbd_mon_host(options, &local_err); if (local_err) { error_propagate(errp, local_err); r = -EINVAL; goto failed_opts; } secretid = qemu_opt_get(opts, "password-secret"); pool = qemu_opt_get(opts, "pool"); conf = qemu_opt_get(opts, "conf"); snap = qemu_opt_get(opts, "snapshot"); user = qemu_opt_get(opts, "user"); image_name = qemu_opt_get(opts, "image"); keypairs = qemu_opt_get(opts, "=keyvalue-pairs"); if (!pool || !image_name) { error_setg(errp, "Parameters 'pool' and 'image' are required"); r = -EINVAL; goto failed_opts; } r = rados_create(&s->cluster, user); if (r < 0) { error_setg_errno(errp, -r, "error initializing"); goto failed_opts; } s->snap = g_strdup(snap); s->image_name = g_strdup(image_name); /* try default location when conf=NULL, but ignore failure */ r = rados_conf_read_file(s->cluster, conf); if (conf && r < 0) { error_setg_errno(errp, -r, "error reading conf file %s", conf); goto failed_shutdown; } r = qemu_rbd_set_keypairs(s->cluster, keypairs, errp); if (r < 0) { goto failed_shutdown; } if (mon_host) { r = rados_conf_set(s->cluster, "mon_host", mon_host); if (r < 0) { goto failed_shutdown; } } if (qemu_rbd_set_auth(s->cluster, secretid, errp) < 0) { r = -EIO; goto failed_shutdown; } /* * Fallback to more conservative semantics if setting cache * options fails. Ignore errors from setting rbd_cache because the * only possible error is that the option does not exist, and * librbd defaults to no caching. If write through caching cannot * be set up, fall back to no caching. */ if (flags & BDRV_O_NOCACHE) { rados_conf_set(s->cluster, "rbd_cache", "false"); } else { rados_conf_set(s->cluster, "rbd_cache", "true"); } r = rados_connect(s->cluster); if (r < 0) { error_setg_errno(errp, -r, "error connecting"); goto failed_shutdown; } r = rados_ioctx_create(s->cluster, pool, &s->io_ctx); if (r < 0) { error_setg_errno(errp, -r, "error opening pool %s", pool); goto failed_shutdown; } /* rbd_open is always r/w */ r = rbd_open(s->io_ctx, s->image_name, &s->image, s->snap); if (r < 0) { error_setg_errno(errp, -r, "error reading header from %s", s->image_name); goto failed_open; } /* If we are using an rbd snapshot, we must be r/o, otherwise * leave as-is */ if (s->snap != NULL) { if (!bdrv_is_read_only(bs)) { error_report("Opening rbd snapshots without an explicit " "read-only=on option is deprecated. Future versions " "will refuse to open the image instead of " "automatically marking the image read-only."); r = bdrv_set_read_only(bs, true, &local_err); if (r < 0) { error_propagate(errp, local_err); goto failed_open; } } } qemu_opts_del(opts); return 0; failed_open: rados_ioctx_destroy(s->io_ctx); failed_shutdown: rados_shutdown(s->cluster); g_free(s->snap); g_free(s->image_name); failed_opts: qemu_opts_del(opts); g_free(mon_host); exit: return r; }
static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags, Error **errp) { BDRVRBDState *s = bs->opaque; char pool[RBD_MAX_POOL_NAME_SIZE]; char snap_buf[RBD_MAX_SNAP_NAME_SIZE]; char conf[RBD_MAX_CONF_SIZE]; char clientname_buf[RBD_MAX_CONF_SIZE]; char *clientname; QemuOpts *opts; Error *local_err = NULL; const char *filename; int r; opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort); qemu_opts_absorb_qdict(opts, options, &local_err); if (local_err) { qerror_report_err(local_err); error_free(local_err); qemu_opts_del(opts); return -EINVAL; } filename = qemu_opt_get(opts, "filename"); if (qemu_rbd_parsename(filename, pool, sizeof(pool), snap_buf, sizeof(snap_buf), s->name, sizeof(s->name), conf, sizeof(conf)) < 0) { r = -EINVAL; goto failed_opts; } clientname = qemu_rbd_parse_clientname(conf, clientname_buf); r = rados_create(&s->cluster, clientname); if (r < 0) { error_report("error initializing"); goto failed_opts; } s->snap = NULL; if (snap_buf[0] != '\0') { s->snap = g_strdup(snap_buf); } /* * Fallback to more conservative semantics if setting cache * options fails. Ignore errors from setting rbd_cache because the * only possible error is that the option does not exist, and * librbd defaults to no caching. If write through caching cannot * be set up, fall back to no caching. */ if (flags & BDRV_O_NOCACHE) { rados_conf_set(s->cluster, "rbd_cache", "false"); } else { rados_conf_set(s->cluster, "rbd_cache", "true"); } if (strstr(conf, "conf=") == NULL) { /* try default location, but ignore failure */ rados_conf_read_file(s->cluster, NULL); } if (conf[0] != '\0') { r = qemu_rbd_set_conf(s->cluster, conf); if (r < 0) { error_report("error setting config options"); goto failed_shutdown; } } r = rados_connect(s->cluster); if (r < 0) { error_report("error connecting"); goto failed_shutdown; } r = rados_ioctx_create(s->cluster, pool, &s->io_ctx); if (r < 0) { error_report("error opening pool %s", pool); goto failed_shutdown; } r = rbd_open(s->io_ctx, s->name, &s->image, s->snap); if (r < 0) { error_report("error reading header from %s", s->name); goto failed_open; } bs->read_only = (s->snap != NULL); qemu_opts_del(opts); return 0; failed_open: rados_ioctx_destroy(s->io_ctx); failed_shutdown: rados_shutdown(s->cluster); g_free(s->snap); failed_opts: qemu_opts_del(opts); return r; }
static int virStorageBackendRBDOpenRADOSConn(virStorageBackendRBDStatePtr ptr, virConnectPtr conn, virStoragePoolSourcePtr source) { int ret = -1; int r = 0; virStorageAuthDefPtr authdef = source->auth; unsigned char *secret_value = NULL; size_t secret_value_size = 0; char *rados_key = NULL; virBuffer mon_host = VIR_BUFFER_INITIALIZER; size_t i; char *mon_buff = NULL; const char *client_mount_timeout = "30"; const char *mon_op_timeout = "30"; const char *osd_op_timeout = "30"; const char *rbd_default_format = "2"; if (authdef) { VIR_DEBUG("Using cephx authorization, username: %s", authdef->username); if ((r = rados_create(&ptr->cluster, authdef->username)) < 0) { virReportSystemError(-r, "%s", _("failed to initialize RADOS")); goto cleanup; } if (!conn) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("'ceph' authentication not supported " "for autostarted pools")); return -1; } if (virSecretGetSecretString(conn, &authdef->seclookupdef, VIR_SECRET_USAGE_TYPE_CEPH, &secret_value, &secret_value_size) < 0) goto cleanup; if (!(rados_key = virStringEncodeBase64(secret_value, secret_value_size))) goto cleanup; VIR_DEBUG("Found cephx key: %s", rados_key); if (rados_conf_set(ptr->cluster, "key", rados_key) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("failed to set RADOS option: %s"), "rados_key"); goto cleanup; } if (rados_conf_set(ptr->cluster, "auth_supported", "cephx") < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("failed to set RADOS option: %s"), "auth_supported"); goto cleanup; } } else { VIR_DEBUG("Not using cephx authorization"); if (rados_create(&ptr->cluster, NULL) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("failed to create the RADOS cluster")); goto cleanup; } if (rados_conf_set(ptr->cluster, "auth_supported", "none") < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("failed to set RADOS option: %s"), "auth_supported"); goto cleanup; } } VIR_DEBUG("Found %zu RADOS cluster monitors in the pool configuration", source->nhost); for (i = 0; i < source->nhost; i++) { if (source->hosts[i].name != NULL && !source->hosts[i].port) { virBufferAsprintf(&mon_host, "%s,", source->hosts[i].name); } else if (source->hosts[i].name != NULL && source->hosts[i].port) { virBufferAsprintf(&mon_host, "%s:%d,", source->hosts[i].name, source->hosts[i].port); } else { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("received malformed monitor, check the XML definition")); } } if (virBufferCheckError(&mon_host) < 0) goto cleanup; mon_buff = virBufferContentAndReset(&mon_host); VIR_DEBUG("RADOS mon_host has been set to: %s", mon_buff); if (rados_conf_set(ptr->cluster, "mon_host", mon_buff) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("failed to set RADOS option: %s"), "mon_host"); goto cleanup; } /* * Set timeout options for librados. * In case the Ceph cluster is down libvirt won't block forever. * Operations in librados will return -ETIMEDOUT when the timeout is reached. */ VIR_DEBUG("Setting RADOS option client_mount_timeout to %s", client_mount_timeout); rados_conf_set(ptr->cluster, "client_mount_timeout", client_mount_timeout); VIR_DEBUG("Setting RADOS option rados_mon_op_timeout to %s", mon_op_timeout); rados_conf_set(ptr->cluster, "rados_mon_op_timeout", mon_op_timeout); VIR_DEBUG("Setting RADOS option rados_osd_op_timeout to %s", osd_op_timeout); rados_conf_set(ptr->cluster, "rados_osd_op_timeout", osd_op_timeout); /* * Librbd supports creating RBD format 2 images. We no longer have to invoke * rbd_create3(), we can tell librbd to default to format 2. * This leaves us to simply use rbd_create() and use the default behavior of librbd */ VIR_DEBUG("Setting RADOS option rbd_default_format to %s", rbd_default_format); rados_conf_set(ptr->cluster, "rbd_default_format", rbd_default_format); ptr->starttime = time(0); if ((r = rados_connect(ptr->cluster)) < 0) { virReportSystemError(-r, _("failed to connect to the RADOS monitor on: %s"), mon_buff); goto cleanup; } ret = 0; cleanup: VIR_DISPOSE_N(secret_value, secret_value_size); VIR_DISPOSE_STRING(rados_key); virBufferFreeAndReset(&mon_host); VIR_FREE(mon_buff); return ret; }
static void uwsgi_rados_add_mountpoint(char *arg, size_t arg_len) { struct uwsgi_rados_mountpoint *urmp = uwsgi_calloc(sizeof(struct uwsgi_rados_mountpoint)); if (uwsgi_kvlist_parse(arg, arg_len, ',', '=', "mountpoint", &urmp->mountpoint, "config", &urmp->config, "pool", &urmp->pool, "timeout", &urmp->str_timeout, "allow_put", &urmp->allow_put, "allow_delete", &urmp->allow_delete, "allow_mkcol", &urmp->allow_mkcol, "allow_propfind", &urmp->allow_propfind, "username", &urmp->username, "buffer_size", &urmp->str_buffer_size, "put_buffer_size", &urmp->str_put_buffer_size, NULL)) { uwsgi_log("unable to parse rados mountpoint definition\n"); exit(1); } if (!urmp->mountpoint|| !urmp->pool) { uwsgi_log("[rados] mount requires a mountpoint, and a pool name.\n"); exit(1); } if (urmp->str_timeout) { urmp->timeout = atoi(urmp->str_timeout); } if (urmp->str_buffer_size) { urmp->buffer_size = atoi(urmp->str_buffer_size); if (urmp->buffer_size > MAX_BUF_SIZE) { urmp->buffer_size = MAX_BUF_SIZE; } else if (urmp->buffer_size < MIN_BUF_SIZE) { urmp->buffer_size = MIN_BUF_SIZE; } } else { urmp->buffer_size = DEF_BUF_SIZE; } if (urmp->str_put_buffer_size) { urmp->put_buffer_size = atoi(urmp->str_put_buffer_size); if (urmp->put_buffer_size > MAX_BUF_SIZE) { urmp->put_buffer_size = MAX_BUF_SIZE; } else if (urmp->put_buffer_size < MIN_BUF_SIZE) { urmp->put_buffer_size = MIN_BUF_SIZE; } } else { urmp->put_buffer_size = urmp->buffer_size; } time_t now = uwsgi_now(); uwsgi_log("[rados] mounting %s ...\n", urmp->mountpoint); rados_t cluster; if (rados_create(&cluster, urmp->username) < 0) { uwsgi_error("can't create Ceph cluster handle"); exit(1); } urmp->cluster = cluster; if (urmp->config) uwsgi_log("using Ceph conf:%s\n", urmp->config); else uwsgi_log("using default Ceph conf.\n"); if (rados_conf_read_file(cluster, urmp->config) < 0) { uwsgi_error("can't configure Ceph cluster handle"); exit(1); } int timeout = urmp->timeout ? urmp->timeout : urados.timeout; char *timeout_str = uwsgi_num2str(timeout); rados_conf_set(cluster, "client_mount_timeout", timeout_str); rados_conf_set(cluster, "rados_mon_op_timeout", timeout_str); rados_conf_set(cluster, "rados_osd_op_timeout", timeout_str); free(timeout_str); if (rados_connect(cluster) < 0) { uwsgi_error("can't connect with Ceph cluster"); exit(1); } void *ctx_ptr; if (uwsgi.threads > 1) { int i; rados_ioctx_t *ctxes = uwsgi_calloc(sizeof(rados_ioctx_t) * uwsgi.threads); for(i=0;i<uwsgi.threads;i++) { if (rados_ioctx_create(cluster, urmp->pool, &ctxes[i]) < 0) { uwsgi_error("can't open rados pool") rados_shutdown(cluster); exit(1); } } ctx_ptr = ctxes; } else { rados_ioctx_t ctx; if (rados_ioctx_create(cluster, urmp->pool, &ctx) < 0) { uwsgi_error("can't open rados pool") rados_shutdown(cluster); exit(1); } ctx_ptr = ctx; } char fsid[37]; rados_cluster_fsid(cluster, fsid, 37); uwsgi_log("connected to Ceph pool: %s on cluster %.*s\n", urmp->pool, 37, fsid); int id = uwsgi_apps_cnt; struct uwsgi_app *ua = uwsgi_add_app(id, rados_plugin.modifier1, urmp->mountpoint, strlen(urmp->mountpoint), NULL, (void*)1); if (!ua) { uwsgi_log("[rados] unable to mount %s\n", urmp->mountpoint); rados_shutdown(cluster); exit(1); } ua->responder0 = ctx_ptr; ua->responder1 = urmp; ua->started_at = now; ua->startup_time = uwsgi_now() - now; uwsgi_log("Rados app/mountpoint %d (%s) loaded in %d seconds at %p\n", id, urmp->mountpoint, (int) ua->startup_time, ctx_ptr); }
static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags, Error **errp) { BDRVRBDState *s = bs->opaque; const char *pool, *snap, *conf, *clientname, *name, *keypairs; const char *secretid; QemuOpts *opts; Error *local_err = NULL; char *mon_host = NULL; int r; opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort); qemu_opts_absorb_qdict(opts, options, &local_err); if (local_err) { error_propagate(errp, local_err); r = -EINVAL; goto failed_opts; } mon_host = qemu_rbd_mon_host(options, &local_err); if (local_err) { error_propagate(errp, local_err); r = -EINVAL; goto failed_opts; } secretid = qemu_opt_get(opts, "password-secret"); pool = qemu_opt_get(opts, "pool"); conf = qemu_opt_get(opts, "conf"); snap = qemu_opt_get(opts, "snapshot"); clientname = qemu_opt_get(opts, "user"); name = qemu_opt_get(opts, "image"); keypairs = qemu_opt_get(opts, "=keyvalue-pairs"); if (!pool || !name) { error_setg(errp, "Parameters 'pool' and 'image' are required"); r = -EINVAL; goto failed_opts; } r = rados_create(&s->cluster, clientname); if (r < 0) { error_setg_errno(errp, -r, "error initializing"); goto failed_opts; } s->snap = g_strdup(snap); s->name = g_strdup(name); /* try default location when conf=NULL, but ignore failure */ r = rados_conf_read_file(s->cluster, conf); if (conf && r < 0) { error_setg_errno(errp, -r, "error reading conf file %s", conf); goto failed_shutdown; } r = qemu_rbd_set_keypairs(s->cluster, keypairs, errp); if (r < 0) { goto failed_shutdown; } if (mon_host) { r = rados_conf_set(s->cluster, "mon_host", mon_host); if (r < 0) { goto failed_shutdown; } } if (qemu_rbd_set_auth(s->cluster, secretid, errp) < 0) { r = -EIO; goto failed_shutdown; } /* * Fallback to more conservative semantics if setting cache * options fails. Ignore errors from setting rbd_cache because the * only possible error is that the option does not exist, and * librbd defaults to no caching. If write through caching cannot * be set up, fall back to no caching. */ if (flags & BDRV_O_NOCACHE) { rados_conf_set(s->cluster, "rbd_cache", "false"); } else { rados_conf_set(s->cluster, "rbd_cache", "true"); } r = rados_connect(s->cluster); if (r < 0) { error_setg_errno(errp, -r, "error connecting"); goto failed_shutdown; } r = rados_ioctx_create(s->cluster, pool, &s->io_ctx); if (r < 0) { error_setg_errno(errp, -r, "error opening pool %s", pool); goto failed_shutdown; } r = rbd_open(s->io_ctx, s->name, &s->image, s->snap); if (r < 0) { error_setg_errno(errp, -r, "error reading header from %s", s->name); goto failed_open; } bs->read_only = (s->snap != NULL); qemu_opts_del(opts); return 0; failed_open: rados_ioctx_destroy(s->io_ctx); failed_shutdown: rados_shutdown(s->cluster); g_free(s->snap); g_free(s->name); failed_opts: qemu_opts_del(opts); g_free(mon_host); return r; }
static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx, BlockdevOptionsRbd *opts, bool cache, const char *keypairs, const char *secretid, Error **errp) { char *mon_host = NULL; Error *local_err = NULL; int r; if (secretid) { if (opts->key_secret) { error_setg(errp, "Legacy 'password-secret' clashes with 'key-secret'"); return -EINVAL; } opts->key_secret = g_strdup(secretid); opts->has_key_secret = true; } mon_host = qemu_rbd_mon_host(opts, &local_err); if (local_err) { error_propagate(errp, local_err); r = -EINVAL; goto failed_opts; } r = rados_create(cluster, opts->user); if (r < 0) { error_setg_errno(errp, -r, "error initializing"); goto failed_opts; } /* try default location when conf=NULL, but ignore failure */ r = rados_conf_read_file(*cluster, opts->conf); if (opts->has_conf && r < 0) { error_setg_errno(errp, -r, "error reading conf file %s", opts->conf); goto failed_shutdown; } r = qemu_rbd_set_keypairs(*cluster, keypairs, errp); if (r < 0) { goto failed_shutdown; } if (mon_host) { r = rados_conf_set(*cluster, "mon_host", mon_host); if (r < 0) { goto failed_shutdown; } } r = qemu_rbd_set_auth(*cluster, opts, errp); if (r < 0) { goto failed_shutdown; } /* * Fallback to more conservative semantics if setting cache * options fails. Ignore errors from setting rbd_cache because the * only possible error is that the option does not exist, and * librbd defaults to no caching. If write through caching cannot * be set up, fall back to no caching. */ if (cache) { rados_conf_set(*cluster, "rbd_cache", "true"); } else { rados_conf_set(*cluster, "rbd_cache", "false"); } r = rados_connect(*cluster); if (r < 0) { error_setg_errno(errp, -r, "error connecting"); goto failed_shutdown; } r = rados_ioctx_create(*cluster, opts->pool, io_ctx); if (r < 0) { error_setg_errno(errp, -r, "error opening pool %s", opts->pool); goto failed_shutdown; } return 0; failed_shutdown: rados_shutdown(*cluster); failed_opts: g_free(mon_host); return r; }
static int qemu_rbd_open(BlockDriverState *bs, const char *filename, int flags) { BDRVRBDState *s = bs->opaque; char pool[RBD_MAX_POOL_NAME_SIZE]; char snap_buf[RBD_MAX_SNAP_NAME_SIZE]; char conf[RBD_MAX_CONF_SIZE]; char clientname_buf[RBD_MAX_CONF_SIZE]; char *clientname; int r; if (qemu_rbd_parsename(filename, pool, sizeof(pool), snap_buf, sizeof(snap_buf), s->name, sizeof(s->name), conf, sizeof(conf)) < 0) { return -EINVAL; } clientname = qemu_rbd_parse_clientname(conf, clientname_buf); r = rados_create(&s->cluster, clientname); if (r < 0) { error_report("error initializing"); return r; } s->snap = NULL; if (snap_buf[0] != '\0') { s->snap = g_strdup(snap_buf); } /* * Fallback to more conservative semantics if setting cache * options fails. Ignore errors from setting rbd_cache because the * only possible error is that the option does not exist, and * librbd defaults to no caching. If write through caching cannot * be set up, fall back to no caching. */ if (flags & BDRV_O_NOCACHE) { rados_conf_set(s->cluster, "rbd_cache", "false"); } else { rados_conf_set(s->cluster, "rbd_cache", "true"); } if (strstr(conf, "conf=") == NULL) { /* try default location, but ignore failure */ rados_conf_read_file(s->cluster, NULL); } if (conf[0] != '\0') { r = qemu_rbd_set_conf(s->cluster, conf); if (r < 0) { error_report("error setting config options"); goto failed_shutdown; } } r = rados_connect(s->cluster); if (r < 0) { error_report("error connecting"); goto failed_shutdown; } r = rados_ioctx_create(s->cluster, pool, &s->io_ctx); if (r < 0) { error_report("error opening pool %s", pool); goto failed_shutdown; } r = rbd_open(s->io_ctx, s->name, &s->image, s->snap); if (r < 0) { error_report("error reading header from %s", s->name); goto failed_open; } bs->read_only = (s->snap != NULL); s->event_reader_pos = 0; r = qemu_pipe(s->fds); if (r < 0) { error_report("error opening eventfd"); goto failed; } fcntl(s->fds[0], F_SETFL, O_NONBLOCK); fcntl(s->fds[1], F_SETFL, O_NONBLOCK); qemu_aio_set_fd_handler(s->fds[RBD_FD_READ], qemu_rbd_aio_event_reader, NULL, qemu_rbd_aio_flush_cb, s); return 0; failed: rbd_close(s->image); failed_open: rados_ioctx_destroy(s->io_ctx); failed_shutdown: rados_shutdown(s->cluster); g_free(s->snap); return r; }
static int virStorageBackendRBDOpenRADOSConn(virStorageBackendRBDStatePtr ptr, virConnectPtr conn, virStoragePoolObjPtr pool) { int ret = -1; int r = 0; unsigned char *secret_value = NULL; size_t secret_value_size; char *rados_key = NULL; virBuffer mon_host = VIR_BUFFER_INITIALIZER; virSecretPtr secret = NULL; char secretUuid[VIR_UUID_STRING_BUFLEN]; size_t i; char *mon_buff = NULL; const char *client_mount_timeout = "30"; const char *mon_op_timeout = "30"; const char *osd_op_timeout = "30"; VIR_DEBUG("Found Cephx username: %s", pool->def->source.auth.cephx.username); if (pool->def->source.auth.cephx.username != NULL) { VIR_DEBUG("Using cephx authorization"); r = rados_create(&ptr->cluster, pool->def->source.auth.cephx.username); if (r < 0) { virReportSystemError(-r, "%s", _("failed to initialize RADOS")); goto cleanup; } if (!conn) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("'ceph' authentication not supported " "for autostarted pools")); return -1; } if (pool->def->source.auth.cephx.secret.uuidUsable) { virUUIDFormat(pool->def->source.auth.cephx.secret.uuid, secretUuid); VIR_DEBUG("Looking up secret by UUID: %s", secretUuid); secret = virSecretLookupByUUIDString(conn, secretUuid); } else if (pool->def->source.auth.cephx.secret.usage != NULL) { VIR_DEBUG("Looking up secret by usage: %s", pool->def->source.auth.cephx.secret.usage); secret = virSecretLookupByUsage(conn, VIR_SECRET_USAGE_TYPE_CEPH, pool->def->source.auth.cephx.secret.usage); } if (secret == NULL) { if (pool->def->source.auth.cephx.secret.uuidUsable) { virReportError(VIR_ERR_NO_SECRET, _("no secret matches uuid '%s'"), secretUuid); } else { virReportError(VIR_ERR_NO_SECRET, _("no secret matches usage value '%s'"), pool->def->source.auth.cephx.secret.usage); } goto cleanup; } secret_value = conn->secretDriver->secretGetValue(secret, &secret_value_size, 0, VIR_SECRET_GET_VALUE_INTERNAL_CALL); if (!secret_value) { if (pool->def->source.auth.cephx.secret.uuidUsable) { virReportError(VIR_ERR_INTERNAL_ERROR, _("could not get the value of the secret " "for username '%s' using uuid '%s'"), pool->def->source.auth.cephx.username, secretUuid); } else { virReportError(VIR_ERR_INTERNAL_ERROR, _("could not get the value of the secret " "for username '%s' using usage value '%s'"), pool->def->source.auth.cephx.username, pool->def->source.auth.cephx.secret.usage); } goto cleanup; } base64_encode_alloc((char *)secret_value, secret_value_size, &rados_key); memset(secret_value, 0, secret_value_size); if (rados_key == NULL) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("failed to decode the RADOS key")); goto cleanup; } VIR_DEBUG("Found cephx key: %s", rados_key); if (rados_conf_set(ptr->cluster, "key", rados_key) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("failed to set RADOS option: %s"), "rados_key"); goto cleanup; } memset(rados_key, 0, strlen(rados_key)); if (rados_conf_set(ptr->cluster, "auth_supported", "cephx") < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("failed to set RADOS option: %s"), "auth_supported"); goto cleanup; } } else { VIR_DEBUG("Not using cephx authorization"); if (rados_create(&ptr->cluster, NULL) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("failed to create the RADOS cluster")); goto cleanup; } if (rados_conf_set(ptr->cluster, "auth_supported", "none") < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("failed to set RADOS option: %s"), "auth_supported"); goto cleanup; } } VIR_DEBUG("Found %zu RADOS cluster monitors in the pool configuration", pool->def->source.nhost); for (i = 0; i < pool->def->source.nhost; i++) { if (pool->def->source.hosts[i].name != NULL && !pool->def->source.hosts[i].port) { virBufferAsprintf(&mon_host, "%s:6789,", pool->def->source.hosts[i].name); } else if (pool->def->source.hosts[i].name != NULL && pool->def->source.hosts[i].port) { virBufferAsprintf(&mon_host, "%s:%d,", pool->def->source.hosts[i].name, pool->def->source.hosts[i].port); } else { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("received malformed monitor, check the XML definition")); } } if (virBufferError(&mon_host)) { virReportOOMError(); goto cleanup; } mon_buff = virBufferContentAndReset(&mon_host); VIR_DEBUG("RADOS mon_host has been set to: %s", mon_buff); if (rados_conf_set(ptr->cluster, "mon_host", mon_buff) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("failed to set RADOS option: %s"), "mon_host"); goto cleanup; } /* * Set timeout options for librados. * In case the Ceph cluster is down libvirt won't block forever. * Operations in librados will return -ETIMEDOUT when the timeout is reached. */ VIR_DEBUG("Setting RADOS option client_mount_timeout to %s", client_mount_timeout); rados_conf_set(ptr->cluster, "client_mount_timeout", client_mount_timeout); VIR_DEBUG("Setting RADOS option rados_mon_op_timeout to %s", mon_op_timeout); rados_conf_set(ptr->cluster, "rados_mon_op_timeout", mon_op_timeout); VIR_DEBUG("Setting RADOS option rados_osd_op_timeout to %s", osd_op_timeout); rados_conf_set(ptr->cluster, "rados_osd_op_timeout", osd_op_timeout); ptr->starttime = time(0); r = rados_connect(ptr->cluster); if (r < 0) { virReportSystemError(-r, _("failed to connect to the RADOS monitor on: %s"), mon_buff); goto cleanup; } ret = 0; cleanup: VIR_FREE(secret_value); VIR_FREE(rados_key); if (secret != NULL) virSecretFree(secret); virBufferFreeAndReset(&mon_host); VIR_FREE(mon_buff); return ret; }