sagemaker-hyperpod 3.0.0__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.
Files changed (66) hide show
  1. sagemaker/__init__.py +0 -0
  2. sagemaker/hyperpod/__init__.py +2 -0
  3. sagemaker/hyperpod/cli/__init__.py +0 -0
  4. sagemaker/hyperpod/cli/clients/__init__.py +12 -0
  5. sagemaker/hyperpod/cli/clients/kubernetes_client.py +365 -0
  6. sagemaker/hyperpod/cli/commands/__init__.py +0 -0
  7. sagemaker/hyperpod/cli/commands/cluster.py +627 -0
  8. sagemaker/hyperpod/cli/commands/inference.py +659 -0
  9. sagemaker/hyperpod/cli/commands/training.py +347 -0
  10. sagemaker/hyperpod/cli/constants/__init__.py +0 -0
  11. sagemaker/hyperpod/cli/constants/command_constants.py +105 -0
  12. sagemaker/hyperpod/cli/constants/exception_constants.py +13 -0
  13. sagemaker/hyperpod/cli/constants/hyperpod_instance_types.py +100 -0
  14. sagemaker/hyperpod/cli/constants/kueue_constants.py +17 -0
  15. sagemaker/hyperpod/cli/constants/pytorch_constants.py +15 -0
  16. sagemaker/hyperpod/cli/hyp_cli.py +132 -0
  17. sagemaker/hyperpod/cli/inference_utils.py +121 -0
  18. sagemaker/hyperpod/cli/service/__init__.py +12 -0
  19. sagemaker/hyperpod/cli/service/cancel_training_job.py +70 -0
  20. sagemaker/hyperpod/cli/service/discover_namespaces.py +108 -0
  21. sagemaker/hyperpod/cli/service/exec_command.py +75 -0
  22. sagemaker/hyperpod/cli/service/get_logs.py +136 -0
  23. sagemaker/hyperpod/cli/service/get_namespaces.py +59 -0
  24. sagemaker/hyperpod/cli/service/get_training_job.py +110 -0
  25. sagemaker/hyperpod/cli/service/list_pods.py +138 -0
  26. sagemaker/hyperpod/cli/service/list_training_jobs.py +178 -0
  27. sagemaker/hyperpod/cli/service/self_subject_access_review.py +47 -0
  28. sagemaker/hyperpod/cli/telemetry/__init__.py +12 -0
  29. sagemaker/hyperpod/cli/telemetry/user_agent.py +36 -0
  30. sagemaker/hyperpod/cli/templates/__init__.py +12 -0
  31. sagemaker/hyperpod/cli/templates/k8s_pytorch_job_template.py +74 -0
  32. sagemaker/hyperpod/cli/training_utils.py +200 -0
  33. sagemaker/hyperpod/cli/utils.py +183 -0
  34. sagemaker/hyperpod/cli/validators/__init__.py +12 -0
  35. sagemaker/hyperpod/cli/validators/cluster_validator.py +52 -0
  36. sagemaker/hyperpod/cli/validators/job_validator.py +346 -0
  37. sagemaker/hyperpod/cli/validators/validator.py +75 -0
  38. sagemaker/hyperpod/common/__init__.py +0 -0
  39. sagemaker/hyperpod/common/config/__init__.py +1 -0
  40. sagemaker/hyperpod/common/config/metadata.py +18 -0
  41. sagemaker/hyperpod/common/utils.py +299 -0
  42. sagemaker/hyperpod/inference/__init__.py +11 -0
  43. sagemaker/hyperpod/inference/config/__init__.py +0 -0
  44. sagemaker/hyperpod/inference/config/constants.py +18 -0
  45. sagemaker/hyperpod/inference/config/hp_endpoint_config.py +767 -0
  46. sagemaker/hyperpod/inference/config/hp_jumpstart_endpoint_config.py +572 -0
  47. sagemaker/hyperpod/inference/hp_endpoint.py +203 -0
  48. sagemaker/hyperpod/inference/hp_endpoint_base.py +223 -0
  49. sagemaker/hyperpod/inference/hp_jumpstart_endpoint.py +232 -0
  50. sagemaker/hyperpod/observability/MonitoringConfig.py +10 -0
  51. sagemaker/hyperpod/observability/__init__.py +0 -0
  52. sagemaker/hyperpod/observability/constants.py +2 -0
  53. sagemaker/hyperpod/observability/utils.py +64 -0
  54. sagemaker/hyperpod/training/__init__.py +9 -0
  55. sagemaker/hyperpod/training/config/__init__.py +1 -0
  56. sagemaker/hyperpod/training/config/hyperpod_pytorch_job_config.py +2977 -0
  57. sagemaker/hyperpod/training/config/hyperpod_pytorch_job_status.py +3083 -0
  58. sagemaker/hyperpod/training/hyperpod_pytorch_job.py +253 -0
  59. sagemaker_hyperpod-3.0.0.dist-info/METADATA +534 -0
  60. sagemaker_hyperpod-3.0.0.dist-info/RECORD +66 -0
  61. sagemaker_hyperpod-3.0.0.dist-info/WHEEL +5 -0
  62. sagemaker_hyperpod-3.0.0.dist-info/entry_points.txt +2 -0
  63. sagemaker_hyperpod-3.0.0.dist-info/licenses/LICENSE +175 -0
  64. sagemaker_hyperpod-3.0.0.dist-info/licenses/NOTICE +1 -0
  65. sagemaker_hyperpod-3.0.0.dist-info/top_level.txt +1 -0
  66. sagemaker_hyperpod-3.0.0.dist-info/zip-safe +1 -0
@@ -0,0 +1,59 @@
1
+ # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License"). You
4
+ # may not use this file except in compliance with the License. A copy of
5
+ # the License is located at
6
+ #
7
+ # http://aws.amazon.com/apache2.0/
8
+ #
9
+ # or in the "license" file accompanying this file. This file is
10
+ # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
11
+ # ANY KIND, either express or implied. See the License for the specific
12
+ # language governing permissions and limitations under the License.
13
+ from sagemaker.hyperpod.cli.clients.kubernetes_client import (
14
+ KubernetesClient,
15
+ )
16
+
17
+ from sagemaker.hyperpod.cli.constants.command_constants import SAGEMAKER_MANAGED_QUEUE_LABEL
18
+
19
+
20
+ LIMIT_PER_REQUEST = 200
21
+
22
+ class GetNamespaces:
23
+
24
+ def __init__(self):
25
+ return
26
+
27
+ def get_namespaces(self, label_selector=None):
28
+ """
29
+ Get namespaces in the cluster
30
+ """
31
+ core_v1_api = KubernetesClient().get_core_v1_api()
32
+ all_namespaces = list()
33
+ continue_token = None
34
+
35
+ while True:
36
+ response = None
37
+ if continue_token:
38
+ response = core_v1_api.list_namespace(
39
+ limit=LIMIT_PER_REQUEST, label_selector=label_selector, _continue=continue_token
40
+ )
41
+ else:
42
+ response = core_v1_api.list_namespace(
43
+ limit=LIMIT_PER_REQUEST, label_selector=label_selector
44
+ )
45
+
46
+ all_namespaces.extend([ns.metadata.name for ns in response.items])
47
+ continue_token = response.metadata._continue
48
+
49
+ if not continue_token:
50
+ break
51
+
52
+ return all_namespaces
53
+
54
+ def get_sagemaker_managed_namespaces(self):
55
+ """
56
+ Get sagemaker managed namespaces in the cluster
57
+ """
58
+
59
+ return self.get_namespaces(SAGEMAKER_MANAGED_QUEUE_LABEL + "=true")
@@ -0,0 +1,110 @@
1
+ # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License"). You
4
+ # may not use this file except in compliance with the License. A copy of
5
+ # the License is located at
6
+ #
7
+ # http://aws.amazon.com/apache2.0/
8
+ #
9
+ # or in the "license" file accompanying this file. This file is
10
+ # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
11
+ # ANY KIND, either express or implied. See the License for the specific
12
+ # language governing permissions and limitations under the License.
13
+ from typing import Optional
14
+
15
+ import json
16
+
17
+ from sagemaker.hyperpod.cli.clients.kubernetes_client import (
18
+ KubernetesClient,
19
+ )
20
+
21
+ from sagemaker.hyperpod.cli import utils
22
+ from kubernetes.client.rest import ApiException
23
+ from kubernetes.client import (
24
+ V1ResourceAttributes
25
+ )
26
+
27
+ from sagemaker.hyperpod.cli.constants.pytorch_constants import PYTORCH_CUSTOM_OBJECT_GROUP, PYTORCH_CUSTOM_OBJECT_PLURAL
28
+ from sagemaker.hyperpod.cli.service.discover_namespaces import DiscoverNamespaces
29
+
30
+ class GetTrainingJob:
31
+ def __init__(self):
32
+ return
33
+
34
+ def get_training_job(
35
+ self,
36
+ job_name: str,
37
+ namespace: Optional[str],
38
+ verbose: Optional[bool],
39
+ ):
40
+ """
41
+ Describe training job provided by the user in the specified namespace.
42
+ If namespace is not provided job is described from the default namespace in user context
43
+ """
44
+
45
+ k8s_client = KubernetesClient()
46
+ if not namespace:
47
+ resource_attributes_template = V1ResourceAttributes(
48
+ verb="get",
49
+ group=PYTORCH_CUSTOM_OBJECT_GROUP,
50
+ resource=PYTORCH_CUSTOM_OBJECT_PLURAL,
51
+ )
52
+ namespace = DiscoverNamespaces().discover_accessible_namespace(
53
+ resource_attributes_template
54
+ )
55
+
56
+ try:
57
+ result = k8s_client.get_job(
58
+ job_name=job_name,
59
+ namespace=namespace,
60
+ )
61
+ except ApiException as e:
62
+ raise RuntimeError(f"Unexpected API error: {e.reason} ({e.status})")
63
+
64
+ if not verbose:
65
+ return self._format_output_to_keep_needed_fields(result)
66
+ else:
67
+ return self._format_verbose_output(result)
68
+
69
+ def _format_output_to_keep_needed_fields(self, output):
70
+ result = {}
71
+ if output:
72
+ if output.get("metadata"):
73
+ result = {
74
+ "Name": output.get("metadata").get("name"),
75
+ "Namespace": output.get("metadata").get("namespace"),
76
+ "Label": output.get("metadata").get("labels"),
77
+ "CreationTimestamp": output.get("metadata").get(
78
+ "creationTimestamp"
79
+ ),
80
+ }
81
+ result.update({"Status": output.get("status")})
82
+ result.update({"ConsoleURL": utils.get_cluster_console_url()})
83
+ return json.dumps(result, indent=1, sort_keys=False)
84
+
85
+ def _format_verbose_output(self, output):
86
+ result = {}
87
+ if output:
88
+ if output.get("metadata"):
89
+ result = {
90
+ "Name": output.get("metadata").get("name"),
91
+ "Namespace": output.get("metadata").get("namespace"),
92
+ "Label": output.get("metadata").get("labels"),
93
+ "Annotations": output.get("metadata").get("annotations"),
94
+ "Metadata": {
95
+ "CreationTimestamp": output.get("metadata").get(
96
+ "creationTimestamp"
97
+ ),
98
+ "Generation": output.get("metadata").get("generation"),
99
+ "ResourceVersion": output.get("metadata").get(
100
+ "resourceVersion"
101
+ ),
102
+ "UID": output.get("metadata").get("uid"),
103
+ },
104
+ }
105
+ result.update({"Kind": output.get("kind")})
106
+ result.update({"ApiVersion": output.get("apiVersion")})
107
+ result.update({"Spec": output.get("spec")})
108
+ result.update({"Status": output.get("status")})
109
+ result.update({"ConsoleURL": utils.get_cluster_console_url()})
110
+ return json.dumps(result, indent=1, sort_keys=False)
@@ -0,0 +1,138 @@
1
+ # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License"). You
4
+ # may not use this file except in compliance with the License. A copy of
5
+ # the License is located at
6
+ #
7
+ # http://aws.amazon.com/apache2.0/
8
+ #
9
+ # or in the "license" file accompanying this file. This file is
10
+ # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
11
+ # ANY KIND, either express or implied. See the License for the specific
12
+ # language governing permissions and limitations under the License.
13
+ from collections import defaultdict
14
+ from typing import List, Optional
15
+ import json
16
+
17
+ from kubernetes.client import V1Pod, V1PodList
18
+
19
+ from sagemaker.hyperpod.cli.clients.kubernetes_client import (
20
+ KubernetesClient,
21
+ )
22
+ from kubernetes.client.rest import ApiException
23
+ from kubernetes.client import (
24
+ V1ResourceAttributes
25
+ )
26
+
27
+ from sagemaker.hyperpod.cli.constants.command_constants import NVIDIA_GPU_RESOURCE_LIMIT_KEY
28
+ from sagemaker.hyperpod.cli.service.discover_namespaces import DiscoverNamespaces
29
+
30
+ class ListPods:
31
+ def __init__(self):
32
+ return
33
+
34
+ def list_pods_for_training_job(
35
+ self,
36
+ job_name: str,
37
+ namespace: Optional[str],
38
+ pretty: Optional[bool],
39
+ ):
40
+ """
41
+ List pods associated with a training job
42
+ """
43
+ k8s_client = KubernetesClient()
44
+
45
+ if not namespace:
46
+ resource_attributes_template = V1ResourceAttributes(
47
+ verb="list",
48
+ group="",
49
+ resource="pods",
50
+ )
51
+ namespace = DiscoverNamespaces().discover_accessible_namespace(
52
+ resource_attributes_template
53
+ )
54
+
55
+ label_filter = f"training.kubeflow.org/job-name={job_name}"
56
+
57
+ try:
58
+ _pods: V1PodList = k8s_client.list_pods_with_labels(namespace, label_filter)
59
+ except ApiException as e:
60
+ raise RuntimeError(f"Unexpected API error: {e.reason} ({e.status})")
61
+
62
+ if pretty:
63
+ return self._generate_list_pods_output(_pods)
64
+ else:
65
+ return self._generate_pods_list(_pods)
66
+
67
+ def list_pods_and_get_requested_resources_group_by_node_name(
68
+ self,
69
+ ):
70
+ """
71
+ List pods for all namespaces and initialized by kubeflow.
72
+ Group by the node_name of the pod and the value is the
73
+ accelerator devices resources requested
74
+ """
75
+ k8s_client = KubernetesClient()
76
+
77
+ label_filter = f"training.kubeflow.org/job-name"
78
+ pods = k8s_client.list_pods_in_all_namespaces_with_labels(label_filter)
79
+
80
+ # Dictionary to hold total GPU/Neuron requests per node
81
+ accelerator_devices_requests_by_node = defaultdict(int)
82
+
83
+ # Loop through each pod and aggregate the GPU resource requests per node
84
+ for pod in pods:
85
+ node_name = pod.spec.node_name
86
+ # Check if the pod has a node_name assigned, if pod is not scheduled, it may not have node_name
87
+ if node_name:
88
+ for container in pod.spec.containers:
89
+ if container.resources and container.resources.requests:
90
+ gpu_request = container.resources.requests.get(NVIDIA_GPU_RESOURCE_LIMIT_KEY)
91
+ neuron_request = container.resources.requests.get(
92
+ "aws.amazon.com/neurondevice"
93
+ )
94
+ if gpu_request:
95
+ accelerator_devices_requests_by_node[node_name] += int(
96
+ gpu_request
97
+ )
98
+ if neuron_request:
99
+ accelerator_devices_requests_by_node[node_name] += int(
100
+ neuron_request
101
+ )
102
+
103
+ return accelerator_devices_requests_by_node
104
+
105
+ def _generate_list_pods_output(self, pods: V1PodList) -> Optional[str]:
106
+ output_pods = {"pods": []}
107
+ if pods.items and len(pods.items) > 0:
108
+ _pod: V1Pod
109
+ for _pod in pods.items:
110
+ if _pod.metadata and _pod.metadata.name and _pod.metadata.namespace:
111
+ name = _pod.metadata.name
112
+ namespace = _pod.metadata.namespace
113
+ status = None
114
+ creation_timestamp = None
115
+ if _pod.status and _pod.status.phase:
116
+ status = _pod.status.phase
117
+ if _pod.metadata.creation_timestamp:
118
+ creation_timestamp = str(_pod.metadata.creation_timestamp)
119
+ output_pods["pods"].append(
120
+ {
121
+ "PodName": name,
122
+ "Namespace": namespace,
123
+ "Status": status,
124
+ "CreationTime": creation_timestamp,
125
+ }
126
+ )
127
+
128
+ return json.dumps(output_pods, indent=1, sort_keys=False)
129
+
130
+ def _generate_pods_list(self, pods: V1PodList) -> List:
131
+ output_pods = []
132
+ if pods.items and len(pods.items) > 0:
133
+ _pod: V1Pod
134
+ for _pod in pods.items:
135
+ if _pod.metadata and _pod.metadata.name:
136
+ name = _pod.metadata.name
137
+ output_pods.append(name)
138
+ return output_pods
@@ -0,0 +1,178 @@
1
+ # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License"). You
4
+ # may not use this file except in compliance with the License. A copy of
5
+ # the License is located at
6
+ #
7
+ # http://aws.amazon.com/apache2.0/
8
+ #
9
+ # or in the "license" file accompanying this file. This file is
10
+ # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
11
+ # ANY KIND, either express or implied. See the License for the specific
12
+ # language governing permissions and limitations under the License.
13
+ from typing import List, Optional
14
+
15
+ import json
16
+ from datetime import datetime
17
+
18
+ from sagemaker.hyperpod.cli.clients.kubernetes_client import (
19
+ KubernetesClient,
20
+ )
21
+ from sagemaker.hyperpod.cli.utils import setup_logger
22
+ from kubernetes.client.rest import ApiException
23
+ from kubernetes.client import (
24
+ V1ResourceAttributes
25
+ )
26
+
27
+ from sagemaker.hyperpod.cli.constants.command_constants import KUEUE_WORKLOAD_PRIORITY_CLASS_LABEL_KEY, OutputFormat
28
+ from sagemaker.hyperpod.cli.constants.pytorch_constants import PYTORCH_CUSTOM_OBJECT_GROUP, PYTORCH_CUSTOM_OBJECT_PLURAL
29
+ from sagemaker.hyperpod.cli.service.discover_namespaces import DiscoverNamespaces
30
+ from tabulate import tabulate
31
+
32
+
33
+ class ListTrainingJobs:
34
+ def __init__(self):
35
+ return
36
+
37
+ def list_training_jobs(
38
+ self,
39
+ namespace: Optional[str],
40
+ all_namespaces: Optional[bool],
41
+ selector: Optional[str],
42
+ output: Optional[str],
43
+ ) -> str:
44
+ """
45
+ List training job provided by the user in the specified namespace.
46
+ If namespace is not provided job are listed the default namespace in user context
47
+ If all_namespace is true we will list training job from all namespaces that user has access
48
+ Selector when specified will filter list of job addisional based on labels filter provided
49
+ """
50
+ k8s_client = KubernetesClient()
51
+
52
+ jobs: List = []
53
+ logger = setup_logger(__name__)
54
+ logger.debug(namespace)
55
+ try:
56
+ if all_namespaces:
57
+ namespaces: List[str] = k8s_client.list_namespaces()
58
+ for _namespace in namespaces:
59
+ _jobs = k8s_client.list_training_jobs(
60
+ namespace=_namespace,
61
+ label_selector=selector,
62
+ )
63
+ if _jobs.get("items") and len(_jobs.get("items")) > 0:
64
+ for _job in _jobs.get("items"):
65
+ jobs.append(_job)
66
+ else:
67
+ if not namespace:
68
+ resource_attributes_template = V1ResourceAttributes(
69
+ verb="list",
70
+ group=PYTORCH_CUSTOM_OBJECT_GROUP,
71
+ resource=PYTORCH_CUSTOM_OBJECT_PLURAL,
72
+ )
73
+ namespace = DiscoverNamespaces().discover_accessible_namespace(
74
+ resource_attributes_template
75
+ )
76
+ else:
77
+ if not k8s_client.check_if_namespace_exists(namespace):
78
+ raise ValueError(f"Namespace {namespace} does not exist!")
79
+
80
+ namespace_jobs = k8s_client.list_training_jobs(
81
+ namespace=namespace,
82
+ label_selector=selector,
83
+ )
84
+ if namespace_jobs.get("items") and len(namespace_jobs.get("items")) > 0:
85
+ for namespace_job in namespace_jobs.get("items"):
86
+ jobs.append(namespace_job)
87
+ except ApiException as e:
88
+ raise RuntimeError(f"Unexpected API error: {e.reason} ({e.status})")
89
+
90
+ return self._generate_list_training_job_output(jobs, output)
91
+
92
+ def _generate_list_training_job_output(self, jobs: List, output: Optional[str]):
93
+ output_jobs = {"jobs": []}
94
+ priority_header_required = False
95
+
96
+ for job in jobs:
97
+ if job.get("metadata"):
98
+ name = job.get("metadata").get("name")
99
+ namespace = job.get("metadata").get("namespace")
100
+ creation_time = None
101
+ state = None
102
+ priority = self._get_job_priority(job)
103
+ if job.get("status"):
104
+ creation_time = job.get("status").get("startTime")
105
+ state = self._get_job_status(job.get("status").get("conditions"))
106
+
107
+ job_summary = {
108
+ "Name": name,
109
+ "Namespace": namespace,
110
+ "CreationTime": creation_time,
111
+ "State": state,
112
+ }
113
+
114
+ if priority is not None:
115
+ job_summary["priority"] = priority
116
+ priority_header_required = True
117
+
118
+ output_jobs["jobs"].append(job_summary)
119
+
120
+ if output == OutputFormat.TABLE.value:
121
+ return self._generate_table(output_jobs, priority_header_required)
122
+ return json.dumps(output_jobs, indent=4, sort_keys=False)
123
+
124
+ def _generate_table(self, output_jobs, priority_header_required):
125
+ headers = [
126
+ "Name",
127
+ "Namespace",
128
+ "CreationTime",
129
+ "State"
130
+ ]
131
+
132
+ if priority_header_required:
133
+ headers.append("Priority")
134
+
135
+ jobs = []
136
+ if "jobs" in output_jobs and isinstance(output_jobs["jobs"], list):
137
+ for job in output_jobs["jobs"]:
138
+ job_values = list(job.values())
139
+ if priority_header_required and len(job_values) == 4:
140
+ job_values.append("NA")
141
+ jobs.append(job_values)
142
+
143
+ return tabulate(jobs, headers=headers, tablefmt="presto")
144
+
145
+ def _get_job_status(self, status: List) -> Optional[str]:
146
+ current_status = None
147
+ last_date_time = datetime.strptime(
148
+ "2001-08-27T22:47:57Z",
149
+ "%Y-%m-%dT%H:%M:%SZ",
150
+ )
151
+ for state in status:
152
+ state_date_time = datetime.strptime(
153
+ state.get("lastTransitionTime"),
154
+ "%Y-%m-%dT%H:%M:%SZ",
155
+ )
156
+ if state_date_time >= last_date_time:
157
+ last_date_time = state_date_time
158
+ current_status = state.get("type")
159
+ return current_status
160
+
161
+ def _get_job_priority(self, job) -> Optional[str]:
162
+ worker_template = job.get("spec", {}).get("pytorchReplicaSpecs", {}).get("Worker", {}).get("template", {})
163
+ wl_priority_cls = worker_template.get("metadata", {}).get("labels", {}).get(KUEUE_WORKLOAD_PRIORITY_CLASS_LABEL_KEY, None)
164
+ spec_priority_cls = worker_template.get("spec", {}).get("priorityClassName", None)
165
+
166
+ # For reference: https://kueue.sigs.k8s.io/docs/concepts/workload_priority_class/
167
+ # The workload priority class takes precedence over the k8s priority class.
168
+ # Because the cli focuses on the job level which means workload priority is more essential.
169
+ # There is possibility that these two priorities coexist at the same time. In this case,
170
+ # the k8s priority class will be used as pod priority. cli should still take workload
171
+ # priority in this scenario.
172
+
173
+ if wl_priority_cls is not None:
174
+ return wl_priority_cls
175
+ elif spec_priority_cls is not None:
176
+ return spec_priority_cls
177
+
178
+ return None
@@ -0,0 +1,47 @@
1
+ # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License"). You
4
+ # may not use this file except in compliance with the License. A copy of
5
+ # the License is located at
6
+ #
7
+ # http://aws.amazon.com/apache2.0/
8
+ #
9
+ # or in the "license" file accompanying this file. This file is
10
+ # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
11
+ # ANY KIND, either express or implied. See the License for the specific
12
+ # language governing permissions and limitations under the License.
13
+ from sagemaker.hyperpod.cli.clients.kubernetes_client import (
14
+ KubernetesClient,
15
+ )
16
+ from kubernetes.client import (
17
+ V1SelfSubjectAccessReview,
18
+ V1SelfSubjectAccessReviewSpec,
19
+ )
20
+
21
+
22
+ class SelfSubjectAccessReview:
23
+ def __init__(self):
24
+ return
25
+
26
+ def self_subject_access_review(
27
+ self,
28
+ resource_attributes=None,
29
+ non_resource_attributes=None,
30
+ local_vars_configuration=None,
31
+ ):
32
+ """
33
+ Submit self subject access review
34
+ """
35
+ auth_v1_api = KubernetesClient().get_auth_v1_api()
36
+
37
+ access_review = V1SelfSubjectAccessReview(
38
+ spec=V1SelfSubjectAccessReviewSpec(
39
+ resource_attributes=resource_attributes,
40
+ non_resource_attributes=non_resource_attributes,
41
+ local_vars_configuration=local_vars_configuration,
42
+ )
43
+ )
44
+
45
+ response = auth_v1_api.create_self_subject_access_review(body=access_review)
46
+
47
+ return response
@@ -0,0 +1,12 @@
1
+ # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License"). You
4
+ # may not use this file except in compliance with the License. A copy of
5
+ # the License is located at
6
+ #
7
+ # http://aws.amazon.com/apache2.0/
8
+ #
9
+ # or in the "license" file accompanying this file. This file is
10
+ # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
11
+ # ANY KIND, either express or implied. See the License for the specific
12
+ # language governing permissions and limitations under the License.
@@ -0,0 +1,36 @@
1
+ # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License"). You
4
+ # may not use this file except in compliance with the License. A copy of
5
+ # the License is located at
6
+ #
7
+ # http://aws.amazon.com/apache2.0/
8
+ #
9
+ # or in the "license" file accompanying this file. This file is
10
+ # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
11
+ # ANY KIND, either express or implied. See the License for the specific
12
+ # language governing permissions and limitations under the License.
13
+ """Placeholder docstring"""
14
+
15
+ from __future__ import absolute_import
16
+
17
+ import importlib.metadata
18
+
19
+
20
+ CLI_PREFIX = "AWS-SageMaker-Hyperpod-CLI"
21
+
22
+
23
+ def get_user_agent_extra_suffix():
24
+ """Get the user agent extra suffix string specific to SageMaker Hyperpod CLI
25
+
26
+ Adhers to new boto recommended User-Agent 2.0 header format
27
+
28
+ Returns:
29
+ str: The user agent extra suffix string to be appended
30
+ """
31
+ suffix = "cli/{}#{}".format(
32
+ CLI_PREFIX,
33
+ importlib.metadata.version("sagemaker-hyperpod"),
34
+ )
35
+
36
+ return suffix
@@ -0,0 +1,12 @@
1
+ # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License"). You
4
+ # may not use this file except in compliance with the License. A copy of
5
+ # the License is located at
6
+ #
7
+ # http://aws.amazon.com/apache2.0/
8
+ #
9
+ # or in the "license" file accompanying this file. This file is
10
+ # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
11
+ # ANY KIND, either express or implied. See the License for the specific
12
+ # language governing permissions and limitations under the License.
@@ -0,0 +1,74 @@
1
+ # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License"). You
4
+ # may not use this file except in compliance with the License. A copy of
5
+ # the License is located at
6
+ #
7
+ # http://aws.amazon.com/apache2.0/
8
+ #
9
+ # or in the "license" file accompanying this file. This file is
10
+ # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
11
+ # ANY KIND, either express or implied. See the License for the specific
12
+ # language governing permissions and limitations under the License.
13
+ KUBERNETES_PYTORCH_JOB_TEMPLATE = """### Please keep template file unchanged ###
14
+ defaults:
15
+ - override hydra/job_logging: stdout
16
+
17
+ hydra:
18
+ run:
19
+ dir: .
20
+ output_subdir: null
21
+
22
+ training_cfg:
23
+ entry_script: ??? # Path to the entry script of training/fine-tuning. This path should be inside container or relative path in git repo
24
+ script_args: ??? # Entry script arguments
25
+ run:
26
+ nodes: ??? # Number of nodes to use for current training
27
+ ntasks_per_node: ??? # Number of tasks per node
28
+ cluster:
29
+ cluster_type: k8s # currently k8s only
30
+ instance_type: ???
31
+ cluster_config:
32
+ namespace: ??? # the namespace to submit job
33
+ custom_labels: ???
34
+ service_account_name: null
35
+ annotations: ???
36
+ priority_class_name: ???
37
+ # Create k8s NodeAffinity to select nodes to deploy jobs which matches required and preferred labels
38
+ # Structure:
39
+ # label_selector:
40
+ # required: <required label key-values pair>
41
+ # preferred: <preferred label key-values pair>
42
+ # weights: <weights list used by preferred labels to get nodes priority>
43
+ # Example:
44
+ # label_selector:
45
+ # required:
46
+ # example-label-key:
47
+ # - expected-label-value-1
48
+ # - expected-label-value-2
49
+ # preferred:
50
+ # preferred-label-key:
51
+ # - preferred-label-value-1
52
+ # - preferred-label-value-2
53
+ # weights:
54
+ # - 100
55
+ label_selector: ???
56
+ # persistent volume, usually used to mount FSx
57
+ persistent_volume_claims: null
58
+ pullPolicy: ??? # policy to pull container, can be Always, IfNotPresent and Never
59
+ restartPolicy: ??? # PyTorchJob restart policy
60
+ # temp volume, usually used to mount temp directory
61
+ # volumes, used to mount temp path to container
62
+ # example:
63
+ # volumes:
64
+ # - volumeName: data1
65
+ # hostPath: "/data"
66
+ # mountPath: "/data"
67
+ volumes: null
68
+
69
+ base_results_dir: ??? # Location to store the results, checkpoints and logs.
70
+ container: ??? # container to use
71
+
72
+ env_vars:
73
+ NCCL_DEBUG: INFO # Logging level for NCCL. Set to "INFO" for debug information
74
+ """