Skip to content

Commit 7cd5e4b

Browse files
chasefortierdsblank
authored andcommitted
Create migrate-users function
Creating a new cometx/cli/migrate_users.py module, which takes a chargeback report from a source environment, and invites users to all of the same workspaces in a destination environment Adding --create-workspaces argument to both copy and migreate_users so user can decide whether to create a workspace when it doesn't exist.
1 parent 4af443b commit 7cd5e4b

File tree

4 files changed

+405
-22
lines changed

4 files changed

+405
-22
lines changed

README.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ for ML management.
4646
* [cometx download](#cometx-download)
4747
* [cometx list](#cometx-list)
4848
* [cometx log](#cometx-log)
49+
* [cometx migrate-users](#cometx-migrate-users)
4950
* [cometx rename-duplicates](#cometx-rename-duplicates)
5051
* [cometx reproduce](#cometx-reproduce)
5152
* [cometx smoke-test](#cometx-smoke-test)
@@ -268,6 +269,7 @@ Not all combinations are possible:
268269
* `--symlink` - Instead of copying, create a link to an experiment in a project
269270
* `--sync` - Check to see if experiment name has been created first; if so, skip
270271
* `--path PATH` - Path to prepend to workspace_src when accessing files (supports ~ for home directory)
272+
* `--create-workspaces` - Attempt to create the destination workspace if it does not exist (requires appropriate API permissions)
271273

272274
### Using --path
273275

@@ -329,6 +331,43 @@ Where TYPE is one of the following names:
329331

330332
For more information, `cometx log --help`
331333

334+
## cometx migrate-users
335+
336+
This command is used to migrate users into workspaces from a source Comet environment to a destination environment. It reads workspace membership from a chargeback report from the source environment and invites each user to the corresponding workspace in the destination environment by email. If a user with the email does not exist in the destination environment, they still will be provisioned access to these workspaces once they sign up using that email.
337+
338+
The chargeback report can be fetched automatically from the source environment's admin API, or you can provide a pre-downloaded JSON file.
339+
340+
```
341+
cometx migrate-users --api-key DEST_KEY --source-api-key SOURCE_KEY [FLAGS ...]
342+
cometx migrate-users --api-key DEST_KEY --chargeback-report /path/to/report.json [FLAGS ...]
343+
```
344+
345+
**Arguments:**
346+
* `--api-key API_KEY` - API key for the destination environment where users will be added. Falls back to `COMET_API_KEY` environment variable if not provided.
347+
* `--source-api-key SOURCE_API_KEY` - API key for the source environment. Used to fetch the chargeback report. Falls back to `COMET_API_KEY` environment variable if not provided. Required unless `--chargeback-report` is given.
348+
* `--chargeback-report PATH` - Path to a local chargeback report JSON file. When provided, the report is loaded from this file instead of being fetched from the source environment, and `--source-api-key` is not required.
349+
350+
### Flags
351+
352+
* `--create-workspaces` - Create workspaces on the destination environment if they don't already exist (default: off)
353+
* `--dry-run` - Print what would happen without making any changes
354+
355+
### Examples
356+
357+
```bash
358+
# Dry run — preview what would happen
359+
cometx migrate-users --api-key DEST_KEY --source-api-key SOURCE_KEY --dry-run
360+
361+
# Execute the migration
362+
cometx migrate-users --api-key DEST_KEY --source-api-key SOURCE_KEY
363+
364+
# Use a local chargeback report file
365+
cometx migrate-users --api-key DEST_KEY --chargeback-report /tmp/chargeback_reports.json
366+
367+
```
368+
369+
For more information, `cometx migrate-users --help`
370+
332371
## cometx rename-duplicates
333372

334373
This command is used to rename duplicate experiments within projects. When multiple experiments share the same name in a project, this command renames the duplicates to NAME-1, NAME-2, etc. while avoiding conflicts with existing names.

cometx/cli/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
cometx smoke-test
2727
cometx update
2828
cometx admin
29+
cometx migrate-users
2930
3031
For more information:
3132
cometx COMMAND --help
@@ -47,6 +48,7 @@
4748
download,
4849
list_command,
4950
log,
51+
migrate_users,
5052
rename_duplicates,
5153
reproduce,
5254
smoke_test,
@@ -108,6 +110,7 @@ def main(raw_args=sys.argv[1:]):
108110
add_subparser(subparsers, config, "config")
109111
add_subparser(subparsers, rename_duplicates, "rename-duplicates")
110112
add_subparser(subparsers, smoke_test, "smoke-test")
113+
add_subparser(subparsers, migrate_users, "migrate-users")
111114
add_subparser(
112115
subparsers, upload_optimizer_experiments, "upload-optimizer-experiments"
113116
)

cometx/cli/copy.py

Lines changed: 35 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,12 @@ def get_parser_arguments(parser):
197197
type=str,
198198
default=None,
199199
)
200+
parser.add_argument(
201+
"--create-workspaces",
202+
help="Attempt to create the destination workspace if it does not exist",
203+
default=False,
204+
action="store_true",
205+
)
200206

201207

202208
def copy(parsed_args, remaining=None):
@@ -214,6 +220,7 @@ def copy(parsed_args, remaining=None):
214220
parsed_args.ignore,
215221
parsed_args.debug,
216222
parsed_args.sync,
223+
parsed_args.create_workspaces,
217224
)
218225

219226
# Wait for all uploads to complete
@@ -790,7 +797,7 @@ def cleanup(self):
790797
# Restore default signal handler
791798
signal.signal(signal.SIGINT, signal.default_int_handler)
792799

793-
def copy(self, source, destination, symlink, ignore, debug, sync):
800+
def copy(self, source, destination, symlink, ignore, debug, sync, create_workspaces=False):
794801
""" """
795802
self.ignore = ignore
796803
self.debug = debug
@@ -820,31 +827,37 @@ def copy(self, source, destination, symlink, ignore, debug, sync):
820827
else:
821828
raise Exception("invalid COMET_SOURCE: %r" % source)
822829

823-
# First check to make sure workspace_dst exists; try to create if not:
830+
# First check to make sure workspace_dst exists:
824831
workspaces = self.api.get_workspaces()
825832
if workspace_dst not in workspaces:
826-
print(
827-
f"Workspace {workspace_dst!r} does not exist, attempting to create it..."
828-
)
829-
try:
830-
import requests
831-
832-
url = f"{self.api.server_url}/api/rest/v2/write/workspace/new"
833-
response = requests.post(
834-
url,
835-
json={"name": workspace_dst},
836-
headers={
837-
"Authorization": self.api.api_key,
838-
"Content-Type": "application/json",
839-
},
833+
if create_workspaces:
834+
print(
835+
f"Workspace {workspace_dst!r} does not exist, attempting to create it..."
840836
)
841-
response.raise_for_status()
842-
print(f"Workspace {workspace_dst!r} created successfully.")
843-
except Exception as exc:
837+
try:
838+
import requests
839+
840+
url = f"{self.api.server_url}/api/rest/v2/write/workspace/new"
841+
response = requests.post(
842+
url,
843+
json={"name": workspace_dst},
844+
headers={
845+
"Authorization": self.api.api_key,
846+
"Content-Type": "application/json",
847+
},
848+
)
849+
response.raise_for_status()
850+
print(f"Workspace {workspace_dst!r} created successfully.")
851+
except Exception as exc:
852+
raise Exception(
853+
f"Workspace {workspace_dst!r} does not exist and could not be "
854+
f"created automatically: {exc}. "
855+
f"Please create it via the Comet UI and try again."
856+
)
857+
else:
844858
raise Exception(
845-
f"Workspace {workspace_dst!r} does not exist and could not be "
846-
f"created automatically: {exc}. "
847-
f"Please create it via the Comet UI or with an admin API Key and try again."
859+
f"{workspace_dst} does not exist; use --create-workspaces to "
860+
f"create it automatically, or create it via the Comet UI"
848861
)
849862

850863
if project_src == "panels":

0 commit comments

Comments
 (0)