cid-cmd 4.2.5__tar.gz → 4.2.7__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 (126) hide show
  1. {cid_cmd-4.2.5/cid_cmd.egg-info → cid_cmd-4.2.7}/PKG-INFO +1 -1
  2. cid_cmd-4.2.7/cid/_version.py +2 -0
  3. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/common.py +17 -18
  4. cid_cmd-4.2.7/cid/helpers/parameter_store.py +88 -0
  5. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/helpers/quicksight/__init__.py +6 -2
  6. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/helpers/quicksight/dataset.py +45 -2
  7. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/utils.py +1 -1
  8. {cid_cmd-4.2.5 → cid_cmd-4.2.7/cid_cmd.egg-info}/PKG-INFO +1 -1
  9. cid_cmd-4.2.5/cid/_version.py +0 -2
  10. cid_cmd-4.2.5/cid/helpers/parameter_store.py +0 -51
  11. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/LICENSE +0 -0
  12. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/MANIFEST.in +0 -0
  13. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/README.md +0 -0
  14. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/__init__.py +0 -0
  15. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/base.py +0 -0
  16. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/__init__.py +0 -0
  17. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/__init__.py +0 -0
  18. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/data/datasets/cid/compute.json +0 -0
  19. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/data/datasets/cid/ec2_running_cost.json +0 -0
  20. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/data/datasets/cid/s3_view.json +0 -0
  21. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/data/datasets/cid/summary_view.json +0 -0
  22. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/data/datasets/co/dataset.json +0 -0
  23. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/data/datasets/cudos/hourly_view.json +0 -0
  24. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/data/datasets/cudos/resource_view.json +0 -0
  25. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/data/datasets/kpi/kpi_ebs_snap.json +0 -0
  26. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/data/datasets/kpi/kpi_ebs_storage_all.json +0 -0
  27. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/data/datasets/kpi/kpi_instance_all.json +0 -0
  28. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/data/datasets/kpi/kpi_s3_storage_all.json +0 -0
  29. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/data/datasets/kpi/kpi_tracker.json +0 -0
  30. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/data/datasets/shared/customer_all.json +0 -0
  31. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/data/datasets/tao/dataset.json +0 -0
  32. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/data/datasets/trends/daily_anomaly_detection.json +0 -0
  33. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/data/datasets/trends/monthly_anomaly_detection.json +0 -0
  34. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/data/datasets/trends/monthly_bill_by_account.json +0 -0
  35. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/data/permissions/dashboard_permissions.json +0 -0
  36. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/data/permissions/dashboard_permissions_namespace.json +0 -0
  37. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/data/permissions/data_set_permissions.json +0 -0
  38. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/data/permissions/data_source_permissions.json +0 -0
  39. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/data/permissions/folder_permissions.json +0 -0
  40. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/data/queries/cid/compute_savings_plan_eligible_spend.sql +0 -0
  41. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/data/queries/cid/ec2_running_cost.sql +0 -0
  42. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/data/queries/cid/ri_sp_mapping.sql +0 -0
  43. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/data/queries/cid/s3.sql +0 -0
  44. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/data/queries/cid/summary_view.sql +0 -0
  45. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/data/queries/co/all_options.sql +0 -0
  46. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/data/queries/co/auto_scale.json +0 -0
  47. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/data/queries/co/auto_scale_options.sql +0 -0
  48. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/data/queries/co/ebs_volume.json +0 -0
  49. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/data/queries/co/ebs_volume_options.sql +0 -0
  50. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/data/queries/co/ec2_instance.json +0 -0
  51. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/data/queries/co/ec2_instance_options.sql +0 -0
  52. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/data/queries/co/ecs_service.json +0 -0
  53. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/data/queries/co/ecs_service_options.sql +0 -0
  54. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/data/queries/co/idle.json +0 -0
  55. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/data/queries/co/idle_options.sql +0 -0
  56. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/data/queries/co/lambda.json +0 -0
  57. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/data/queries/co/lambda_options.sql +0 -0
  58. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/data/queries/co/license.json +0 -0
  59. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/data/queries/co/license_options.sql +0 -0
  60. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/data/queries/co/rds_database.json +0 -0
  61. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/data/queries/co/rds_instance_options.sql +0 -0
  62. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/data/queries/co/rds_storage_options.sql +0 -0
  63. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/data/queries/cudos/hourly_view.sql +0 -0
  64. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/data/queries/cudos/resource_view.sql +0 -0
  65. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/data/queries/kpi/first_kpi_instance_mapping_view.sql +0 -0
  66. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/data/queries/kpi/kpi_ebs_snap_view.sql +0 -0
  67. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/data/queries/kpi/kpi_ebs_storage_view.sql +0 -0
  68. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/data/queries/kpi/kpi_instance_all_view.sql +0 -0
  69. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/data/queries/kpi/kpi_s3_storage_view.sql +0 -0
  70. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/data/queries/kpi/last_kpi_tracker_view.sql +0 -0
  71. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/data/queries/shared/account_map.sql +0 -0
  72. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/data/queries/shared/account_map_cur2.sql +0 -0
  73. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/data/queries/shared/account_map_dummy.sql +0 -0
  74. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/data/queries/shared/aws_accounts.sql +0 -0
  75. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/data/queries/shared/aws_regions.sql +0 -0
  76. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/data/queries/shared/aws_service_category_map.sql +0 -0
  77. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/data/queries/shared/business_units_map.sql +0 -0
  78. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/data/queries/shared/cur.yaml +0 -0
  79. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/data/queries/shared/customer_all_unlimited.sql +0 -0
  80. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/data/queries/shared/payer_account_name_map.sql +0 -0
  81. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/data/queries/shared/ta_descriptions.sql +0 -0
  82. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/data/queries/tao/glue_table.json +0 -0
  83. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/data/queries/tao/ta_org_view.sql +0 -0
  84. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/data/queries/trends/daily_anomaly_detection.sql +0 -0
  85. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/data/queries/trends/monthly_anomaly_detection.sql +0 -0
  86. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/data/queries/trends/monthly_bill_by_account.sql +0 -0
  87. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/builtin/core/data/resources.yaml +0 -0
  88. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/cli.py +0 -0
  89. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/commands/__init__.py +0 -0
  90. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/commands/command_base.py +0 -0
  91. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/commands/init_qs.py +0 -0
  92. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/exceptions.py +0 -0
  93. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/export.py +0 -0
  94. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/helpers/__init__.py +0 -0
  95. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/helpers/account_map.py +0 -0
  96. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/helpers/athena.py +0 -0
  97. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/helpers/cloudformation.py +0 -0
  98. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/helpers/csv2view.py +0 -0
  99. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/helpers/cur.py +0 -0
  100. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/helpers/cur_proxy.py +0 -0
  101. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/helpers/diff.py +0 -0
  102. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/helpers/glue.py +0 -0
  103. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/helpers/iam.py +0 -0
  104. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/helpers/organizations.py +0 -0
  105. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/helpers/quicksight/dashboard.py +0 -0
  106. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/helpers/quicksight/dashboard_patching.py +0 -0
  107. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/helpers/quicksight/datasource.py +0 -0
  108. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/helpers/quicksight/definition.py +0 -0
  109. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/helpers/quicksight/resource.py +0 -0
  110. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/helpers/quicksight/template.py +0 -0
  111. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/helpers/quicksight/version.py +0 -0
  112. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/helpers/randtime.py +0 -0
  113. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/helpers/s3.py +0 -0
  114. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/helpers/timezone.py +0 -0
  115. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/logger.py +0 -0
  116. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/plugin.py +0 -0
  117. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/test/python/test_csv2view.py +0 -0
  118. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/test/python/test_isolated_parameters.py +0 -0
  119. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid/test/python/test_merge.py +0 -0
  120. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid_cmd.egg-info/SOURCES.txt +0 -0
  121. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid_cmd.egg-info/dependency_links.txt +0 -0
  122. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid_cmd.egg-info/entry_points.txt +0 -0
  123. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid_cmd.egg-info/requires.txt +0 -0
  124. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/cid_cmd.egg-info/top_level.txt +0 -0
  125. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/pyproject.toml +0 -0
  126. {cid_cmd-4.2.5 → cid_cmd-4.2.7}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cid-cmd
