cortexapps-cli 1.7.0__tar.gz → 1.10.0__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 (59) hide show
  1. {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/PKG-INFO +2 -2
  2. {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/backup.py +4 -0
  3. {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/integrations_commands/newrelic.py +59 -21
  4. {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/cortex_client.py +23 -2
  5. {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/pyproject.toml +2 -2
  6. {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/LICENSE +0 -0
  7. {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/README.rst +0 -0
  8. {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/cli.py +0 -0
  9. {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/command_options.py +0 -0
  10. {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/api_keys.py +0 -0
  11. {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/audit_logs.py +0 -0
  12. {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/backup_commands/cortex_export.py +0 -0
  13. {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/catalog.py +0 -0
  14. {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/custom_data.py +0 -0
  15. {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/custom_events.py +0 -0
  16. {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/custom_metrics.py +0 -0
  17. {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/dependencies.py +0 -0
  18. {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/deploys.py +0 -0
  19. {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/discovery_audit.py +0 -0
  20. {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/docs.py +0 -0
  21. {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/entity_relationship_types.py +0 -0
  22. {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/entity_relationships.py +0 -0
  23. {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/entity_types.py +0 -0
  24. {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/gitops_logs.py +0 -0
  25. {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/groups.py +0 -0
  26. {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/initiatives.py +0 -0
  27. {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/integrations.py +0 -0
  28. {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/integrations_commands/aws.py +0 -0
  29. {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/integrations_commands/azure_devops.py +0 -0
  30. {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/integrations_commands/azure_resources.py +0 -0
  31. {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/integrations_commands/circleci.py +0 -0
  32. {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/integrations_commands/coralogix.py +0 -0
  33. {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/integrations_commands/datadog.py +0 -0
  34. {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/integrations_commands/github.py +0 -0
  35. {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/integrations_commands/gitlab.py +0 -0
  36. {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/integrations_commands/incidentio.py +0 -0
  37. {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/integrations_commands/launchdarkly.py +0 -0
  38. {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/integrations_commands/pagerduty.py +0 -0
  39. {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/integrations_commands/prometheus.py +0 -0
  40. {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/integrations_commands/sonarqube.py +0 -0
  41. {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/ip_allowlist.py +0 -0
  42. {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/on_call.py +0 -0
  43. {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/packages.py +0 -0
  44. {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/packages_commands/go.py +0 -0
  45. {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/packages_commands/java.py +0 -0
  46. {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/packages_commands/node.py +0 -0
  47. {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/packages_commands/nuget.py +0 -0
  48. {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/packages_commands/python.py +0 -0
  49. {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/plugins.py +0 -0
  50. {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/queries.py +0 -0
  51. {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/rest.py +0 -0
  52. {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/scim.py +0 -0
  53. {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/scorecards.py +0 -0
  54. {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/scorecards_commands/exemptions.py +0 -0
  55. {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/secrets.py +0 -0
  56. {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/teams.py +0 -0
  57. {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/workflows.py +0 -0
  58. {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/models/team.py +0 -0
  59. {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cortexapps-cli
3
- Version: 1.7.0
3
+ Version: 1.10.0
4
4
  Summary: Command Line Interface for cortexapps
5
5
  License: MIT
6
6
  License-File: LICENSE
@@ -18,7 +18,7 @@ Requires-Dist: click (<8.2)
18
18
  Requires-Dist: pyyaml (>=6.0.1,<7)
19
19
  Requires-Dist: requests (>=2.32.4,<3.0.0)
20
20
  Requires-Dist: typer (>=0.12.5,<0.13.0)
21
- Requires-Dist: urllib3 (>=2.2.2)
21
+ Requires-Dist: urllib3 (>=2.6.0)
22
22
  Project-URL: Bug Tracker, https://github.com/cortexapps/cli/issues
23
23
  Project-URL: Changes, https://github.com/cortexapps/cli/blob/main/HISTORY.md
24
24
  Project-URL: Documentation, https://github.com/cortexapps/cli/blob/main/README.rst
@@ -698,3 +698,7 @@ def import_tenant(
698
698
  print(f"cortex scorecards create -f \"{file_path}\"")
699
699
  elif import_type == "workflows":
700
700
  print(f"cortex workflows create -f \"{file_path}\"")
701
+
702
+ # Exit with non-zero code if any imports failed
703
+ if total_failed > 0:
704
+ raise typer.Exit(1)
@@ -1,16 +1,24 @@
1
+ from enum import Enum
1
2
  import json
2
3
  from rich import print_json
3
4
  import typer
4
5
  from typing_extensions import Annotated
6
+ from cortexapps_cli.command_options import ListCommandOptions
7
+ from cortexapps_cli.utils import print_output_with_context
5
8
 
6
9
  app = typer.Typer(help="New Relic commands", no_args_is_help=True)
7
10
 
8
- @app.command()
11
+ class Region(str, Enum):
12
+ US = "US"
13
+ EU = "EU"
14
+
15
+ @app.command(no_args_is_help=True)
9
16
  def add(
10
17
  ctx: typer.Context,
11
- alias: str = typer.Option(..., "--alias", "-a", help="Alias for this configuration"),
12
- api_key: str = typer.Option(..., "--api-key", "-api", help="API key"),
13
- host: str = typer.Option(None, "--host", "-h", help="Optional host name"),
18
+ alias: str = typer.Option(None, "--alias", "-a", help="Alias for this configuration"),
19
+ account_id: str = typer.Option(None, "--account-id", "-acc", help="New Relic account ID"),
20
+ personal_key: str = typer.Option(None, "--personal-key", "-pk", help="New Relic personal API key"),
21
+ region: Region = typer.Option(Region.US, "--region", "-r", help="Region (US or EU)"),
14
22
  is_default: bool = typer.Option(False, "--is-default", "-i", help="If this is the default configuration"),
15
23
  file_input: Annotated[typer.FileText, typer.Option("--file", "-f", help="JSON file containing configurations, if command line options not used; can be passed as stdin with -, example: -f-")] = None,
16
24
  ):
@@ -21,40 +29,56 @@ def add(
21
29
  client = ctx.obj["client"]
22
30
 
23
31
  if file_input:
24
- if alias or api_key or is_default or host:
25
- raise typer.BadParameter("When providing a custom event definition file, do not specify any other custom event attributes")
32
+ if alias or account_id or personal_key:
33
+ raise typer.BadParameter("When providing a file, do not specify --alias, --account-id, or --personal-key")
26
34
  data = json.loads("".join([line for line in file_input]))
27
35
  else:
36
+ if not alias or not account_id or not personal_key:
37
+ raise typer.BadParameter("--alias, --account-id, and --personal-key are required when not using --file")
38
+ if not personal_key.startswith("NRAK"):
39
+ raise typer.BadParameter("--personal-key must start with 'NRAK'")
28
40
  data = {
29
41
  "alias": alias,
30
- "apiKey": api_key,
31
- "host": host,
42
+ "accountId": account_id,
43
+ "personalKey": personal_key,
44
+ "region": region.value,
32
45
  "isDefault": is_default,
33
- }
46
+ }
34
47
 
35
- # remove any data elements that are None - can only be is_default
36
- data = {k: v for k, v in data.items() if v is not None}
37
-
38
48
  r = client.post("api/v1/newrelic/configuration", data=data)
39
49
  print_json(data=r)
40
50
 
41
- @app.command()
51
+ @app.command(no_args_is_help=True)
42
52
  def add_multiple(
43
53
  ctx: typer.Context,
44
54
  file_input: Annotated[typer.FileText, typer.Option("--file", "-f", help="JSON file containing configurations; can be passed as stdin with -, example: -f-")] = None,
45
55
  ):
46
56
  """
47
57
  Add multiple configurations
58
+
59
+ JSON file format:
60
+ \b
61
+ {
62
+ "configurations": [
63
+ {
64
+ "accountId": 1,
65
+ "alias": "text",
66
+ "isDefault": true,
67
+ "personalKey": "text",
68
+ "region": "US"
69
+ }
70
+ ]
71
+ }
48
72
  """
49
73
 
50
74
  client = ctx.obj["client"]
51
75
 
52
76
  data = json.loads("".join([line for line in file_input]))
53
77
 
54
- r = client.put("api/v1/newrelic/configurations", data=data)
78
+ r = client.post("api/v1/newrelic/configurations", data=data)
55
79
  print_json(data=r)
56
80
 
57
- @app.command()
81
+ @app.command(no_args_is_help=True)
58
82
  def delete(
59
83
  ctx: typer.Context,
60
84
  alias: str = typer.Option(..., "--alias", "-a", help="The alias of the configuration"),
@@ -81,7 +105,7 @@ def delete_all(
81
105
  r = client.delete("api/v1/newrelic/configurations")
82
106
  print_json(data=r)
83
107
 
84
- @app.command()
108
+ @app.command(no_args_is_help=True)
85
109
  def get(
86
110
  ctx: typer.Context,
87
111
  alias: str = typer.Option(..., "--alias", "-a", help="The alias of the configuration"),
@@ -98,6 +122,12 @@ def get(
98
122
  @app.command()
99
123
  def list(
100
124
  ctx: typer.Context,
125
+ table_output: ListCommandOptions.table_output = False,
126
+ csv_output: ListCommandOptions.csv_output = False,
127
+ columns: ListCommandOptions.columns = [],
128
+ no_headers: ListCommandOptions.no_headers = False,
129
+ filters: ListCommandOptions.filters = [],
130
+ sort: ListCommandOptions.sort = [],
101
131
  ):
102
132
  """
103
133
  Get all configurations
@@ -105,8 +135,16 @@ def list(
105
135
 
106
136
  client = ctx.obj["client"]
107
137
 
138
+ if (table_output or csv_output) and not ctx.params.get('columns'):
139
+ ctx.params['columns'] = [
140
+ "Alias=alias",
141
+ "AccountId=accountId",
142
+ "Region=region",
143
+ "IsDefault=isDefault",
144
+ ]
145
+
108
146
  r = client.get("api/v1/newrelic/configurations")
109
- print_json(data=r)
147
+ print_output_with_context(ctx, r)
110
148
 
111
149
  @app.command()
112
150
  def get_default(
@@ -122,7 +160,7 @@ def get_default(
122
160
  print_json(data=r)
123
161
 
124
162
 
125
- @app.command()
163
+ @app.command(no_args_is_help=True)
126
164
  def update(
127
165
  ctx: typer.Context,
128
166
  alias: str = typer.Option(..., "--alias", "-a", help="The alias of the configuration"),
@@ -142,7 +180,7 @@ def update(
142
180
  r = client.put("api/v1/newrelic/configuration/" + alias, data=data)
143
181
  print_json(data=r)
144
182
 
145
- @app.command()
183
+ @app.command(no_args_is_help=True)
146
184
  def validate(
147
185
  ctx: typer.Context,
148
186
  alias: str = typer.Option(..., "--alias", "-a", help="The alias of the configuration"),
@@ -153,7 +191,7 @@ def validate(
153
191
 
154
192
  client = ctx.obj["client"]
155
193
 
156
- r = client.post("api/v1/newrelic/configurations/validate" + alias)
194
+ r = client.post("api/v1/newrelic/configuration/validate/" + alias)
157
195
  print_json(data=r)
158
196
 
159
197
  @app.command()
@@ -166,5 +204,5 @@ def validate_all(
166
204
 
167
205
  client = ctx.obj["client"]
168
206
 
169
- r = client.post("api/v1/newrelic/configurations")
207
+ r = client.post("api/v1/newrelic/configuration/validate")
170
208
  print_json(data=r)
@@ -149,6 +149,23 @@ class CortexClient:
149
149
  # try to parse the error message
150
150
  error = response.json()
151
151
  status = response.status_code
152
+
153
+ # Check for validation error format with violations array
154
+ if 'violations' in error and isinstance(error['violations'], list):
155
+ print(f'[red][bold]HTTP Error {status}[/bold][/red]: Validation failed')
156
+ for violation in error['violations']:
157
+ title = violation.get('title', 'Validation Error')
158
+ description = violation.get('description', 'No description')
159
+ violation_type = violation.get('violationType', '')
160
+ pointer = violation.get('pointer', '')
161
+ print(f' [yellow]{title}[/yellow]: {description}')
162
+ if pointer:
163
+ print(f' [dim]Location: {pointer}[/dim]')
164
+ if violation_type:
165
+ print(f' [dim]Type: {violation_type}[/dim]')
166
+ raise typer.Exit(code=1)
167
+
168
+ # Standard error format with message/details
152
169
  message = error.get('message', 'Unknown error')
153
170
  details = error.get('details', 'No details')
154
171
  request_id = error.get('requestId', 'No request ID')
@@ -156,8 +173,12 @@ class CortexClient:
156
173
  print(error_str)
157
174
  raise typer.Exit(code=1)
158
175
  except json.JSONDecodeError:
159
- # if we can't parse the error message, just raise the HTTP error
160
- response.raise_for_status()
176
+ # if we can't parse the error message, print a clean error and exit
177
+ status = response.status_code
178
+ reason = response.reason or 'Unknown error'
179
+ error_str = f'[red][bold]HTTP Error {status}[/bold][/red]: {reason}'
180
+ print(error_str)
181
+ raise typer.Exit(code=1)
161
182
 
162
183
  if raw_response:
163
184
  return response
@@ -1,7 +1,7 @@
1
1
  [tool.poetry]
2
2
  name = "cortexapps-cli"
3
3
  # version will be incremented via command line as part of github actions build
4
- version = "1.7.0"
4
+ version = "1.10.0"
5
5
  description = "Command Line Interface for cortexapps"
6
6
  license = "MIT"
7
7
  authors = [
@@ -19,7 +19,7 @@ classifiers = [
19
19
  python = "^3.11"
20
20
  requests = "^2.32.4"
21
21
  pyyaml = ">= 6.0.1, < 7"
22
- urllib3 = ">= 2.2.2"
22
+ urllib3 = ">= 2.6.0"
23
23
  typer = "^0.12.5"
24
24
  click = "<8.2"
25
25
 
File without changes