fix: preserve admin-set host state across worker re-registration in makeWorker_
When a worker re-joins and already exists in workermgr, makeWorker_() now overrides the existing slot instead of returning EEXIST. Admin-set flags (LOCKEDU, CLOSED, HIDDEN, CLOSED_BY_ADMIN) survive the override. Add XCE_WORKER_CLOSED_BY_ADMIN flag to distinguish admin-closed hosts from workload-closed ones. worker_ctrl sets/clears it alongside CLOSED. Refactor worker_init/worker_destroy into copy_worker/kill_worker helpers shared by both fresh creation and override paths. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
d47b3375e7
commit
febb4a6c4d
6 changed files with 111 additions and 57 deletions
|
|
@ -616,13 +616,13 @@ int worker_ctrl(cluster_t* c, xce_hostctrl_t* ctrl)
|
|||
if (!(w->host.status & XCE_WORKER_CLOSED)) {
|
||||
goto clean;
|
||||
}
|
||||
w->host.status &= ~XCE_WORKER_CLOSED;
|
||||
w->host.status &= ~(XCE_WORKER_CLOSED | XCE_WORKER_CLOSED_BY_ADMIN);
|
||||
break;
|
||||
case HOST_CLOSE:
|
||||
if (w->host.status & XCE_WORKER_CLOSED) {
|
||||
goto clean;
|
||||
}
|
||||
w->host.status |= XCE_WORKER_CLOSED;
|
||||
w->host.status |= (XCE_WORKER_CLOSED | XCE_WORKER_CLOSED_BY_ADMIN);
|
||||
break;
|
||||
default:
|
||||
rc = -1;
|
||||
|
|
|
|||
|
|
@ -536,21 +536,16 @@ func validateHost(ctx *gin.Context, control int, hostnames []string) (successHos
|
|||
}
|
||||
|
||||
func isHostControlActionAllowed(actionType int, status int) bool {
|
||||
isClosed := (status&models.HOSTSTAT["CLOSED"]) != 0 ||
|
||||
(status&models.HOSTSTAT["CLOSED_BY_ADMIN"]) != 0
|
||||
switch actionType {
|
||||
case 1: // open strictly
|
||||
if status&models.HOSTSTAT["CLOSED"] != 0 {
|
||||
return true
|
||||
}
|
||||
case 1: // open
|
||||
return isClosed
|
||||
case 2: // close
|
||||
if (status & models.HOSTSTAT["CLOSED"]) != 0 {
|
||||
return false
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
return !isClosed
|
||||
default:
|
||||
return false
|
||||
}
|
||||
return false
|
||||
}
|
||||
func preCheckHostControlRequest(req *models.HostControlRequest) (bool, error) {
|
||||
logger.Debug("Enter preCheckHostControlRequest")
|
||||
|
|
|
|||
|
|
@ -10,16 +10,19 @@ const (
|
|||
var SupportedHostActions = []string{"open", "close"}
|
||||
|
||||
var HOSTSTAT = map[string]int{
|
||||
"UNAVAIL": 0x00010000,
|
||||
"LOCKEDU": 0x00020000,
|
||||
"LOCKEDW": 0x00040000,
|
||||
"BUSY": 0x00080000,
|
||||
"CLOSED": 0x00100000,
|
||||
"UNAVAIL": 0x00010000,
|
||||
"LOCKEDU": 0x00020000,
|
||||
"LOCKEDW": 0x00040000,
|
||||
"BUSY": 0x00080000,
|
||||
"CLOSED": 0x00100000,
|
||||
"CLOSED_BY_ADMIN": 0x00400000,
|
||||
}
|
||||
|
||||
func HostStateStr(state int) string {
|
||||
if (state & HOSTSTAT["UNAVAIL"]) != 0 {
|
||||
return "UNAVAIL"
|
||||
} else if (state & HOSTSTAT["CLOSED_BY_ADMIN"]) != 0 {
|
||||
return "CLOSED_BY_ADMIN"
|
||||
} else if (state & HOSTSTAT["CLOSED"]) != 0 {
|
||||
return "CLOSED"
|
||||
} else if (state & HOSTSTAT["BUSY"]) != 0 {
|
||||
|
|
|
|||
|
|
@ -23,6 +23,11 @@ func TestHostStateStr(t *testing.T) {
|
|||
state: HOSTSTAT["CLOSED"],
|
||||
want: "CLOSED",
|
||||
},
|
||||
{
|
||||
name: "CLOSED_BY_ADMIN flag",
|
||||
state: HOSTSTAT["CLOSED_BY_ADMIN"],
|
||||
want: "CLOSED_BY_ADMIN",
|
||||
},
|
||||
{
|
||||
name: "BUSY flag",
|
||||
state: HOSTSTAT["BUSY"],
|
||||
|
|
@ -48,6 +53,11 @@ func TestHostStateStr(t *testing.T) {
|
|||
state: HOSTSTAT["UNAVAIL"] | HOSTSTAT["CLOSED"],
|
||||
want: "UNAVAIL", // UNAVAIL takes priority
|
||||
},
|
||||
{
|
||||
name: "combined CLOSED+CLOSED_BY_ADMIN flags",
|
||||
state: HOSTSTAT["CLOSED"] | HOSTSTAT["CLOSED_BY_ADMIN"],
|
||||
want: "CLOSED_BY_ADMIN", // CLOSED_BY_ADMIN overrides generic CLOSED
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
|
|
|
|||
|
|
@ -172,11 +172,13 @@ typedef struct {
|
|||
#define XCE_WORKER_LOCKEDW (0x00040000)
|
||||
#define XCE_WORKER_BUSY (0x00080000)
|
||||
#define XCE_WORKER_CLOSED (0x00100000)
|
||||
#define XCE_WORKER_HIDDEN (0x00200000) /* Admin explicitly removed — invisible but not yet cleaned up */
|
||||
#define XCE_WORKER_HIDDEN (0x00200000) /* Admin explicitly removed — invisible but not yet cleaned up */
|
||||
#define XCE_WORKER_CLOSED_BY_ADMIN (0x00400000) /* Admin closed — host closed explicitly by admin */
|
||||
|
||||
#define IS_WORKER_UNAVAIL(status) (((status) & XCE_WORKER_UNAVAIL) != 0)
|
||||
#define IS_WORKER_LOCKEDU(status) (((status) & XCE_WORKER_LOCKEDU) != 0)
|
||||
#define IS_WORKER_LOCKEDW(status) (((status) & XCE_WORKER_LOCKEDW) != 0)
|
||||
#define IS_WORKER_UNAVAIL(status) (((status) & XCE_WORKER_UNAVAIL) != 0)
|
||||
#define IS_WORKER_LOCKEDU(status) (((status) & XCE_WORKER_LOCKEDU) != 0)
|
||||
#define IS_WORKER_LOCKEDW(status) (((status) & XCE_WORKER_LOCKEDW) != 0)
|
||||
#define IS_WORKER_CLOSED_BY_ADMIN(status) (((status) & XCE_WORKER_CLOSED_BY_ADMIN) != 0)
|
||||
#define IS_WORKER_LOCKED(status) \
|
||||
(IS_WORKER_LOCKEDU(status) || IS_WORKER_LOCKEDW(status))
|
||||
#define IS_WORKER_BUSY(status) (((status) & XCE_WORKER_BUSY) != 0)
|
||||
|
|
|
|||
116
src/lib/wobj.c
116
src/lib/wobj.c
|
|
@ -22,12 +22,34 @@ static size_t worker_datasize(va_list ap)
|
|||
return sz;
|
||||
}
|
||||
|
||||
static int worker_init(meta_obj_t* obj, va_list ap)
|
||||
static void kill_worker(worker_t* w)
|
||||
{
|
||||
worker_t* dst = RTTI_OBJ_TO_DATA(worker_t, obj);
|
||||
worker_private_t* priv = (worker_private_t*)RTTI_OBJ_TO_PRIV(obj);
|
||||
xce_worker_t* src = va_arg(ap, xce_worker_t*);
|
||||
dereference(w->host.name);
|
||||
|
||||
if (w->host.attrs != NULL) {
|
||||
dereference(w->host.attrs->hosttype);
|
||||
dereference(w->host.attrs->hostmodel);
|
||||
FREEUP(w->host.attrs);
|
||||
}
|
||||
|
||||
if (w->host.dispatch_window_config != NULL) {
|
||||
free_timewindow_config(w->host.dispatch_window_config);
|
||||
w->host.dispatch_window_config = NULL;
|
||||
}
|
||||
|
||||
if (w->host.thresholds != NULL) {
|
||||
free_resource_thresholds(w->host.thresholds, w->host.nthresholds);
|
||||
w->host.thresholds = NULL;
|
||||
w->host.nthresholds = 0;
|
||||
}
|
||||
|
||||
zarray_fini(&(w->host.resvals));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int copy_worker(worker_t* dst, xce_worker_t* src)
|
||||
{
|
||||
if ((src == NULL) || (src->attrs == NULL)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
@ -55,6 +77,42 @@ static int worker_init(meta_obj_t* obj, va_list ap)
|
|||
dst->host.nresvals_to_sched = 0;
|
||||
dst->host.resvals_to_sched = NULL;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int override_worker(worker_t* dst, xce_worker_t* w)
|
||||
{
|
||||
#define XCE_WORKER_ADMIN_MASK \
|
||||
(XCE_WORKER_LOCKEDU | XCE_WORKER_CLOSED | XCE_WORKER_HIDDEN | XCE_WORKER_CLOSED_BY_ADMIN)
|
||||
uint32_t admin_status = 0;
|
||||
int rc = 0;
|
||||
|
||||
admin_status = dst->host.status & XCE_WORKER_ADMIN_MASK;
|
||||
|
||||
kill_worker(dst);
|
||||
|
||||
rc = copy_worker(dst, w);
|
||||
if (rc >= 0) {
|
||||
dst->host.status |= admin_status;
|
||||
dst->ep = NULL;
|
||||
}
|
||||
|
||||
return rc;
|
||||
#undef XCE_WORKER_ADMIN_MASK
|
||||
}
|
||||
|
||||
static int worker_init(meta_obj_t* obj, va_list ap)
|
||||
{
|
||||
worker_t* dst = RTTI_OBJ_TO_DATA(worker_t, obj);
|
||||
worker_private_t* priv = (worker_private_t*)RTTI_OBJ_TO_PRIV(obj);
|
||||
xce_worker_t* src = va_arg(ap, xce_worker_t*);
|
||||
int rc = 0;
|
||||
|
||||
rc = copy_worker(dst, src);
|
||||
if (rc < 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
my_rwlock_init(&(priv->lock));
|
||||
priv->refcount = 1;
|
||||
|
||||
|
|
@ -66,26 +124,7 @@ static void worker_destroy(meta_obj_t* obj)
|
|||
worker_t* w = RTTI_OBJ_TO_DATA(worker_t, obj);
|
||||
worker_private_t* priv = (worker_private_t*)RTTI_OBJ_TO_PRIV(obj);
|
||||
|
||||
dereference(w->host.name);
|
||||
|
||||
if (w->host.attrs != NULL) {
|
||||
dereference(w->host.attrs->hosttype);
|
||||
dereference(w->host.attrs->hostmodel);
|
||||
FREEUP(w->host.attrs);
|
||||
}
|
||||
|
||||
if (w->host.dispatch_window_config != NULL) {
|
||||
free_timewindow_config(w->host.dispatch_window_config);
|
||||
w->host.dispatch_window_config = NULL;
|
||||
}
|
||||
|
||||
if (w->host.thresholds != NULL) {
|
||||
free_resource_thresholds(w->host.thresholds, w->host.nthresholds);
|
||||
w->host.thresholds = NULL;
|
||||
w->host.nthresholds = 0;
|
||||
}
|
||||
|
||||
zarray_fini(&(w->host.resvals));
|
||||
kill_worker(w);
|
||||
|
||||
my_rwlock_fini(&(priv->lock));
|
||||
memset(priv, 0x0, sizeof(*priv));
|
||||
|
|
@ -163,9 +202,10 @@ static typeinfo_t worker_type = {
|
|||
static worker_t* makeWorker_(var workermgr, xce_worker_t* w)
|
||||
{
|
||||
worker_t* worker = NULL;
|
||||
worker_t* w1 = NULL;
|
||||
int rc = 0;
|
||||
|
||||
rc = key_find(workermgr, (void*)w->name, (void**)&worker);
|
||||
rc = key_find(workermgr, (void*)w->name, (void**)&w1);
|
||||
|
||||
if ((rc < 0) && (rc != -ENOENT)) {
|
||||
errno = -rc;
|
||||
|
|
@ -174,20 +214,24 @@ static worker_t* makeWorker_(var workermgr, xce_worker_t* w)
|
|||
}
|
||||
|
||||
if (rc > 0) {
|
||||
errno = EEXIST;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
worker = makeInstance(&worker_type, w);
|
||||
if (worker != NULL) {
|
||||
rc = key_add(workermgr, (void*)worker->host.name, (void*)worker);
|
||||
|
||||
rc = override_worker(w1, w);
|
||||
if (rc < 0) {
|
||||
destroy(worker);
|
||||
|
||||
errno = -rc;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
worker = w1;
|
||||
} else {
|
||||
worker = makeInstance(&worker_type, w);
|
||||
if (worker != NULL) {
|
||||
rc = key_add(workermgr, (void*)worker->host.name, (void*)worker);
|
||||
|
||||
if (rc < 0) {
|
||||
destroy(worker);
|
||||
|
||||
errno = -rc;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return worker;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue