oks-cli 1.21__tar.gz → 1.22__tar.gz

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 (30) hide show
  1. {oks_cli-1.21 → oks_cli-1.22}/PKG-INFO +1 -1
  2. {oks_cli-1.21 → oks_cli-1.22}/oks_cli/cluster.py +4 -4
  3. {oks_cli-1.21 → oks_cli-1.22}/oks_cli/project.py +2 -1
  4. {oks_cli-1.21 → oks_cli-1.22}/oks_cli/user.py +35 -0
  5. {oks_cli-1.21 → oks_cli-1.22}/oks_cli/utils.py +34 -3
  6. {oks_cli-1.21 → oks_cli-1.22}/oks_cli.egg-info/PKG-INFO +1 -1
  7. {oks_cli-1.21 → oks_cli-1.22}/setup.py +1 -1
  8. {oks_cli-1.21 → oks_cli-1.22}/tests/test_user.py +33 -1
  9. {oks_cli-1.21 → oks_cli-1.22}/LICENSE +0 -0
  10. {oks_cli-1.21 → oks_cli-1.22}/README.md +0 -0
  11. {oks_cli-1.21 → oks_cli-1.22}/oks_cli/__init__.py +0 -0
  12. {oks_cli-1.21 → oks_cli-1.22}/oks_cli/cache.py +0 -0
  13. {oks_cli-1.21 → oks_cli-1.22}/oks_cli/main.py +0 -0
  14. {oks_cli-1.21 → oks_cli-1.22}/oks_cli/netpeering.py +0 -0
  15. {oks_cli-1.21 → oks_cli-1.22}/oks_cli/profile.py +0 -0
  16. {oks_cli-1.21 → oks_cli-1.22}/oks_cli/quotas.py +0 -0
  17. {oks_cli-1.21 → oks_cli-1.22}/oks_cli.egg-info/SOURCES.txt +0 -0
  18. {oks_cli-1.21 → oks_cli-1.22}/oks_cli.egg-info/dependency_links.txt +0 -0
  19. {oks_cli-1.21 → oks_cli-1.22}/oks_cli.egg-info/entry_points.txt +0 -0
  20. {oks_cli-1.21 → oks_cli-1.22}/oks_cli.egg-info/requires.txt +0 -0
  21. {oks_cli-1.21 → oks_cli-1.22}/oks_cli.egg-info/top_level.txt +0 -0
  22. {oks_cli-1.21 → oks_cli-1.22}/setup.cfg +0 -0
  23. {oks_cli-1.21 → oks_cli-1.22}/tests/test_cache.py +0 -0
  24. {oks_cli-1.21 → oks_cli-1.22}/tests/test_cluster.py +0 -0
  25. {oks_cli-1.21 → oks_cli-1.22}/tests/test_netpeering.py +0 -0
  26. {oks_cli-1.21 → oks_cli-1.22}/tests/test_nodepool.py +0 -0
  27. {oks_cli-1.21 → oks_cli-1.22}/tests/test_profile.py +0 -0
  28. {oks_cli-1.21 → oks_cli-1.22}/tests/test_project.py +0 -0
  29. {oks_cli-1.21 → oks_cli-1.22}/tests/test_quota.py +0 -0
  30. {oks_cli-1.21 → oks_cli-1.22}/tests/test_shell_completion.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: oks-cli
3
- Version: 1.21
3
+ Version: 1.22
4
4
  Author: Outscale SAS
5
5
  Author-email: opensource@outscale.com
6
6
  License: BSD
@@ -373,8 +373,8 @@ def _create_cluster(project_name, cluster_config, output):
373
373
  @click.option('--cidr-service', help='CIDR of services')
374
374
  @click.option('--control-plane', shell_complete=shell_completions, help="Controlplane plan")
375
375
  @click.option('--zone', '-z', multiple=True, shell_complete=shell_completions, help="List of Control Plane availability zones")
376
- @click.option('--enable-admission-plugins', help="List of admission plugins, separated by commas")
377
- @click.option('--disable-admission-plugins', help="List of admission plugins, separated by commas")
376
+ @click.option('--enable-admission-plugins', shell_complete=shell_completions, help="List of admission plugins, separated by commas")
377
+ @click.option('--disable-admission-plugins', shell_complete=shell_completions, help="List of admission plugins, separated by commas")
378
378
  @click.option('--quirk', '-q', multiple=True, help="Quirk")
379
379
  @click.option('--tags', '-t', help="Comma-separated list of tags, example: 'key1=value1,key2=value2'")
380
380
  @click.option('--disable-api-termination', type=click.BOOL, help="Disable delete action by API")
@@ -472,8 +472,8 @@ def cluster_create_command(ctx, project_name, cluster_name, description, admin,
472
472
  @click.option('--admin', '-a', help="Admin Whitelist ips. you can use 'my-ip' to automatically use your current IP.")
473
473
  @click.option('--version', '-v', shell_complete=shell_completions, help="Kubernetes version")
474
474
  @click.option('--tags', '-t', help="Comma-separated list of tags, example: 'key1=value1,key2=value2'")
475
- @click.option('--enable-admission-plugins', help="List of admission plugins, separated by commas")
476
- @click.option('--disable-admission-plugins', help="List of admission plugins, separated by commas")
475
+ @click.option('--enable-admission-plugins', shell_complete=shell_completions, help="List of admission plugins, separated by commas")
476
+ @click.option('--disable-admission-plugins', shell_complete=shell_completions, help="List of admission plugins, separated by commas")
477
477
  @click.option('--quirk', '-q', multiple=True, help="Quirk")
478
478
  @click.option('--disable-api-termination', type=click.BOOL, help="Disable delete action by API")
479
479
  @click.option('--control-plane', shell_complete=shell_completions, help="Controlplane plan")
@@ -365,7 +365,8 @@ def project_get_quotas(ctx, project_name, output, profile):
365
365
  ["Collection", "QuotaCollection"],
366
366
  ["Description", "ShortDescription"],
367
367
  ["Max Value", "MaxValue"],
368
- ["Used Value", "UsedValue"]])
368
+ ["Used Value", "UsedValue"],
369
+ ["AccountId", "AccountId"]])
369
370
  print_table(data["subregions"], [["Region", "RegionName"],
370
371
  ["Availability Zone", "SubregionName"],
371
372
  ["State", "State"]])
@@ -7,6 +7,7 @@ import json
7
7
 
8
8
  from nacl.public import PrivateKey, SealedBox
9
9
  from nacl.encoding import Base64Encoder
10
+ from prettytable import TableStyle
10
11
 
11
12
  from .utils import do_request, print_output, find_project_id_by_name, ctx_update, login_profile, profile_completer, project_completer, JSONClickException
12
13
 
@@ -166,4 +167,38 @@ def user_delete(ctx, project_name, user, output, dry_run, force, profile):
166
167
  if force or click.confirm(f"Are you sure you want to delete the user '{user}'?", abort=True):
167
168
  data = do_request("DELETE", f"projects/{project_id}/eim_users/{user}")
168
169
  print_output(data, output)
170
+
171
+
172
+ @user.command('types', help="List available user types")
173
+ @click.option('--project-name', '-p', required=False, help="Project Name", shell_complete=project_completer)
174
+ @click.option('--output', '-o', type=click.Choice(["json", "yaml"]), help="Specify output format")
175
+ @click.option('--plain', is_flag=True, help="Plain table format")
176
+ @click.option('--profile', help="Configuration profile to use", shell_complete=profile_completer)
177
+ @click.pass_context
178
+ def user_types(ctx, project_name, output, plain, profile):
179
+ """Display available user types."""
180
+ project_name, _, profile = ctx_update(ctx, project_name, None, profile)
181
+ login_profile(profile)
182
+
183
+ project_id = find_project_id_by_name(project_name)
184
+
185
+ data = do_request("GET", f'projects/{project_id}/eim_users/types')
186
+
187
+ if output:
188
+ print_output(data, output)
189
+ return
190
+
191
+ table = prettytable.PrettyTable()
192
+ table.field_names = ["USER TYPE", "DESCRIPTION"]
193
+
194
+ if plain:
195
+ table.set_style(TableStyle.PLAIN_COLUMNS)
196
+
197
+ for entry in data:
198
+ table.add_row([
199
+ entry.get("UserType", ""),
200
+ entry.get("Description") or "-"
201
+ ])
202
+
203
+ click.echo(table)
169
204
 
@@ -83,8 +83,12 @@ def find_response_object(data):
83
83
  return response["EimUsers"]
84
84
  elif key == "EimUser":
85
85
  return response["EimUser"]
86
+ elif key == "AdmissionPlugins":
87
+ return response["AdmissionPlugins"]
86
88
  elif key == "Data":
87
89
  return response
90
+ elif key == "EimUserTypes":
91
+ return response["EimUserTypes"]
88
92
 
89
93
  raise click.ClickException("The API response format is incorrect.")
90
94
 
@@ -847,9 +851,11 @@ def kubeconfig_parse_fields(kubeconfig, cluster_name, user, group):
847
851
 
848
852
  return kubedata
849
853
 
850
- def retrieve_cp_sized(filepath, endpoint):
854
+ def retrieve_cp_sized(filepath, endpoint, key = None):
851
855
  """Fetch control plane sizes from API and save to file."""
852
856
  cp_list = do_request("GET", endpoint)
857
+ if key:
858
+ cp_list = cp_list.get(key)
853
859
 
854
860
  with open(filepath, "w") as file:
855
861
  json.dump(cp_list, file)
@@ -871,6 +877,8 @@ def shell_completions(ctx, param: click.core.Option, incomplete):
871
877
  if profile not in profiles:
872
878
  return []
873
879
 
880
+ key = None
881
+
874
882
  login_profile(profile)
875
883
 
876
884
  if param.name == "version":
@@ -879,6 +887,16 @@ def shell_completions(ctx, param: click.core.Option, incomplete):
879
887
  endpoint = "clusters/limits/control_plane_plans"
880
888
  elif param.name == "zone":
881
889
  endpoint = "clusters/limits/cp_subregions"
