Commit eafebcf1 authored by Sebastien Gougeaud's avatar Sebastien Gougeaud Committed by Thomas Leibovici
Browse files

refactor: move dss "drive unlock" code to the admin module



Now that admin operations require to notify the daemon if it is online,
we will try to remove all dss-related code from the CLI to add it in the
admin module and let the CLI only be a command line interpreter.

Change-Id: Ic2c94b23ae2bb3f47d788bc1c6a9a72f880622c5
Signed-off-by: default avatarSebastien Gougeaud <sebastien.gougeaud@cea.fr>
Reviewed-on: https://gerrit.ccc.ocre.cea.fr/gerrit/c/phobos/+/6792

Tested-by: default avatarJenkins s8open_nr <s8open_nr@ccc.ocre.cea.fr>
Reviewed-by: default avatarQuentin Bouget <quentin.bouget@cea.fr>
Reviewed-by: default avatarThomas Leibovici <thomas.leibovici@cea.fr>
parent 5c8bacb4
......@@ -28,10 +28,12 @@
#include "phobos_admin.h"
#include <sys/syscall.h>
#include <unistd.h>
#include "pho_cfg.h"
#include "pho_comm.h"
#include "pho_common.h"
#include "pho_dss.h"
#include "pho_srl_lrs.h"
......@@ -53,7 +55,7 @@ const struct pho_config_item cfg_admin[] = {
};
/* ****************************************************************************/
/* Static Functions ***********************************************************/
/* Static Communication-related Functions *************************************/
/* ****************************************************************************/
static int _send_and_receive(struct admin_handle *adm, pho_req_t *req,
......@@ -143,6 +145,117 @@ out:
return rc;
}
/* ****************************************************************************/
/* Static Database-related Functions ******************************************/
/* ****************************************************************************/
static int _get_device_by_id(struct admin_handle *adm, struct pho_id *dev_id,
struct dev_info **dev_res)
{
struct dss_filter filter;
int dcnt;
int rc;
rc = dss_filter_build(&filter,
"{\"$AND\": ["
" {\"DSS::DEV::family\": \"%s\"},"
" {\"$OR\": ["
" {\"DSS::DEV::serial\": \"%s\"},"
" {\"DSS::DEV::path\": \"%s\"}"
" ]}"
"]}",
rsc_family2str(dev_id->family),
dev_id->name, dev_id->name);
if (rc)
return rc;
rc = dss_device_get(&adm->dss, &filter, dev_res, &dcnt);
dss_filter_free(&filter);
if (rc)
return rc;
if (dcnt == 0)
LOG_RETURN(-ENXIO, "Device '%s' not found", dev_id->name);
assert(dcnt == 1);
return 0;
}
static int _device_unlock(struct admin_handle *adm, struct pho_id *dev_ids,
int num_dev, bool is_forced)
{
struct dev_info *devices;
int avail_devices = 0;
int rc;
int i;
devices = calloc(num_dev, sizeof(*devices));
if (!devices)
LOG_RETURN(-ENOMEM, "Device info allocation failed");
for (i = 0; i < num_dev; ++i) {
struct dev_info *dev_res;
rc = _get_device_by_id(adm, dev_ids + i, &dev_res);
if (rc)
goto out_free;
rc = dss_device_lock(&adm->dss, dev_res, 1, adm->lock_owner);
if (rc) {
pho_error(-EBUSY, "Device '%s' is in use by '%s'", dev_ids[i].name,
dev_res->lock.lock);
dss_res_free(dev_res, 1);
continue;
}
dss_res_free(dev_res, 1);
rc = _get_device_by_id(adm, dev_ids + i, &dev_res);
if (rc)
goto out_free;
/* TODO: to uncomment once the dss_device_lock() is removed ie. when
* the update of a single database field will be implemented
*/
/* if (strcmp(dev_res->lock.lock, "") && !is_forced) {
* pho_error(-EBUSY, "Device '%s' is in use by '%s'", dev_ids[i].name,
* dev_res->lock.lock);
* dss_res_free(dev_res, 1);
* continue;
* }
*/
if (dev_res->rsc.adm_status == PHO_RSC_ADM_ST_UNLOCKED)
pho_warn("Device '%s' is already unlocked", dev_ids[i].name);
dev_res->rsc.adm_status = PHO_RSC_ADM_ST_UNLOCKED;
memcpy(devices + i, dev_res, sizeof(*dev_res));
dss_res_free(dev_res, 1);
++avail_devices;
}
if (avail_devices != num_dev)
LOG_GOTO(out_free, rc = -EBUSY,
"At least one device is in use, use --force");
rc = dss_device_set(&adm->dss, devices, num_dev, DSS_SET_UPDATE);
if (rc)
goto out_free;
// in case the name given by the user is not the device ID name
for (i = 0; i < num_dev; ++i)
if (strcmp(dev_ids[i].name, devices[i].rsc.id.name))
strcpy(dev_ids[i].name, devices[i].rsc.id.name);
out_free:
dss_device_unlock(&adm->dss, devices, num_dev, adm->lock_owner);
free(devices);
return rc;
}
/* ****************************************************************************/
/* API Functions **************************************************************/
/* ****************************************************************************/
......@@ -155,9 +268,13 @@ void phobos_admin_fini(struct admin_handle *adm)
if (rc)
pho_error(rc, "Cannot close the communication socket");
free(adm->lock_owner);
dss_fini(&adm->dss);
}
static __thread uint64_t adm_lock_number;
int phobos_admin_init(struct admin_handle *adm, bool lrs_required)
{
const char *sock_path;
......@@ -166,6 +283,15 @@ int phobos_admin_init(struct admin_handle *adm, bool lrs_required)
memset(adm, 0, sizeof(*adm));
adm->comm = pho_comm_info_init();
rc = asprintf(&adm->lock_owner, "%.213s:%.8lx:%.16lx:%.16lx",
get_hostname(), syscall(SYS_gettid), time(NULL),
adm_lock_number);
if (rc == -1)
LOG_GOTO(out, rc, "Cannot allocate lock_owner");
++adm_lock_number;
rc = pho_cfg_init_local(NULL);
if (rc && rc != -EALREADY)
return rc;
......@@ -218,16 +344,16 @@ int phobos_admin_device_add(struct admin_handle *adm, enum rsc_family family,
return 0;
}
/**
* TODO: admin_device_unlock will have the responsability to update the device
* state, to then remove this part of code from the CLI.
*/
int phobos_admin_device_unlock(struct admin_handle *adm, struct pho_id *dev_ids,
int num_dev)
int num_dev, bool is_forced)
{
int rc = 0;
int rc;
int i;
rc = _device_unlock(adm, dev_ids, num_dev, is_forced);
if (rc)
return rc;
if (!adm->daemon_is_online)
return 0;
......@@ -238,7 +364,7 @@ int phobos_admin_device_unlock(struct admin_handle *adm, struct pho_id *dev_ids,
if (rc2)
pho_error(rc2, "Failure during daemon notification for '%s'",
dev_ids[i].name);
rc = rc ? rc : rc2;
rc = rc ? : rc2;
}
return rc;
......
......@@ -665,53 +665,17 @@ class DeviceOptHandler(BaseResourceOptHandler):
def exec_unlock(self):
"""Device unlock"""
serials = self.params.get('res')
devices = []
for serial in serials:
device = self.filter(serial)
if not device:
self.logger.error("No such device: %s", serial)
sys.exit(os.EX_DATAERR)
assert len(device) == 1
try:
self.client.devices.lock([device[0]])
except EnvironmentError as err:
self.logger.error("Failed to lock device '%s': %s", serial,
env_error_format(err))
continue
device = self.filter(serial)
assert len(device) == 1
if device[0].rsc.adm_status == PHO_RSC_ADM_ST_UNLOCKED:
self.logger.warn("Device %s is already unlocked", serial)
device[0].rsc.adm_status = PHO_RSC_ADM_ST_UNLOCKED
devices.append(device[0])
if len(devices) != len(serials):
self.logger.error("At least one device is in use, use --force")
sys.exit(os.EX_DATAERR)
names = self.params.get('res')
try:
self.client.devices.update(devices)
with AdminClient(lrs_required=False) as adm:
adm.device_unlock(self.family, names, self.params.get('force'))
except EnvironmentError as err:
self.logger.error("Failed to unlock device(s): %s",
env_error_format(err))
sys.exit(os.EX_DATAERR)
try:
with AdminClient(lrs_required=False) as adm:
names = [dev.rsc.id.name for dev in devices]
adm.device_unlock(self.family, names)
except EnvironmentError as err:
self.logger.error("Failed to notify: %s", env_error_format(err))
sys.exit(os.EX_DATAERR)
finally:
self.client.devices.unlock(devices)
self.logger.info("%d device(s) unlocked", len(devices))
self.logger.info("%d device(s) unlocked", len(names))
class MediaOptHandler(BaseResourceOptHandler):
"""Shared interface for media."""
......
......@@ -36,10 +36,10 @@ from phobos.core.ffi import CommInfo, LIBPHOBOS_ADMIN, LRS, Id
class AdminHandle(Structure):
"""Admin handler"""
_fields_ = [
('dss', DSSHandle),
('lrs', LRS),
('comm', CommInfo),
('dir_sock_path', c_char_p),
('dss', DSSHandle),
('daemon_is_online', c_int),
('lock_owner', c_char_p),
]
class Client(object):
......@@ -100,13 +100,14 @@ class Client(object):
raise EnvironmentError(rc, "Cannot add device '%s' to the LRS"
% dev_name)
def device_unlock(self, dev_family, dev_names):
"""Inform the daemon that devices are unlocked."""
def device_unlock(self, dev_family, dev_names, is_forced):
"""Wrapper for the device unlock command."""
c_id = Id * len(dev_names)
dev_ids = [Id(dev_family, name) for name in dev_names]
rc = LIBPHOBOS_ADMIN.phobos_admin_device_unlock(byref(self.handle),
c_id(*dev_ids),
len(dev_ids))
len(dev_ids),
is_forced)
if rc:
raise EnvironmentError(rc, "Cannot notify the daemon")
raise EnvironmentError(rc, "Error during device unlock")
......@@ -27,8 +27,10 @@
#endif
#include "pho_common.h"
#include <stdio.h>
#include <stdlib.h>
#include <sys/utsname.h>
#include <ctype.h>
#include <unistd.h>
#include <assert.h>
......@@ -335,3 +337,23 @@ int pho_ht_foreach(GHashTable *ht, pho_ht_iter_cb_t cb, void *data)
g_hash_table_find(ht, pho_ht_iter_cb_wrapper, &phd);
return phd.rc;
}
const char *get_hostname()
{
static struct utsname host_info;
char *dot;
if (host_info.nodename[0] != '\0')
return host_info.nodename;
if (uname(&host_info) != 0) {
pho_error(errno, "Failed to get host name");
return NULL;
}
dot = strchr(host_info.nodename, '.');
if (dot)
*dot = '\0';
return host_info.nodename;
}
......@@ -263,4 +263,9 @@ static inline bool is_medium_global_error(int errcode)
return errcode == -ENOSPC || errcode == -EROFS || errcode == -EDQUOT;
}
/**
* Get short host name once (/!\ not thread-safe).
*/
const char *get_hostname(void);
#endif
......@@ -34,9 +34,10 @@
* Phobos admin handle.
*/
struct admin_handle {
struct dss_handle dss; /**< DSS handle, configured from conf. */
struct pho_comm_info comm; /**< Communication socket info. */
struct dss_handle dss; /**< DSS handle, configured from conf. */
bool daemon_is_online; /**< True if phobosd is online. */
char *lock_owner; /**< Lock owner name for this client. */
};
/**
......@@ -82,12 +83,13 @@ int phobos_admin_device_add(struct admin_handle *adm, enum rsc_family family,
* \param[in] adm Admin module handler.
* \param[in] dev_ids Device IDs to unlock.
* \param[in] num_dev Number of device to unlock.
* \param[in] is_forced true if forced unlock is requested.
*
* \return 0 on success,
* -errno on failure.
*/
int phobos_admin_device_unlock(struct admin_handle *adm, struct pho_id *dev_ids,
int num_dev);
int num_dev, bool is_forced);
/**
* Load and format a medium to the given fs type.
......
......@@ -41,7 +41,6 @@
#include <sys/syscall.h>
#include <sys/types.h>
#include <assert.h>
#include <sys/utsname.h>
#include <jansson.h>
#include <stdbool.h>
#include <stdio.h>
......@@ -87,25 +86,6 @@ static char *mount_point(const char *id)
return mnt_out;
}
static struct utsname host_info;
/** get host name once (/!\ not thread-safe). */
static const char *get_hostname(void)
{
if (host_info.nodename[0] == '\0') {
char *dot;
if (uname(&host_info) != 0) {
pho_error(errno, "Failed to get host name");
return NULL;
}
dot = strchr(host_info.nodename, '.');
if (dot)
*dot = '\0';
}
return host_info.nodename;
}
/** all needed information to select devices */
struct dev_descr {
struct dev_info *dss_dev_info; /**< device info from DSS */
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment