diff --git a/docs/user-guide/assets/export-complete.png b/docs/user-guide/assets/export-complete.png new file mode 100644 index 0000000..24a33f0 Binary files /dev/null and b/docs/user-guide/assets/export-complete.png differ diff --git a/docs/user-guide/assets/import-complete.png b/docs/user-guide/assets/import-complete.png new file mode 100644 index 0000000..adbec57 Binary files /dev/null and b/docs/user-guide/assets/import-complete.png differ diff --git a/docs/user-guide/assets/import-copy-ls.png b/docs/user-guide/assets/import-copy-ls.png new file mode 100644 index 0000000..59ce6ea Binary files /dev/null and b/docs/user-guide/assets/import-copy-ls.png differ diff --git a/docs/user-guide/sharing.md b/docs/user-guide/sharing.md new file mode 100644 index 0000000..84f924a --- /dev/null +++ b/docs/user-guide/sharing.md @@ -0,0 +1,65 @@ +# Sharing Environment + +OGC provides a way to share an environment with another user, they are facilitated through the `ogc export-env` and `ogc import-env` commands. +This document will walk through how to accomplish this plus any caveats to be aware of. + +## Exporting + +First, we need to export the current environment. This will dump the database of node information, +the environment variables used in the deployment, and will include the public ssh key of the shared user on all nodes. + +The person you are sharing with should provide you with a passwordless public ssh key. This can either be the +contents of the public ssh key or a GitHub username that has public ssh keys associated with their profile. + +``` sh +$ ogc export-env + +How would you like to import the users public ssh key [github/manual] (github): +Please enter your Github username: adam-stokes +``` + +Once the export is complete it will print out the results including some instructions on what to do next + +![Export Complete](./assets/export-complete.png) + +## Importing + +Once the user has both the database `ogc-dump.sql` and the environment `ogc-env.json` they will need to import that on their machine. + +!!! caution + If the user already has `ogc` installed and a deployment created, they may want to keep that information intact. To avoid overwriting + the users database during import make sure to prefix the command with `POSTGRES_DB`: + + ``` sh + $ POSTGRES_DB="ogcopydb" ogc import-env + ``` + + Also, the import command will automatically write to files `ogc.yml` and `.env`. If those files already exist in the directory where the import command is run + then you will want to do one of two things: + + * Create a backup of those files + * Run `ogc import-env` from a different directory, perhaps creating a temporary directory for working with the shared environment. + +To do the import run the following: + +``` sh +$ POSTGRES_DB="ogcopydb" ogc import-env --env-file ../ogc-env.json \ + --db-file ../ogc-dump.sql \ + --private-ssh-key ~/.ssh/id_rsa \ + --public-ssh-key ~/.ssh/id_rsa.pub +``` + +The `private-ssh-key` and `public-ssh-key` should be the locations of the keys associated with the one shared during export. + +![Import complete](./assets/import-complete.png) + +Once import is complete, you can access this environment: + +``` sh +$ POSTGRES_DB="ogccopydb" ogc ls +``` + +![Import copy](./assets/import-copy-ls.png) + +!!! Warning + The cloud credentials are not copied over, you will need to setup your credentials again in the newly created `.env`. You will need to make sure that the correct project/region is set and accessible by your cloud account. \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index fc22356..76e7f3d 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -66,6 +66,7 @@ nav: - 'Scripting': 'user-guide/scripting.md' - 'Providers': 'user-guide/providers.md' - 'Upgrading': 'user-guide/upgrading.md' + - 'Sharing': 'user-guide/sharing.md' - 'Cookbook': - 'Access node info': 'user-guide/cookbook/template-access-node-info.md' - 'Developer Guide': diff --git a/ogc/actions.py b/ogc/actions.py index a13fe8c..d564cbd 100644 --- a/ogc/actions.py +++ b/ogc/actions.py @@ -397,7 +397,7 @@ def exec_async(name: str, tag: str, cmd: str) -> list[bool]: rows = session.query(db.Node).all() count = len(rows) - log.info(f"Executing '{cmd}' across [green]{count}[/] nodes.") + log.info(f"Executing '{cmd}' across {count} nodes.") with ProcessPoolExecutor(max_workers=MAX_WORKERS) as executor: func = partial(exec, cmd=cmd) results = executor.map( diff --git a/ogc/commands/share.py b/ogc/commands/share.py index 3dfe47b..2428194 100644 --- a/ogc/commands/share.py +++ b/ogc/commands/share.py @@ -10,7 +10,7 @@ from rich.padding import Padding from rich.prompt import Prompt -from ogc import actions, db, state +from ogc import actions, db, enums, state from ogc.log import Logger as log from ogc.spec import SpecLoader @@ -40,12 +40,7 @@ default="ogc-env.json", help="Filename of where to store the OGC environment to be shared", ) -@click.option( - "--public-ssh-key", - required=False, - help="The public ssh key contents from the shared user", -) -def export_env(spec, db_file, env_file, public_ssh_key): +def export_env(spec, db_file, env_file): """Exports the deployment to be shared with other users This exports the current database and imports the public ssh key of the @@ -59,13 +54,31 @@ def export_env(spec, db_file, env_file, public_ssh_key): sys.exit(1) # begin setup - if not public_ssh_key: + ssh_key_type = Prompt.ask( + "How would you like to import the users public ssh key", + choices=["github", "manual"], + default="github", + ) + + cmd = None + if ssh_key_type.lower() == "manual": public_ssh_key = Prompt.ask( "Paste the public ssh key of the user you are sharing with" ) + cmd = f"echo '{public_ssh_key}' >> ~/.ssh/authorized_keys" + elif ssh_key_type.lower() == "github": + public_ssh_key = Prompt.ask("Please enter your Github username") + cmd = ( + f"wget -O get-pip.py https://bootstrap.pypa.io/get-pip.py && " + "sudo python3 get-pip.py && " + "sudo pip install ssh-import-id && " + f"ssh-import-id gh:{public_ssh_key}" + ) + else: + log.error("Could not import a public ssh key") + sys.exit(1) log.info("Importing public key to all nodes") - cmd = f"echo '{public_ssh_key}' >> ~/.ssh/authorized_keys" results = actions.exec_async(None, None, cmd) passed = all(result == True for result in results) if passed: @@ -75,7 +88,6 @@ def export_env(spec, db_file, env_file, public_ssh_key): log.info("Exporting database") sh.pg_dump( - "-Fc", "-h", db.DB_HOST, "-p", @@ -88,7 +100,14 @@ def export_env(spec, db_file, env_file, public_ssh_key): ) specs = SpecLoader.load(list(spec)) - ogc_env_out = {"env": {**dotenv_values(".env")}, "spec": {**specs.as_dict()}} + ogc_env_out = { + "env": { + k: v + for k, v in dotenv_values(".env").items() + if not any(k.startswith(s) for s in enums.SUPPORTED_PROVIDERS) + }, + "spec": {**specs.as_dict()}, + } Path(env_file).write_text(json.dumps(ogc_env_out)) console = Console() @@ -180,12 +199,12 @@ def import_env(db_file, env_file, private_ssh_key, public_ssh_key): env_file_out = Path(".env") with open(env_file_out, "w") as env_f: for k, v in env_data["env"].items(): - env_f.write(f"{k.upper()}={v}") + env_f.write(f"{k.upper()}={v}\n") spec_file_out = Path("ogc.yml") with open(spec_file_out, "w") as spec_f: - spec_f.write(yaml.dumps(env_data["spec"])) + spec_f.write(yaml.dump(env_data["spec"])) private_ssh_key = Path(private_ssh_key) public_ssh_key = Path(public_ssh_key) diff --git a/ogc/enums.py b/ogc/enums.py index 3fb21b3..af163c7 100644 --- a/ogc/enums.py +++ b/ogc/enums.py @@ -4,6 +4,8 @@ PID_FILE = "ogc-server.pid" LOCAL_ARTIFACT_PATH = "artifacts" +SUPPORTED_PROVIDERS = ["AWS", "GOOGLE"] + class SpecCore: NAME = "name" diff --git a/ogc/spec.py b/ogc/spec.py index 154626a..435f594 100644 --- a/ogc/spec.py +++ b/ogc/spec.py @@ -198,7 +198,7 @@ def __repr__(self): def as_dict(self): return { "name": self.name, - "layouts": [layout.as_dict() for layout in self.layouts], + "layouts": {layout.name: layout.as_dict() for layout in self.layouts}, } def _sighandler(self, sig, frame):