890
+ elif param.name == "disable_admission_plugins" and ctx.params["version"]:
891
+ key = "DisableAdmissionPlugins"
892
+ version = ctx.params["version"]
893
+ endpoint = f"clusters/limits/admission_plugins?version={version}"
894
+ param.name += f".{version}"
895
+ elif param.name == "enable_admission_plugins" and ctx.params["version"]:
896
+ key = "EnableAdmissionPlugins"
897
+ version = ctx.params["version"]
898
+ endpoint = f"clusters/limits/admission_plugins?version={version}"
899
+ param.name += f".{version}"
882
900
  else:
883
901
  return []
884
902
 
@@ -888,9 +906,9 @@ def shell_completions(ctx, param: click.core.Option, incomplete):
888
906
  if os.path.exists(CP_SIZES_PATH):
889
907
  file_ctime = os.path.getctime(CP_SIZES_PATH)
890
908
  if datetime.timestamp(datetime.now()) - file_ctime > 300:
891
- retrieve_cp_sized(CP_SIZES_PATH, endpoint)
909
+ retrieve_cp_sized(CP_SIZES_PATH, endpoint, key)
892
910
  else:
893
- retrieve_cp_sized(CP_SIZES_PATH, endpoint)
911
+ retrieve_cp_sized(CP_SIZES_PATH, endpoint, key)
894
912
 
895
913
  if os.path.exists(CP_SIZES_PATH):
896
914
  with open(CP_SIZES_PATH, "r") as file:
@@ -898,6 +916,19 @@ def shell_completions(ctx, param: click.core.Option, incomplete):
898
916
  else:
899
917
  cp_list = []
900
918
 
919
+ # Handle comma-separated values
920
+ if "," in incomplete:
921
+ parts = incomplete.split(",")
922
+ selected = set(parts[:-1])
923
+ current = parts[-1]
924
+ prefix = ",".join(parts[:-1])
925
+
926
+ return [
927
+ f"{prefix},{item}"
928
+ for item in cp_list
929
+ if item.startswith(current) and item not in selected
930
+ ]
931
+
901
932
  return [k for k in cp_list if k.startswith(incomplete)]
902
933
 
903
934
  def update_shell_profile(shell_profile, filepath):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: oks-cli
3
- Version: 1.21
3
+ Version: 1.22
4
4
  Author: Outscale SAS
5
5
  Author-email: opensource@outscale.com
6
6
  License: BSD
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
2
2
 
3
3
  setup(
4
4
  name="oks-cli",
5
- version="1.21",
5
+ version="1.22",
6
6
  packages=['oks_cli'],
7
7
  author="Outscale SAS",
8
8
  author_email="opensource@outscale.com",
@@ -53,4 +53,36 @@ def test_user_delete_command(mock_request, add_default_profile):
53
53
  runner = CliRunner()
54
54
  result = runner.invoke(cli, ["user", "delete", "-p", "test", "-u", "OKSAuditor", "--force"])
55
55
  assert result.exit_code == 0
56
- assert 'User has been deleted.' in result.output
56
+ assert 'User has been deleted.' in result.output
57
+
58
+ @patch("oks_cli.utils.requests.request")
59
+ def test_user_types_command(mock_request, add_default_profile):
60
+ mock_request.side_effect = [
61
+ MagicMock(status_code=200, headers={}, json=lambda: {"ResponseContext": {}, "Projects": [{"id": "12345"}]}),
62
+ MagicMock(status_code=200, headers={}, json=lambda: {"ResponseContext": {}, "EimUserTypes": [
63
+ {"UserType": "OKSSnapshotsManager", "Description": "OKS user with full access to snapshots"},
64
+ {"UserType": "OKSVolumesManager", "Description": "OKS user with management access to volumes BSU"},
65
+ ]})
66
+ ]
67
+
68
+ runner = CliRunner()
69
+ result = runner.invoke(cli, ["user", "types", "-p", "test"])
70
+ assert result.exit_code == 0
71
+ assert 'OKSSnapshotsManager' in result.output
72
+ assert 'OKSVolumesManager' in result.output
73
+
74
+ @patch("oks_cli.utils.requests.request")
75
+ def test_user_types_command_json(mock_request, add_default_profile):
76
+ mock_request.side_effect = [
77
+ MagicMock(status_code=200, headers={}, json=lambda: {"ResponseContext": {}, "Projects": [{"id": "12345"}]}),
78
+ MagicMock(status_code=200, headers={}, json=lambda: {"ResponseContext": {}, "EimUserTypes": [
79
+ {"UserType": "OKSSnapshotsManager", "Description": "OKS user with full access to snapshots"},
80
+ {"UserType": "OKSVolumesManager", "Description": "OKS user with management access to volumes BSU"},
81
+ ]})
82
+ ]
83
+
84
+ runner = CliRunner()
85
+ result = runner.invoke(cli, ["user", "types", "-p", "test", "-o", "json"])
86
+ assert result.exit_code == 0
87
+ assert 'OKSSnapshotsManager' in result.output
88
+ assert 'OKS user with full access to snapshots' in result.output
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes