client: handle changes to project master URLs

The Einstein@home web site says its master URL is
https://einsteinathome.org.
But its scheduler replies say the master URL is
https://einstein.phys.uwm.edu
If you attach to URL1 the client creates a file
account_einsteinathome.org.xml
Then it does a scheduler RPC and gets a reply saying the master URL is URL2.
It then creates a file
account_einstein.phys.uwm.edu.xml

If you then detach from the project, it deletes the 2nd account file
but the first one is still there,
so the next time you run the client you're still attached to Einstein@home!

To fix this situation:

1) on startup, check for misnamed account files
(file name doesn't match master URL in the file).
Delete (if there's already a file of the right name) or rename.

2) on scheduler RPC reply with a URL that differs by more than http(s)://,
rename the account file and the project directory.
Reset the project (remove jobs and other info)
since soft links point to the old project dir.
This commit is contained in:
David Anderson 2024-01-07 17:58:04 -08:00
parent 86669cd2c1
commit 1c3d99e3bc
3 changed files with 102 additions and 9 deletions

View File

@ -323,6 +323,7 @@ int CLIENT_STATE::parse_account_files() {
PROJECT* project;
FILE* f;
int retval;
char path[MAXPATHLEN];
DirScanner dir(".");
while (dir.scan(name)) {
@ -345,16 +346,50 @@ int CLIENT_STATE::parse_account_files() {
"Couldn't parse account file %s", name.c_str()
);
delete project;
} else {
if (lookup_project(project->master_url)) {
continue;
}
// see if the account file name doesn't match the master URL.
// This can happen if a project changes its URL
//
// If this happens, anything in client_state.xml for the old project
// will be ignored.
//
get_account_filename(project->master_url, path, sizeof(path));
if (strcmp(path, name.c_str())) {
// if not, see if account file with proper name exists
//
if (boinc_file_exists(path)) {
// yes - delete this file
//
msg_printf(project, MSG_INFO,
"Duplicate account file %s - ignoring", name.c_str()
"Misnamed account file %s - deleting", name.c_str()
);
boinc_delete_file(name.c_str());
delete project;
continue;
} else {
projects.push_back(project);
// no - rename this file
//
msg_printf(project, MSG_INFO,
"Misnamed account file %s - renaming to %s",
name.c_str(), path
);
boinc_rename(name.c_str(), path);
}
}
// shouldn't happen given the above logic, but just in case
//
if (lookup_project(project->master_url)) {
msg_printf(project, MSG_INFO,
"Duplicate account file %s - ignoring", name.c_str()
);
delete project;
continue;
}
projects.push_back(project);
}
return 0;
}

View File

@ -87,15 +87,39 @@ bool CLIENT_STATE::start_new_file_xfer(PERS_FILE_XFER& pfx) {
return true;
}
// Make a directory for each of the projects in the client state
// Make a directory for each of the projects in the client state,
// and delete other stuff in projects/
//
int CLIENT_STATE::make_project_dirs() {
unsigned int i;
int retval;
vector<string> pds;
for (i=0; i<projects.size(); i++) {
retval = make_project_dir(*projects[i]);
PROJECT *p = projects[i];
retval = make_project_dir(*p);
if (retval) return retval;
pds.push_back(p->project_dir());
}
string name;
char path[MAXPATHLEN];
DirScanner dir("projects");
while (dir.scan(name)) {
snprintf(path, sizeof(path), "projects/%s", name.c_str());
if (std::find(pds.begin(), pds.end(), path) != pds.end()) {
continue;
}
msg_printf(0, MSG_INFO,
"%s is not a project dir - removing", path
);
if (is_dir(path)) {
clean_out_dir(path);
boinc_rmdir(path);
} else {
boinc_delete_file(path);
}
}
return 0;
}

View File

@ -567,7 +567,9 @@ int CLIENT_STATE::handle_scheduler_reply(
// (which comes from the project's config.xml).
// - if http -> https transition, use the https: one from now on
// - if https -> http transition, keep using the https: one
// - otherwise notify the user.
// - otherwise switch to the new master URL:
// rename and rewrite account file
// rename project dir
//
if (strlen(sr.master_url)) {
canonicalize_master_url(sr.master_url, sizeof(sr.master_url));
@ -587,9 +589,41 @@ int CLIENT_STATE::handle_scheduler_reply(
// keep using https://
} else {
msg_printf(project, MSG_USER_ALERT,
_("This project seems to have changed its URL. When convenient, remove the project, then add %s"),
sr.master_url
_("Master URL changed from %s to %s"),
current_url.c_str(), reply_url.c_str()
);
char path[MAXPATHLEN], path2[MAXPATHLEN], old_project_dir[MAXPATHLEN];
// rename statistics file
//
get_statistics_filename(
(char*)current_url.c_str(), path, sizeof(path)
);
get_statistics_filename(
(char*)reply_url.c_str(), path2, sizeof(path2)
);
boinc_rename(path, path2);
strcpy(old_project_dir, project->project_dir());
// delete account file and write new one
//
get_account_filename(project->master_url, path, sizeof(path));
boinc_delete_file(path);
strcpy(project->master_url, reply_url.c_str());
project->write_account_file();
// rename project dir
//
strcpy(project->_project_dir, "");
strcpy(path2, project->project_dir());
boinc_rename(old_project_dir, path2);
// reset the project (clear jobs etc.).
// If any jobs are running, their soft links
// point to the old project dir
//
reset_project(project, false);
}
}
}