outerbounds 0.3.55rc5__py3-none-any.whl → 0.3.56__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,12 +1,10 @@
1
1
  import click
2
2
  from . import local_setup_cli
3
3
  from . import workstations_cli
4
- from . import perimeters_cli
5
4
 
6
5
 
7
6
  @click.command(
8
- cls=click.CommandCollection,
9
- sources=[local_setup_cli.cli, workstations_cli.cli, perimeters_cli.cli],
7
+ cls=click.CommandCollection, sources=[local_setup_cli.cli, workstations_cli.cli]
10
8
  )
11
9
  def cli(**kwargs):
12
10
  pass
@@ -586,12 +586,6 @@ class ConfigurationWriter:
586
586
  self.out_dir = out_dir
587
587
  self.profile = profile
588
588
 
589
- ob_config_dir = path.expanduser(os.getenv("OBP_CONFIG_DIR", out_dir))
590
- self.ob_config_path = path.join(
591
- ob_config_dir,
592
- "ob_config_{}.json".format(profile) if profile else "ob_config.json",
593
- )
594
-
595
589
  def decode(self):
596
590
  self.decoded_config = deserialize(self.encoded_config)
597
591
 
@@ -654,21 +648,6 @@ class ConfigurationWriter:
654
648
  with open(config_path, "w") as fd:
655
649
  json.dump(self.existing, fd, indent=4)
656
650
 
657
- # Every time a config is initialized, we should also reset the corresponding ob_config[_profile].json
658
- remote_config = metaflowconfig.init_config(self.out_dir, self.profile)
659
- if (
660
- "OBP_PERIMETER" in remote_config
661
- and "OBP_METAFLOW_CONFIG_URL" in remote_config
662
- ):
663
- with open(self.ob_config_path, "w") as fd:
664
- ob_config_dict = {
665
- "OB_CURRENT_PERIMETER": remote_config["OBP_PERIMETER"],
666
- "OB_CURRENT_PERIMETER_URL": remote_config[
667
- "OBP_METAFLOW_CONFIG_URL"
668
- ],
669
- }
670
- json.dump(ob_config_dict, fd, indent=4)
671
-
672
651
  def confirm_overwrite_config(self, config_path):
673
652
  if os.path.exists(config_path):
