Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/initial pr #8

Merged
merged 30 commits into from
Oct 4, 2023
Merged

Feature/initial pr #8

merged 30 commits into from
Oct 4, 2023

Conversation

dbernstein
Copy link
Collaborator

@dbernstein dbernstein commented Sep 7, 2023

Initial pull request for the palace-quicksight command-line tool.

It includes 3 functions:

  1. Export a Quicksight Analysis and related data sets as a Quicksight template in the json format.
  2. Import a previously exported Quicksight template from json and hook it up to a data source of choice
  3. Publish a previously imported Template to a dashboard.

The process has been tested manually in the tpp-dev quicksight account.

You can run those tests against the dev environment yourself by running the following commands:

Export Analysis

poetry run ./bin/palace-quicksight export-analysis --aws-profile palace-dev --aws-account-id 128682227026 --analysis-id d954330e-7b80-4a4a-ab64-47f53d8eea38 --output-dir /path/to/output/dir

Import Template

poetry run ./bin/palace-quicksight import-template --aws-profile palace-dev --aws-account-id 128682227026 --template-name "library" --data-source-arn arn:aws:quicksight:us-west-2:128682227026:datasource/2d70d5ea-1143-4de4-adcb-0dbce7ce0d6e --input-dir /path/to/output/dir --target-namespace tpp-test-env

Publish Template

poetry run ./bin/palace-quicksight  publish-dashboard --aws-profile palace-dev --aws-account-id 128682227026 --template-id "tpp-test-env-library" --group-name readers --target-namespace tpp-test-env

Copy link

@RishiDiwanTT RishiDiwanTT left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added some feedback which is mostly about code style or alternative APIs. Logically everything seems fine 👍

core/cli.py Outdated


@click.command()
@click.option("--aws-profile", required=True, help="The AWS account profile")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not rely on the built-in boto3 methods of picking a profile and credentials?
https://boto3.amazonaws.com/v1/documentation/api/latest/guide/configuration.html#using-environment-variables

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose because I wanted to require that the user to make an explicit choice - ie I don't want default aws configs to be used by mistake.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But in looking more closely at this, there really is no good reason not to use AWS_PROFILE or other standard approaches. Plus it fits better with our terraform usage. I will fix.

core/cli.py Outdated
"""
Exports a template and dependent data sets based on the specified analysis to JSON files.
"""
click.echo(f"Create version")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we change from echo to logging. We may run this locally for now, but we may have this as a CI trigger in the future in which case we may want finer control over the output.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. Good idea.

try:
response = self._qs_client.create_template(**template_data)
except self._qs_client.exceptions.ResourceExistsException as e:
response = self._qs_client.update_template(**template_data)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The API definition for updateTemplate doesn't seem to have "permissions" and "tags" as parameters that the createTemplate API has, should we looking to either

  • raise an exception if they exist
  • or delete the parameters before updating the template

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it makes more sense to delete the template (or dataset) if it exists and recreate it. That way we don't have to deal with tags and permissions updates separately.

f"Unexpected response from trying to create/update template : {json.dumps(response, indent=4)} "
)
else:
return response["Arn"], response["VersionArn"], response["TemplateId"]

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is more of a code style opinion, when returning multiple values it is easier to maintain the code when returning dataclasses of named and typed information as opposed to tuples or data

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Example.

@dataclass
class TemplateResponse:
    arn: str
    version_arn: str
    template_id: str

...

def ....
    return TemplateResponse(arn, version_arn, template_id)

retry(verify_success)

# get the newly created template definition
self._log.info(f"Writing template definition response to disk")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add the filename to the log, so it is easy to find for the user.

with open(template_file) as template_file:
template_data = json.loads(template_file.read())

# create namespace if not exists

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume this is to be deleted?

try:
response = self._qs_client.create_data_set(**dataset_definition)
except self._qs_client.exceptions.ResourceExistsException as e:
response = self._qs_client.update_data_set(**dataset_definition)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did not check, but maybe the create and update APIs have differing parameters here as well?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above: I will fix by deleting and re-creating.

from time import sleep


def retry(func) -> bool:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are libraries that provide configurable methods of retrying till success, eg. https://github.com/invl/retry
If we don't need the configurability of these libraries we can stick to this implementation.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the time being I don't think we need configurability.

:param val:
:return:
"""
if key in mydict:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Imaginary edge case: What if key is not a str but a list or dict, should we safeguard against replacing such values?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's case I don't think we need to worry about.

class TestExportAnalysisOperation:
def test(self):
analysis_id = "my-quicksight-analysis-id"
output_dir = "/tmp/test-output"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A more platform independent API exists under https://docs.python.org/3/library/tempfile.html
Or you can use the mocking strategy https://docs.python.org/3/library/unittest.mock.html#mock-open

Copy link
Collaborator Author

@dbernstein dbernstein left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@RishiDiwanTT : Thanks for the great feedback. I've updated the PR with your suggested changes. I also added tests to cover import and publish.

@dbernstein
Copy link
Collaborator Author

@RishiDiwanTT : can you give the updates a quick look: if all is well, approve it and I'll merge it.


# there can be some latency between the completion of the deletion command
# and the complete backend deletion operation.
time.sleep(3)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should add a log here so we can track when resources were deleted

Copy link

@RishiDiwanTT RishiDiwanTT left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One more tiny comment, all good 👍

@dbernstein dbernstein merged commit aa4f65c into main Oct 4, 2023
8 checks passed
@dbernstein dbernstein deleted the feature/initial-pr branch October 4, 2023 16:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants