dayhoff-tools 1.0.8__py3-none-any.whl → 1.0.9__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- dayhoff_tools/cli/cloud_commands.py +489 -118
- {dayhoff_tools-1.0.8.dist-info → dayhoff_tools-1.0.9.dist-info}/METADATA +1 -1
- {dayhoff_tools-1.0.8.dist-info → dayhoff_tools-1.0.9.dist-info}/RECORD +5 -5
- {dayhoff_tools-1.0.8.dist-info → dayhoff_tools-1.0.9.dist-info}/WHEEL +0 -0
- {dayhoff_tools-1.0.8.dist-info → dayhoff_tools-1.0.9.dist-info}/entry_points.txt +0 -0
@@ -2,14 +2,19 @@
|
|
2
2
|
|
3
3
|
This module provides commands for authenticating with GCP and AWS from within
|
4
4
|
development containers. It handles both immediate shell environment configuration
|
5
|
-
via the --export flag and persistent configuration via
|
5
|
+
via the --export flag (deprecated for GCP) and persistent configuration via
|
6
|
+
shell RC files (AWS only) or gcloud config settings (GCP).
|
6
7
|
|
7
8
|
The implementation focuses on:
|
8
9
|
1. Unifying cloud authentication with the `dh` CLI tool
|
9
|
-
2. Maintaining persistence across shell sessions via RC file modifications
|
10
|
+
2. Maintaining persistence across shell sessions via RC file modifications (AWS)
|
11
|
+
or gcloud config (GCP).
|
10
12
|
3. Providing similar capabilities to the shell scripts it replaces
|
13
|
+
4. For GCP, leveraging `gcloud config` and Application Default Credentials (ADC)
|
14
|
+
updates for a streamlined, keyless, no-`eval` workflow.
|
11
15
|
"""
|
12
16
|
|
17
|
+
import json
|
13
18
|
import os
|
14
19
|
import re
|
15
20
|
import shutil
|
@@ -128,6 +133,129 @@ def _get_env_var(variable: str) -> Optional[str]:
|
|
128
133
|
|
129
134
|
|
130
135
|
# --- GCP Functions ---
|
136
|
+
|
137
|
+
# New approach: Use gcloud config settings instead of environment variables
|
138
|
+
# for impersonation and project settings. This avoids modifying RC files
|
139
|
+
# and the need for `eval "$(dh gcp use-... --export)"`.
|
140
|
+
# ADC is updated during the initial `dh gcp login` for the user.
|
141
|
+
# Subsequent ADC updates for impersonation or user mode must be done manually
|
142
|
+
# if required by libraries, as the underlying gcloud commands can force interaction.
|
143
|
+
|
144
|
+
|
145
|
+
def _get_short_name(account: str) -> str:
|
146
|
+
"""Extracts a short name ('dma', 'devcon') from a GCP account email.
|
147
|
+
|
148
|
+
Args:
|
149
|
+
account: The full account string (e.g., 'dma@dayhofflabs.com',
|
150
|
+
'devcon@...', 'None', 'Not authenticated').
|
151
|
+
|
152
|
+
Returns:
|
153
|
+
The short name or the original string if not a recognized email pattern.
|
154
|
+
"""
|
155
|
+
if account == GCP_DEVCON_SA:
|
156
|
+
return "devcon"
|
157
|
+
if "@" in account:
|
158
|
+
# Attempt to get the part before @, common for user accounts
|
159
|
+
user_part = account.split("@")[0]
|
160
|
+
# You might want more specific logic here if user formats vary
|
161
|
+
# For now, assume simple user name like 'dma'
|
162
|
+
return user_part
|
163
|
+
# Handle special strings like 'None', 'Not authenticated', etc.
|
164
|
+
return account
|
165
|
+
|
166
|
+
|
167
|
+
def _gcloud_set_config(key: str, value: str) -> Tuple[int, str, str]:
|
168
|
+
"""Set a gcloud configuration value using `gcloud config set`.
|
169
|
+
|
170
|
+
Args:
|
171
|
+
key: The configuration key (e.g., 'project', 'auth/impersonate_service_account').
|
172
|
+
value: The value to set for the key.
|
173
|
+
|
174
|
+
Returns:
|
175
|
+
Tuple of (return_code, stdout_str, stderr_str) from _run_command.
|
176
|
+
"""
|
177
|
+
gcloud_path = _find_executable("gcloud")
|
178
|
+
cmd = [gcloud_path, "config", "set", key, value, "--quiet"]
|
179
|
+
return _run_command(cmd, capture=True, check=False, suppress_output=True)
|
180
|
+
|
181
|
+
|
182
|
+
def _gcloud_unset_config(key: str) -> Tuple[int, str, str]:
|
183
|
+
"""Unset a gcloud configuration value using `gcloud config unset`.
|
184
|
+
|
185
|
+
Args:
|
186
|
+
key: The configuration key to unset.
|
187
|
+
|
188
|
+
Returns:
|
189
|
+
Tuple of (return_code, stdout_str, stderr_str) from _run_command.
|
190
|
+
"""
|
191
|
+
gcloud_path = _find_executable("gcloud")
|
192
|
+
cmd = [gcloud_path, "config", "unset", key, "--quiet"]
|
193
|
+
return _run_command(cmd, capture=True, check=False, suppress_output=True)
|
194
|
+
|
195
|
+
|
196
|
+
def _get_adc_status() -> str:
|
197
|
+
"""Check the status and type of Application Default Credentials (ADC).
|
198
|
+
|
199
|
+
Attempts to determine the effective credential source, including the
|
200
|
+
default GCE metadata server fallback if no explicit config is found.
|
201
|
+
|
202
|
+
Returns:
|
203
|
+
A short string describing the ADC principal ('dma', 'devcon',
|
204
|
+
'default VM service account', 'Other/External', 'Not configured', etc.).
|
205
|
+
"""
|
206
|
+
adc_file = (
|
207
|
+
Path.home() / ".config" / "gcloud" / "application_default_credentials.json"
|
208
|
+
)
|
209
|
+
|
210
|
+
# Check environment variable first (highest precedence after explicit file)
|
211
|
+
if _get_env_var("GOOGLE_APPLICATION_CREDENTIALS"):
|
212
|
+
# We don't know *what* key it points to without reading/parsing it.
|
213
|
+
return "Keyfile (GOOGLE_APPLICATION_CREDENTIALS)"
|
214
|
+
|
215
|
+
# Check explicit ADC JSON file
|
216
|
+
if adc_file.is_file():
|
217
|
+
try:
|
218
|
+
with open(adc_file, "r") as f:
|
219
|
+
adc_data = json.load(f)
|
220
|
+
cred_type = adc_data.get("type")
|
221
|
+
|
222
|
+
if cred_type == "authorized_user":
|
223
|
+
return "dma" # Assuming 'dma' is the likely user
|
224
|
+
elif cred_type == "impersonated_service_account":
|
225
|
+
sa_url = adc_data.get("service_account_impersonation_url", "")
|
226
|
+
sa_match = re.search(r"serviceAccounts/([^:]+)", sa_url)
|
227
|
+
if sa_match and sa_match.group(1) == GCP_DEVCON_SA:
|
228
|
+
return "devcon"
|
229
|
+
elif sa_match:
|
230
|
+
return f"Other SA ({_get_short_name(sa_match.group(1))})"
|
231
|
+
else:
|
232
|
+
return "devcon (?)" # Likely devcon but failed parse
|
233
|
+
elif cred_type == "external_account":
|
234
|
+
return "Other/External"
|
235
|
+
elif cred_type == "service_account":
|
236
|
+
# This type in the file usually means it was created pointing
|
237
|
+
# to a specific key file, but not via the env var.
|
238
|
+
# Hard to know details without parsing more.
|
239
|
+
return "Keyfile (from ADC json)"
|
240
|
+
else:
|
241
|
+
return f"Unknown ({cred_type})"
|
242
|
+
|
243
|
+
except json.JSONDecodeError:
|
244
|
+
return "Invalid format"
|
245
|
+
except (IOError, PermissionError, Exception) as e:
|
246
|
+
print(f"Warning: Could not read ADC file {adc_file}: {e}", file=sys.stderr)
|
247
|
+
return "Error reading"
|
248
|
+
|
249
|
+
# If no env var and no JSON file, check for GCE default SA fallback
|
250
|
+
# We infer this by checking the *CLI*'s current user status
|
251
|
+
cli_user = _get_current_gcp_user() # Reuse existing helper
|
252
|
+
if cli_user == "default VM service account":
|
253
|
+
return "default VM service account" # ADC likely uses this via metadata
|
254
|
+
|
255
|
+
# If none of the above, ADC is likely unconfigured for this environment
|
256
|
+
return "Not configured"
|
257
|
+
|
258
|
+
|
131
259
|
def _is_gcp_user_authenticated() -> bool:
|
132
260
|
"""Check if the current gcloud user authentication is valid and non-interactive.
|
133
261
|
|
@@ -151,7 +279,7 @@ def _is_gcp_user_authenticated() -> bool:
|
|
151
279
|
|
152
280
|
|
153
281
|
def _get_current_gcp_user() -> str:
|
154
|
-
"""Get the currently authenticated GCP user."""
|
282
|
+
"""Get the currently authenticated GCP user or indicate default VM SA."""
|
155
283
|
gcloud_path = _find_executable("gcloud")
|
156
284
|
cmd = [
|
157
285
|
gcloud_path,
|
@@ -165,74 +293,134 @@ def _get_current_gcp_user() -> str:
|
|
165
293
|
account = stdout.strip()
|
166
294
|
if account:
|
167
295
|
if "compute@developer.gserviceaccount.com" in account:
|
168
|
-
|
296
|
+
# Return a more user-friendly string for the default VM SA case
|
297
|
+
return "default VM service account"
|
169
298
|
return account
|
170
299
|
return "Not authenticated"
|
171
300
|
|
172
301
|
|
173
302
|
def _get_current_gcp_impersonation() -> str:
|
174
|
-
"""Get the current impersonated service account
|
175
|
-
|
303
|
+
"""Get the current impersonated service account from gcloud config."""
|
304
|
+
gcloud_path = _find_executable("gcloud")
|
305
|
+
cmd = [
|
306
|
+
gcloud_path,
|
307
|
+
"config",
|
308
|
+
"get-value",
|
309
|
+
"auth/impersonate_service_account",
|
310
|
+
"--quiet",
|
311
|
+
]
|
312
|
+
returncode, stdout, _ = _run_command(cmd, capture=True, check=False)
|
313
|
+
sa = stdout.strip() if returncode == 0 else ""
|
176
314
|
return sa if sa else "None"
|
177
315
|
|
178
316
|
|
179
317
|
def _run_gcloud_login() -> None:
|
180
|
-
"""Run the gcloud auth login command.
|
318
|
+
"""Run the gcloud auth login command, updating ADC using device flow.
|
319
|
+
|
320
|
+
Always uses --update-adc to ensure libraries using ADC work immediately for the user.
|
321
|
+
Uses --no-launch-browser for headless environments.
|
322
|
+
"""
|
181
323
|
gcloud_path = _find_executable("gcloud")
|
182
|
-
print(f"{BLUE}Authenticating with Google Cloud...{NC}")
|
183
|
-
|
184
|
-
|
324
|
+
print(f"{BLUE}Authenticating with Google Cloud (will update ADC)...{NC}")
|
325
|
+
|
326
|
+
# Directly use device flow as remote browser consistently failed
|
327
|
+
cmd = [gcloud_path, "auth", "login", "--update-adc", "--no-launch-browser"]
|
328
|
+
|
329
|
+
print(f"{YELLOW}Initiating device flow login... Follow the instructions below.{NC}")
|
330
|
+
# Remove capture=True, rely on direct output and return code
|
331
|
+
returncode, _, _ = _run_command(
|
332
|
+
cmd,
|
333
|
+
capture=False, # Changed from True
|
334
|
+
check=False,
|
335
|
+
suppress_output=False,
|
336
|
+
)
|
337
|
+
|
338
|
+
if returncode != 0:
|
339
|
+
# stderr is not captured, provide a generic error
|
340
|
+
print(
|
341
|
+
f"{RED}Login command failed (return code: {returncode}). Please check gcloud output above.{NC}",
|
342
|
+
file=sys.stderr,
|
343
|
+
)
|
344
|
+
sys.exit(1)
|
345
|
+
|
346
|
+
print(f"{GREEN}User authentication complete. ADC updated for user account.{NC}")
|
185
347
|
|
186
348
|
|
187
349
|
def _test_gcp_credentials(user: str, impersonation_sa: str) -> None:
|
188
|
-
"""Test GCP credentials
|
350
|
+
"""Test GCP credentials. Only prints output on failure (to stderr)."""
|
189
351
|
gcloud_path = _find_executable("gcloud")
|
190
|
-
|
191
|
-
|
352
|
+
user_short = _get_short_name(user)
|
353
|
+
impersonation_short = _get_short_name(impersonation_sa)
|
192
354
|
|
193
355
|
if user != "Not authenticated" and "Not authenticated" not in user:
|
356
|
+
cmd = [
|
357
|
+
gcloud_path,
|
358
|
+
"compute",
|
359
|
+
"zones",
|
360
|
+
"list",
|
361
|
+
"--limit=1",
|
362
|
+
f"--project={GCP_PROJECT_ID}",
|
363
|
+
]
|
364
|
+
|
194
365
|
if impersonation_sa != "None":
|
195
|
-
|
196
|
-
|
197
|
-
"
|
366
|
+
orig_sa = impersonation_sa
|
367
|
+
unset_rc, _, unset_err = _gcloud_unset_config(
|
368
|
+
"auth/impersonate_service_account"
|
198
369
|
)
|
199
|
-
if
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
if returncode == 0:
|
207
|
-
print(f"{GREEN}✓ User has direct GCP access{NC}")
|
208
|
-
else:
|
209
|
-
print(f"{YELLOW}✗ User lacks direct GCP access{NC}")
|
370
|
+
if unset_rc != 0:
|
371
|
+
# Failure to unset is an error state
|
372
|
+
print(
|
373
|
+
f"{RED}✗ Test Error: Failed to temporarily disable impersonation: {unset_err}{NC}",
|
374
|
+
file=sys.stderr,
|
375
|
+
)
|
210
376
|
|
211
|
-
|
212
|
-
if
|
213
|
-
|
214
|
-
|
377
|
+
user_returncode, _, _ = _run_command(cmd, suppress_output=True, check=False)
|
378
|
+
if user_returncode != 0:
|
379
|
+
# Failure to access as user
|
380
|
+
print(
|
381
|
+
f"{RED}✗ Test Failure: Cannot access resources directly as user '{user_short}'. Check roles/project.{NC}",
|
382
|
+
file=sys.stderr,
|
215
383
|
)
|
216
384
|
|
217
|
-
|
218
|
-
|
385
|
+
set_rc, _, set_err = _gcloud_set_config(
|
386
|
+
"auth/impersonate_service_account", orig_sa
|
387
|
+
)
|
388
|
+
if set_rc != 0:
|
389
|
+
# Failure to restore is an error state
|
390
|
+
print(
|
391
|
+
f"{RED}✗ Test Error: Failed to restore impersonation config for {impersonation_short}: {set_err}{NC}",
|
392
|
+
file=sys.stderr,
|
393
|
+
)
|
219
394
|
|
220
|
-
|
221
|
-
|
222
|
-
|
395
|
+
impersonation_returncode, _, _ = _run_command(
|
396
|
+
cmd, suppress_output=True, check=False
|
397
|
+
)
|
398
|
+
if impersonation_returncode != 0:
|
399
|
+
# Failure to access while impersonating
|
223
400
|
print(
|
224
|
-
f"{RED}
|
401
|
+
f"{RED}✗ Test Failure: Cannot access resources impersonating '{impersonation_short}'. Check permissions/config.{NC}",
|
402
|
+
file=sys.stderr,
|
225
403
|
)
|
404
|
+
|
226
405
|
else:
|
227
|
-
# Test user account directly (no impersonation)
|
228
|
-
print(f"Using user account {user} (no impersonation):")
|
229
|
-
cmd = [gcloud_path, "compute", "zones", "list", "--limit=1"]
|
406
|
+
# Test user account directly (no impersonation config)
|
230
407
|
returncode, _, _ = _run_command(cmd, suppress_output=True, check=False)
|
231
|
-
|
232
|
-
|
233
|
-
print(
|
234
|
-
|
235
|
-
|
408
|
+
if returncode != 0:
|
409
|
+
# Failure to access as user
|
410
|
+
print(
|
411
|
+
f"{RED}✗ Test Failure: Cannot access resources directly as user '{user_short}'. Check roles/project.{NC}",
|
412
|
+
file=sys.stderr,
|
413
|
+
)
|
414
|
+
# Success: No output
|
415
|
+
# else:
|
416
|
+
# print(f"{GREEN}✓ Direct access as user {user_short}: OK{NC}")
|
417
|
+
# Correctly indented pass statement if no action needed on success
|
418
|
+
pass
|
419
|
+
else:
|
420
|
+
# If user isn't authenticated at all, maybe print a warning?
|
421
|
+
# print(f"{YELLOW}User not authenticated, skipping credential test.{NC}")
|
422
|
+
# Decided against this to keep output minimal unless actual test fails.
|
423
|
+
pass # Explicit pass for the outer else
|
236
424
|
|
237
425
|
|
238
426
|
# --- AWS Functions ---
|
@@ -319,160 +507,343 @@ def _get_available_aws_profiles() -> List[str]:
|
|
319
507
|
|
320
508
|
|
321
509
|
# --- Typer Applications ---
|
322
|
-
gcp_app = typer.Typer(
|
323
|
-
|
510
|
+
gcp_app = typer.Typer(
|
511
|
+
help="Manage GCP authentication using gcloud config and ADC. (RC file/env var methods are deprecated)."
|
512
|
+
)
|
513
|
+
aws_app = typer.Typer(help="Manage AWS SSO authentication using RC files.")
|
324
514
|
|
325
515
|
|
326
516
|
# --- GCP Commands ---
|
327
517
|
@gcp_app.command("status")
|
328
518
|
def gcp_status():
|
329
|
-
"""Show
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
519
|
+
"""Show active GCP credentials for CLI and Libraries/ADC."""
|
520
|
+
cli_user = _get_current_gcp_user()
|
521
|
+
cli_impersonation = _get_current_gcp_impersonation()
|
522
|
+
adc_principal = _get_adc_status()
|
523
|
+
|
524
|
+
# Determine active principal for CLI
|
525
|
+
if cli_impersonation != "None":
|
526
|
+
cli_active_short = _get_short_name(cli_impersonation)
|
527
|
+
else:
|
528
|
+
cli_active_short = _get_short_name(cli_user)
|
529
|
+
|
530
|
+
# Get short name for ADC principal
|
531
|
+
adc_active_short = _get_short_name(adc_principal)
|
532
|
+
|
533
|
+
# Define a fixed width for the principal name field
|
534
|
+
name_width = 10
|
535
|
+
|
536
|
+
print(
|
537
|
+
f"Using {GREEN}{cli_active_short:<{name_width}}{NC} for {BLUE}gcloud CLI{NC} (gcloud, gsutil)"
|
538
|
+
)
|
337
539
|
print(
|
338
|
-
f"
|
540
|
+
f"Using {GREEN}{adc_active_short:<{name_width}}{NC} for {BLUE}Libraries/Tools{NC} (warehouse, Terraform, Python clients)\n"
|
339
541
|
)
|
340
542
|
|
341
|
-
|
543
|
+
# Run tests silently, they will print to stderr only on failure
|
544
|
+
_test_gcp_credentials(cli_user, cli_impersonation)
|
342
545
|
|
343
546
|
|
344
547
|
@gcp_app.command("login")
|
345
548
|
def gcp_login():
|
346
|
-
"""Authenticate
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
print(f
|
549
|
+
"""Authenticate user & configure CLI to impersonate devcon SA."""
|
550
|
+
# Step 1: Authenticate the user (updates ADC for user)
|
551
|
+
_run_gcloud_login() # Uses device flow
|
552
|
+
|
553
|
+
# Step 2: Configure gcloud CLI for devcon SA impersonation
|
554
|
+
print(f"\n{BLUE}Configuring gcloud CLI to impersonate {GCP_DEVCON_SA}...{NC}")
|
555
|
+
set_sa_rc, _, set_sa_err = _gcloud_set_config(
|
556
|
+
"auth/impersonate_service_account", GCP_DEVCON_SA
|
557
|
+
)
|
558
|
+
if set_sa_rc != 0:
|
559
|
+
print(
|
560
|
+
f"{RED}Error setting impersonation config: {set_sa_err}{NC}",
|
561
|
+
file=sys.stderr,
|
562
|
+
)
|
563
|
+
print(f"{YELLOW}Warning: CLI impersonation failed to configure.{NC}")
|
564
|
+
# Attempt to show status anyway before exiting command
|
565
|
+
print("\n{BLUE}Current status:{NC}")
|
566
|
+
gcp_status()
|
567
|
+
return
|
568
|
+
|
569
|
+
set_proj_rc, _, set_proj_err = _gcloud_set_config("project", GCP_PROJECT_ID)
|
570
|
+
if set_proj_rc != 0:
|
571
|
+
print(f"{RED}Error setting project config: {set_proj_err}{NC}", file=sys.stderr)
|
572
|
+
# Continue, but warn user
|
573
|
+
|
574
|
+
# Step 3: Print configuration options
|
575
|
+
print(f"\n{GREEN}Login successful. CLI configured for devcon impersonation.{NC}")
|
576
|
+
print(f"{BLUE}--- Common Configuration Commands ---\n{NC}")
|
577
|
+
|
578
|
+
cmd_width = 25 # Adjusted width for dh commands
|
579
|
+
|
580
|
+
print(f" {BLUE}Set CLI to use User:{NC}")
|
581
|
+
print(f" {YELLOW}{f'dh gcp use-user':<{cmd_width}}{NC}")
|
582
|
+
|
583
|
+
print(f" {BLUE}Set CLI to use Devcon SA:{NC}")
|
584
|
+
print(
|
585
|
+
f" {YELLOW}{f'dh gcp use-devcon':<{cmd_width}}{NC} {GREEN}(Current default after login){NC}"
|
586
|
+
)
|
587
|
+
|
588
|
+
print(f" {BLUE}Set Libraries/Tools (ADC) to use User:{NC}")
|
589
|
+
print(f" {YELLOW}{f'dh gcp use-user-adc':<{cmd_width}}{NC}")
|
590
|
+
|
591
|
+
print(f" {BLUE}Set Libraries/Tools (ADC) to use Devcon SA:{NC}")
|
592
|
+
print(f" {YELLOW}{f'dh gcp use-devcon-adc':<{cmd_width}}{NC}")
|
593
|
+
|
594
|
+
# Step 4: Show current status automatically
|
595
|
+
print(f"\n{BLUE}--- Current Status ---{NC}")
|
596
|
+
gcp_status()
|
352
597
|
|
353
598
|
|
354
599
|
@gcp_app.command("use-devcon")
|
355
600
|
def gcp_use_devcon(
|
356
601
|
export: bool = typer.Option(
|
357
|
-
False,
|
602
|
+
False,
|
603
|
+
"--export",
|
604
|
+
"-x",
|
605
|
+
help="Deprecated. Has no effect. Settings are applied directly via gcloud config.",
|
606
|
+
hidden=True,
|
358
607
|
),
|
359
608
|
):
|
360
|
-
"""Configure gcloud CLI to impersonate the devcon SA
|
609
|
+
"""Configure gcloud CLI to impersonate the devcon SA.
|
361
610
|
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
if you need libraries (like DVC) to use these credentials.
|
611
|
+
This command updates gcloud configuration settings directly.
|
612
|
+
It DOES NOT modify shell RC files or require `eval`.
|
613
|
+
It DOES NOT automatically update Application Default Credentials (ADC) for impersonation.
|
366
614
|
|
367
|
-
Ensures the primary user login is valid first
|
615
|
+
Ensures the primary user login is valid first.
|
368
616
|
"""
|
617
|
+
if export:
|
618
|
+
print(
|
619
|
+
f"{YELLOW}Warning: --export/-x is deprecated and has no effect. "
|
620
|
+
f"GCP settings are now managed via gcloud config.{NC}",
|
621
|
+
file=sys.stderr,
|
622
|
+
)
|
623
|
+
|
369
624
|
if not _is_gcp_user_authenticated():
|
370
625
|
print(
|
371
626
|
f"{RED}Error: GCP user authentication is invalid or requires interactive login.{NC}",
|
372
627
|
file=sys.stderr,
|
373
628
|
)
|
374
629
|
print(
|
375
|
-
f"{YELLOW}Please run '
|
630
|
+
f"{YELLOW}Please run 'dh gcp login' interactively first, then try this command again.{NC}",
|
376
631
|
file=sys.stderr,
|
377
632
|
)
|
378
633
|
sys.exit(1)
|
379
634
|
|
380
|
-
|
381
|
-
_modify_rc_files("CLOUDSDK_AUTH_IMPERSONATE_SERVICE_ACCOUNT", f"'{GCP_DEVCON_SA}'")
|
382
|
-
_modify_rc_files("GOOGLE_CLOUD_PROJECT", f"'{GCP_PROJECT_ID}'")
|
383
|
-
|
384
|
-
if export:
|
385
|
-
# Print export commands for the current shell (for gcloud CLI)
|
386
|
-
print(f"export CLOUDSDK_AUTH_IMPERSONATE_SERVICE_ACCOUNT='{GCP_DEVCON_SA}'")
|
387
|
-
print(f"export GOOGLE_CLOUD_PROJECT='{GCP_PROJECT_ID}'")
|
635
|
+
print(f"{BLUE}Configuring gcloud CLI to impersonate {GCP_DEVCON_SA}...{NC}")
|
388
636
|
|
389
|
-
|
637
|
+
# Set gcloud CLI impersonation via config
|
638
|
+
set_sa_rc, _, set_sa_err = _gcloud_set_config(
|
639
|
+
"auth/impersonate_service_account", GCP_DEVCON_SA
|
640
|
+
)
|
641
|
+
if set_sa_rc != 0:
|
390
642
|
print(
|
391
|
-
f"{
|
643
|
+
f"{RED}Error setting impersonation config: {set_sa_err}{NC}",
|
392
644
|
file=sys.stderr,
|
393
645
|
)
|
646
|
+
sys.exit(1)
|
647
|
+
|
648
|
+
set_proj_rc, _, set_proj_err = _gcloud_set_config("project", GCP_PROJECT_ID)
|
649
|
+
if set_proj_rc != 0:
|
650
|
+
print(f"{RED}Error setting project config: {set_proj_err}{NC}", file=sys.stderr)
|
651
|
+
# Continue, but warn user
|
652
|
+
|
653
|
+
# Check for lingering legacy environment variable
|
654
|
+
if _get_env_var("CLOUDSDK_AUTH_IMPERSONATE_SERVICE_ACCOUNT"):
|
394
655
|
print(
|
395
|
-
f"{YELLOW}
|
656
|
+
f"{YELLOW}Warning: Legacy env var CLOUDSDK_AUTH_IMPERSONATE_SERVICE_ACCOUNT is set.{NC}",
|
396
657
|
file=sys.stderr,
|
397
658
|
)
|
398
659
|
print(
|
399
|
-
f"{YELLOW}
|
660
|
+
f"{YELLOW} This may override gcloud config. Consider running:{NC}",
|
400
661
|
file=sys.stderr,
|
401
662
|
)
|
402
|
-
else:
|
403
|
-
# Print confirmation
|
404
|
-
print(
|
405
|
-
f"{GREEN}RC files updated to use devcon SA for future gcloud CLI sessions.{NC}"
|
406
|
-
)
|
407
|
-
print(f"To apply gcloud CLI settings in current shell, run:")
|
408
|
-
print(f' {YELLOW}eval "$(dh gcp use-devcon --export)"{NC}')
|
409
|
-
print(
|
410
|
-
f"{YELLOW}NOTE: ADC file not updated. To update ADC for libraries, run:{NC}"
|
411
|
-
)
|
412
663
|
print(
|
413
|
-
f"{YELLOW}
|
664
|
+
f"{YELLOW} unset CLOUDSDK_AUTH_IMPERSONATE_SERVICE_ACCOUNT{NC}",
|
665
|
+
file=sys.stderr,
|
414
666
|
)
|
415
667
|
|
668
|
+
print(f"\n{GREEN}GCP CLI configured to use devcon SA ({GCP_DEVCON_SA}).{NC}")
|
669
|
+
print(f"Project set to: {GCP_PROJECT_ID}")
|
670
|
+
print(
|
671
|
+
f"{YELLOW}NOTE: If libraries/tools (e.g., for DVC, Terraform) need to use impersonation, update Application Default Credentials (ADC) manually:{NC}"
|
672
|
+
)
|
673
|
+
print(
|
674
|
+
f"{YELLOW} gcloud auth application-default login --impersonate-service-account={GCP_DEVCON_SA}{NC}"
|
675
|
+
)
|
676
|
+
print(f"Run 'dh gcp status' to verify CLI configuration.")
|
677
|
+
|
416
678
|
|
417
679
|
@gcp_app.command("use-user")
|
418
680
|
def gcp_use_user(
|
419
681
|
export: bool = typer.Option(
|
420
|
-
False,
|
682
|
+
False,
|
683
|
+
"--export",
|
684
|
+
"-x",
|
685
|
+
help="Deprecated. Has no effect. Settings are applied directly via gcloud config.",
|
686
|
+
hidden=True,
|
421
687
|
),
|
422
688
|
):
|
423
|
-
"""Configure gcloud CLI to use the personal user account
|
689
|
+
"""Configure gcloud CLI to use the personal user account via gcloud config.
|
424
690
|
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
if you need libraries (like DVC) to use your personal credentials.
|
691
|
+
This command updates gcloud configuration settings directly.
|
692
|
+
It DOES NOT modify shell RC files or require `eval`.
|
693
|
+
It DOES NOT automatically update Application Default Credentials (ADC).
|
429
694
|
|
430
695
|
Ensures the primary user login is valid first.
|
431
696
|
"""
|
697
|
+
if export:
|
698
|
+
print(
|
699
|
+
f"{YELLOW}Warning: --export/-x is deprecated and has no effect. "
|
700
|
+
f"GCP settings are now managed via gcloud config.{NC}",
|
701
|
+
file=sys.stderr,
|
702
|
+
)
|
703
|
+
|
432
704
|
if not _is_gcp_user_authenticated():
|
433
705
|
print(
|
434
706
|
f"{RED}Error: GCP user authentication is invalid or requires interactive login.{NC}",
|
435
707
|
file=sys.stderr,
|
436
708
|
)
|
437
709
|
print(
|
438
|
-
f"{YELLOW}Please run '
|
710
|
+
f"{YELLOW}Please run 'dh gcp login' interactively first, then try this command again.{NC}",
|
439
711
|
file=sys.stderr,
|
440
712
|
)
|
441
713
|
sys.exit(1)
|
442
714
|
|
443
|
-
|
444
|
-
_modify_rc_files("CLOUDSDK_AUTH_IMPERSONATE_SERVICE_ACCOUNT", None)
|
445
|
-
_modify_rc_files("GOOGLE_CLOUD_PROJECT", f"'{GCP_PROJECT_ID}'")
|
715
|
+
print(f"{BLUE}Configuring gcloud CLI to use personal user account...{NC}")
|
446
716
|
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
717
|
+
# Unset gcloud CLI impersonation via config
|
718
|
+
unset_sa_rc, _, unset_sa_err = _gcloud_unset_config(
|
719
|
+
"auth/impersonate_service_account"
|
720
|
+
)
|
721
|
+
if unset_sa_rc != 0:
|
722
|
+
print(
|
723
|
+
f"{RED}Error unsetting impersonation config: {unset_sa_err}{NC}",
|
724
|
+
file=sys.stderr,
|
725
|
+
)
|
726
|
+
# Continue, but warn user
|
451
727
|
|
452
|
-
|
728
|
+
set_proj_rc, _, set_proj_err = _gcloud_set_config("project", GCP_PROJECT_ID)
|
729
|
+
if set_proj_rc != 0:
|
730
|
+
print(f"{RED}Error setting project config: {set_proj_err}{NC}", file=sys.stderr)
|
731
|
+
# Continue, but warn user
|
732
|
+
|
733
|
+
# Check for lingering legacy environment variable
|
734
|
+
if _get_env_var("CLOUDSDK_AUTH_IMPERSONATE_SERVICE_ACCOUNT"):
|
453
735
|
print(
|
454
|
-
f"{
|
736
|
+
f"{YELLOW}Warning: Legacy env var CLOUDSDK_AUTH_IMPERSONATE_SERVICE_ACCOUNT is set.{NC}",
|
455
737
|
file=sys.stderr,
|
456
738
|
)
|
457
739
|
print(
|
458
|
-
f"{YELLOW}
|
740
|
+
f"{YELLOW} This may interfere with using your personal account. Consider running:{NC}",
|
459
741
|
file=sys.stderr,
|
460
742
|
)
|
461
743
|
print(
|
462
|
-
f"{YELLOW}
|
744
|
+
f"{YELLOW} unset CLOUDSDK_AUTH_IMPERSONATE_SERVICE_ACCOUNT{NC}",
|
463
745
|
file=sys.stderr,
|
464
746
|
)
|
747
|
+
|
748
|
+
print(f"\n{GREEN}GCP CLI configured to use personal account.{NC}")
|
749
|
+
print(f"Project set to: {GCP_PROJECT_ID}")
|
750
|
+
print(
|
751
|
+
f"{YELLOW}NOTE: If libraries/tools (e.g., for DVC, Terraform) need to use impersonation, update Application Default Credentials (ADC) manually:{NC}"
|
752
|
+
)
|
753
|
+
print(f"{YELLOW} gcloud auth application-default login{NC}")
|
754
|
+
print(f"Run 'dh gcp status' to verify CLI configuration.")
|
755
|
+
|
756
|
+
|
757
|
+
# === NEW ADC Commands ===
|
758
|
+
|
759
|
+
|
760
|
+
@gcp_app.command("use-user-adc")
|
761
|
+
def gcp_use_user_adc():
|
762
|
+
"""Configure Libraries/Tools (ADC) to use your PERSONAL account."""
|
763
|
+
if not _is_gcp_user_authenticated():
|
764
|
+
print(
|
765
|
+
f"{RED}Error: GCP user authentication is invalid or requires interactive login.{NC}",
|
766
|
+
file=sys.stderr,
|
767
|
+
)
|
768
|
+
print(
|
769
|
+
f"{YELLOW}Please run 'dh gcp login' interactively first.{NC}",
|
770
|
+
file=sys.stderr,
|
771
|
+
)
|
772
|
+
sys.exit(1)
|
773
|
+
|
774
|
+
print(f"{BLUE}Attempting to configure ADC for your personal user account...{NC}")
|
775
|
+
print(
|
776
|
+
f"{YELLOW}This may require you to complete a browser authentication flow.{NC}"
|
777
|
+
)
|
778
|
+
|
779
|
+
gcloud_path = _find_executable("gcloud")
|
780
|
+
cmd = [gcloud_path, "auth", "application-default", "login"]
|
781
|
+
|
782
|
+
# Allow interaction, don't capture output
|
783
|
+
returncode, _, _ = _run_command(
|
784
|
+
cmd, capture=False, check=False, suppress_output=False
|
785
|
+
)
|
786
|
+
|
787
|
+
if returncode == 0:
|
788
|
+
print(f"\n{GREEN}Successfully configured ADC for personal user account.{NC}")
|
789
|
+
print(f"{BLUE}--- Current Status ---{NC}")
|
790
|
+
gcp_status() # Show status after successful change
|
465
791
|
else:
|
466
|
-
# Print confirmation
|
467
792
|
print(
|
468
|
-
f"{
|
793
|
+
f"{RED}Failed to configure ADC (Return code: {returncode}). Check messages above.{NC}",
|
794
|
+
file=sys.stderr,
|
795
|
+
)
|
796
|
+
sys.exit(1)
|
797
|
+
|
798
|
+
|
799
|
+
@gcp_app.command("use-devcon-adc")
|
800
|
+
def gcp_use_devcon_adc():
|
801
|
+
"""Configure Libraries/Tools (ADC) to use the DEVCON service account."""
|
802
|
+
if not _is_gcp_user_authenticated():
|
803
|
+
print(
|
804
|
+
f"{RED}Error: GCP user authentication is invalid or requires interactive login.{NC}",
|
805
|
+
file=sys.stderr,
|
806
|
+
)
|
807
|
+
print(
|
808
|
+
f"{YELLOW}Please run 'dh gcp login' interactively first.{NC}",
|
809
|
+
file=sys.stderr,
|
469
810
|
)
|
470
|
-
|
471
|
-
|
811
|
+
sys.exit(1)
|
812
|
+
|
813
|
+
print(f"{BLUE}Attempting to configure ADC for devcon SA ({GCP_DEVCON_SA})...{NC}")
|
814
|
+
print(
|
815
|
+
f"{YELLOW}This may require you to complete a browser authentication flow.{NC}"
|
816
|
+
)
|
817
|
+
|
818
|
+
gcloud_path = _find_executable("gcloud")
|
819
|
+
cmd = [
|
820
|
+
gcloud_path,
|
821
|
+
"auth",
|
822
|
+
"application-default",
|
823
|
+
"login",
|
824
|
+
f"--impersonate-service-account={GCP_DEVCON_SA}",
|
825
|
+
]
|
826
|
+
|
827
|
+
# Allow interaction, don't capture output
|
828
|
+
returncode, _, _ = _run_command(
|
829
|
+
cmd, capture=False, check=False, suppress_output=False
|
830
|
+
)
|
831
|
+
|
832
|
+
if returncode == 0:
|
472
833
|
print(
|
473
|
-
f"{
|
834
|
+
f"\n{GREEN}Successfully configured ADC for devcon SA ({GCP_DEVCON_SA}).{NC}"
|
474
835
|
)
|
475
|
-
print(f"{
|
836
|
+
print(f"{BLUE}--- Current Status ---{NC}")
|
837
|
+
gcp_status() # Show status after successful change
|
838
|
+
else:
|
839
|
+
print(
|
840
|
+
f"{RED}Failed to configure ADC (Return code: {returncode}). Check messages above.{NC}",
|
841
|
+
file=sys.stderr,
|
842
|
+
)
|
843
|
+
sys.exit(1)
|
844
|
+
|
845
|
+
|
846
|
+
# === End NEW ADC Commands ===
|
476
847
|
|
477
848
|
|
478
849
|
# --- AWS Commands ---
|
@@ -2,7 +2,7 @@ dayhoff_tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
2
|
dayhoff_tools/chemistry/standardizer.py,sha256=uMn7VwHnx02nc404eO6fRuS4rsl4dvSPf2ElfZDXEpY,11188
|
3
3
|
dayhoff_tools/chemistry/utils.py,sha256=jt-7JgF-GeeVC421acX-bobKbLU_X94KNOW24p_P-_M,2257
|
4
4
|
dayhoff_tools/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
5
|
-
dayhoff_tools/cli/cloud_commands.py,sha256=
|
5
|
+
dayhoff_tools/cli/cloud_commands.py,sha256=KiYEuD3nSg8QPWBYfrhdze2La_CJe4iqK-8uOAHyS8U,35827
|
6
6
|
dayhoff_tools/cli/main.py,sha256=E1-3rZ26LMgJVKBz6CdJwsHs9fJsSGa2_9tot3hNgz4,3604
|
7
7
|
dayhoff_tools/cli/swarm_commands.py,sha256=5EyKj8yietvT5lfoz8Zx0iQvVaNgc3SJX1z2zQR6o6M,5614
|
8
8
|
dayhoff_tools/cli/utility_commands.py,sha256=AsZMpvUNP2xjn5cZ9_BrBNHggfuy6PLwlHw1WP0d7o0,9602
|
@@ -25,7 +25,7 @@ dayhoff_tools/sqlite.py,sha256=jV55ikF8VpTfeQqqlHSbY8OgfyfHj8zgHNpZjBLos_E,18672
|
|
25
25
|
dayhoff_tools/structure.py,sha256=ufN3gAodQxhnt7psK1VTQeu9rKERmo_PhoxIbB4QKMw,27660
|
26
26
|
dayhoff_tools/uniprot.py,sha256=BZYJQF63OtPcBBnQ7_P9gulxzJtqyorgyuDiPeOJqE4,16456
|
27
27
|
dayhoff_tools/warehouse.py,sha256=TqV8nex1AluNaL4JuXH5zuu9P7qmE89lSo6f_oViy6U,14965
|
28
|
-
dayhoff_tools-1.0.
|
29
|
-
dayhoff_tools-1.0.
|
30
|
-
dayhoff_tools-1.0.
|
31
|
-
dayhoff_tools-1.0.
|
28
|
+
dayhoff_tools-1.0.9.dist-info/METADATA,sha256=z5v8zbt4z_B5283bqkkFlybQox_tZacU-Z6JPNyg1vc,1930
|
29
|
+
dayhoff_tools-1.0.9.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
|
30
|
+
dayhoff_tools-1.0.9.dist-info/entry_points.txt,sha256=iAf4jteNqW3cJm6CO6czLxjW3vxYKsyGLZ8WGmxamSc,49
|
31
|
+
dayhoff_tools-1.0.9.dist-info/RECORD,,
|
File without changes
|
File without changes
|