674
653
  if not click.confirm(
@@ -89,7 +89,7 @@ def generate_workstation_token(config_dir=None, profile=None):
89
89
  @click.option(
90
90
  "-p",
91
91
  "--profile",
92
- default=os.environ.get("METAFLOW_PROFILE", ""),
92
+ default="",
93
93
  help="The named metaflow profile in which your workstation exists",
94
94
  )
95
95
  @click.option(
@@ -110,6 +110,7 @@ def configure_cloud_workstation(config_dir=None, profile=None, binary=None, outp
110
110
  kubeconfig_configure_step = CommandStatus(
111
111
  "ConfigureKubeConfig", OuterboundsCommandStatus.OK, "Kubeconfig is configured"
112
112
  )
113
+
113
114
  try:
114
115
  metaflow_token = metaflowconfig.get_metaflow_token_from_config(
115
116
  config_dir, profile
@@ -190,25 +191,10 @@ def configure_cloud_workstation(config_dir=None, profile=None, binary=None, outp
190
191
  @click.option(
191
192
  "-p",
192
193
  "--profile",
193
- default=os.environ.get("METAFLOW_PROFILE", ""),
194
+ default="",
194
195
  help="The named metaflow profile in which your workstation exists",
195
196
  )
196
- @click.option(
197
- "-o",
198
- "--output",
199
- default="json",
200
- help="Show output in the specified format.",
201
- type=click.Choice(["json"]),
202
- )
203
- def list_workstations(config_dir=None, profile=None, output="json"):
204
- list_response = OuterboundsCommandResponse()
205
- list_step = CommandStatus(
206
- "listWorkstations",
207
- OuterboundsCommandStatus.OK,
208
- "Workstation list successfully fetched!",
209
- )
210
- list_response.add_or_update_data("workstations", [])
211
-
197
+ def list_workstations(config_dir=None, profile=None):
212
198
  try:
213
199
  metaflow_token = metaflowconfig.get_metaflow_token_from_config(
214
200
  config_dir, profile
@@ -219,23 +205,17 @@ def list_workstations(config_dir=None, profile=None, output="json"):
219
205
  workstations_response = requests.get(
220
206
  f"{api_url}/v1/workstations", headers={"x-api-key": metaflow_token}
221
207
  )
222
- workstations_response.raise_for_status()
223
- list_response.add_or_update_data(
224
- "workstations", workstations_response.json()["workstations"]
225
- )
226
- if output == "json":
227
- click.echo(json.dumps(list_response.as_dict(), indent=4))
208
+ try:
209
+ workstations_response.raise_for_status()
210
+ click.echo(json.dumps(workstations_response.json(), indent=4))
211
+ except HTTPError:
212
+ click.secho("Failed to generate workstation token.", fg="red")
213
+ click.secho(
214
+ "Error: {}".format(json.dumps(workstations_response.json(), indent=4))
215
+ )
228
216
  except Exception as e:
229
- list_step.update(
230
- OuterboundsCommandStatus.FAIL, "Failed to list workstations", ""
231
- )
232
- list_response.add_step(list_step)
233
- if output == "json":
234
- list_response.add_or_update_data("error", str(e))
235
- click.echo(json.dumps(list_response.as_dict(), indent=4))
236
- else:
237
- click.secho("Failed to list workstations", fg="red", err=True)
238
- click.secho("Error: {}".format(str(e)), fg="red", err=True)
217
+ click.secho("Failed to list workstations", fg="red")
218
+ click.secho("Error: {}".format(str(e)))
239
219
 
240
220
 
241
221
  @cli.command(help="Hibernate workstation", hidden=True)
@@ -255,7 +235,7 @@ def list_workstations(config_dir=None, profile=None, output="json"):
255
235
  @click.option(
256
236
  "-w",
257
237
  "--workstation",
258
- default=os.environ.get("METAFLOW_PROFILE", ""),
238
+ default="",
259
239
  help="The ID of the workstation to hibernate",
260
240
  )
261
241
  def hibernate_workstation(config_dir=None, profile=None, workstation=None):
@@ -263,8 +243,6 @@ def hibernate_workstation(config_dir=None, profile=None, workstation=None):
263
243
  click.secho("Please specify a workstation ID", fg="red")
264
244
  return
265
245
  try:
266
- if not profile:
267
- profile = metaflowconfig.get_metaflow_profile()
268
246
  metaflow_token = metaflowconfig.get_metaflow_token_from_config(
269
247
  config_dir, profile
270
248
  )
@@ -289,7 +267,7 @@ def hibernate_workstation(config_dir=None, profile=None, workstation=None):
289
267
  )
290
268
  except Exception as e:
291
269
  click.secho("Failed to hibernate workstation", fg="red")
292
- click.secho("Error: {}".format(str(e)), fg="red")
270
+ click.secho("Error: {}".format(str(e)))
293
271
 
294
272
 
295
273
  @cli.command(help="Restart workstation to the int", hidden=True)
@@ -303,7 +281,7 @@ def hibernate_workstation(config_dir=None, profile=None, workstation=None):
303
281
  @click.option(
304
282
  "-p",
305
283
  "--profile",
306
- default=os.environ.get("METAFLOW_PROFILE", ""),
284
+ default="",
307
285
  help="The named metaflow profile in which your workstation exists",
308
286
  )
309
287
  @click.option(
@@ -341,7 +319,7 @@ def restart_workstation(config_dir=None, profile=None, workstation=None):
341
319
  )
342
320
  except Exception as e:
343
321
  click.secho("Failed to restart workstation", fg="red")
344
- click.secho("Error: {}".format(str(e)), fg="red")
322
+ click.secho("Error: {}".format(str(e)))
345
323
 
346
324
 
347
325
  @cli.command(help="Install dependencies needed by workstations", hidden=True)
@@ -513,63 +491,3 @@ def add_to_path(program_path, platform):
513
491
 
514
492
  def to_windows_path(path):
515
493
  return os.path.normpath(path).replace(os.sep, "\\")
516
-
517
-
518
- @cli.command(help="Show relevant links for a deployment & perimeter", hidden=True)
519
- @click.option(
520
- "-d",
521
- "--config-dir",
522
- default=path.expanduser(os.environ.get("METAFLOW_HOME", "~/.metaflowconfig")),
523
- help="Path to Metaflow configuration directory",
524
- show_default=True,
525
- )
526
- @click.option(
527
- "-p",
528
- "--profile",
529
- default="",
530
- help="The named metaflow profile in which your workstation exists",
531
- )
532
- @click.option(
533
- "--perimeter-id",
534
- default="",
535
- help="The id of the perimeter to use",
536
- )
537
- @click.option(
538
- "-o",
539
- "--output",
540
- default="",
541
- help="Show output in the specified format.",
542
- type=click.Choice(["json", ""]),
543
- )
544
- def show_relevant_links(config_dir=None, profile=None, perimeter_id="", output=""):
545
- show_links_response = OuterboundsCommandResponse()
546
- show_links_step = CommandStatus(
547
- "showRelevantLinks",
548
- OuterboundsCommandStatus.OK,
549
- "Relevant links successfully fetched!",
550
- )
551
- show_links_response.add_or_update_data("links", [])
552
- links = []
553
- try:
554
- metaflow_config = metaflowconfig.init_config(config_dir, profile)
555
- links.append(
556
- {
557
- "id": "metaflow-ui-url",
558
- "url": metaflow_config["METAFLOW_UI_URL"],
559
- "label": "Metaflow UI URL",
560
- }
561
- )
562
- show_links_response.add_or_update_data("links", links)
563
- if output == "json":
564
- click.echo(json.dumps(show_links_response.as_dict(), indent=4))
565
- except Exception as e:
566
- show_links_step.update(
567
- OuterboundsCommandStatus.FAIL, "Failed to show relevant links", ""
568
- )
569
- show_links_response.add_step(show_links_step)
570
- if output == "json":
571
- show_links_response.add_or_update_data("error", str(e))
572
- click.echo(json.dumps(show_links_response.as_dict(), indent=4))
573
- else:
574
- click.secho("Failed to show relevant links", fg="red", err=True)
575
- click.secho("Error: {}".format(str(e)), fg="red", err=True)
@@ -1,13 +1,11 @@
1
1
  import json
2
2
  import os
3
3
  import requests
4
- from os import path
5
- import requests
6
4
 
7
5
 
8
- def init_config(config_dir="", profile="") -> dict:
9
- profile = profile or os.environ.get("METAFLOW_PROFILE")
10
- config_dir = config_dir or os.path.expanduser(
6
+ def init_config() -> dict:
7
+ profile = os.environ.get("METAFLOW_PROFILE")
8
+ config_dir = os.path.expanduser(
11
9
  os.environ.get("METAFLOW_HOME", "~/.metaflowconfig")
12
10
  )
13
11
 
@@ -46,10 +44,13 @@ def get_metaflow_token_from_config(config_dir: str, profile: str) -> str:
46
44
  config_dir (str): Path to the config directory
47
45
  profile (str): The named metaflow profile
48
46
  """
49
- config = init_config(config_dir, profile)
50
- if config is None or "METAFLOW_SERVICE_AUTH_KEY" not in config:
51
- raise Exception("METAFLOW_SERVICE_AUTH_KEY not found in config file")
52
- return config["METAFLOW_SERVICE_AUTH_KEY"]
47
+ config_filename = f"config_{profile}.json" if profile else "config.json"
48
+ config_path = os.path.join(config_dir, config_filename)
49
+ with open(config_path) as json_file:
50
+ config = json.load(json_file)
51
+ if config is None or "METAFLOW_SERVICE_AUTH_KEY" not in config:
52
+ raise Exception("METAFLOW_SERVICE_AUTH_KEY not found in config file")
53
+ return config["METAFLOW_SERVICE_AUTH_KEY"]
53
54
 
54
55
 
55
56
  def get_sanitized_url_from_config(config_dir: str, profile: str, key: str) -> str:
@@ -61,12 +62,16 @@ def get_sanitized_url_from_config(config_dir: str, profile: str, key: str) -> st
61
62
  profile (str): The named metaflow profile
62
63
  key (str): The key to look up in the config file
63
64
  """
64
- config = init_config(config_dir, profile)
65
- if key not in config:
66
- raise Exception(f"Key {key} not found in config")
67
- url_in_config = config[key]
68
- if not url_in_config.startswith("https://"):
69
- url_in_config = f"https://{url_in_config}"
65
+ config_filename = f"config_{profile}.json" if profile else "config.json"
66
+ config_path = os.path.join(config_dir, config_filename)
67
+
68
+ with open(config_path) as json_file:
69
+ config = json.load(json_file)
70
+ if key not in config:
71
+ raise Exception(f"Key {key} not found in config file {config_path}")
72
+ url_in_config = config[key]
73
+ if not url_in_config.startswith("https://"):
74
+ url_in_config = f"https://{url_in_config}"
70
75
 
71
- url_in_config = url_in_config.rstrip("/")
72
- return url_in_config
76
+ url_in_config = url_in_config.rstrip("/")
77
+ return url_in_config
@@ -37,14 +37,10 @@ class OuterboundsCommandResponse:
37
37
  self._message = ""
38
38
  self._steps = []
39
39
  self.metadata = {}
40
- self._data = {}
41
40
 
42
41
  def add_or_update_metadata(self, key, value):
43
42
  self.metadata[key] = value
44
43
 
45
- def add_or_update_data(self, key, value):
46
- self._data[key] = value
47
-
48
44
  def add_step(self, step: CommandStatus):
49
45
  self._steps.append(step)
50
46
  self._process_step_status(step)
@@ -63,11 +59,10 @@ class OuterboundsCommandResponse:
63
59
  self._message = "We found one or more warnings with your installation."
64
60
 
65
61
  def as_dict(self):
66
- self._data["steps"] = [step.as_dict() for step in self._steps]
67
62
  return {
68
63
  "status": self.status.value,
69
64
  "code": self._code,
70
65
  "message": self._message,
66
+ "steps": [step.as_dict() for step in self._steps],
71
67
  "metadata": self.metadata,
72
- "data": self._data,
73
68
  }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: outerbounds
3
- Version: 0.3.55rc5
3
+ Version: 0.3.56
4
4
  Summary: More Data Science, Less Administration
5
5
  License: Proprietary
6
6
  Keywords: data science,machine learning,MLOps
@@ -23,8 +23,9 @@ Requires-Dist: click (>=8.1.3,<9.0.0)
23
23
  Requires-Dist: google-api-core (>=2.16.1,<3.0.0) ; extra == "gcp"
24
24
  Requires-Dist: google-auth (>=2.27.0,<3.0.0) ; extra == "gcp"
25
25
  Requires-Dist: google-cloud-storage (>=2.14.0,<3.0.0) ; extra == "gcp"
26
- Requires-Dist: ob-metaflow (==2.11.0.4)
27
- Requires-Dist: ob-metaflow-extensions (==1.1.45rc2)
26
+ Requires-Dist: ob-metaflow (==2.11.4.1)
27
+ Requires-Dist: ob-metaflow-extensions (==1.1.46)
28
+ Requires-Dist: ob-metaflow-stubs (==2.11.4.1)
28
29
  Requires-Dist: opentelemetry-distro (==0.41b0)
29
30
  Requires-Dist: opentelemetry-exporter-otlp-proto-http (==1.20.0)
30
31
  Requires-Dist: opentelemetry-instrumentation-requests (==0.41b0)
@@ -0,0 +1,14 @@
1
+ outerbounds/__init__.py,sha256=GPdaubvAYF8pOFWJ3b-sPMKCpyfpteWVMZWkmaYhxRw,32
2
+ outerbounds/cli_main.py,sha256=e9UMnPysmc7gbrimq2I4KfltggyU7pw59Cn9aEguVcU,74
3
+ outerbounds/command_groups/__init__.py,sha256=QPWtj5wDRTINDxVUL7XPqG3HoxHNvYOg08EnuSZB2Hc,21
4
+ outerbounds/command_groups/cli.py,sha256=61VsBlPG2ykP_786eCyllqeM8DMhPAOfj2FhktrSd7k,207
5
+ outerbounds/command_groups/local_setup_cli.py,sha256=g_kkrlDGzYvZTm184pW6QwotpkcqBamB14kH_Kv8TbM,28685
6
+ outerbounds/command_groups/workstations_cli.py,sha256=VgydQzCas3mlAFyzZuanjl1E8Zh7pBrbKbbP6t6N2WU,18237
7
+ outerbounds/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
+ outerbounds/utils/kubeconfig.py,sha256=l1mUP1j9VIq3fsffi5bJ1Nk-hYlwd1dIqkpj7DvVS1E,7936
9
+ outerbounds/utils/metaflowconfig.py,sha256=6u9D4x-pQVCPKnmGkTg9uSSHrq4mGnWQl7TurwyV2e8,2945
10
+ outerbounds/utils/schema.py,sha256=nBuarFbdZu0LGhG0YkJ6pEIvdglfM_TO_W_Db2vksb0,2017
11
+ outerbounds-0.3.56.dist-info/METADATA,sha256=iYALnqAuZVDKxhiQf02jv_XGCv1NVBnCcHX1MHPn4gw,1407
12
+ outerbounds-0.3.56.dist-info/WHEEL,sha256=vVCvjcmxuUltf8cYhJ0sJMRDLr1XsPuxEId8YDzbyCY,88
13
+ outerbounds-0.3.56.dist-info/entry_points.txt,sha256=7ye0281PKlvqxu15rjw60zKg2pMsXI49_A8BmGqIqBw,47
14
+ outerbounds-0.3.56.dist-info/RECORD,,
@@ -1,374 +0,0 @@
1
- import base64
2
- import hashlib
3
- import json
4
- import os
5
- import re
6
- import subprocess
7
- import sys
8
- import zlib
9
- from base64 import b64decode, b64encode
10
- from importlib.machinery import PathFinder
11
- from os import path
12
- from pathlib import Path
13
- from typing import Any, Callable, Dict, List
14
-
15
- import boto3
16
- import click
17
- import requests
18
- from requests.exceptions import HTTPError
19
-
20
- from ..utils import kubeconfig, metaflowconfig
21
- from ..utils.schema import (
22
- CommandStatus,
23
- OuterboundsCommandResponse,
24
- OuterboundsCommandStatus,
25
- )
26
-
27
-
28
- @click.group()
29
- def cli(**kwargs):
30
- pass
31
-
32
-
33
- @cli.command(help="Switch current perimeter", hidden=True)
34
- @click.option(
35
- "-d",
36
- "--config-dir",
37
- default=path.expanduser(os.environ.get("METAFLOW_HOME", "~/.metaflowconfig")),
38
- help="Path to Metaflow configuration directory",
39
- show_default=True,
40
- )
41
- @click.option(
42
- "-p",
43
- "--profile",
44
- default=os.environ.get("METAFLOW_PROFILE", ""),
45
- help="The named metaflow profile in which your workstation exists",
46
- )
47
- @click.option(
48
- "-o",
49
- "--output",
50
- default="",
51
- help="Show output in the specified format.",
52
- type=click.Choice(["json", ""]),
53
- )
54
- @click.option("--id", default="", type=str, help="Perimeter name to switch to")
55
- @click.option(
56
- "-f",
57
- "--force",
58
- is_flag=True,
59
- help="Force change the existing perimeter",
60
- default=False,
61
- )
62
- def switch_perimeter(config_dir=None, profile=None, output="", id=None, force=False):
63
- switch_perimeter_response = OuterboundsCommandResponse()
64
-
65
- switch_perimeter_step = CommandStatus(
66
- "SwitchPerimeter",
67
- OuterboundsCommandStatus.OK,
68
- "Perimeter was successfully switched!",
69
- )
70
-
71
- perimeters = get_perimeters_from_api_or_fail_command(
72
- config_dir, profile, output, switch_perimeter_response, switch_perimeter_step
73
- )
74
- confirm_user_has_access_to_perimeter_or_fail(
75
- id, perimeters, output, switch_perimeter_response, switch_perimeter_step
76
- )
77
-
78
- path_to_config = get_ob_config_file_path(config_dir, profile)
79
-
80
- import fcntl
81
-
82
- try:
83
- if os.path.exists(path_to_config):
84
- if not force:
85
- fd = os.open(path_to_config, os.O_WRONLY)
86
- # Try to acquire an exclusive lock
87
- fcntl.flock(fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
88
- else:
89
- click.secho(
90
- "Force flag is set. Perimeter will be switched, but can have unintended consequences on other running processes.",
91
- fg="yellow",
92
- err=True,
93
- )
94
-
95
- ob_config_dict = {
96
- "OB_CURRENT_PERIMETER": str(id),
97
- "OB_CURRENT_PERIMETER_URL": perimeters[id]["remote_config_url"],
98
- }
99
-
100
- # Now that we have the lock, we can safely write to the file
101
- with open(path_to_config, "w") as file:
102
- json.dump(ob_config_dict, file, indent=4)
103
-
104
- click.secho("Perimeter switched to {}".format(id), fg="green", err=True)
105
- except BlockingIOError:
106
- # This exception is raised if the file is already locked (non-blocking mode)
107
- # Note that its the metaflow package (the extension actually) that acquires a shared read lock
108
- # on the file whenever a process imports metaflow.
109
- # In the future we might want to get smarter about it and show which process is holding the lock.
110
- click.secho(
111
- "Can't switch perimeter while Metaflow is in use. Please make sure there are no running python processes or notebooks using metaflow.",
112
- fg="red",
113
- err=True,
114
- )
115
- switch_perimeter_step.update(
116
- status=OuterboundsCommandStatus.FAIL,
117
- reason="Can't switch perimeter while Metaflow is in use.",
118
- mitigation="Please make sure there are no running python processes or notebooks using metaflow.",
119
- )
120
-
121
- switch_perimeter_response.add_step(switch_perimeter_step)
122
- if output == "json":
123
- click.echo(json.dumps(switch_perimeter_response.as_dict(), indent=4))
124
- return
125
-
126
-
127
- @cli.command(help="Show current perimeter", hidden=True)
128
- @click.option(
129
- "-d",
130
- "--config-dir",
131
- default=path.expanduser(os.environ.get("METAFLOW_HOME", "~/.metaflowconfig")),
132
- help="Path to Metaflow configuration directory",
133
- show_default=True,
134
- )
135
- @click.option(
136
- "-p",
137
- "--profile",
138
- default=os.environ.get("METAFLOW_PROFILE", ""),
139
- help="Configure a named profile. Activate the profile by setting "
140
- "`METAFLOW_PROFILE` environment variable.",
141
- )
142
- @click.option(
143
- "-o",
144
- "--output",
145
- default="",
146
- help="Show output in the specified format.",
147
- type=click.Choice(["json", ""]),
148
- )
149
- def show_current_perimeter(config_dir=None, profile=None, output=""):
150
- show_current_perimeter_response = OuterboundsCommandResponse()
151
-
152
- show_current_perimeter_step = CommandStatus(
153
- "ShowCurrentPerimeter",
154
- OuterboundsCommandStatus.OK,
155
- "Current Perimeter Fetch Successful.",
156
- )
157
-
158
- ob_config_dict = get_ob_config_or_fail_command(
159
- config_dir,
160
- profile,
161
- output,
162
- show_current_perimeter_response,
163
- show_current_perimeter_step,
164
- )
165
-
166
- perimeters = get_perimeters_from_api_or_fail_command(
167
- config_dir,
168
- profile,
169
- output,
170
- show_current_perimeter_response,
171
- show_current_perimeter_step,
172
- )
173
- confirm_user_has_access_to_perimeter_or_fail(
174
- ob_config_dict["OB_CURRENT_PERIMETER"],
175
- perimeters,
176
- output,
177
- show_current_perimeter_response,
178
- show_current_perimeter_step,
179
- )
180
-
181
- click.secho(
182
- "Current Perimeter: {}".format(ob_config_dict["OB_CURRENT_PERIMETER"]),
183
- fg="green",
184
- err=True,
185
- )
186
-
187
- show_current_perimeter_response.add_or_update_data(
188
- "current_perimeter", ob_config_dict["OB_CURRENT_PERIMETER"]
189
- )
190
-
191
- if output == "json":
192
- click.echo(json.dumps(show_current_perimeter_response.as_dict(), indent=4))
193
-
194
-
195
- @cli.command(help="List all available perimeters", hidden=True)
196
- @click.option(
197
- "-d",
198
- "--config-dir",
199
- default=path.expanduser(os.environ.get("METAFLOW_HOME", "~/.metaflowconfig")),
200
- help="Path to Metaflow configuration directory",
201
- show_default=True,
202
- )
203
- @click.option(
204
- "-p",
205
- "--profile",
206
- default=os.environ.get("METAFLOW_PROFILE", ""),
207
- help="The named metaflow profile in which your workstation exists",
208
- )
209
- @click.option(
210
- "-o",
211
- "--output",
212
- default="",
213
- help="Show output in the specified format.",
214
- type=click.Choice(["json", ""]),
215
- )
216
- def list_perimeters(config_dir=None, profile=None, output=""):
217
- list_perimeters_response = OuterboundsCommandResponse()
218
-
219
- list_perimeters_step = CommandStatus(
220
- "ListPerimeters", OuterboundsCommandStatus.OK, "Perimeter Fetch Successful."
221
- )
222
-
223
- ob_config_dict = get_ob_config_or_fail_command(
224
- config_dir, profile, output, list_perimeters_response, list_perimeters_step
225
- )
226
- active_perimeter = ob_config_dict["OB_CURRENT_PERIMETER"]
227
-
228
- perimeters = get_perimeters_from_api_or_fail_command(
229
- config_dir, profile, output, list_perimeters_response, list_perimeters_step
230
- )
231
-
232
- perimeter_list = []
233
- for perimeter in perimeters.values():
234
- status = "OK"
235
- perimeter_list.append(
236
- {
237
- "id": perimeter["perimeter"],
238
- "active": perimeter["perimeter"] == active_perimeter,
239
- "status": status,
240
- }
241
- )
242
- if perimeter["perimeter"] != active_perimeter:
243
- click.secho("Perimeter: {}".format(perimeter["perimeter"]), err=True)
244
- else:
245
- click.secho(
246
- "Perimeter: {} (active)".format(perimeter["perimeter"]),
247
- fg="green",
248
- err=True,
249
- )
250
-
251
- list_perimeters_response.add_or_update_data("perimeters", perimeter_list)
252
-
253
- if output == "json":
254
- click.echo(json.dumps(list_perimeters_response.as_dict(), indent=4))
255
-
256
-
257
- def get_list_perimeters_api_response(config_dir, profile):
258
- metaflow_token = metaflowconfig.get_metaflow_token_from_config(config_dir, profile)
259
- api_url = metaflowconfig.get_sanitized_url_from_config(
260
- config_dir, profile, "OBP_API_SERVER"
261
- )
262
- perimeters_response = requests.get(
263
- f"{api_url}/v1/me/perimeters?privilege=Execute",
264
- headers={"x-api-key": metaflow_token},
265
- )
266
- perimeters_response.raise_for_status()
267
- return perimeters_response.json()["perimeters"]
268
-
269
-
270
- def get_ob_config_file_path(config_dir: str, profile: str) -> str:
271
- # If OBP_CONFIG_DIR is set, use that, otherwise use METAFLOW_HOME
272
- # If neither are set, use ~/.metaflowconfig
273
- obp_config_dir = path.expanduser(os.environ.get("OBP_CONFIG_DIR", config_dir))
274
-
275
- ob_config_filename = f"ob_config_{profile}.json" if profile else "ob_config.json"
276
- return os.path.expanduser(os.path.join(obp_config_dir, ob_config_filename))
277
-
278
-
279
- def get_perimeters_from_api_or_fail_command(
280
- config_dir: str,
281
- profile: str,
282
- output: str,
283
- command_response: OuterboundsCommandResponse,
284
- command_step: CommandStatus,
285
- ) -> Dict[str, Dict[str, str]]:
286
- try:
287
- perimeters = get_list_perimeters_api_response(config_dir, profile)
288
- except:
289
- click.secho(
290
- "Failed to fetch perimeters from API.",
291
- fg="red",
292
- err=True,
293
- )
294
- command_step.update(
295
- status=OuterboundsCommandStatus.FAIL,
296
- reason="Failed to fetch perimeters from API",
297
- mitigation="",
298
- )
299
- command_response.add_step(command_step)
300
- if output == "json":
301
- click.echo(json.dumps(command_response.as_dict(), indent=4))
302
- sys.exit(1)
303
- return {p["perimeter"]: p for p in perimeters}
304
-
305
-
306
- def get_ob_config_or_fail_command(
307
- config_dir: str,
308
- profile: str,
309
- output: str,
310
- command_response: OuterboundsCommandResponse,
311
- command_step: CommandStatus,
312
- ) -> Dict[str, str]:
313
- path_to_config = get_ob_config_file_path(config_dir, profile)
314
-
315
- if not os.path.exists(path_to_config):
316
- click.secho(
317
- "Config file not found at {}".format(path_to_config), fg="red", err=True
318
- )
319
- command_step.update(
320
- status=OuterboundsCommandStatus.FAIL,
321
- reason="Config file not found",
322
- mitigation="Please make sure the config file exists at {}".format(
323
- path_to_config
324
- ),
325
- )
326
- command_response.add_step(command_step)
327
- if output == "json":
328
- click.echo(json.dumps(command_response.as_dict(), indent=4))
329
- sys.exit(1)
330
-
331
- with open(path_to_config, "r") as file:
332
- ob_config_dict = json.load(file)
333
-
334
- if "OB_CURRENT_PERIMETER" not in ob_config_dict:
335
- click.secho(
336
- "OB_CURRENT_PERIMETER not found in Config file: {}".format(path_to_config),
337
- fg="red",
338
- err=True,
339
- )
340
- command_step.update(
341
- status=OuterboundsCommandStatus.FAIL,
342
- reason="OB_CURRENT_PERIMETER not found in Config file: {}",
343
- mitigation="",
344
- )
345
- command_response.add_step(command_step)
346
- if output == "json":
347
- click.echo(json.dumps(command_response.as_dict(), indent=4))
348
- sys.exit(1)
349
-
350
- return ob_config_dict
351
-
352
-
353
- def confirm_user_has_access_to_perimeter_or_fail(
354
- perimeter_id: str,
355
- perimeters: Dict[str, Any],
356
- output: str,
357
- command_response: OuterboundsCommandResponse,
358
- command_step: CommandStatus,
359
- ):
360
- if perimeter_id not in perimeters:
361
- click.secho(
362
- f"You do not have access to perimeter {perimeter_id} or it does not exist.",
363
- fg="red",
364
- err=True,
365
- )
366
- command_step.update(
367
- status=OuterboundsCommandStatus.FAIL,
368
- reason=f"You do not have access to perimeter {perimeter_id} or it does not exist.",
369
- mitigation="",
370
- )
371
- command_response.add_step(command_step)
372
- if output == "json":
373
- click.echo(json.dumps(command_response.as_dict(), indent=4))
374
- sys.exit(1)
@@ -1,15 +0,0 @@
1
- outerbounds/__init__.py,sha256=GPdaubvAYF8pOFWJ3b-sPMKCpyfpteWVMZWkmaYhxRw,32
2
- outerbounds/cli_main.py,sha256=e9UMnPysmc7gbrimq2I4KfltggyU7pw59Cn9aEguVcU,74
3
- outerbounds/command_groups/__init__.py,sha256=QPWtj5wDRTINDxVUL7XPqG3HoxHNvYOg08EnuSZB2Hc,21
4
- outerbounds/command_groups/cli.py,sha256=H4LxcYTmsY9DQUrReSRLjvbg9s9Ro7s-eUrcMqEJ_9A,261
5
- outerbounds/command_groups/local_setup_cli.py,sha256=I5KVp3D9KPfQB78eTNupAtvJm7kEFlUbuQXUr_q3GxM,29618
6
- outerbounds/command_groups/perimeters_cli.py,sha256=9tOql42d00KfHpZYkLLGEAOiy8iRbIzsknldCyICwU0,12063
7
- outerbounds/command_groups/workstations_cli.py,sha256=kxUUPT-JMzRjlnMuAxR9UC_Dwv4d7R-60R1_1cpTGbs,21202
8
- outerbounds/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
- outerbounds/utils/kubeconfig.py,sha256=l1mUP1j9VIq3fsffi5bJ1Nk-hYlwd1dIqkpj7DvVS1E,7936
10
- outerbounds/utils/metaflowconfig.py,sha256=HgaDmK3F97rppfGUdysS1Zppe28ERTLV_HcB5IuPpV4,2631
11
- outerbounds/utils/schema.py,sha256=Ht_Yf5uoKO0m36WXHZLSPmWPH6EFWXfZDQsiAUquc5k,2160
12
- outerbounds-0.3.55rc5.dist-info/METADATA,sha256=HOUl7pwPYtQoeCNGPG04Xa0MlfKpGnsTdit8hyxncVs,1367
13
- outerbounds-0.3.55rc5.dist-info/WHEEL,sha256=vVCvjcmxuUltf8cYhJ0sJMRDLr1XsPuxEId8YDzbyCY,88
14
- outerbounds-0.3.55rc5.dist-info/entry_points.txt,sha256=7ye0281PKlvqxu15rjw60zKg2pMsXI49_A8BmGqIqBw,47
15
- outerbounds-0.3.55rc5.dist-info/RECORD,,