3
- Version: 4.2.5
3
+ Version: 4.2.7
4
4
  Summary: Cloud Intelligence Dashboards deployment helper tool
5
5
  Home-page: https://github.com/aws-samples/aws-cudos-framework-deployment
6
6
  Author: AWS CUDOS Team
@@ -0,0 +1,2 @@
1
+ __version__ = '4.2.7'
2
+
@@ -282,16 +282,22 @@ class Cid():
282
282
  export_analysis(self.qs, self.athena, glue=self.glue)
283
283
 
284
284
  def track(self, action, dashboard_id):
285
- """ Send dashboard_id and account_id to adoption tracker """
285
+ """ Send dashboard_id and account_id to CID adoption tracker """
286
286
  method = {'created':'PUT', 'updated':'PATCH', 'deleted': 'DELETE'}.get(action, None)
287
287
  if not method:
288
288
  logger.debug(f"This will not fail the deployment. Logging action {action} is not supported. This issue will be ignored")
289
289
  return
290
- endpoint = 'https://okakvoavfg.execute-api.eu-west-1.amazonaws.com/'
290
+ endpoint = 'https://okakvoavfg.execute-api.eu-west-1.amazonaws.com/' # AWS Managed
291
+ if os.environ.get('AWS_DEPLOYMENT_TYPE'):
292
+ deployment_type = os.environ.get('AWS_DEPLOYMENT_TYPE')
293
+ elif os.environ.get('AWS_EXECUTION_ENV', '').startswith('AWS_Lambda'):
294
+ deployment_type = 'Lambda'
295
+ else:
296
+ deployment_type = 'CID'
291
297
  payload = {
292
298
  'dashboard_id': dashboard_id,
293
299
  'account_id': self.base.account_id,
294
- action + '_via': 'Lambda' if os.environ.get('AWS_EXECUTION_ENV', '').startswith('AWS_Lambda') else 'CID',
300
+ action + '_via': deployment_type,
295
301
  }
