aws-cost-calculator-cli 1.5.1__py3-none-any.whl → 1.6.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.
Potentially problematic release.
This version of aws-cost-calculator-cli might be problematic. Click here for more details.
- {aws_cost_calculator_cli-1.5.1.dist-info → aws_cost_calculator_cli-1.6.0.dist-info}/METADATA +29 -14
- aws_cost_calculator_cli-1.6.0.dist-info/RECORD +13 -0
- {aws_cost_calculator_cli-1.5.1.dist-info → aws_cost_calculator_cli-1.6.0.dist-info}/WHEEL +1 -1
- cost_calculator/cli.py +167 -40
- cost_calculator/executor.py +22 -11
- aws_cost_calculator_cli-1.5.1.dist-info/RECORD +0 -13
- {aws_cost_calculator_cli-1.5.1.dist-info → aws_cost_calculator_cli-1.6.0.dist-info}/entry_points.txt +0 -0
- {aws_cost_calculator_cli-1.5.1.dist-info → aws_cost_calculator_cli-1.6.0.dist-info}/licenses/LICENSE +0 -0
- {aws_cost_calculator_cli-1.5.1.dist-info → aws_cost_calculator_cli-1.6.0.dist-info}/top_level.txt +0 -0
{aws_cost_calculator_cli-1.5.1.dist-info → aws_cost_calculator_cli-1.6.0.dist-info}/METADATA
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: aws-cost-calculator-cli
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.6.0
|
|
4
4
|
Summary: AWS Cost Calculator CLI - Calculate daily and annual AWS costs across multiple accounts
|
|
5
5
|
Home-page: https://github.com/yourusername/cost-calculator
|
|
6
6
|
Author: Cost Optimization Team
|
|
@@ -49,36 +49,51 @@ pip install -e .
|
|
|
49
49
|
|
|
50
50
|
## Quick Start
|
|
51
51
|
|
|
52
|
-
###
|
|
52
|
+
### Authentication Methods
|
|
53
53
|
|
|
54
|
+
The CLI supports three authentication methods:
|
|
55
|
+
|
|
56
|
+
#### 1. SSO (Recommended)
|
|
54
57
|
```bash
|
|
55
|
-
|
|
58
|
+
# The CLI will automatically trigger SSO login if needed
|
|
59
|
+
cc calculate --profile khoros --sso khoros_umbrella
|
|
56
60
|
```
|
|
57
61
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
62
|
+
#### 2. Static Credentials
|
|
63
|
+
```bash
|
|
64
|
+
cc calculate --profile khoros \
|
|
65
|
+
--access-key-id ASIA3D3QOXPO6EBAPXVI \
|
|
66
|
+
--secret-access-key /9ijZEUoszN/S2A8IlCrHpW+1fMZ7aUb7fPvU0dL \
|
|
67
|
+
--session-token IQoJb3JpZ2luX2VjENr...
|
|
68
|
+
```
|
|
61
69
|
|
|
70
|
+
#### 3. Environment Variables
|
|
62
71
|
```bash
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
72
|
+
# For SSO
|
|
73
|
+
export AWS_PROFILE=khoros_umbrella
|
|
74
|
+
cc calculate --profile khoros
|
|
75
|
+
|
|
76
|
+
# For static credentials
|
|
77
|
+
export AWS_ACCESS_KEY_ID=ASIA...
|
|
78
|
+
export AWS_SECRET_ACCESS_KEY=...
|
|
79
|
+
export AWS_SESSION_TOKEN=...
|
|
80
|
+
cc calculate --profile khoros
|
|
66
81
|
```
|
|
67
82
|
|
|
68
|
-
###
|
|
83
|
+
### Basic Usage
|
|
69
84
|
|
|
70
85
|
```bash
|
|
71
86
|
# Default: Today minus 2 days, going back 30 days
|
|
72
|
-
cc calculate --profile
|
|
87
|
+
cc calculate --profile khoros --sso khoros_umbrella
|
|
73
88
|
|
|
74
89
|
# Specific start date
|
|
75
|
-
cc calculate --profile
|
|
90
|
+
cc calculate --profile khoros --sso khoros_umbrella --start-date 2025-11-04
|
|
76
91
|
|
|
77
92
|
# Custom offset and window
|
|
78
|
-
cc calculate --profile
|
|
93
|
+
cc calculate --profile khoros --sso khoros_umbrella --offset 2 --window 30
|
|
79
94
|
|
|
80
95
|
# JSON output
|
|
81
|
-
cc calculate --profile
|
|
96
|
+
cc calculate --profile khoros --sso khoros_umbrella --json-output
|
|
82
97
|
```
|
|
83
98
|
|
|
84
99
|
### 4. Analyze cost trends
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
aws_cost_calculator_cli-1.6.0.dist-info/licenses/LICENSE,sha256=cYtmQZHNGGTXOtg3T7LHDRneleaH0dHXHfxFV3WR50Y,1079
|
|
2
|
+
cost_calculator/__init__.py,sha256=PJeIqvWh5AYJVrJxPPkI4pJnAt37rIjasrNS0I87kaM,52
|
|
3
|
+
cost_calculator/api_client.py,sha256=LUzQmveDF0X9MqAyThp9mbSzJzkOO73Pk4F7IEJjASU,2353
|
|
4
|
+
cost_calculator/cli.py,sha256=sJYvzbdHCxOEcCgOjZs4o9MOogV1Yh8r7x0hJtd__K0,38639
|
|
5
|
+
cost_calculator/drill.py,sha256=hGi-prLgZDvNMMICQc4fl3LenM7YaZ3To_Ei4LKwrdc,10543
|
|
6
|
+
cost_calculator/executor.py,sha256=tVyyBtXIj9OPyG-xQj8CUmyFjDhb9IVK639360dUZDc,8076
|
|
7
|
+
cost_calculator/monthly.py,sha256=6k9F8S7djhX1wGV3-T1MZP7CvWbbfhSTEaddwCfVu5M,7932
|
|
8
|
+
cost_calculator/trends.py,sha256=k_s4ylBX50sqoiM_fwepi58HW01zz767FMJhQUPDznk,12246
|
|
9
|
+
aws_cost_calculator_cli-1.6.0.dist-info/METADATA,sha256=AaLbUH-anBc1lv2o2DpdJR3v0tSavhPtDo5Sjb7VsHA,8612
|
|
10
|
+
aws_cost_calculator_cli-1.6.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
11
|
+
aws_cost_calculator_cli-1.6.0.dist-info/entry_points.txt,sha256=_5Qy4EcHbYVYrdgOu1E48faMHb9fLUl5VJ3djDHuJBo,47
|
|
12
|
+
aws_cost_calculator_cli-1.6.0.dist-info/top_level.txt,sha256=PRwGPPlNqASfyhGHDjSfyl4SXeE7GF3OVTu1tY1Uqyc,16
|
|
13
|
+
aws_cost_calculator_cli-1.6.0.dist-info/RECORD,,
|
cost_calculator/cli.py
CHANGED
|
@@ -19,49 +19,143 @@ from cost_calculator.drill import format_drill_down_markdown
|
|
|
19
19
|
from cost_calculator.executor import execute_trends, execute_monthly, execute_drill
|
|
20
20
|
|
|
21
21
|
|
|
22
|
+
def apply_auth_options(config, sso=None, access_key_id=None, secret_access_key=None, session_token=None):
|
|
23
|
+
"""Apply authentication options to profile config
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
config: Profile configuration dict
|
|
27
|
+
sso: AWS SSO profile name
|
|
28
|
+
access_key_id: AWS Access Key ID
|
|
29
|
+
secret_access_key: AWS Secret Access Key
|
|
30
|
+
session_token: AWS Session Token
|
|
31
|
+
|
|
32
|
+
Returns:
|
|
33
|
+
Updated config dict
|
|
34
|
+
"""
|
|
35
|
+
import subprocess
|
|
36
|
+
|
|
37
|
+
if sso:
|
|
38
|
+
# SSO authentication - trigger login if needed
|
|
39
|
+
try:
|
|
40
|
+
# Test if SSO session is valid
|
|
41
|
+
result = subprocess.run(
|
|
42
|
+
['aws', 'sts', 'get-caller-identity', '--profile', sso],
|
|
43
|
+
capture_output=True,
|
|
44
|
+
text=True,
|
|
45
|
+
timeout=5
|
|
46
|
+
)
|
|
47
|
+
if result.returncode != 0:
|
|
48
|
+
if 'expired' in result.stderr.lower() or 'token' in result.stderr.lower():
|
|
49
|
+
click.echo(f"SSO session expired or not initialized. Logging in...")
|
|
50
|
+
subprocess.run(['aws', 'sso', 'login', '--profile', sso], check=True)
|
|
51
|
+
except Exception as e:
|
|
52
|
+
click.echo(f"Warning: Could not verify SSO session: {e}")
|
|
53
|
+
|
|
54
|
+
config['aws_profile'] = sso
|
|
55
|
+
elif access_key_id and secret_access_key:
|
|
56
|
+
# Static credentials provided via CLI
|
|
57
|
+
config['credentials'] = {
|
|
58
|
+
'aws_access_key_id': access_key_id,
|
|
59
|
+
'aws_secret_access_key': secret_access_key,
|
|
60
|
+
'region': 'us-east-1'
|
|
61
|
+
}
|
|
62
|
+
if session_token:
|
|
63
|
+
config['credentials']['aws_session_token'] = session_token
|
|
64
|
+
|
|
65
|
+
return config
|
|
66
|
+
|
|
67
|
+
|
|
22
68
|
def load_profile(profile_name):
|
|
23
|
-
"""Load profile configuration from
|
|
69
|
+
"""Load profile configuration from local file or DynamoDB API"""
|
|
70
|
+
import os
|
|
71
|
+
import requests
|
|
72
|
+
|
|
24
73
|
config_dir = Path.home() / '.config' / 'cost-calculator'
|
|
25
74
|
config_file = config_dir / 'profiles.json'
|
|
26
75
|
creds_file = config_dir / 'credentials.json'
|
|
27
76
|
|
|
28
|
-
|
|
77
|
+
# Try local file first
|
|
78
|
+
if config_file.exists():
|
|
79
|
+
with open(config_file) as f:
|
|
80
|
+
profiles = json.load(f)
|
|
81
|
+
|
|
82
|
+
if profile_name in profiles:
|
|
83
|
+
profile = profiles[profile_name]
|
|
84
|
+
|
|
85
|
+
# Load credentials if using static credentials (not SSO)
|
|
86
|
+
if 'aws_profile' not in profile:
|
|
87
|
+
if not creds_file.exists():
|
|
88
|
+
# Try environment variables
|
|
89
|
+
if os.environ.get('AWS_ACCESS_KEY_ID'):
|
|
90
|
+
profile['credentials'] = {
|
|
91
|
+
'aws_access_key_id': os.environ['AWS_ACCESS_KEY_ID'],
|
|
92
|
+
'aws_secret_access_key': os.environ['AWS_SECRET_ACCESS_KEY'],
|
|
93
|
+
'aws_session_token': os.environ.get('AWS_SESSION_TOKEN')
|
|
94
|
+
}
|
|
95
|
+
return profile
|
|
96
|
+
|
|
97
|
+
raise click.ClickException(
|
|
98
|
+
f"No credentials found for profile '{profile_name}'.\n"
|
|
99
|
+
f"Run: cc configure --profile {profile_name}"
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
with open(creds_file) as f:
|
|
103
|
+
creds = json.load(f)
|
|
104
|
+
|
|
105
|
+
if profile_name not in creds:
|
|
106
|
+
raise click.ClickException(
|
|
107
|
+
f"No credentials found for profile '{profile_name}'.\n"
|
|
108
|
+
f"Run: cc configure --profile {profile_name}"
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
profile['credentials'] = creds[profile_name]
|
|
112
|
+
|
|
113
|
+
return profile
|
|
114
|
+
|
|
115
|
+
# Profile not found locally - try DynamoDB API
|
|
116
|
+
api_secret = os.environ.get('COST_API_SECRET')
|
|
117
|
+
if not api_secret:
|
|
29
118
|
raise click.ClickException(
|
|
30
|
-
f"Profile
|
|
119
|
+
f"Profile '{profile_name}' not found locally and COST_API_SECRET not set.\n"
|
|
31
120
|
f"Run: cc init --profile {profile_name}"
|
|
32
121
|
)
|
|
33
122
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
f"Available profiles: {', '.join(profiles.keys())}"
|
|
123
|
+
try:
|
|
124
|
+
response = requests.post(
|
|
125
|
+
'https://64g7jq7sjygec2zmll5lsghrpi0txrzo.lambda-url.us-east-1.on.aws/',
|
|
126
|
+
headers={'X-API-Secret': api_secret, 'Content-Type': 'application/json'},
|
|
127
|
+
json={'operation': 'get', 'profile_name': profile_name},
|
|
128
|
+
timeout=10
|
|
41
129
|
)
|
|
42
|
-
|
|
43
|
-
profile = profiles[profile_name]
|
|
44
|
-
|
|
45
|
-
# Load credentials if using static credentials (not SSO)
|
|
46
|
-
if 'aws_profile' not in profile:
|
|
47
|
-
if not creds_file.exists():
|
|
48
|
-
raise click.ClickException(
|
|
49
|
-
f"No credentials found for profile '{profile_name}'.\n"
|
|
50
|
-
f"Run: cc configure --profile {profile_name}"
|
|
51
|
-
)
|
|
52
|
-
|
|
53
|
-
with open(creds_file) as f:
|
|
54
|
-
creds = json.load(f)
|
|
55
130
|
|
|
56
|
-
if
|
|
131
|
+
if response.status_code == 200:
|
|
132
|
+
response_data = response.json()
|
|
133
|
+
# API returns {"profile": {...}} wrapper
|
|
134
|
+
profile_data = response_data.get('profile', response_data)
|
|
135
|
+
profile = {'accounts': profile_data['accounts']}
|
|
136
|
+
|
|
137
|
+
# Check for AWS_PROFILE environment variable (SSO support)
|
|
138
|
+
if os.environ.get('AWS_PROFILE'):
|
|
139
|
+
profile['aws_profile'] = os.environ['AWS_PROFILE']
|
|
140
|
+
# Use environment credentials
|
|
141
|
+
elif os.environ.get('AWS_ACCESS_KEY_ID'):
|
|
142
|
+
profile['credentials'] = {
|
|
143
|
+
'aws_access_key_id': os.environ['AWS_ACCESS_KEY_ID'],
|
|
144
|
+
'aws_secret_access_key': os.environ['AWS_SECRET_ACCESS_KEY'],
|
|
145
|
+
'aws_session_token': os.environ.get('AWS_SESSION_TOKEN')
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return profile
|
|
149
|
+
else:
|
|
57
150
|
raise click.ClickException(
|
|
58
|
-
f"
|
|
59
|
-
f"Run: cc
|
|
151
|
+
f"Profile '{profile_name}' not found in DynamoDB.\n"
|
|
152
|
+
f"Run: cc profile create --name {profile_name} --accounts \"...\""
|
|
60
153
|
)
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
154
|
+
except requests.exceptions.RequestException as e:
|
|
155
|
+
raise click.ClickException(
|
|
156
|
+
f"Failed to fetch profile from API: {e}\n"
|
|
157
|
+
f"Run: cc init --profile {profile_name}"
|
|
158
|
+
)
|
|
65
159
|
|
|
66
160
|
|
|
67
161
|
def calculate_costs(profile_config, accounts, start_date, offset, window):
|
|
@@ -296,12 +390,30 @@ def cli():
|
|
|
296
390
|
@click.option('--offset', default=2, help='Days to go back from start date (default: 2)')
|
|
297
391
|
@click.option('--window', default=30, help='Number of days to analyze (default: 30)')
|
|
298
392
|
@click.option('--json-output', is_flag=True, help='Output as JSON')
|
|
299
|
-
|
|
300
|
-
|
|
393
|
+
@click.option('--sso', help='AWS SSO profile name (e.g., khoros_umbrella)')
|
|
394
|
+
@click.option('--access-key-id', help='AWS Access Key ID (for static credentials)')
|
|
395
|
+
@click.option('--secret-access-key', help='AWS Secret Access Key (for static credentials)')
|
|
396
|
+
@click.option('--session-token', help='AWS Session Token (for static credentials)')
|
|
397
|
+
def calculate(profile, start_date, offset, window, json_output, sso, access_key_id, secret_access_key, session_token):
|
|
398
|
+
"""Calculate AWS costs for the specified period
|
|
399
|
+
|
|
400
|
+
\b
|
|
401
|
+
Authentication Options:
|
|
402
|
+
1. SSO: --sso <profile_name>
|
|
403
|
+
Example: cc calculate --profile khoros --sso khoros_umbrella
|
|
404
|
+
|
|
405
|
+
2. Static Credentials: --access-key-id, --secret-access-key, --session-token
|
|
406
|
+
Example: cc calculate --profile khoros --access-key-id ASIA... --secret-access-key ... --session-token ...
|
|
407
|
+
|
|
408
|
+
3. Environment Variables: AWS_PROFILE or AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY
|
|
409
|
+
"""
|
|
301
410
|
|
|
302
411
|
# Load profile configuration
|
|
303
412
|
config = load_profile(profile)
|
|
304
413
|
|
|
414
|
+
# Apply authentication options
|
|
415
|
+
config = apply_auth_options(config, sso, access_key_id, secret_access_key, session_token)
|
|
416
|
+
|
|
305
417
|
# Calculate costs
|
|
306
418
|
result = calculate_costs(
|
|
307
419
|
profile_config=config,
|
|
@@ -547,12 +659,17 @@ def configure(profile, access_key_id, secret_access_key, session_token, region):
|
|
|
547
659
|
@click.option('--profile', required=True, help='Profile name')
|
|
548
660
|
@click.option('--weeks', default=3, help='Number of weeks to analyze (default: 3)')
|
|
549
661
|
@click.option('--output', default='cost_trends.md', help='Output markdown file (default: cost_trends.md)')
|
|
550
|
-
@click.option('--json-output', is_flag=True, help='Output as JSON
|
|
551
|
-
|
|
662
|
+
@click.option('--json-output', is_flag=True, help='Output as JSON')
|
|
663
|
+
@click.option('--sso', help='AWS SSO profile name')
|
|
664
|
+
@click.option('--access-key-id', help='AWS Access Key ID')
|
|
665
|
+
@click.option('--secret-access-key', help='AWS Secret Access Key')
|
|
666
|
+
@click.option('--session-token', help='AWS Session Token')
|
|
667
|
+
def trends(profile, weeks, output, json_output, sso, access_key_id, secret_access_key, session_token):
|
|
552
668
|
"""Analyze cost trends with Week-over-Week and Trailing 30-Day comparisons"""
|
|
553
669
|
|
|
554
670
|
# Load profile configuration
|
|
555
671
|
config = load_profile(profile)
|
|
672
|
+
config = apply_auth_options(config, sso, access_key_id, secret_access_key, session_token)
|
|
556
673
|
|
|
557
674
|
click.echo(f"Analyzing last {weeks} weeks...")
|
|
558
675
|
click.echo("")
|
|
@@ -613,12 +730,17 @@ def trends(profile, weeks, output, json_output):
|
|
|
613
730
|
@click.option('--profile', required=True, help='Profile name')
|
|
614
731
|
@click.option('--months', default=6, help='Number of months to analyze (default: 6)')
|
|
615
732
|
@click.option('--output', default='monthly_trends.md', help='Output markdown file (default: monthly_trends.md)')
|
|
616
|
-
@click.option('--json-output', is_flag=True, help='Output as JSON
|
|
617
|
-
|
|
733
|
+
@click.option('--json-output', is_flag=True, help='Output as JSON')
|
|
734
|
+
@click.option('--sso', help='AWS SSO profile name')
|
|
735
|
+
@click.option('--access-key-id', help='AWS Access Key ID')
|
|
736
|
+
@click.option('--secret-access-key', help='AWS Secret Access Key')
|
|
737
|
+
@click.option('--session-token', help='AWS Session Token')
|
|
738
|
+
def monthly(profile, months, output, json_output, sso, access_key_id, secret_access_key, session_token):
|
|
618
739
|
"""Analyze month-over-month cost trends at service level"""
|
|
619
740
|
|
|
620
|
-
# Load profile
|
|
741
|
+
# Load profile
|
|
621
742
|
config = load_profile(profile)
|
|
743
|
+
config = apply_auth_options(config, sso, access_key_id, secret_access_key, session_token)
|
|
622
744
|
|
|
623
745
|
click.echo(f"Analyzing last {months} months...")
|
|
624
746
|
click.echo("")
|
|
@@ -680,12 +802,17 @@ def monthly(profile, months, output, json_output):
|
|
|
680
802
|
@click.option('--account', help='Filter by account ID')
|
|
681
803
|
@click.option('--usage-type', help='Filter by usage type')
|
|
682
804
|
@click.option('--output', default='drill_down.md', help='Output markdown file (default: drill_down.md)')
|
|
683
|
-
@click.option('--json-output', is_flag=True, help='Output as JSON
|
|
684
|
-
|
|
805
|
+
@click.option('--json-output', is_flag=True, help='Output as JSON')
|
|
806
|
+
@click.option('--sso', help='AWS SSO profile name')
|
|
807
|
+
@click.option('--access-key-id', help='AWS Access Key ID')
|
|
808
|
+
@click.option('--secret-access-key', help='AWS Secret Access Key')
|
|
809
|
+
@click.option('--session-token', help='AWS Session Token')
|
|
810
|
+
def drill(profile, weeks, service, account, usage_type, output, json_output, sso, access_key_id, secret_access_key, session_token):
|
|
685
811
|
"""Drill down into cost changes by service, account, or usage type"""
|
|
686
812
|
|
|
687
|
-
# Load profile
|
|
813
|
+
# Load profile
|
|
688
814
|
config = load_profile(profile)
|
|
815
|
+
config = apply_auth_options(config, sso, access_key_id, secret_access_key, session_token)
|
|
689
816
|
|
|
690
817
|
# Show filters
|
|
691
818
|
click.echo(f"Analyzing last {weeks} weeks...")
|
cost_calculator/executor.py
CHANGED
|
@@ -11,22 +11,33 @@ def get_credentials_dict(config):
|
|
|
11
11
|
Extract credentials from config in format needed for API.
|
|
12
12
|
|
|
13
13
|
Returns:
|
|
14
|
-
dict with access_key, secret_key, session_token
|
|
14
|
+
dict with access_key, secret_key, session_token, or None if profile is 'dummy'
|
|
15
15
|
"""
|
|
16
16
|
if 'aws_profile' in config:
|
|
17
|
-
#
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
frozen_creds = credentials.get_frozen_credentials()
|
|
17
|
+
# Skip credential loading for dummy profile (API-only mode)
|
|
18
|
+
if config['aws_profile'] == 'dummy':
|
|
19
|
+
return None
|
|
21
20
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
'
|
|
25
|
-
|
|
26
|
-
|
|
21
|
+
# Get temporary credentials from SSO session
|
|
22
|
+
try:
|
|
23
|
+
session = boto3.Session(profile_name=config['aws_profile'])
|
|
24
|
+
credentials = session.get_credentials()
|
|
25
|
+
frozen_creds = credentials.get_frozen_credentials()
|
|
26
|
+
|
|
27
|
+
return {
|
|
28
|
+
'access_key': frozen_creds.access_key,
|
|
29
|
+
'secret_key': frozen_creds.secret_key,
|
|
30
|
+
'session_token': frozen_creds.token
|
|
31
|
+
}
|
|
32
|
+
except Exception:
|
|
33
|
+
# If profile not found, return None (API will handle)
|
|
34
|
+
return None
|
|
27
35
|
else:
|
|
28
36
|
# Use static credentials
|
|
29
|
-
creds = config
|
|
37
|
+
creds = config.get('credentials', {})
|
|
38
|
+
if not creds:
|
|
39
|
+
return None
|
|
40
|
+
|
|
30
41
|
result = {
|
|
31
42
|
'access_key': creds['aws_access_key_id'],
|
|
32
43
|
'secret_key': creds['aws_secret_access_key']
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
aws_cost_calculator_cli-1.5.1.dist-info/licenses/LICENSE,sha256=cYtmQZHNGGTXOtg3T7LHDRneleaH0dHXHfxFV3WR50Y,1079
|
|
2
|
-
cost_calculator/__init__.py,sha256=PJeIqvWh5AYJVrJxPPkI4pJnAt37rIjasrNS0I87kaM,52
|
|
3
|
-
cost_calculator/api_client.py,sha256=LUzQmveDF0X9MqAyThp9mbSzJzkOO73Pk4F7IEJjASU,2353
|
|
4
|
-
cost_calculator/cli.py,sha256=ufK28divdvrceEryWd8cCWjvG5pT2owaqprskX2epeQ,32589
|
|
5
|
-
cost_calculator/drill.py,sha256=hGi-prLgZDvNMMICQc4fl3LenM7YaZ3To_Ei4LKwrdc,10543
|
|
6
|
-
cost_calculator/executor.py,sha256=aPYEm8KdQl7xTpG1gvJ-2adAIJ2PW1_ly27xggQxNNE,7671
|
|
7
|
-
cost_calculator/monthly.py,sha256=6k9F8S7djhX1wGV3-T1MZP7CvWbbfhSTEaddwCfVu5M,7932
|
|
8
|
-
cost_calculator/trends.py,sha256=k_s4ylBX50sqoiM_fwepi58HW01zz767FMJhQUPDznk,12246
|
|
9
|
-
aws_cost_calculator_cli-1.5.1.dist-info/METADATA,sha256=g9xQIorywmJ-Xq3zQO0IYdW7otVkkDkZhJwbXgN5PjU,8176
|
|
10
|
-
aws_cost_calculator_cli-1.5.1.dist-info/WHEEL,sha256=Nw36Djuh_5VDukK0H78QzOX-_FQEo6V37m3nkm96gtU,91
|
|
11
|
-
aws_cost_calculator_cli-1.5.1.dist-info/entry_points.txt,sha256=_5Qy4EcHbYVYrdgOu1E48faMHb9fLUl5VJ3djDHuJBo,47
|
|
12
|
-
aws_cost_calculator_cli-1.5.1.dist-info/top_level.txt,sha256=PRwGPPlNqASfyhGHDjSfyl4SXeE7GF3OVTu1tY1Uqyc,16
|
|
13
|
-
aws_cost_calculator_cli-1.5.1.dist-info/RECORD,,
|
{aws_cost_calculator_cli-1.5.1.dist-info → aws_cost_calculator_cli-1.6.0.dist-info}/entry_points.txt
RENAMED
|
File without changes
|
{aws_cost_calculator_cli-1.5.1.dist-info → aws_cost_calculator_cli-1.6.0.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|
{aws_cost_calculator_cli-1.5.1.dist-info → aws_cost_calculator_cli-1.6.0.dist-info}/top_level.txt
RENAMED
|
File without changes
|