cid-cmd 0.2.45__tar.gz → 0.2.47__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-0.2.45/cid_cmd.egg-info → cid-cmd-0.2.47}/PKG-INFO +1 -1
- cid-cmd-0.2.47/cid/_version.py +2 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/base.py +6 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/cli.py +7 -1
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/common.py +59 -19
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/export.py +15 -3
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/helpers/quicksight/__init__.py +62 -9
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/helpers/quicksight/dashboard.py +10 -6
- cid-cmd-0.2.47/cid/test/python/test_isolated_parameters.py +12 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/utils.py +10 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47/cid_cmd.egg-info}/PKG-INFO +1 -1
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid_cmd.egg-info/SOURCES.txt +1 -0
- cid-cmd-0.2.45/cid/_version.py +0 -2
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/LICENSE +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/MANIFEST.in +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/README.md +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/__init__.py +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/__init__.py +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/__init__.py +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/datasets/cid/compute.json +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/datasets/cid/ec2_running_cost.json +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/datasets/cid/s3_view.json +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/datasets/cid/summary_view.json +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/datasets/co/dataset.json +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/datasets/cudos/hourly_view.json +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/datasets/cudos/resource_view.json +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/datasets/kpi/kpi_ebs_snap.json +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/datasets/kpi/kpi_ebs_storage_all.json +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/datasets/kpi/kpi_instance_all.json +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/datasets/kpi/kpi_s3_storage_all.json +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/datasets/kpi/kpi_tracker.json +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/datasets/shared/customer_all.json +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/datasets/tao/dataset.json +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/datasets/trends/daily_anomaly_detection.json +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/datasets/trends/monthly_anomaly_detection.json +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/datasets/trends/monthly_bill_by_account.json +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/permissions/dashboard_permissions.json +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/permissions/dashboard_permissions_namespace.json +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/permissions/data_set_permissions.json +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/permissions/data_source_permissions.json +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/permissions/folder_permissions.json +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/queries/cid/compute_savings_plan_eligible_spend.sql +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/queries/cid/ec2_running_cost.sql +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/queries/cid/ec2_running_cost_ri.sql +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/queries/cid/ec2_running_cost_sp.sql +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/queries/cid/ec2_running_cost_sp_ri.sql +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/queries/cid/ri_sp_mapping.sql +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/queries/cid/ri_sp_mapping_ri.sql +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/queries/cid/ri_sp_mapping_sp.sql +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/queries/cid/ri_sp_mapping_sp_ri.sql +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/queries/cid/s3.sql +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/queries/cid/summary_view.sql +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/queries/cid/summary_view_ri.sql +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/queries/cid/summary_view_sp.sql +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/queries/cid/summary_view_sp_ri.sql +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/queries/co/all_options.sql +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/queries/co/auto_scale.json +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/queries/co/auto_scale_options.sql +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/queries/co/ebs_volume.json +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/queries/co/ebs_volume_options.sql +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/queries/co/ec2_instance.json +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/queries/co/ec2_instance_options.sql +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/queries/co/lambda.json +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/queries/co/lambda_options.sql +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/queries/cudos/hourly_view.sql +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/queries/cudos/hourly_view_ri.sql +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/queries/cudos/hourly_view_sp.sql +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/queries/cudos/hourly_view_sp_ri.sql +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/queries/cudos/resource_view.sql +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/queries/cudos/resource_view_ri.sql +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/queries/cudos/resource_view_sp.sql +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/queries/cudos/resource_view_sp_ri.sql +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/queries/kpi/first_kpi_instance_mapping_view.sql +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/queries/kpi/kpi_ebs_snap_view.sql +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/queries/kpi/kpi_ebs_storage_view.sql +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/queries/kpi/kpi_instance_all_view.sql +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/queries/kpi/kpi_instance_all_view_noRI.sql +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/queries/kpi/kpi_instance_all_view_noRISP.sql +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/queries/kpi/kpi_instance_all_view_noSP.sql +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/queries/kpi/kpi_s3_storage_view.sql +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/queries/kpi/last_kpi_tracker_view.sql +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/queries/shared/account_map.sql +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/queries/shared/account_map_dummy.sql +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/queries/shared/aws_accounts.sql +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/queries/shared/aws_regions.sql +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/queries/shared/aws_service_category_map.sql +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/queries/shared/business_units_map.sql +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/queries/shared/payer_account_name_map.sql +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/queries/shared/ta_descriptions.sql +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/queries/tao/glue_table.json +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/queries/tao/ta_org_view.sql +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/queries/trends/daily_anomaly_detection.sql +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/queries/trends/monthly_anomaly_detection.sql +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/queries/trends/monthly_bill_by_account.sql +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/queries/trends/monthly_bill_by_account_ri.sql +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/queries/trends/monthly_bill_by_account_sp.sql +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/queries/trends/monthly_bill_by_account_sp_ri.sql +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/resources.yaml +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/commands/__init__.py +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/commands/command_base.py +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/commands/init_qs.py +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/exceptions.py +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/helpers/__init__.py +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/helpers/account_map.py +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/helpers/athena.py +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/helpers/csv2view.py +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/helpers/cur.py +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/helpers/diff.py +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/helpers/glue.py +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/helpers/organizations.py +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/helpers/quicksight/dataset.py +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/helpers/quicksight/datasource.py +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/helpers/quicksight/resource.py +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/helpers/quicksight/template.py +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/helpers/randtime.py +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/helpers/s3.py +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/helpers/timezone.py +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/logger.py +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/plugin.py +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/test/python/test_csv2view.py +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/test/python/test_merge.py +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid_cmd.egg-info/dependency_links.txt +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid_cmd.egg-info/entry_points.txt +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid_cmd.egg-info/requires.txt +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid_cmd.egg-info/top_level.txt +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/pyproject.toml +0 -0
- {cid-cmd-0.2.45 → cid-cmd-0.2.47}/setup.cfg +0 -0
|
@@ -21,6 +21,12 @@ class CidBase():
|
|
|
21
21
|
def account_id(self) -> str:
|
|
22
22
|
return self.awsIdentity.get('Account')
|
|
23
23
|
|
|
24
|
+
@property
|
|
25
|
+
def domain(self) -> str:
|
|
26
|
+
if self.region.startswith('cn-'):
|
|
27
|
+
return 'amazonaws.cn'
|
|
28
|
+
return 'aws.amazon.com'
|
|
29
|
+
|
|
24
30
|
@property
|
|
25
31
|
def awsIdentity(self) -> dict:
|
|
26
32
|
if not self._awsIdentity:
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import os
|
|
1
2
|
import logging
|
|
3
|
+
import platform
|
|
2
4
|
|
|
3
5
|
import click
|
|
4
6
|
|
|
@@ -14,7 +16,6 @@ prog_name="CLOUD INTELLIGENCE DASHBOARDS (CID) CLI"
|
|
|
14
16
|
print(f'{prog_name} {version}\n')
|
|
15
17
|
|
|
16
18
|
if __version__ != latest_version and latest_version != 'UNDEFINED':
|
|
17
|
-
|
|
18
19
|
print('\033[93mUPDATE AVAILABLE\033[0m')
|
|
19
20
|
print(f'\033[93mA new version {latest_version} is available, please consider update cid-cmd package via pip\033[0m\n\n')
|
|
20
21
|
logger.info(f'A new version {latest_version} is available, please consider update cid-cmd package via pip')
|
|
@@ -67,6 +68,11 @@ def cid_command(func):
|
|
|
67
68
|
@click.option('-y', '--yes', help='confirm all', is_flag=True, default=False)
|
|
68
69
|
@click.pass_context
|
|
69
70
|
def main(ctx, **kwargs):
|
|
71
|
+
|
|
72
|
+
# enable color for windows terminal
|
|
73
|
+
if platform.system() == "Windows":
|
|
74
|
+
os.system('color') #nosec B605, B607
|
|
75
|
+
|
|
70
76
|
ctx.obj = Cid(**kwargs)
|
|
71
77
|
|
|
72
78
|
|
|
@@ -23,7 +23,7 @@ from botocore.exceptions import ClientError, NoCredentialsError, CredentialRetri
|
|
|
23
23
|
from cid import utils
|
|
24
24
|
from cid.base import CidBase
|
|
25
25
|
from cid.plugin import Plugin
|
|
26
|
-
from cid.utils import get_parameter, get_parameters, set_parameters, unset_parameter, get_yesno_parameter, cid_print, isatty, merge_objects
|
|
26
|
+
from cid.utils import get_parameter, get_parameters, set_parameters, unset_parameter, get_yesno_parameter, cid_print, isatty, merge_objects, IsolatedParameters
|
|
27
27
|
from cid.helpers.account_map import AccountMap
|
|
28
28
|
from cid.helpers import Athena, CUR, Glue, QuickSight, Dashboard, Dataset, Datasource, csv2view, Organizations
|
|
29
29
|
from cid.helpers.quicksight.template import Template as CidQsTemplate
|
|
@@ -45,7 +45,7 @@ class Cid():
|
|
|
45
45
|
self.plugins = self.__loadPlugins()
|
|
46
46
|
self._clients = dict()
|
|
47
47
|
self._visited_views = [] # Views updated in the current session
|
|
48
|
-
self.qs_url = 'https://{region}.quicksight.
|
|
48
|
+
self.qs_url = 'https://{region}.quicksight.{domain}/sn/dashboards/{dashboard_id}'
|
|
49
49
|
self.all_yes = kwargs.get('yes')
|
|
50
50
|
self.verbose = kwargs.get('verbose')
|
|
51
51
|
set_parameters(kwargs, self.all_yes)
|
|
@@ -75,7 +75,8 @@ class Cid():
|
|
|
75
75
|
logger.info(f'AWS profile name: {self.base.session.profile_name}')
|
|
76
76
|
self.qs_url_params = {
|
|
77
77
|
'account_id': self.base.account_id,
|
|
78
|
-
'region': self.base.session.region_name
|
|
78
|
+
'region': self.base.session.region_name,
|
|
79
|
+
'domain': self.base.domain,
|
|
79
80
|
}
|
|
80
81
|
except (NoCredentialsError, CredentialRetrievalError):
|
|
81
82
|
raise CidCritical('Error: Not authenticated, please check AWS credentials')
|
|
@@ -630,24 +631,63 @@ class Cid():
|
|
|
630
631
|
@command
|
|
631
632
|
def status(self, dashboard_id, **kwargs):
|
|
632
633
|
"""Check QuickSight dashboard status"""
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
if not self.qs.dashboards:
|
|
636
|
-
print('No deployed dashboards found')
|
|
637
|
-
return
|
|
638
|
-
dashboard_id = self.qs.select_dashboard(force=True)
|
|
634
|
+
next_selection = None
|
|
635
|
+
while next_selection != 'exit':
|
|
639
636
|
if not dashboard_id:
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
637
|
+
if not self.qs.dashboards:
|
|
638
|
+
print('No deployed dashboards found')
|
|
639
|
+
return
|
|
640
|
+
dashboard_id = self.qs.select_dashboard(force=True)
|
|
641
|
+
if not dashboard_id:
|
|
642
|
+
print('No dashboard selected')
|
|
643
|
+
return
|
|
644
644
|
dashboard = self.qs.discover_dashboard(dashboardId=dashboard_id)
|
|
645
645
|
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
646
|
+
if dashboard is not None:
|
|
647
|
+
dashboard.display_status()
|
|
648
|
+
dashboard.display_url(self.qs_url, **self.qs_url_params)
|
|
649
|
+
with IsolatedParameters():
|
|
650
|
+
next_selection = get_parameter(
|
|
651
|
+
param_name=f'{dashboard.id}',
|
|
652
|
+
message="Please make a selection",
|
|
653
|
+
choices={
|
|
654
|
+
'[◀] Back': 'back',
|
|
655
|
+
'[↗] Open': 'open',
|
|
656
|
+
'[◴] Refresh datasets': 'refresh',
|
|
657
|
+
'[↺] Update dashboard': 'update',
|
|
658
|
+
'[✕] Exit': 'exit',
|
|
659
|
+
}
|
|
660
|
+
)
|
|
661
|
+
if next_selection == 'open':
|
|
662
|
+
self.open(dashboard.id, **kwargs)
|
|
663
|
+
|
|
664
|
+
elif next_selection == 'refresh':
|
|
665
|
+
dashboard.refresh_datasets()
|
|
666
|
+
|
|
667
|
+
elif next_selection == 'update':
|
|
668
|
+
if dashboard.latest:
|
|
669
|
+
if not get_yesno_parameter(
|
|
670
|
+
param_name=f'redeploy-{dashboard.id}',
|
|
671
|
+
message=f'\nThe selected dashboard {dashboard.id} is already on the latest version.\nDo you want to re-deploy it?',
|
|
672
|
+
default='no'):
|
|
673
|
+
logger.info(f'Not re-deploying {dashboard.id} as it is on latest version.\n')
|
|
674
|
+
continue
|
|
675
|
+
recursive = get_parameter(
|
|
676
|
+
param_name='recursive',
|
|
677
|
+
message=f'\nRecursive update the Datasets and Views in addition to the Dashboard update?\nATTENTION: This could lead to the loss of dataset customization.\nRecursive update?',
|
|
678
|
+
choices={
|
|
679
|
+
'[→] Simple Update (only dashboard)': 'simple',
|
|
680
|
+
'[⇶] Recursive Update (dashboard and all dependencies)': 'recursive',
|
|
681
|
+
}
|
|
682
|
+
) == 'recursive'
|
|
683
|
+
logger.info(f'Updating dashboard: {dashboard.id} with Recursive = {recursive}')
|
|
684
|
+
self._deploy(dashboard_id, recursive=recursive, update=True)
|
|
685
|
+
logger.info('Rediscover dashboards after update')
|
|
686
|
+
self.qs.discover_dashboards()
|
|
687
|
+
self.qs.clear_dashboard_selection()
|
|
688
|
+
dashboard_id = None
|
|
689
|
+
else:
|
|
690
|
+
cid_print('not deployed.')
|
|
651
691
|
|
|
652
692
|
@command
|
|
653
693
|
def delete(self, dashboard_id, **kwargs):
|
|
@@ -1284,7 +1324,7 @@ class Cid():
|
|
|
1284
1324
|
athena_datasource = Datasource(raw={
|
|
1285
1325
|
'AthenaParameters':{},
|
|
1286
1326
|
"Id": datasource_id,
|
|
1287
|
-
"Arn": f"arn:
|
|
1327
|
+
"Arn": f"arn:{self.base.partition}:quicksight:{self.base.session.region_name}:{self.base.account_id}:datasource/{datasource_id}",
|
|
1288
1328
|
})
|
|
1289
1329
|
except Exception as exc:
|
|
1290
1330
|
raise CidCritical(
|
|
@@ -69,6 +69,16 @@ def choose_analysis(qs):
|
|
|
69
69
|
return choices[choice]['AnalysisId']
|
|
70
70
|
|
|
71
71
|
|
|
72
|
+
def get_theme(analysis):
|
|
73
|
+
theme_arn = analysis.get('ThemeArn')
|
|
74
|
+
if not theme_arn:
|
|
75
|
+
return None
|
|
76
|
+
if theme_arn.startswith('arn:aws:quicksight::aws:theme/'):
|
|
77
|
+
return theme_arn.split('/')[-1]
|
|
78
|
+
logger.warning(f'Theme {theme_arn} is not standard and is not supported yet. Theme will be ignored.')
|
|
79
|
+
return None
|
|
80
|
+
|
|
81
|
+
|
|
72
82
|
def export_analysis(qs, athena):
|
|
73
83
|
""" Export analysis to yaml resource File
|
|
74
84
|
"""
|
|
@@ -94,7 +104,7 @@ def export_analysis(qs, athena):
|
|
|
94
104
|
resources = {}
|
|
95
105
|
resources['dashboards'] = {}
|
|
96
106
|
resources['datasets'] = {}
|
|
97
|
-
|
|
107
|
+
theme_id = get_theme(analysis)
|
|
98
108
|
|
|
99
109
|
cur_helper = CUR(session=athena.session)
|
|
100
110
|
resources_datasets = []
|
|
@@ -270,6 +280,8 @@ def export_analysis(qs, athena):
|
|
|
270
280
|
dashboard_resource['name'] = analysis['Name']
|
|
271
281
|
dashboard_resource['dashboardId'] = dashboard_id
|
|
272
282
|
dashboard_resource['category'] = get_parameters().get('category', 'Custom')
|
|
283
|
+
if theme_id:
|
|
284
|
+
dashboard_resource['theme'] = theme_id
|
|
273
285
|
|
|
274
286
|
dashboard_export_method = None
|
|
275
287
|
if get_parameters().get('template-id'):
|
|
@@ -344,7 +356,7 @@ def export_analysis(qs, athena):
|
|
|
344
356
|
TemplateId=template_id,
|
|
345
357
|
GrantPermissions=[
|
|
346
358
|
{
|
|
347
|
-
"Principal": f'arn:
|
|
359
|
+
"Principal": f'arn:{qs.partition}:iam::{reader_account_id}:root' if reader_account_id != '*' else '*',
|
|
348
360
|
'Actions': [
|
|
349
361
|
"quicksight:DescribeTemplate",
|
|
350
362
|
]
|
|
@@ -363,7 +375,7 @@ def export_analysis(qs, athena):
|
|
|
363
375
|
|
|
364
376
|
for dataset in definition.get('DataSetIdentifierDeclarations', []):
|
|
365
377
|
# Hide region and account number of the source account
|
|
366
|
-
dataset["DataSetArn"] = 'arn:
|
|
378
|
+
dataset["DataSetArn"] = f'arn:{qs.partition}:quicksight:::dataset/' + dataset["DataSetArn"].split('/')[-1]
|
|
367
379
|
dashboard_resource['data'] = yaml.safe_dump(definition)
|
|
368
380
|
|
|
369
381
|
resources['dashboards'][analysis['Name'].upper()] = dashboard_resource
|
|
@@ -2,6 +2,7 @@ import re
|
|
|
2
2
|
import json
|
|
3
3
|
import uuid
|
|
4
4
|
import time
|
|
5
|
+
import datetime
|
|
5
6
|
import logging
|
|
6
7
|
from string import Template
|
|
7
8
|
from typing import Dict, List, Union
|
|
@@ -15,7 +16,7 @@ from cid.helpers.quicksight.dashboard import Dashboard
|
|
|
15
16
|
from cid.helpers.quicksight.dataset import Dataset
|
|
16
17
|
from cid.helpers.quicksight.datasource import Datasource
|
|
17
18
|
from cid.helpers.quicksight.template import Template as CidQsTemplate
|
|
18
|
-
from cid.utils import get_parameter, get_parameters, exec_env, cid_print, ago
|
|
19
|
+
from cid.utils import get_parameter, get_parameters, exec_env, cid_print, ago, unset_parameter
|
|
19
20
|
from cid.exceptions import CidCritical, CidError
|
|
20
21
|
|
|
21
22
|
logger = logging.getLogger(__name__)
|
|
@@ -604,6 +605,10 @@ class QuickSight(CidBase):
|
|
|
604
605
|
logger.debug(exc, exc_info=True)
|
|
605
606
|
return list()
|
|
606
607
|
|
|
608
|
+
def clear_dashboard_selection (self):
|
|
609
|
+
""" Clears the current dashboard selection. """
|
|
610
|
+
unset_parameter('dashboard-id')
|
|
611
|
+
|
|
607
612
|
def select_dashboard(self, force=False) -> str:
|
|
608
613
|
""" Select from a list of discovered dashboards """
|
|
609
614
|
dashboard_id = get_parameters().get('dashboard-id')
|
|
@@ -614,8 +619,9 @@ class QuickSight(CidBase):
|
|
|
614
619
|
return None
|
|
615
620
|
choices = {}
|
|
616
621
|
for dashboard in self.dashboards.values():
|
|
617
|
-
health = '
|
|
618
|
-
|
|
622
|
+
health = '' if dashboard.health else ' UNHEALTHY'
|
|
623
|
+
status = '' if dashboard.status == 'up to date' else ' ' + dashboard.status.upper()
|
|
624
|
+
key = f'{dashboard.name} ({dashboard.arn.split("/")[-1]}){health}{status}'
|
|
619
625
|
notice = dashboard.definition.get('deprecationNotice', '')
|
|
620
626
|
if notice:
|
|
621
627
|
key = f'{key} {notice}'
|
|
@@ -950,6 +956,29 @@ class QuickSight(CidBase):
|
|
|
950
956
|
logger.debug(exc, exc_info=True)
|
|
951
957
|
logger.info('No datasets found')
|
|
952
958
|
|
|
959
|
+
def refresh_dataset(self, dataset_id):
|
|
960
|
+
""" Refresh the dataset """
|
|
961
|
+
|
|
962
|
+
logger.info(f'Starting refresh for dataset: {dataset_id}')
|
|
963
|
+
status = 'FAILED'
|
|
964
|
+
try:
|
|
965
|
+
response = self.client.describe_data_set(
|
|
966
|
+
AwsAccountId=self.account_id,
|
|
967
|
+
DataSetId=dataset_id)
|
|
968
|
+
mode = response.get('DataSet').get('ImportMode')
|
|
969
|
+
if mode == 'DIRECT_QUERY':
|
|
970
|
+
return mode, 'DIRECT'
|
|
971
|
+
response = self.client.create_ingestion(
|
|
972
|
+
DataSetId=dataset_id,
|
|
973
|
+
IngestionId=datetime.datetime.now().strftime("%d%m%y-%H%M%S-%f"),
|
|
974
|
+
AwsAccountId=self.account_id)
|
|
975
|
+
status = response.get('IngestionStatus')
|
|
976
|
+
except self.client.exceptions.AccessDeniedException:
|
|
977
|
+
logger.error(f'Access denied refreshing dataset: {dataset_id}')
|
|
978
|
+
except Exception as exc:
|
|
979
|
+
logger.debug(exc, exc_info=True)
|
|
980
|
+
raise CidError(f'Unable to list refresh dataset {dataset_id}: {str(exc)}') from exc
|
|
981
|
+
return mode, status
|
|
953
982
|
|
|
954
983
|
def describe_data_source(self, id: str, update: bool=False) -> Datasource:
|
|
955
984
|
""" Describes an AWS QuickSight DataSource """
|
|
@@ -1125,12 +1154,27 @@ class QuickSight(CidBase):
|
|
|
1125
1154
|
try:
|
|
1126
1155
|
existing_schedules = self.get_dataset_refresh_schedules(dataset_id)
|
|
1127
1156
|
except CidError as exc:
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1157
|
+
# We cannot access schedules, but let's check if there are scheduled ingestions.
|
|
1158
|
+
ingestions_exist = False
|
|
1159
|
+
try:
|
|
1160
|
+
ingestions_exist = list(
|
|
1161
|
+
self.client.get_paginator('list_ingestions').paginate(
|
|
1162
|
+
DataSetId=dataset_id,
|
|
1163
|
+
AwsAccountId=self.account_id
|
|
1164
|
+
).search("Ingestions[?RequestSource=='SCHEDULED']")
|
|
1165
|
+
)
|
|
1166
|
+
except Exception:
|
|
1167
|
+
logger.debug(f'List refresh schedule throws: {exc}')
|
|
1168
|
+
logger.warning(
|
|
1169
|
+
f'Cannot read dataset schedules for dataset = {dataset_id}. {str(exc)}. Skipping schedule management.'
|
|
1170
|
+
' Please make sure scheduled refresh is configured manually.'
|
|
1171
|
+
)
|
|
1172
|
+
return
|
|
1173
|
+
if ingestions_exist:
|
|
1174
|
+
logger.debug(f'We cannot read schedules but there are ingestions. Skipping creation of schedule.')
|
|
1175
|
+
return
|
|
1176
|
+
logger.debug(f'We cannot read schedules but there no ingestions. Continue to creation of schedule.')
|
|
1177
|
+
existing_schedules = []
|
|
1134
1178
|
|
|
1135
1179
|
if schedules:
|
|
1136
1180
|
if exec_env()['terminal'] in ('lambda'):
|
|
@@ -1198,6 +1242,8 @@ class QuickSight(CidBase):
|
|
|
1198
1242
|
logger.error(f'Unable to create refresh schedule with id {schedule["ScheduleId"]}. Dataset {dataset_id} does not exist.')
|
|
1199
1243
|
except self.client.exceptions.AccessDeniedException:
|
|
1200
1244
|
logger.error(f'Unable to create refresh schedule with id {schedule["ScheduleId"]}. Please add quicksight:CreateDataSet permission.')
|
|
1245
|
+
except self.client.exceptions.ResourceExistsException:
|
|
1246
|
+
logger.info(f'Schedule with id {schedule["ScheduleId"]} exists. But can have other settings. You better check.')
|
|
1201
1247
|
except Exception as exc:
|
|
1202
1248
|
logger.error(f'Unable to create refresh schedule with id {schedule["ScheduleId"]} for dataset "{dataset_id}": {str(exc)}')
|
|
1203
1249
|
else:
|
|
@@ -1271,6 +1317,13 @@ class QuickSight(CidBase):
|
|
|
1271
1317
|
'Name': definition.get('name'),
|
|
1272
1318
|
'ValidationStrategy': {'Mode': 'LENIENT'},
|
|
1273
1319
|
}
|
|
1320
|
+
theme = definition.get('theme')
|
|
1321
|
+
if theme:
|
|
1322
|
+
if not theme.startswith('arn:'):
|
|
1323
|
+
theme_arn = 'arn:aws:quicksight::aws:theme/' + theme
|
|
1324
|
+
else:
|
|
1325
|
+
raise NotImplementedError('Only standard themes are supported now.')
|
|
1326
|
+
create_parameters['ThemeArn'] = theme_arn
|
|
1274
1327
|
|
|
1275
1328
|
if definition.get('sourceTemplate'):
|
|
1276
1329
|
dataset_references = [
|
|
@@ -81,7 +81,7 @@ class Dashboard(CidQsResource):
|
|
|
81
81
|
if self.version.get('Status') not in ['CREATION_SUCCESSFUL']:
|
|
82
82
|
self._status = 'broken'
|
|
83
83
|
self.status_detail = f"{self.version.get('Status')}: {self.version.get('Errors')}"
|
|
84
|
-
# Not
|
|
84
|
+
# Not discovered yet
|
|
85
85
|
elif not self.definition:
|
|
86
86
|
self._status = 'undiscovered'
|
|
87
87
|
# Missing dataset
|
|
@@ -147,13 +147,17 @@ class Dashboard(CidQsResource):
|
|
|
147
147
|
if self.datasets:
|
|
148
148
|
cid_print(f" <BOLD>Datasets:<END>")
|
|
149
149
|
for dataset_name, dataset_id in sorted(self.datasets.items()):
|
|
150
|
-
status = self.qs.get_dataset_last_ingestion(dataset_id) or '<BLUE>DIRECT<END>'
|
|
150
|
+
status = self.qs.get_dataset_last_ingestion(dataset_id) or '<BLUE>DIRECT<END>' #todo fix this Blue using dataset import type.
|
|
151
151
|
cid_print(f' {dataset_name: <36} ({dataset_id: <36}) {status}')
|
|
152
152
|
|
|
153
|
-
print('\n')
|
|
154
|
-
if get_yesno_parameter('display-raw', 'Display dashboard raw data?', default='yes'):
|
|
155
|
-
print(json.dumps(self.raw, indent=4, sort_keys=True, default=str))
|
|
156
|
-
|
|
157
153
|
def display_url(self, url_template: str, launch: bool = False, **kwargs) -> None:
|
|
158
154
|
url = url_template.format(dashboard_id=self.id, **kwargs)
|
|
159
155
|
print(f"#######\n####### {self.name} is available at: " + url + "\n#######")
|
|
156
|
+
|
|
157
|
+
def refresh_datasets(self) -> None:
|
|
158
|
+
"""Refresh datasets of dashboard"""
|
|
159
|
+
if self.datasets:
|
|
160
|
+
cid_print(f" <BOLD>Refreshing Datasets:<END>")
|
|
161
|
+
for dataset_name, dataset_id in sorted(self.datasets.items()):
|
|
162
|
+
mode, status = self.qs.refresh_dataset(dataset_id)
|
|
163
|
+
cid_print(f' {dataset_name: <36} ({dataset_id: <36}) Refresh Status: {status} Mode: {mode}')
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from cid.utils import IsolatedParameters, get_parameters, set_parameters
|
|
2
|
+
|
|
3
|
+
def test_isolated_parameter_context():
|
|
4
|
+
""" make sure the isolated_parameter works
|
|
5
|
+
"""
|
|
6
|
+
set_parameters({'param': 'a'})
|
|
7
|
+
|
|
8
|
+
with IsolatedParameters():
|
|
9
|
+
set_parameters({'param': 'b'})
|
|
10
|
+
assert get_parameters().get('param') == 'b', 'parameters within context must be B'
|
|
11
|
+
|
|
12
|
+
assert get_parameters().get('param') == 'a', 'parameters within context must be A'
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import sys
|
|
3
|
+
import copy
|
|
3
4
|
import math
|
|
4
5
|
import inspect
|
|
5
6
|
import logging
|
|
@@ -279,6 +280,15 @@ def ago(time):
|
|
|
279
280
|
return 'just now'
|
|
280
281
|
|
|
281
282
|
|
|
283
|
+
class IsolatedParameters:
|
|
284
|
+
"""A context manager to run something in isolated set of parameters"""
|
|
285
|
+
def __enter__(self):
|
|
286
|
+
self.backup = copy.deepcopy(params)
|
|
287
|
+
|
|
288
|
+
def __exit__(self, exc_type, exc_value, traceback):
|
|
289
|
+
global params
|
|
290
|
+
params = self.backup
|
|
291
|
+
|
|
282
292
|
def merge_objects(obj1, obj2, depth=2):
|
|
283
293
|
""" merging objects with a depth
|
|
284
294
|
|
|
@@ -115,6 +115,7 @@ cid/helpers/quicksight/datasource.py
|
|
|
115
115
|
cid/helpers/quicksight/resource.py
|
|
116
116
|
cid/helpers/quicksight/template.py
|
|
117
117
|
cid/test/python/test_csv2view.py
|
|
118
|
+
cid/test/python/test_isolated_parameters.py
|
|
118
119
|
cid/test/python/test_merge.py
|
|
119
120
|
cid_cmd.egg-info/PKG-INFO
|
|
120
121
|
cid_cmd.egg-info/SOURCES.txt
|
cid-cmd-0.2.45/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
|
{cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/datasets/kpi/kpi_ebs_storage_all.json
RENAMED
|
File without changes
|
|
File without changes
|
{cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/datasets/kpi/kpi_s3_storage_all.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/datasets/trends/daily_anomaly_detection.json
RENAMED
|
File without changes
|
|
File without changes
|
{cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/datasets/trends/monthly_bill_by_account.json
RENAMED
|
File without changes
|
{cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/permissions/dashboard_permissions.json
RENAMED
|
File without changes
|
|
File without changes
|
{cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/permissions/data_set_permissions.json
RENAMED
|
File without changes
|
{cid-cmd-0.2.45 → cid-cmd-0.2.47}/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
|
{cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/queries/cid/ec2_running_cost_sp_ri.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
|
{cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/queries/cudos/resource_view_sp_ri.sql
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/queries/kpi/kpi_ebs_storage_view.sql
RENAMED
|
File without changes
|
{cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/queries/kpi/kpi_instance_all_view.sql
RENAMED
|
File without changes
|
{cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/queries/kpi/kpi_instance_all_view_noRI.sql
RENAMED
|
File without changes
|
{cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/queries/kpi/kpi_instance_all_view_noRISP.sql
RENAMED
|
File without changes
|
{cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/queries/kpi/kpi_instance_all_view_noSP.sql
RENAMED
|
File without changes
|
|
File without changes
|
{cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/queries/kpi/last_kpi_tracker_view.sql
RENAMED
|
File without changes
|
|
File without changes
|
{cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/queries/shared/account_map_dummy.sql
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/queries/shared/aws_service_category_map.sql
RENAMED
|
File without changes
|
{cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/queries/shared/business_units_map.sql
RENAMED
|
File without changes
|
{cid-cmd-0.2.45 → cid-cmd-0.2.47}/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-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/queries/trends/daily_anomaly_detection.sql
RENAMED
|
File without changes
|
{cid-cmd-0.2.45 → cid-cmd-0.2.47}/cid/builtin/core/data/queries/trends/monthly_anomaly_detection.sql
RENAMED
|
File without changes
|
{cid-cmd-0.2.45 → cid-cmd-0.2.47}/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
|