296
302
  try:
297
303
  res = requests.request(
@@ -470,17 +476,16 @@ class Cid():
470
476
  set_defaults(defaults)
471
477
 
472
478
  def dump_default_parameters(self):
473
-
474
479
  stop_list = ['profile-name', 'region', 'aws-access-key-id', 'aws-secret-access-key', 'aws-session-token', 'athena-database', 'athena-workgroup']
475
- current_defaults = self.parameters_controller.load_parameters(
476
- context=get_parameters().get('dashboard-id')
477
- )
478
- current_defaults = current_defaults | get_parameters()
480
+ current_defaults = get_parameters()
479
481
  for key in list(current_defaults.keys()):
480
482
  if key in stop_list:
481
483
  del current_defaults[key]
482
484
  logger.trace(f'dumping parameters {current_defaults}')
483
- self.parameters_controller.dump_parameters(current_defaults, context=get_parameters().get('dashboard-id'))
485
+ self.parameters_controller.dump_parameters(
486
+ current_defaults,
487
+ context=get_parameters().get('dashboard-id')
488
+ )
484
489
 
485
490
 
486
491
  def ensure_subscription(self):
@@ -1668,17 +1673,11 @@ class Cid():
1668
1673
  update_dataset = True
1669
1674
  break
1670
1675
 
1671
- identical = False # check if dataset needs an update
1672
- if isinstance(found_dataset, Dataset):
1673
- identical = True
1674
- for key in 'PhysicalTableMap LogicalTableMap OutputColumns ImportMode DataSetUsageConfiguration RowLevelPermissionDataSet FieldFolders RowLevelPermissionTagConfiguration DatasetParameters'.split():
1675
- if found_dataset.raw.get(key) != compiled_dataset.get(key):
1676
- logger.trace(f'not identical {key} {found_dataset.raw.get(key)} != {compiled_dataset.get(key)}')
1677
- identical = False
1678
- logger.trace(f'identical to existing = {identical}')
1676
+ identical = Dataset.datasets_are_identical(found_dataset, compiled_dataset) # check if dataset needs an update
1679
1677
 
1680
1678
  if update_dataset and not identical:
1681
- self.qs.update_dataset(compiled_dataset)
1679
+ merged_dataset = Dataset.merge_datasets(compiled_dataset, found_dataset)
1680
+ self.qs.update_dataset(merged_dataset)
1682
1681
  if compiled_dataset.get("ImportMode") == "SPICE":
1683
1682
  dataset_id = compiled_dataset.get('DataSetId')
1684
1683
  schedules_definitions = []
@@ -0,0 +1,88 @@
1
+ import logging
2
+ from datetime import datetime
3
+
4
+ from cid.exceptions import CidCritical
5
+
6
+ logger = logging.getLogger(__name__)
7
+
8
+ class AthenaStore():
9
+ def __init__(self, athena, view_name='cid_parameters'):
10
+ self.athena = athena
11
+ self.view_name = view_name
12
+
13
+ def dump(self, data):
14
+ ''' dump data to athena
15
+ '''
16
+ try:
17
+ # FIXME: make it multi view
18
+ self.athena.query(self._generate_view_query(data, self.view_name))
19
+ except (CidCritical, Exception) as exc:
20
+ logger.debug(f'failed to save parameters store: {exc}')
21
+
22
+ def load(self):
23
+ ''' load from athena
24
+ '''
25
+ try:
26
+ res = self.athena.query(f'''select * from {self.view_name}''', include_header=True)
27
+ except CidCritical as exc:
28
+ if 'TABLE_NOT_FOUND' in str(exc):
29
+ res = []
30
+ else:
31
+ raise
32
+ return [{k:v for k, v in zip(res[0], row)} for row in res[1:]]
33
+
34
+ def _to_sql_str(self, val):
35
+ if val is None:
36
+ return "''"
37
+ return "'" + str(val).replace("'", "''") + "'"
38
+
39
+ def _generate_view_query(self, data, name):
40
+ all_keys = {key for dictionary in data for key in dictionary.keys()}
41
+ lines = ',\n '.join([f'''ROW({','.join([self._to_sql_str(line.get(k)) for k in all_keys])})''' for line in data])
42
+ query = f"""
43
+ CREATE OR REPLACE VIEW {name} AS
44
+ SELECT *
45
+ FROM (
46
+ VALUES
47
+ {lines}
48
+ ) ignored_table_name ({','.join([key for key in all_keys])})
49
+ """
50
+ return query
51
+
52
+ class ParametersController(AthenaStore):
53
+ def load_parameters(self, context):
54
+ data = self.load()
55
+ context_parameters = {}
56
+ any_parameters = {}
57
+ # get any context and then override with specific context
58
+ for line in sorted(data, key=lambda x: x.get('date', '')): # latest should override
59
+ any_parameters[line.get('parameter')] = line.get('value')
60
+ if line.get('context') == str(context):
61
+ context_parameters[line.get('parameter')] = line.get('value')
62
+ return any_parameters | context_parameters
63
+
64
+ def dump_parameters(self, params, context=None):
65
+ data = self.load()
66
+ logger.trace(f'loaded parameters {data}')
67
+ params = dict(params)
68
+ date = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
69
+
70
+ #Update parameters if they are present already
71
+ for line in data:
72
+ for key, val in list(params.items()):
73
+ if line.get('context') == str(context) and line.get('parameter') == key:
74
+ line['value'] = val
75
+ line['date'] = date
76
+ del params[key]
77
+
78
+ #add parameters that are new
79
+ for key, val in list(params.items()):
80
+ data.append({
81
+ 'parameter': key,
82
+ 'value': ','.join([str(v) for v in val]) if isinstance(val, list) else str(val),
83
+ 'context': str(context),
84
+ 'date': date
85
+ })
86
+
87
+ logger.trace(f'dumping parameters {data}')
88
+ self.dump(data)
@@ -261,7 +261,9 @@ class QuickSight(CidBase):
261
261
  return True
262
262
  except self.client.exceptions.AccessDeniedException as exc:
263
263
  logger.debug(f'Cannot tag {arn} (AccessDenied).')
264
- return False
264
+ except self.client.exceptions.ClientError as exc:
265
+ logger.debug(f'Cannot tag {arn} ({exc}).')
266
+ return False
265
267
 
266
268
 
267
269
  def get_tags(self, arn):
@@ -733,6 +735,7 @@ class QuickSight(CidBase):
733
735
  'AwsAccountId': self.account_id,
734
736
  'DashboardId': dashboard_id
735
737
  }
