cid-cmd 4.2.2__tar.gz → 4.2.4__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.
- {cid_cmd-4.2.2/cid_cmd.egg-info → cid_cmd-4.2.4}/PKG-INFO +1 -1
- cid_cmd-4.2.4/cid/_version.py +2 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/datasets/kpi/kpi_tracker.json +6 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/queries/co/idle.json +1 -1
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/queries/co/idle_options.sql +1 -1
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/queries/kpi/last_kpi_tracker_view.sql +2 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/common.py +13 -9
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/export.py +1 -1
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/helpers/account_map.py +18 -14
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/helpers/athena.py +10 -8
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/helpers/cur.py +7 -3
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/helpers/quicksight/__init__.py +2 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/helpers/quicksight/dataset.py +36 -32
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/utils.py +3 -2
- {cid_cmd-4.2.2 → cid_cmd-4.2.4/cid_cmd.egg-info}/PKG-INFO +1 -1
- cid_cmd-4.2.2/cid/_version.py +0 -2
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/LICENSE +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/MANIFEST.in +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/README.md +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/__init__.py +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/base.py +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/__init__.py +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/__init__.py +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/datasets/cid/compute.json +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/datasets/cid/ec2_running_cost.json +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/datasets/cid/s3_view.json +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/datasets/cid/summary_view.json +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/datasets/co/dataset.json +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/datasets/cudos/hourly_view.json +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/datasets/cudos/resource_view.json +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/datasets/kpi/kpi_ebs_snap.json +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/datasets/kpi/kpi_ebs_storage_all.json +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/datasets/kpi/kpi_instance_all.json +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/datasets/kpi/kpi_s3_storage_all.json +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/datasets/shared/customer_all.json +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/datasets/tao/dataset.json +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/datasets/trends/daily_anomaly_detection.json +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/datasets/trends/monthly_anomaly_detection.json +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/datasets/trends/monthly_bill_by_account.json +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/permissions/dashboard_permissions.json +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/permissions/dashboard_permissions_namespace.json +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/permissions/data_set_permissions.json +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/permissions/data_source_permissions.json +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/permissions/folder_permissions.json +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/queries/cid/compute_savings_plan_eligible_spend.sql +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/queries/cid/ec2_running_cost.sql +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/queries/cid/ri_sp_mapping.sql +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/queries/cid/s3.sql +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/queries/cid/summary_view.sql +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/queries/co/all_options.sql +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/queries/co/auto_scale.json +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/queries/co/auto_scale_options.sql +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/queries/co/ebs_volume.json +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/queries/co/ebs_volume_options.sql +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/queries/co/ec2_instance.json +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/queries/co/ec2_instance_options.sql +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/queries/co/ecs_service.json +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/queries/co/ecs_service_options.sql +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/queries/co/lambda.json +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/queries/co/lambda_options.sql +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/queries/co/license.json +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/queries/co/license_options.sql +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/queries/co/rds_database.json +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/queries/co/rds_instance_options.sql +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/queries/co/rds_storage_options.sql +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/queries/cudos/hourly_view.sql +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/queries/cudos/resource_view.sql +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/queries/kpi/first_kpi_instance_mapping_view.sql +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/queries/kpi/kpi_ebs_snap_view.sql +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/queries/kpi/kpi_ebs_storage_view.sql +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/queries/kpi/kpi_instance_all_view.sql +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/queries/kpi/kpi_s3_storage_view.sql +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/queries/shared/account_map.sql +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/queries/shared/account_map_cur2.sql +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/queries/shared/account_map_dummy.sql +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/queries/shared/aws_accounts.sql +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/queries/shared/aws_regions.sql +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/queries/shared/aws_service_category_map.sql +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/queries/shared/business_units_map.sql +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/queries/shared/cur.yaml +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/queries/shared/customer_all_unlimited.sql +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/queries/shared/payer_account_name_map.sql +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/queries/shared/ta_descriptions.sql +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/queries/tao/glue_table.json +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/queries/tao/ta_org_view.sql +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/queries/trends/daily_anomaly_detection.sql +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/queries/trends/monthly_anomaly_detection.sql +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/queries/trends/monthly_bill_by_account.sql +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/resources.yaml +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/cli.py +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/commands/__init__.py +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/commands/command_base.py +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/commands/init_qs.py +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/exceptions.py +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/helpers/__init__.py +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/helpers/cloudformation.py +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/helpers/csv2view.py +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/helpers/cur_proxy.py +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/helpers/diff.py +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/helpers/glue.py +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/helpers/iam.py +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/helpers/organizations.py +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/helpers/parameter_store.py +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/helpers/quicksight/dashboard.py +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/helpers/quicksight/dashboard_patching.py +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/helpers/quicksight/datasource.py +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/helpers/quicksight/definition.py +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/helpers/quicksight/resource.py +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/helpers/quicksight/template.py +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/helpers/quicksight/version.py +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/helpers/randtime.py +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/helpers/s3.py +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/helpers/timezone.py +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/logger.py +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/plugin.py +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/test/python/test_csv2view.py +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/test/python/test_isolated_parameters.py +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/test/python/test_merge.py +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid_cmd.egg-info/SOURCES.txt +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid_cmd.egg-info/dependency_links.txt +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid_cmd.egg-info/entry_points.txt +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid_cmd.egg-info/requires.txt +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid_cmd.egg-info/top_level.txt +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/pyproject.toml +0 -0
- {cid_cmd-4.2.2 → cid_cmd-4.2.4}/setup.cfg +0 -0
|
@@ -48,6 +48,11 @@
|
|
|
48
48
|
"Type": "DECIMAL",
|
|
49
49
|
"SubType": "FLOAT"
|
|
50
50
|
},
|
|
51
|
+
{
|
|
52
|
+
"Name": "ec2_usage_cost",
|
|
53
|
+
"Type": "DECIMAL",
|
|
54
|
+
"SubType": "FLOAT"
|
|
55
|
+
},
|
|
51
56
|
{
|
|
52
57
|
"Name": "ec2_spot_cost",
|
|
53
58
|
"Type": "DECIMAL",
|
|
@@ -397,6 +402,7 @@
|
|
|
397
402
|
"linked_account_id",
|
|
398
403
|
"spend_all_cost",
|
|
399
404
|
"ec2_all_cost",
|
|
405
|
+
"ec2_usage_cost",
|
|
400
406
|
"ec2_spot_cost",
|
|
401
407
|
"ec2_spot_potential_savings",
|
|
402
408
|
"ec2_previous_generation_cost",
|
|
@@ -23,7 +23,7 @@ CREATE OR REPLACE VIEW compute_optimizer_idle_options AS
|
|
|
23
23
|
utilizationmetricsnetworkinbytespersecondmaximum, ';',
|
|
24
24
|
utilizationmetricsdatabaseconnectionsmaximum, ';',
|
|
25
25
|
utilizationmetricsebsvolumereadiopsmaximum, ';',
|
|
26
|
-
|
|
26
|
+
utilizationmetricsebsvolumewriteiopsmaximum, ';',
|
|
27
27
|
utilizationmetricsvolumereadopspersecondmaximum, ';',
|
|
28
28
|
utilizationmetricsvolumewriteopspersecondmaximum
|
|
29
29
|
) utilizationmetrics
|
|
@@ -6,6 +6,7 @@ SELECT DISTINCT
|
|
|
6
6
|
, spend_all.spend_all_cost
|
|
7
7
|
, spend_all.tags_json
|
|
8
8
|
, instance_all.ec2_all_cost
|
|
9
|
+
, instance_all.ec2_usage_cost
|
|
9
10
|
, instance_all.ec2_spot_cost
|
|
10
11
|
, instance_all.ec2_spot_potential_savings
|
|
11
12
|
, instance_all.ec2_previous_generation_cost
|
|
@@ -94,6 +95,7 @@ LEFT JOIN (
|
|
|
94
95
|
, linked_account_id
|
|
95
96
|
, tags_json
|
|
96
97
|
, "sum"("ec2_all_cost") "ec2_all_cost"
|
|
98
|
+
, "sum"("ec2_usage_cost") "ec2_usage_cost"
|
|
97
99
|
, "sum"("ec2_spot_cost") "ec2_spot_cost"
|
|
98
100
|
, "sum"("ec2_spot_potential_savings") "ec2_spot_potential_savings"
|
|
99
101
|
, "sum"("ec2_previous_generation_cost") "ec2_previous_generation_cost"
|
|
@@ -131,10 +131,10 @@ class Cid():
|
|
|
131
131
|
""" get/create parameters_controller """
|
|
132
132
|
return ParametersController(self.athena)
|
|
133
133
|
|
|
134
|
-
def get_cur(self, target_cur_version):
|
|
134
|
+
def get_cur(self, target_cur_version=None):
|
|
135
135
|
""" get a cur """
|
|
136
136
|
cur_version = self.cur.version
|
|
137
|
-
if cur_version != target_cur_version or get_parameters().get('use-cur-proxy'):
|
|
137
|
+
if (target_cur_version and cur_version != target_cur_version) or get_parameters().get('use-cur-proxy'):
|
|
138
138
|
return ProxyCUR(self.cur, target_cur_version=target_cur_version)
|
|
139
139
|
return self.cur
|
|
140
140
|
|
|
@@ -170,7 +170,7 @@ class Cid():
|
|
|
170
170
|
account_map = AccountMap(
|
|
171
171
|
self.base.session,
|
|
172
172
|
self.athena,
|
|
173
|
-
self.
|
|
173
|
+
self.get_cur, # can be any CUR. But it is only needed for trends and dummy
|
|
174
174
|
)
|
|
175
175
|
return account_map.create_or_update(name)
|
|
176
176
|
|
|
@@ -409,9 +409,7 @@ class Cid():
|
|
|
409
409
|
res_list = self.athena.query(query)
|
|
410
410
|
except (self.athena.client.exceptions.ClientError, CidError, CidCritical) as exc:
|
|
411
411
|
raise CidCritical(f'Failed fetching parameter {prefix}{key}: {exc}.') from exc
|
|
412
|
-
|
|
413
|
-
raise CidCritical(f'Failed fetching parameter {prefix}{key}, {value}. Athena returns empty results. {value.get("error")}')
|
|
414
|
-
options = ['-'.join(res) for res in res_list]
|
|
412
|
+
options = ['-'.join(res) for res in (res_list or [])]
|
|
415
413
|
params[key] = self.generic_tags_json(
|
|
416
414
|
param_name=key,
|
|
417
415
|
options=options,
|
|
@@ -1605,9 +1603,15 @@ class Cid():
|
|
|
1605
1603
|
# patch dataset for tags
|
|
1606
1604
|
cur_tags_json_required = False
|
|
1607
1605
|
for dep_view_name in dataset_definition.get('dependsOn', {}).get('views', []):
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1606
|
+
try:
|
|
1607
|
+
tags_type = self.resources['views'][dep_view_name]['dependsOn']['tags']
|
|
1608
|
+
except (KeyError, TypeError, AttributeError):
|
|
1609
|
+
tags_type = None
|
|
1610
|
+
try:
|
|
1611
|
+
param_res_tag = self.resources['views'][dep_view_name]['parameters']['resource-tags']
|
|
1612
|
+
except (KeyError, TypeError, AttributeError):
|
|
1613
|
+
param_res_tag = None
|
|
1614
|
+
if tags_type == 'json' or param_res_tag:
|
|
1611
1615
|
cur_tags_json_required = True
|
|
1612
1616
|
break
|
|
1613
1617
|
custom_fields = {}
|
|
@@ -179,7 +179,7 @@ def export_analysis(qs, athena, glue):
|
|
|
179
179
|
elif 'CustomSql' in value and 'DataSourceArn' in value['CustomSql']:
|
|
180
180
|
logger.debug(f"Dataset {dataset.raw['DataSetId']} looks like CustomSql athena dataset")
|
|
181
181
|
value['CustomSql']['DataSourceArn'] = '${athena_datasource_arn}'
|
|
182
|
-
databases =
|
|
182
|
+
databases = athena.list_databases()
|
|
183
183
|
for database in databases:
|
|
184
184
|
if f'{database}.' in value['CustomSql']['SqlQuery'] or f'"{database}".' in value['CustomSql']['SqlQuery']:
|
|
185
185
|
logger.debug(f"Replacing {database} in text")
|
|
@@ -65,8 +65,8 @@ class AccountMap(CidBase):
|
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
def __init__(self, session: Session, athena: Athena,
|
|
69
|
-
self.
|
|
68
|
+
def __init__(self, session: Session, athena: Athena, get_cur=None) -> None:
|
|
69
|
+
self.get_cur = get_cur # get_cur callback Only for trends and dummy
|
|
70
70
|
self.athena = athena
|
|
71
71
|
super().__init__(session)
|
|
72
72
|
|
|
@@ -121,7 +121,7 @@ class AccountMap(CidBase):
|
|
|
121
121
|
template = Template(
|
|
122
122
|
resource_string(
|
|
123
123
|
view_definition.get('providedBy'),
|
|
124
|
-
f'data/
|
|
124
|
+
f'data/{view_file}'
|
|
125
125
|
).decode('utf-8')
|
|
126
126
|
)
|
|
127
127
|
elif view_definition.get('data'):
|
|
@@ -133,8 +133,8 @@ class AccountMap(CidBase):
|
|
|
133
133
|
vars = {
|
|
134
134
|
'metadata_table_name': metadata_table['Name'],
|
|
135
135
|
'metadata_database_name': metadata_table['Database'],
|
|
136
|
-
'cur_database': self.
|
|
137
|
-
'cur_table_name': self.
|
|
136
|
+
'cur_database': self.get_cur().database if name == 'aws_accounts' and self.get_cur else None, # only for trends in metadata
|
|
137
|
+
'cur_table_name': self.get_cur().table_name if name == 'aws_accounts' and self.get_cur else None, # only for trends in metadata
|
|
138
138
|
}
|
|
139
139
|
for key, val in self.mappings.get(name).get(metadata_table['Name']).items():
|
|
140
140
|
logger.debug(f'Mapping field {key} to {val}')
|
|
@@ -151,7 +151,8 @@ class AccountMap(CidBase):
|
|
|
151
151
|
def get_dummy_account_mapping_sql(self, name) -> list:
|
|
152
152
|
"""Create dummy account mapping"""
|
|
153
153
|
logger.info(f'Creating dummy account mapping for {name}')
|
|
154
|
-
|
|
154
|
+
cur = self.get_cur()
|
|
155
|
+
if cur.version.startswith('2'):
|
|
155
156
|
sql_file = 'data/queries/shared/account_map_cur2.sql'
|
|
156
157
|
else:
|
|
157
158
|
sql_file = 'data/queries/shared/account_map_dummy.sql'
|
|
@@ -161,8 +162,8 @@ class AccountMap(CidBase):
|
|
|
161
162
|
).decode('utf-8'))
|
|
162
163
|
columns_tpl = {
|
|
163
164
|
'athena_view_name': name,
|
|
164
|
-
'cur_table_name':
|
|
165
|
-
'cur_database':
|
|
165
|
+
'cur_table_name': cur.table_name,
|
|
166
|
+
'cur_database': cur.database,
|
|
166
167
|
}
|
|
167
168
|
compiled_query = template.safe_substitute(columns_tpl)
|
|
168
169
|
return compiled_query
|
|
@@ -278,20 +279,23 @@ class AccountMap(CidBase):
|
|
|
278
279
|
except CidError as exc:
|
|
279
280
|
logger.debug(exc)
|
|
280
281
|
|
|
281
|
-
if self.
|
|
282
|
+
if self.get_cur and self.get_cur().version.startswith('2'):
|
|
282
283
|
cid_print('Looks like CUR2 is used. Will use it for account map.')
|
|
283
284
|
set_parameters({'account-map-source': 'dummy'})
|
|
284
285
|
|
|
285
286
|
for attempt in range(3):
|
|
286
287
|
try:
|
|
288
|
+
choices = {
|
|
289
|
+
'AWS Organizations (one time account listing)': 'organization',
|
|
290
|
+
'CSV file (relative path required)': 'csv',
|
|
291
|
+
}
|
|
292
|
+
if self.get_cur:
|
|
293
|
+
choices['Dummy (CUR account data, no names for CUR1)'] = 'dummy'
|
|
294
|
+
|
|
287
295
|
metadata_source = get_parameter(
|
|
288
296
|
param_name='account-map-source',
|
|
289
297
|
message="Please select account metadata collection method",
|
|
290
|
-
choices=
|
|
291
|
-
'Dummy (CUR account data, no names for CUR1)': 'dummy',
|
|
292
|
-
'AWS Organizations (one time account listing)': 'organization',
|
|
293
|
-
'CSV file (relative path required)': 'csv',
|
|
294
|
-
},
|
|
298
|
+
choices=choices,
|
|
295
299
|
)
|
|
296
300
|
logger.info(f'Attempt {attempt + 2}' )
|
|
297
301
|
# Collect account list from different sources of user choice
|
|
@@ -282,16 +282,18 @@ class Athena(CidBase):
|
|
|
282
282
|
logger.debug(f'WorkGroups: {result.get("WorkGroups")}')
|
|
283
283
|
return result.get('WorkGroups')
|
|
284
284
|
|
|
285
|
-
def get_table_metadata(self, table_name: str, database_name: str=None) -> dict:
|
|
286
|
-
table_metadata =
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
'DatabaseName': database_name or self.DatabaseName,
|
|
290
|
-
'TableName': table_name
|
|
291
|
-
}
|
|
285
|
+
def get_table_metadata(self, table_name: str, database_name: str=None, no_cache: bool=False) -> dict:
|
|
286
|
+
table_metadata = None
|
|
287
|
+
if not no_cache:
|
|
288
|
+
table_metadata = self._metadata.get(table_name)
|
|
292
289
|
if not table_metadata:
|
|
290
|
+
params = {
|
|
291
|
+
'CatalogName': self.CatalogName,
|
|
292
|
+
'DatabaseName': database_name or self.DatabaseName,
|
|
293
|
+
'TableName': table_name,
|
|
294
|
+
}
|
|
293
295
|
table_metadata = self.client.get_table_metadata(**params).get('TableMetadata')
|
|
294
|
-
self._metadata
|
|
296
|
+
self._metadata[table_name] = table_metadata
|
|
295
297
|
|
|
296
298
|
return table_metadata
|
|
297
299
|
|
|
@@ -184,8 +184,10 @@ class AbstractCUR(CidBase):
|
|
|
184
184
|
return self._tag_and_cost_category
|
|
185
185
|
|
|
186
186
|
self._tag_and_cost_category = []
|
|
187
|
-
number_of_rows_scanned =
|
|
188
|
-
for tag_type in [
|
|
187
|
+
number_of_rows_scanned = 500000 # empiric value
|
|
188
|
+
for tag_type in ['resource_tags', 'cost_category']:
|
|
189
|
+
if tag_type not in self.fields:
|
|
190
|
+
logging.debug(f'skipping {tag_type} scan')
|
|
189
191
|
cid_print(f'Scanning {tag_type} in {self.table_name}.')
|
|
190
192
|
try:
|
|
191
193
|
res = self.athena.query(
|
|
@@ -211,7 +213,9 @@ class AbstractCUR(CidBase):
|
|
|
211
213
|
cid_print(f' <BOLD>{tag_type:<{max_width}} | Distinct Values <END> ')
|
|
212
214
|
for line in res:
|
|
213
215
|
if int(line[1]) > 10:
|
|
214
|
-
|
|
216
|
+
name = line[0]
|
|
217
|
+
name = name.replace('user_', '')
|
|
218
|
+
cid_print(f' <BOLD>{name:<{max_width}}<END> | {line[1]} ')
|
|
215
219
|
self._tag_and_cost_category += sorted([f"{tag_type}['{line[0]}']" for line in res])
|
|
216
220
|
except (self.athena.client.exceptions.ClientError, CidCritical, ValueError) as exc:
|
|
217
221
|
logger.error(f'Failed to read {tag_type} from {self.table_name}: "{exc}". Will continue without.')
|
|
@@ -1205,6 +1205,8 @@ class QuickSight(CidBase):
|
|
|
1205
1205
|
schedule["RefreshType"] = schedule.get("RefreshType", "FULL_REFRESH")
|
|
1206
1206
|
if "providedBy" in schedule:
|
|
1207
1207
|
del schedule["providedBy"]
|
|
1208
|
+
if "source" in schedule:
|
|
1209
|
+
del schedule["source"]
|
|
1208
1210
|
|
|
1209
1211
|
if not existing_schedule:
|
|
1210
1212
|
# Avoid adding a new schedule when customer already has put a schedule manually as this can lead to additional charges.
|
|
@@ -68,33 +68,12 @@ class Dataset(CidQsResource):
|
|
|
68
68
|
'''
|
|
69
69
|
def _get_athena_columns(table, database=None):
|
|
70
70
|
'''returns athena columns'''
|
|
71
|
+
metadata = athena.get_table_metadata(table, database_name=database, no_cache=True)
|
|
71
72
|
return [
|
|
72
|
-
|
|
73
|
-
for
|
|
74
|
-
f'SHOW COLUMNS FROM {table}',
|
|
75
|
-
include_header=True, database=database
|
|
76
|
-
)
|
|
73
|
+
(col['Name'], col['Type'])
|
|
74
|
+
for col in metadata.get('Columns', [])
|
|
77
75
|
]
|
|
78
76
|
|
|
79
|
-
def _replace_columns(existing_columns, new_columns):
|
|
80
|
-
'''replace columns but keep the order, ignore case changes
|
|
81
|
-
assert _replace_columns(
|
|
82
|
-
[{'Name': 'a'}, {'Name': 'B'}, {'Name': 'c'}],
|
|
83
|
-
[{'Name': 'A'}, {'Name': 'b'}, {'Name': 'd'}]) \
|
|
84
|
-
== [{'Name': 'a'}, {'Name': 'B'}, {'Name': 'd'}]
|
|
85
|
-
Different types will be replaced
|
|
86
|
-
'''
|
|
87
|
-
existing_columns = [
|
|
88
|
-
existing_col
|
|
89
|
-
for existing_col in existing_columns
|
|
90
|
-
if str(existing_col).lower() in [str(c).lower() for c in new_columns]
|
|
91
|
-
] # filter out old
|
|
92
|
-
for col in new_columns: # add new
|
|
93
|
-
if col['Name'].lower() not in [c['Name'].lower() for c in existing_columns]:
|
|
94
|
-
existing_columns.append(col)
|
|
95
|
-
#REFACTOR: what if col is there but another type?
|
|
96
|
-
return existing_columns
|
|
97
|
-
|
|
98
77
|
def _athena_to_qs_type(col, athena_type):
|
|
99
78
|
'''map athena type to QS type
|
|
100
79
|
The following data types are supported in SPICE: Date, Decimal-fixed, Decimal-float, Integer, and String.
|
|
@@ -125,8 +104,14 @@ class Dataset(CidQsResource):
|
|
|
125
104
|
root_lt = dataset['LogicalTableMap'][lt]
|
|
126
105
|
break
|
|
127
106
|
else:
|
|
128
|
-
|
|
129
|
-
|
|
107
|
+
# take the first one and let's hope it is fine
|
|
108
|
+
root_lt = next(iter(dataset['LogicalTableMap'].values()))
|
|
109
|
+
|
|
110
|
+
projected_cols = next( # get the first DataTrasform with ProjectOperation
|
|
111
|
+
ds['ProjectOperation']["ProjectedColumns"]
|
|
112
|
+
for ds in root_lt['DataTransforms']
|
|
113
|
+
if 'ProjectOperation' in ds
|
|
114
|
+
)
|
|
130
115
|
|
|
131
116
|
# Update each PhysicalTableMap with all columns from athena views
|
|
132
117
|
all_columns = []
|
|
@@ -135,12 +120,31 @@ class Dataset(CidQsResource):
|
|
|
135
120
|
database = pt['RelationalTable']['Schema']
|
|
136
121
|
columns = _get_athena_columns(table_name, database)
|
|
137
122
|
logger.trace(f'columns = {columns}')
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
123
|
+
athena_columns = [
|
|
124
|
+
_athena_to_qs_type(name, athena_type.lower())
|
|
125
|
+
for name, athena_type in columns
|
|
126
|
+
]
|
|
127
|
+
logger.trace(f'athena_columns = {columns}')
|
|
128
|
+
athena_columns_names = [c['Name'].lower() for c in athena_columns]
|
|
129
|
+
dataset_columns = pt['RelationalTable']['InputColumns']
|
|
130
|
+
dataset_columns_names = [col['Name'].lower() for col in dataset_columns]
|
|
131
|
+
dataset_columns_to_keep = [
|
|
132
|
+
col for col in dataset_columns
|
|
133
|
+
if col['Name'].lower() in athena_columns_names
|
|
134
|
+
]
|
|
135
|
+
new_columns = [
|
|
136
|
+
col for col in athena_columns
|
|
137
|
+
if col['Name'].lower() not in dataset_columns_names
|
|
138
|
+
] # BTW what if col is there but another type?
|
|
139
|
+
|
|
140
|
+
for col in new_columns: # alter names for columns that already exist
|
|
141
|
+
if col['Name'].lower() in projected_cols:
|
|
142
|
+
col['Name'] = f"{col['Name']}[{table_name}]" # What if it is alrady there?
|
|
143
|
+
|
|
144
|
+
logger.trace(f'dataset_columns_to_keep = {dataset_columns_to_keep}')
|
|
145
|
+
if new_columns:
|
|
146
|
+
logger.trace(f'new_columns = {new_columns}')
|
|
147
|
+
pt['RelationalTable']['InputColumns'] = dataset_columns_to_keep + new_columns
|
|
144
148
|
all_columns += [col['Name'] for col in pt['RelationalTable']['InputColumns']]
|
|
145
149
|
|
|
146
150
|
# Add all needed calc fields
|
|
@@ -190,7 +190,7 @@ def set_defaults(data: dict) -> None:
|
|
|
190
190
|
if data:
|
|
191
191
|
defaults.update(data)
|
|
192
192
|
|
|
193
|
-
def get_defaults() ->
|
|
193
|
+
def get_defaults() -> dict:
|
|
194
194
|
global defaults
|
|
195
195
|
return dict(defaults)
|
|
196
196
|
|
|
@@ -250,7 +250,7 @@ def get_parameter(param_name, message, choices=None, default=None, none_as_disab
|
|
|
250
250
|
param_name = param_name.replace('_', '-')
|
|
251
251
|
|
|
252
252
|
# override defaults from code with outside defaults
|
|
253
|
-
if param_name in
|
|
253
|
+
if param_name in get_defaults():
|
|
254
254
|
default = defaults.get(param_name)
|
|
255
255
|
if multi and isinstance(default, str):
|
|
256
256
|
default = split_respecting_quotes(default)
|
|
@@ -276,6 +276,7 @@ def get_parameter(param_name, message, choices=None, default=None, none_as_disab
|
|
|
276
276
|
if multi:
|
|
277
277
|
default = default or []
|
|
278
278
|
default = default if isinstance(default, list) else [default]
|
|
279
|
+
default = [c for c in defaults if c in choices]
|
|
279
280
|
if not isatty():
|
|
280
281
|
result = default
|
|
281
282
|
else:
|
cid_cmd-4.2.2/cid/_version.py
DELETED
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/datasets/trends/daily_anomaly_detection.json
RENAMED
|
File without changes
|
{cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/datasets/trends/monthly_anomaly_detection.json
RENAMED
|
File without changes
|
{cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/datasets/trends/monthly_bill_by_account.json
RENAMED
|
File without changes
|
{cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/permissions/dashboard_permissions.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/permissions/data_source_permissions.json
RENAMED
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/queries/shared/aws_service_category_map.sql
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/queries/shared/customer_all_unlimited.sql
RENAMED
|
File without changes
|
{cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/queries/shared/payer_account_name_map.sql
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/queries/trends/daily_anomaly_detection.sql
RENAMED
|
File without changes
|
{cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/queries/trends/monthly_anomaly_detection.sql
RENAMED
|
File without changes
|
{cid_cmd-4.2.2 → cid_cmd-4.2.4}/cid/builtin/core/data/queries/trends/monthly_bill_by_account.sql
RENAMED
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|