qwak-core 0.4.265__py3-none-any.whl → 0.4.266__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 (52) hide show
  1. frogml_storage/__init__.py +0 -0
  2. frogml_storage/_artifactory_api.py +315 -0
  3. frogml_storage/_environment.py +22 -0
  4. frogml_storage/_log_config.py +45 -0
  5. frogml_storage/_storage_utils.py +15 -0
  6. frogml_storage/_utils.py +69 -0
  7. frogml_storage/authentication/_authentication_utils.py +259 -0
  8. frogml_storage/authentication/models/_auth_config.py +70 -0
  9. frogml_storage/cli/_frogml_cli.py +40 -0
  10. frogml_storage/cli/_login_cli.py +240 -0
  11. frogml_storage/cli/commands/_login_command.py +74 -0
  12. frogml_storage/cli/models/_cli_login_arguments.py +22 -0
  13. frogml_storage/cli/utils/_cli_utils.py +19 -0
  14. frogml_storage/cli/utils/_login_checks_utility.py +114 -0
  15. frogml_storage/constants.py +56 -0
  16. frogml_storage/dataset_manifest.py +13 -0
  17. frogml_storage/entity_manifest.py +93 -0
  18. frogml_storage/exceptions/checksum_verification_error.py +3 -0
  19. frogml_storage/exceptions/validation_error.py +4 -0
  20. frogml_storage/frog_ml.py +668 -0
  21. frogml_storage/frogml_entity_type_info.py +46 -0
  22. frogml_storage/http/__init__.py +0 -0
  23. frogml_storage/http/http_client.py +83 -0
  24. frogml_storage/model_manifest.py +60 -0
  25. frogml_storage/models/_download_context.py +54 -0
  26. frogml_storage/models/frogml_dataset_version.py +21 -0
  27. frogml_storage/models/frogml_entity_version.py +34 -0
  28. frogml_storage/models/frogml_model_version.py +21 -0
  29. frogml_storage/serialization_metadata.py +15 -0
  30. frogml_storage/storage.py +140 -0
  31. frogml_storage/utils/_input_checks_utility.py +104 -0
  32. qwak/__init__.py +1 -1
  33. qwak/clients/instance_template/client.py +6 -4
  34. qwak/clients/prompt_manager/model_descriptor_mapper.py +21 -19
  35. qwak/feature_store/_common/artifact_utils.py +3 -3
  36. qwak/feature_store/data_sources/base.py +4 -4
  37. qwak/feature_store/data_sources/batch/athena.py +3 -3
  38. qwak/feature_store/feature_sets/streaming.py +3 -3
  39. qwak/feature_store/feature_sets/streaming_backfill.py +1 -1
  40. qwak/feature_store/online/client.py +6 -6
  41. qwak/feature_store/sinks/streaming/factory.py +1 -1
  42. qwak/inner/build_logic/phases/phase_010_fetch_model/fetch_strategy_manager/strategy/git/git_strategy.py +3 -3
  43. qwak/llmops/provider/openai/provider.py +3 -3
  44. qwak/model/tools/adapters/output.py +1 -1
  45. qwak/model/utils/feature_utils.py +12 -8
  46. qwak/model_loggers/artifact_logger.py +7 -7
  47. qwak/tools/logger/logger.py +1 -1
  48. qwak_core-0.4.266.dist-info/METADATA +419 -0
  49. {qwak_core-0.4.265.dist-info → qwak_core-0.4.266.dist-info}/RECORD +51 -19
  50. qwak_core-0.4.266.dist-info/entry_points.txt +3 -0
  51. qwak_core-0.4.265.dist-info/METADATA +0 -53
  52. {qwak_core-0.4.265.dist-info → qwak_core-0.4.266.dist-info}/WHEEL +0 -0
@@ -0,0 +1,259 @@
1
+ import http
2
+ import json
3
+ import os
4
+ from typing import Optional, Tuple, Union
5
+
6
+ import requests
7
+ from requests.auth import AuthBase, HTTPBasicAuth
8
+
9
+ from frogml_storage._artifactory_api import ArtifactoryApi
10
+ from frogml_storage._log_config import logger
11
+ from frogml_storage._utils import BearerAuth, EmptyAuth, join_url
12
+ from frogml_storage.authentication.models._auth_config import AuthConfig
13
+ from frogml_storage.cli.models._cli_login_arguments import LoginArguments
14
+ from frogml_storage.constants import (
15
+ CONFIG_FILE_PATH,
16
+ FROG_ML_CONFIG_ACCESS_TOKEN,
17
+ FROG_ML_CONFIG_ARTIFACTORY_URL,
18
+ FROG_ML_CONFIG_PASSWORD,
19
+ FROG_ML_CONFIG_USER,
20
+ JF_ACCESS_TOKEN,
21
+ JF_URL,
22
+ JFROG_CLI_CONFIG_ACCESS_TOKEN,
23
+ JFROG_CLI_CONFIG_ARTIFACTORY_URL,
24
+ JFROG_CLI_CONFIG_FILE_PATH,
25
+ JFROG_CLI_CONFIG_PASSWORD,
26
+ JFROG_CLI_CONFIG_URL,
27
+ JFROG_CLI_CONFIG_USER,
28
+ SERVER_ID,
29
+ )
30
+
31
+
32
+ def read_jfrog_cli_config() -> Union[dict, None]:
33
+ try:
34
+ with open(JFROG_CLI_CONFIG_FILE_PATH, "r") as file:
35
+ config_data = json.load(file)
36
+ return config_data
37
+ except FileNotFoundError:
38
+ logger.debug("JFrog cli config file was not found.")
39
+ return None
40
+ except json.JSONDecodeError as e:
41
+ print(f"JFrog cli config file is not a valid JSON {e}.")
42
+ return None
43
+
44
+
45
+ def read_frogml_config() -> Union[dict, None]:
46
+ try:
47
+ with open(CONFIG_FILE_PATH, "r") as file:
48
+ config_data = json.load(file)
49
+ return config_data
50
+ except FileNotFoundError:
51
+ logger.debug("FrogMl config file was not found.")
52
+ return None
53
+ except json.JSONDecodeError as e:
54
+ print(f"FrogMl config file is not a valid JSON {e}.")
55
+ return None
56
+
57
+
58
+ def parse_cli_config_server(server_config: dict) -> Union[LoginArguments, None]:
59
+ login_args = LoginArguments()
60
+ login_args.server_id = server_config.get(SERVER_ID)
61
+
62
+ if JFROG_CLI_CONFIG_ARTIFACTORY_URL in server_config:
63
+ login_args.artifactory_url = server_config.get(JFROG_CLI_CONFIG_ARTIFACTORY_URL)
64
+ elif (
65
+ JFROG_CLI_CONFIG_URL in server_config
66
+ and server_config.get(JFROG_CLI_CONFIG_URL) is not None
67
+ ):
68
+ login_args.artifactory_url = join_url(
69
+ server_config[JFROG_CLI_CONFIG_URL], "artifactory"
70
+ )
71
+ else:
72
+ logger.debug(
73
+ "Invalid JFrog CLI file, expected either artifactoryUrl or url in jfrog cli config file"
74
+ )
75
+ return None
76
+
77
+ if JFROG_CLI_CONFIG_ACCESS_TOKEN in server_config:
78
+ login_args.access_token = server_config.get(JFROG_CLI_CONFIG_ACCESS_TOKEN)
79
+ elif (
80
+ JFROG_CLI_CONFIG_USER in server_config
81
+ and JFROG_CLI_CONFIG_PASSWORD in server_config
82
+ ):
83
+ login_args.username = server_config.get(JFROG_CLI_CONFIG_USER)
84
+ login_args.password = server_config.get(JFROG_CLI_CONFIG_PASSWORD)
85
+ else:
86
+ logger.debug(
87
+ "Expected either accessToken or user/password in jfrog cli config file"
88
+ )
89
+ return None
90
+
91
+ return login_args
92
+
93
+
94
+ def get_frogml_configuration() -> Union[LoginArguments, None]:
95
+ frog_ml_config = read_frogml_config()
96
+ if (
97
+ frog_ml_config is not None
98
+ and frog_ml_config.get("servers") is not None
99
+ and len(frog_ml_config["servers"]) > 0
100
+ ):
101
+ server_config = frog_ml_config["servers"][0]
102
+ login_args = LoginArguments()
103
+ if FROG_ML_CONFIG_ARTIFACTORY_URL in server_config:
104
+ login_args.artifactory_url = server_config.get(
105
+ FROG_ML_CONFIG_ARTIFACTORY_URL
106
+ )
107
+ else:
108
+ logger.debug(
109
+ "Invalid FrogMl authentication file, expected either artifactory_url in FrogMl authentication file"
110
+ )
111
+ return None
112
+
113
+ if FROG_ML_CONFIG_ACCESS_TOKEN in server_config:
114
+ login_args.access_token = server_config.get(FROG_ML_CONFIG_ACCESS_TOKEN)
115
+ elif (
116
+ FROG_ML_CONFIG_USER in server_config
117
+ and FROG_ML_CONFIG_PASSWORD in server_config
118
+ ):
119
+ login_args.username = server_config.get(FROG_ML_CONFIG_USER)
120
+ login_args.password = server_config.get(FROG_ML_CONFIG_PASSWORD)
121
+ elif (
122
+ FROG_ML_CONFIG_USER in server_config
123
+ and FROG_ML_CONFIG_PASSWORD not in server_config
124
+ or (
125
+ FROG_ML_CONFIG_USER not in server_config
126
+ and FROG_ML_CONFIG_PASSWORD in server_config
127
+ )
128
+ ):
129
+ logger.debug(
130
+ "Invalid FrogMl authentication file, username or password is missing in FrogMl authentication file"
131
+ )
132
+ return None
133
+ elif (
134
+ login_args.username is None
135
+ and login_args.password is None
136
+ and login_args.access_token is None
137
+ ):
138
+ login_args.isAnonymous = True
139
+ return login_args
140
+ else:
141
+ return None
142
+
143
+
144
+ def get_encrypted_password(
145
+ auth_config: AuthConfig, auth_token: AuthBase
146
+ ) -> Optional[str]:
147
+ try:
148
+ response = ArtifactoryApi(
149
+ auth_config.artifactory_url, auth_token
150
+ ).encrypt_password()
151
+ if response.status_code != http.HTTPStatus.OK:
152
+ logger.debug(
153
+ f"Expected {http.HTTPStatus.OK} status but got {response.status_code} "
154
+ f"when using url {auth_config.artifactory_url}"
155
+ )
156
+ print("Error while trying to encrypt password.")
157
+ return None
158
+ return response.text
159
+ except requests.exceptions.RequestException as e:
160
+ print(f"Error while trying to encrypt password: {e}.")
161
+ return None
162
+
163
+
164
+ def save_auth_config(auth_config: AuthConfig) -> None:
165
+ file_content: dict[str, list] = {}
166
+ file_content.setdefault("servers", []).append(auth_config.to_json())
167
+ os.makedirs(os.path.dirname(CONFIG_FILE_PATH), exist_ok=True)
168
+ with open(CONFIG_FILE_PATH, "w") as file:
169
+ json.dump(file_content, file, indent=2)
170
+
171
+
172
+ def get_credentials(auth_config: Optional[AuthConfig] = None) -> Tuple[str, AuthBase]:
173
+ if not __should_use_file_auth(auth_config):
174
+ __validate_credentials(auth_config)
175
+ return __auth_config_to_auth_tuple(auth_config)
176
+ logger.debug(
177
+ "Login configuration not supplied, attempting to find environment variables"
178
+ )
179
+
180
+ if __should_use_environment_variables():
181
+ return get_environment_variables()
182
+
183
+ logger.debug(
184
+ "Environment variables not supplied, attempting to load configuration from file"
185
+ )
186
+
187
+ if os.path.exists(CONFIG_FILE_PATH):
188
+ return __read_credentials_from_file(CONFIG_FILE_PATH)
189
+ raise ValueError(
190
+ f"Configuration were not provided and configuration file not found in {CONFIG_FILE_PATH},"
191
+ f" either pass configuration in the constructor, add env variables or create the configuration file by "
192
+ f"running `frogml login`"
193
+ )
194
+
195
+
196
+ def __should_use_environment_variables() -> bool:
197
+ return os.getenv("JF_URL") is not None
198
+
199
+
200
+ def get_environment_variables() -> Tuple[str, AuthBase]:
201
+ auth_config: AuthConfig = AuthConfig(
202
+ artifactory_url=os.getenv(JF_URL),
203
+ access_token=os.getenv(JF_ACCESS_TOKEN),
204
+ )
205
+
206
+ return __auth_config_to_auth_tuple(auth_config)
207
+
208
+
209
+ def __should_use_file_auth(credentials: Optional[AuthConfig] = None) -> bool:
210
+ return credentials is None or (
211
+ credentials.artifactory_url is None
212
+ and credentials.user is None
213
+ and credentials.password is None
214
+ and credentials.access_token is None
215
+ )
216
+
217
+
218
+ def __validate_credentials(credentials: Optional[AuthConfig]) -> None:
219
+ if credentials is None:
220
+ raise ValueError("Credentials must be provided.")
221
+ if credentials.artifactory_url is None:
222
+ raise ValueError("Credentials must contain artifactory url.")
223
+ return None
224
+
225
+
226
+ def __read_credentials_from_file(file_path: str) -> Tuple[str, AuthBase]:
227
+ try:
228
+ with open(file_path, "r") as file:
229
+ config_content: dict = json.load(file)
230
+ servers = config_content.get("servers")
231
+ if servers is None or len(servers) == 0:
232
+ raise ValueError(
233
+ "Configuration file was found but it's empty, failing authentication"
234
+ )
235
+ server = servers[0]
236
+ return __auth_config_to_auth_tuple(AuthConfig.from_dict(server))
237
+ except json.JSONDecodeError:
238
+ raise ValueError(f"Error when reading {file_path}, please recreate the file.")
239
+
240
+
241
+ def __auth_config_to_auth_tuple(
242
+ auth_config: Optional[AuthConfig],
243
+ ) -> Tuple[str, AuthBase]:
244
+
245
+ if auth_config is None:
246
+ raise ValueError("No authentication configuration provided")
247
+
248
+ auth: AuthBase = EmptyAuth()
249
+ if auth_config.access_token is not None:
250
+ auth = BearerAuth(auth_config.access_token)
251
+ elif auth_config.user is not None and auth_config.password is not None:
252
+ auth = HTTPBasicAuth(auth_config.user, auth_config.password)
253
+ elif auth_config.user is not None or auth_config.password is not None:
254
+ raise ValueError("User and password must be provided together")
255
+
256
+ if auth_config.artifactory_url is None:
257
+ raise ValueError("No artifactory URL provided")
258
+
259
+ return auth_config.artifactory_url, auth
@@ -0,0 +1,70 @@
1
+ from typing import Optional
2
+
3
+ from frogml_storage.constants import (
4
+ FROG_ML_CONFIG_ACCESS_TOKEN,
5
+ FROG_ML_CONFIG_ARTIFACTORY_URL,
6
+ FROG_ML_CONFIG_PASSWORD,
7
+ FROG_ML_CONFIG_USER,
8
+ SERVER_ID,
9
+ )
10
+
11
+
12
+ class AuthConfig(object):
13
+ def __init__(
14
+ self,
15
+ artifactory_url: Optional[str] = None,
16
+ access_token: Optional[str] = None,
17
+ user: Optional[str] = None,
18
+ password: Optional[str] = None,
19
+ server_id: Optional[str] = None,
20
+ ) -> None:
21
+ self.artifactory_url = artifactory_url
22
+ self.user = user
23
+ self.password = password
24
+ self.access_token = access_token
25
+ self.server_id = server_id
26
+
27
+ def to_json(self):
28
+ include_keys = [
29
+ FROG_ML_CONFIG_ARTIFACTORY_URL,
30
+ FROG_ML_CONFIG_USER,
31
+ FROG_ML_CONFIG_PASSWORD,
32
+ FROG_ML_CONFIG_ACCESS_TOKEN,
33
+ SERVER_ID,
34
+ ]
35
+ return {
36
+ key: getattr(self, key)
37
+ for key in include_keys
38
+ if getattr(self, key) is not None
39
+ }
40
+
41
+ @classmethod
42
+ def by_access_token(cls, artifactory_url: str, access_token: str) -> "AuthConfig":
43
+ return cls(
44
+ artifactory_url=artifactory_url,
45
+ access_token=access_token,
46
+ )
47
+
48
+ @classmethod
49
+ def by_basic_auth(
50
+ cls, artifactory_url: str, user: str, password: str
51
+ ) -> "AuthConfig":
52
+ return cls(
53
+ artifactory_url=artifactory_url,
54
+ user=user,
55
+ password=password,
56
+ )
57
+
58
+ @classmethod
59
+ def by_server_id(cls, server_id: str) -> "AuthConfig":
60
+ return cls(server_id=server_id)
61
+
62
+ @classmethod
63
+ def from_dict(cls, data: dict) -> "AuthConfig":
64
+ return cls(
65
+ artifactory_url=data.get(FROG_ML_CONFIG_ARTIFACTORY_URL),
66
+ access_token=data.get(FROG_ML_CONFIG_ACCESS_TOKEN),
67
+ server_id=data.get(SERVER_ID),
68
+ user=data.get(FROG_ML_CONFIG_USER),
69
+ password=data.get(FROG_ML_CONFIG_PASSWORD),
70
+ )
@@ -0,0 +1,40 @@
1
+ from typing import Optional
2
+
3
+ import typer
4
+ from typing_extensions import Annotated
5
+
6
+ from frogml_storage.cli._login_cli import login as prompt_login
7
+
8
+ app = typer.Typer(add_completion=False)
9
+
10
+
11
+ @app.command("login")
12
+ def login(
13
+ url: Annotated[Optional[str], typer.Option(help="Artifactory base url")] = None,
14
+ username: Annotated[Optional[str], typer.Option(help="The user's username")] = None,
15
+ password: Annotated[Optional[str], typer.Option(help="The user's password")] = None,
16
+ token: Annotated[
17
+ Optional[str], typer.Option(help="Access token to authenticate")
18
+ ] = None,
19
+ anonymous: Annotated[
20
+ bool, typer.Option(help="Run login as anonymous user")
21
+ ] = False,
22
+ interactive: Annotated[
23
+ bool, typer.Option(help="Login with interactive flow")
24
+ ] = False,
25
+ ) -> None:
26
+ # url_value = url if url is not None else ""
27
+ prompt_login(url, username, password, token, anonymous, interactive)
28
+
29
+
30
+ @app.callback()
31
+ def callback():
32
+ pass
33
+
34
+
35
+ def main():
36
+ app()
37
+
38
+
39
+ if __name__ == "__main__":
40
+ main()
@@ -0,0 +1,240 @@
1
+ from typing import List, Optional, Union
2
+
3
+ import typer
4
+
5
+ from frogml_storage._utils import assemble_artifact_url, join_url
6
+ from frogml_storage.authentication._authentication_utils import (
7
+ get_frogml_configuration,
8
+ parse_cli_config_server,
9
+ read_jfrog_cli_config,
10
+ )
11
+ from frogml_storage.authentication.models._auth_config import AuthConfig
12
+ from frogml_storage.cli.commands._login_command import run as run_login
13
+ from frogml_storage.cli.models._cli_login_arguments import LoginArguments
14
+ from frogml_storage.cli.utils._cli_utils import get_list_of_servers_from_config
15
+ from frogml_storage.cli.utils._login_checks_utility import (
16
+ is_login_command_without_params,
17
+ login_input_checks,
18
+ )
19
+ from frogml_storage.constants import CONFIG_FILE_PATH, JFROG_CLI_CONFIG_FILE_PATH
20
+
21
+
22
+ def login(
23
+ url: Optional[str],
24
+ username: Optional[str],
25
+ password: Optional[str],
26
+ token: Optional[str],
27
+ anonymous: Optional[bool],
28
+ is_interactive: Optional[bool],
29
+ ) -> bool:
30
+ if anonymous is None:
31
+ anonymous = False
32
+ if is_login_command_without_params(url, username, password, token, anonymous):
33
+ if not is_interactive:
34
+ return __login_by_frogml_configuration_file_flow()
35
+ else:
36
+ return __interactive_flow()
37
+ elif login_input_checks(url, username, password, token, anonymous):
38
+ url = assemble_artifact_url(url)
39
+ return __login_by_command_line_params(url, username, password, token, anonymous)
40
+ else:
41
+ typer.echo(
42
+ f"{__get_failed_reason(url, username, password, token, anonymous)}Login failed"
43
+ )
44
+ return False
45
+
46
+
47
+ def __get_failed_reason(
48
+ url: Optional[str],
49
+ username: Optional[str],
50
+ password: Optional[str],
51
+ token: Optional[str],
52
+ anonymous: Optional[bool],
53
+ ) -> str:
54
+ details = ""
55
+ if url is None:
56
+ details += "Url is required.\n"
57
+ if token is not None and (
58
+ any(params is not None for params in [username, password])
59
+ ):
60
+ details += "Token is specified when username/password is specified.\n"
61
+ if anonymous is True and any(
62
+ params is not None for params in [username, password, token]
63
+ ):
64
+ details += "Anonymous is specified with authentication details.\n"
65
+ if username is None and password is not None:
66
+ details += "Username is required when password is specified.\n"
67
+ elif username is not None and password is None:
68
+ details += "Password is required when username is specified.\n"
69
+ return details
70
+
71
+
72
+ def __run_interactive_mode() -> Union[LoginArguments, None]:
73
+ jfrog_cli_config = read_jfrog_cli_config()
74
+
75
+ if jfrog_cli_config is not None:
76
+ jfrog_cli_servers = get_list_of_servers_from_config(jfrog_cli_config)
77
+ if jfrog_cli_servers is not None and len(jfrog_cli_servers) > 0:
78
+ login_method_id = typer.prompt(
79
+ f"Please select from the following options:\n" # nosec B608
80
+ f"1.Login by jfrog-cli configuration file: {JFROG_CLI_CONFIG_FILE_PATH}\n"
81
+ f"2.Connecting to a new server\n"
82
+ )
83
+
84
+ while (
85
+ not login_method_id.isdigit()
86
+ or int(login_method_id) > 2
87
+ or int(login_method_id) <= 0
88
+ ):
89
+ login_method_id = typer.prompt(
90
+ "Bad Input. Choose your preferred login option"
91
+ )
92
+
93
+ login_method_id = int(login_method_id)
94
+ if login_method_id == 1:
95
+ return __prompt_jfrog_cli_configuration_list(
96
+ jfrog_cli_config, jfrog_cli_servers
97
+ )
98
+
99
+ return __prompt_manual_details()
100
+
101
+ return None
102
+
103
+
104
+ def __prompt_manual_details() -> Union[LoginArguments, None]:
105
+ login_args = LoginArguments()
106
+ login_args.artifactory_url = typer.prompt("Enter artifactory base url")
107
+
108
+ if login_args.artifactory_url is not None:
109
+ login_args.artifactory_url = join_url(login_args.artifactory_url, "artifactory")
110
+
111
+ auth_options = ["Username and Password", "Access Token", "Anonymous Access"]
112
+ authentication_types = ""
113
+ for index, item in enumerate(auth_options):
114
+ authentication_types += f"{index}: {item} \n"
115
+ selected_auth_type = typer.prompt(
116
+ f"Choose your preferred authentication option:\n{authentication_types}"
117
+ )
118
+ while (
119
+ not selected_auth_type.isdigit()
120
+ or int(selected_auth_type) >= len(auth_options)
121
+ or int(selected_auth_type) < 0
122
+ ):
123
+ selected_auth_type = typer.prompt(
124
+ "Bad Input. Choose your preferred authentication"
125
+ )
126
+ selected_auth_type = int(selected_auth_type)
127
+ if selected_auth_type == 0:
128
+ return __prompt_username_password(login_args)
129
+ elif selected_auth_type == 1:
130
+ return __prompt_access_token(login_args)
131
+ elif selected_auth_type == 2:
132
+ login_args.isAnonymous = True
133
+ return login_args
134
+ return None
135
+
136
+
137
+ def __prompt_username_password(login_args: LoginArguments) -> LoginArguments:
138
+ username = typer.prompt("Enter JFrog user name")
139
+ password = typer.prompt("Enter JFrog password", hide_input=True)
140
+ login_args.username = username
141
+ login_args.password = password
142
+ return login_args
143
+
144
+
145
+ def __prompt_access_token(login_args: LoginArguments) -> LoginArguments:
146
+ token = typer.prompt("Enter JFrog access token", hide_input=True)
147
+ login_args.access_token = token
148
+ return login_args
149
+
150
+
151
+ def __prompt_jfrog_cli_configuration_list(
152
+ jfrog_cli_config: dict, jfrog_cli_servers: List[str]
153
+ ) -> Union[LoginArguments, None]:
154
+ list_server_options = ""
155
+ for index, item in enumerate(jfrog_cli_servers):
156
+ list_server_options += f"{index}: {item}\n"
157
+ server_index_cli_conf = typer.prompt(
158
+ f"Found the following servers in your JFrog CLI configuration, "
159
+ f"choose one of the following:\n{list_server_options}"
160
+ )
161
+ while (
162
+ not server_index_cli_conf.isdigit()
163
+ or int(server_index_cli_conf) < 0
164
+ or int(server_index_cli_conf) >= len(jfrog_cli_servers)
165
+ ):
166
+ server_index_cli_conf = typer.prompt(
167
+ "Invalid choice. Please choose a number from the list"
168
+ )
169
+ server_index_cli_conf = int(server_index_cli_conf)
170
+ typer.echo(f"{jfrog_cli_servers[server_index_cli_conf]} was chosen")
171
+ servers = jfrog_cli_config.get("servers")
172
+ if servers is not None:
173
+ return parse_cli_config_server(servers[server_index_cli_conf])
174
+ else:
175
+ raise ValueError("No servers found in the JFrog CLI configuration.")
176
+
177
+
178
+ def __execute_login(auth_config: AuthConfig, anonymous: bool) -> bool:
179
+ if run_login(auth_config, anonymous):
180
+ success_message = "Logged in successfully"
181
+ if auth_config.artifactory_url is not None:
182
+ success_message += (
183
+ f" to: {auth_config.artifactory_url.replace('/artifactory', '')}"
184
+ )
185
+ typer.echo(success_message)
186
+ return True
187
+ else:
188
+ typer.echo("Failed to login, bad authentication")
189
+ return False
190
+
191
+
192
+ def __login_by_frogml_configuration_file_flow() -> bool:
193
+ login_args = get_frogml_configuration()
194
+ auth_config = None
195
+ if login_args is not None:
196
+ typer.echo(
197
+ f"Using existing frogml authentication config file: {CONFIG_FILE_PATH}"
198
+ )
199
+ auth_config = AuthConfig(
200
+ artifactory_url=login_args.artifactory_url,
201
+ user=login_args.username,
202
+ password=login_args.password,
203
+ access_token=login_args.access_token,
204
+ )
205
+
206
+ if (
207
+ auth_config is not None
208
+ and login_args is not None
209
+ and __execute_login(auth_config, login_args.isAnonymous)
210
+ ):
211
+ return True
212
+
213
+ return __interactive_flow()
214
+
215
+
216
+ def __interactive_flow() -> bool:
217
+ login_args = __run_interactive_mode()
218
+ if login_args is not None:
219
+ auth_config = AuthConfig(
220
+ artifactory_url=login_args.artifactory_url,
221
+ user=login_args.username,
222
+ password=login_args.password,
223
+ access_token=login_args.access_token,
224
+ )
225
+ return __execute_login(auth_config, login_args.isAnonymous)
226
+ return False
227
+
228
+
229
+ def __login_by_command_line_params(
230
+ url: str,
231
+ username: Optional[str],
232
+ password: Optional[str],
233
+ token: Optional[str],
234
+ anonymous: Optional[bool],
235
+ ) -> bool:
236
+ anonymous_value = anonymous if anonymous is not None else False
237
+ auth_config = AuthConfig(
238
+ artifactory_url=url, user=username, password=password, access_token=token
239
+ )
240
+ return __execute_login(auth_config, anonymous_value)
@@ -0,0 +1,74 @@
1
+ import http
2
+ from typing import Optional
3
+
4
+ import requests
5
+ from requests.auth import AuthBase, HTTPBasicAuth
6
+
7
+ from frogml_storage._artifactory_api import ArtifactoryApi
8
+ from frogml_storage._log_config import logger
9
+ from frogml_storage._utils import BearerAuth, EmptyAuth
10
+ from frogml_storage.authentication._authentication_utils import (
11
+ get_encrypted_password,
12
+ save_auth_config,
13
+ )
14
+ from frogml_storage.authentication.models._auth_config import AuthConfig
15
+ from frogml_storage.cli.utils._login_checks_utility import (
16
+ is_access_token_login,
17
+ is_anonymous_login,
18
+ is_username_password_login,
19
+ )
20
+
21
+
22
+ def run(auth_config: AuthConfig, anonymous: Optional[bool] = False) -> bool:
23
+ if is_username_password_login(auth_config, anonymous):
24
+ connection_validation_result = __login_by_username_password(auth_config)
25
+ elif is_access_token_login(auth_config, anonymous):
26
+ connection_validation_result = __validate_server_connection(
27
+ auth_config, BearerAuth(auth_config.access_token)
28
+ )
29
+ elif is_anonymous_login(auth_config, anonymous):
30
+ connection_validation_result = __validate_server_connection(
31
+ auth_config, EmptyAuth()
32
+ )
33
+ else:
34
+ connection_validation_result = False
35
+
36
+ if connection_validation_result:
37
+ save_auth_config(auth_config)
38
+ return connection_validation_result
39
+
40
+
41
+ def __login_by_username_password(auth_config: AuthConfig) -> bool:
42
+ if auth_config.user is not None and auth_config.password is not None:
43
+ auth_token = HTTPBasicAuth(auth_config.user, auth_config.password)
44
+ connection_validation_result = __validate_server_connection(
45
+ auth_config, auth_token
46
+ )
47
+ if connection_validation_result:
48
+ encrypted_password = get_encrypted_password(auth_config, auth_token)
49
+ if encrypted_password is not None:
50
+ auth_config.password = encrypted_password
51
+ return True
52
+ return False
53
+
54
+
55
+ def __validate_server_connection(auth_config: AuthConfig, auth_token: AuthBase) -> bool:
56
+ success = False
57
+ try:
58
+ logger.debug("Attempting to ping artifactory")
59
+ response = ArtifactoryApi(auth_config.artifactory_url, auth_token).ping()
60
+ if response.status_code == http.HTTPStatus.OK:
61
+ success = True
62
+ else:
63
+ logger.debug(
64
+ f"Expected {http.HTTPStatus.OK} status but got {response.status_code} "
65
+ f"when using url {auth_config.artifactory_url}"
66
+ )
67
+ except requests.exceptions.ConnectionError as e:
68
+ logger.debug(f"Unable to connect to the provided url :{e}.")
69
+ except requests.exceptions.MissingSchema as e:
70
+ logger.debug(f"Invalid Artifactory URL provided: {e}.")
71
+ except requests.exceptions.RequestException as e:
72
+ logger.debug(f"Unexpected request exception: {e}.")
73
+ finally:
74
+ return success