738
+ logger.debug(f'describe_dashboard_definition({dashboard_id})')
736
739
  result = self.client.describe_dashboard_definition(**parameters)
737
740
  self._definitions.update({f'{self.account_id}:{self.identityRegion}:{dashboard_id}': CidQsDefinition(result.get('Definition'))})
738
741
  logger.debug(result)
@@ -1287,6 +1290,7 @@ class QuickSight(CidBase):
1287
1290
  'DashboardId': definition.get('dashboardId'),
1288
1291
  'VersionNumber': created_version
1289
1292
  }
1293
+ logger.debug(f"describe_dashboard { definition.get('dashboardId')}")
1290
1294
  dashboard = self.describe_dashboard(poll=True, **describe_parameters)
1291
1295
  logger.debug('dashboard={dashboard}')
1292
1296
  self.set_tags(dashboard.arn, cid_version_tag=dashboard.cid_version) # try to update version tag
@@ -1304,7 +1308,7 @@ class QuickSight(CidBase):
1304
1308
  definition: cid dashboard definition. NOT QS DEFINITION.
1305
1309
  returns: what we need tof create or update API
1306
1310
  """
1307
-
1311
+ cid_print('Preparing dashboard definition')
1308
1312
  create_parameters = {
1309
1313
  'AwsAccountId': self.account_id,
1310
1314
  'DashboardId': definition.get('dashboardId'),
@@ -8,6 +8,12 @@ from cid.helpers.quicksight.resource import CidQsResource
8
8
 
9
9
  logger = logging.getLogger(__name__)
10
10
 
11
+ DATASET_PROPERTIES = [
12
+ 'AwsAccountId', 'DataSetId', 'Name', 'PhysicalTableMap', 'LogicalTableMap', 'ImportMode', 'ColumnGroups',
13
+ 'RowLevelPermissionDataSet', 'RowLevelPermissionTagConfiguration', 'FieldFolders', 'ColumnLevelPermissionRules',
14
+ 'DataSetUsageConfiguration', 'DatasetParameters', 'PerformanceConfiguration'
15
+ ]
16
+
11
17
 
12
18
  class Dataset(CidQsResource):
13
19
 
@@ -189,7 +195,7 @@ class Dataset(CidQsResource):
189
195
  projected_cols.append(col)
190
196
 
191
197
  # filter out all columns that cannot be used for dataset creation
192
- update_ = {key: value for key, value in dataset.items() if key in 'DataSetId, Name, PhysicalTableMap, LogicalTableMap, ImportMode, ColumnGroups, FieldFolders, RowLevelPermissionDataSet, RowLevelPermissionTagConfiguration, ColumnLevelPermissionRules, DataSetUsageConfiguration, DatasetParameters'.split(', ')}
198
+ update_ = {key: value for key, value in dataset.items() if key in DATASET_PROPERTIES}
193
199
  logger.trace(f'update_ = {update_}')
194
200
  return update_
195
201
 
@@ -230,4 +236,41 @@ class Dataset(CidQsResource):
230
236
  for alias, join in join_clauses.items():
231
237
  if isinstance(data['Data'].get(alias), dict) :
232
238
  data['Data'][alias]['clause'] = join
233
- return (yaml.safe_dump(data))
239
+ return (yaml.safe_dump(data))
240
+
241
+ @staticmethod
242
+ def datasets_are_identical(dataset1, dataset2):
243
+ ''' Compare 2 datasets and returns True if no difference found
244
+ '''
245
+ if (not dataset1 and not dataset2):
246
+ return True
247
+ identical = False
248
+ if (dataset1 and not dataset2) or (not dataset1 and dataset2):
249
+ return identical
250
+ dataset1 = dataset1 if isinstance(dataset1, Dataset) else Dataset(dataset1)
251
+ dataset2 = dataset2 if isinstance(dataset2, Dataset) else Dataset(dataset2)
252
+ identical = True
253
+ for key in DATASET_PROPERTIES:
254
+ if key in ['AwsAccountId', 'DataSetId']:
255
+ continue
256
+ if dataset1.raw.get(key) != dataset2.raw.get(key):
257
+ logger.trace(f'not identical {key} {dataset1.raw.get(key)} != {dataset2.raw.get(key)}')
258
+ identical = False
259
+ logger.trace(f'identical to existing = {identical}')
260
+ return identical
261
+
262
+ @staticmethod
263
+ def merge_datasets(dataset1, dataset2):
264
+ ''' merge high level 2 datasets. Not a deep merge.
265
+ '''
266
+ if not dataset2:
267
+ return dataset1
268
+ if not dataset1:
269
+ return dataset2
270
+ dataset1 = dataset1 if isinstance(dataset1, Dataset) else Dataset(dataset1)
271
+ dataset2 = dataset2 if isinstance(dataset2, Dataset) else Dataset(dataset2)
272
+ result = {}
273
+ for key in DATASET_PROPERTIES:
274
+ if dataset1.raw.get(key) or dataset2.raw.get(key):
275
+ result[key] = dataset1.raw.get(key) or dataset2.raw.get(key)
276
+ return result
@@ -276,7 +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
+ default = [c for c in default if c in choices]
280
280
  if not isatty():
281
281
  result = default
282
282
  else:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cid-cmd
3
- Version: 4.2.5
3
+ Version: 4.2.7
4
4
  Summary: Cloud Intelligence Dashboards deployment helper tool
5
5
  Home-page: https://github.com/aws-samples/aws-cudos-framework-deployment
6
6
  Author: AWS CUDOS Team
@@ -1,2 +0,0 @@
1
- __version__ = '4.2.5'
2
-
@@ -1,51 +0,0 @@
1
- from cid.exceptions import CidCritical
2
-
3
- class AthenaStore():
4
- def __init__(self, athena, view_name='cid_parameters'):
5
- self.athena = athena
6
- self.view_name = view_name
7
-
8
- def dump(self, data):
9
- ''' load from athena
10
- '''
11
- # FIXME: make it multi view
12
- self.athena.query(self._generate_view_query(data, self.view_name))
13
-
14
- def load(self):
15
- ''' load from athena
16
- '''
17
- try:
18
- res = self.athena.query(f'''select * from {self.view_name}''', include_header=True)
19
- except CidCritical as exc:
20
- if 'TABLE_NOT_FOUND' in str(exc):
21
- res = []
22
- else:
23
- raise
24
- return [{k:v for k, v in zip(res[0], row)} for row in res[1:]]
25
-
26
- def _to_sql_str(self, val):
27
- if val is None:
28
- return "''"
29
- return "'" + str(val).replace("'", "''") + "'"
30
-
31
- def _generate_view_query(self, data, name):
32
- all_keys = {key for dictionary in data for key in dictionary.keys()}
33
- lines = ',\n '.join([f'''ROW({','.join([self._to_sql_str(line.get(k)) for k in all_keys])})''' for line in data])
34
- query = f"""
35
- CREATE OR REPLACE VIEW {name} AS
36
- SELECT *
37
- FROM (
38
- VALUES
39
- {lines}
40
- ) ignored_table_name ({','.join([key for key in all_keys])})
41
- """
42
- return query
43
-
44
- class ParametersController(AthenaStore):
45
- def load_parameters(self, context):
46
- data = self.load()
47
- return { line.get('parameter'):line.get('value') for line in data}
48
-
49
- def dump_parameters(self, params, context=None):
50
- data = [{'parameter': key, 'value': ','.join(val) if isinstance(val, list) else val, 'context': str(context) } for key, val in params.items()]
51
- self.dump(data)
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