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

Synapse charm review PR #43

Closed
wants to merge 1 commit into from
Closed

Conversation

jdkandersson
Copy link
Contributor

@jdkandersson jdkandersson commented Sep 21, 2023

This is a PR to perform a charm review for the Synapse charm - no need to merge

Finished on 6th of October

@github-actions
Copy link
Contributor

Test coverage for 73677fa

Name                            Stmts   Miss Branch BrPart  Cover   Missing
---------------------------------------------------------------------------
src/actions/__init__.py             3      0      0      0   100%
src/actions/register_user.py       21      0      2      0   100%
src/actions/reset_instance.py      21      3      2      1    83%   54-58
src/charm.py                      108      4     14      1    96%   109-110, 162-163
src/charm_state.py                 57      2     10      2    94%   22, 85
src/charm_types.py                 11      0      0      0   100%
src/constants.py                   25      0      0      0   100%
src/database_client.py             53      1     10      3    94%   35, 47->exit, 69->exit
src/database_observer.py           54      4      6      0    93%   70-72, 88
src/exceptions.py                   4      0      0      0   100%
src/mjolnir.py                     91      2     22      4    95%   72, 84->exit, 120, 168->173
src/observability.py                9      0      0      0   100%
src/pebble.py                      73      4      2      1    93%   100-101, 119-120
src/saml_observer.py               45      1      8      0    98%   64
src/synapse/__init__.py             3      0      0      0   100%
src/synapse/api.py                158      5     20      2    96%   140, 311, 395-397
src/synapse/workload.py           148      6     20      4    94%   226-227, 243, 273->276, 292->295, 331, 462-467
src/user.py                        24      0      4      0   100%
---------------------------------------------------------------------------
TOTAL                             908     32    120     18    95%

Static code analysis report

Run started:2023-09-21 03:30:52.072192

Test results:
  No issues identified.

Code scanned:
  Total lines of code: 4333
  Total lines skipped (#nosec): 7
  Total potential issues skipped due to specifically being disabled (e.g., #nosec BXXX): 0

Run metrics:
  Total issues (by severity):
  	Undefined: 0
  	Low: 0
  	Medium: 0
  	High: 0
  Total issues (by confidence):
  	Undefined: 0
  	Low: 0
  	Medium: 0
  	High: 0
Files skipped (0):

Copy link
Contributor Author

@jdkandersson jdkandersson left a comment

Choose a reason for hiding this comment

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

Up to the rock

@@ -0,0 +1,9 @@
ignore_files:
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Perhaps check if all of these still need to be on the ignore list? Or if we can take some off

Copy link
Collaborator

@amandahla amandahla Sep 27, 2023

Choose a reason for hiding this comment

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

Related: #49

@@ -0,0 +1,4 @@
lib/charms/nginx_ingress_integrator/v0/nginx_route.py
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Looks like we have both wokieignoreandignoreinwoke.yaml`?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Related: #49

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Perhaps a good chance to merge this into charmcraft.yaml along with config.yaml and anything else?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Related: #49

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Also potentially merge this into charmcraft.yaml

Copy link
Collaborator

Choose a reason for hiding this comment

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

Related: #49

requires:
ingress:
interface: ingress
limit: 2
Copy link
Contributor Author

Choose a reason for hiding this comment

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

What is the reason for making this 2 please? I would have guessed that 1 ingress is sufficient? Perhaps worthwhile documenting the reason since others in the future might also wonder

Copy link
Collaborator

Choose a reason for hiding this comment

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

We should probably consider dropping this relation

Copy link
Collaborator

Choose a reason for hiding this comment

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

Related: #49

Comment on lines +56 to +59
nginx-route:
interface: nginx-route
limit: 1
optional: true
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I guess with ingress v2 we should drop support for this since it should do what we need?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Related: #49

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Just a note to remind us that we should consider making this a separate snap rather than including it in the repo since this might be useful elsewhere as well. Like if someone wants to install synapse manually and still would like mjolnir on that installation they might like having a snap available

Copy link
Contributor

Choose a reason for hiding this comment

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

Out of curiosity, if we turn this into a snap do we maintain that too? I'm asking to understand how much overhead that would increase :D

straightforward through Juju’s clean interface. It will allow easy deployment
into multiple environments for testing of changes.

## Project and community
Copy link
Collaborator

Choose a reason for hiding this comment

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

This section is not needed anymore here and we lack "Contributing to this documentation" and "In this documentation" sections

Copy link
Collaborator

Choose a reason for hiding this comment

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

Related: #50

parts:
add-user:
plugin: nil
overlay-script: |
Copy link
Collaborator

Choose a reason for hiding this comment

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

Now there's the possibility of using the user rocks provides out of the box

Copy link
Contributor

Choose a reason for hiding this comment

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

daemon with the next available UID on that range, 584792.

From the rockcraft spec RK011 might be helpful as a reference here!

Copy link
Collaborator

Choose a reason for hiding this comment

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

Related: #51


"""This module defines constants used throughout the Synapse application."""

CHECK_ALIVE_NAME = "synapse-alive"
Copy link
Collaborator

Choose a reason for hiding this comment

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

Some of these constants are only used in pebble.py. I suggest we move them there

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That is a good point, constants, types and anything else should be defined as close as possible to where they are used unless there are circular import issues in which case it makes sense to move them to separate files. The drawback of moving them to separate files is that it is an additional layer of indirection which adds mental overhead to reading the code. This is ok as long as there is a benefit to the additional layer of indirection

Copy link
Collaborator

Choose a reason for hiding this comment

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

Related: #52

COMMAND_MIGRATE_CONFIG = "migrate_config"
SYNAPSE_CONFIG_DIR = "/data"
MJOLNIR_CONFIG_PATH = f"{SYNAPSE_CONFIG_DIR}/config/production.yaml"
MJOLNIR_HEALTH_PORT = 7777
Copy link
Collaborator

Choose a reason for hiding this comment

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

MJOLNIR_HEALTH_PORT and perhaps other constants are used only in tests. They shouldn't be here

Copy link
Collaborator

Choose a reason for hiding this comment

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

Related: #52

"""Exceptions used by the Synapse charm."""


class CharmDatabaseRelationNotFoundError(Exception):
Copy link
Collaborator

Choose a reason for hiding this comment

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

Perhaps this would be better placed in database_client.py

Copy link
Collaborator

Choose a reason for hiding this comment

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

Related: ISD-1070

PEER_RELATION_NAME = "synapse-peers"
PROMETHEUS_TARGET_PORT = "9000"
# Disabling it since these are not hardcoded password
SECRET_ID = "secret-id" # nosec
Copy link
Collaborator

Choose a reason for hiding this comment

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

Some of these also seem to be only used in mjoinir.py

Copy link
Collaborator

Choose a reason for hiding this comment

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

Related: #52

Copy link
Contributor Author

@jdkandersson jdkandersson left a comment

Choose a reason for hiding this comment

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

I'm up to exceptions.py

@@ -0,0 +1,76 @@
#!/usr/bin/env python3
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Are these needed on these files? I think they are only needed to make the file executable, which is required for the src/charm.py, I don't think they are needed here since the file isn't actually intended to be executed directly

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Similar comment applies for any other files with this line

Copy link
Collaborator

Choose a reason for hiding this comment

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

Related: #52

Comment on lines +42 to +43
server: str = "",
admin_access_token: str = "", # nosec
Copy link
Contributor Author

Choose a reason for hiding this comment

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

What is the behaviour here when the default empty string is used please?

Copy link
Collaborator

Choose a reason for hiding this comment

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

A 'f"User {user.username} exists but there is no server/admin access token set."' will be raised. The token is used in case the user already exists so it will return the existing access token.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Related: #52

Comment on lines +28 to +34
def __init__(self, msg: str):
"""Initialize a new instance of the ResetInstanceError exception.

Args:
msg (str): Explanation of the error.
"""
self.msg = msg
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Since these are used in a few places perhaps there could be a BaseException for the entire charm which takes a message in the constructor and then the other exceptions derive from it and don't need to have this constructor defined

Copy link
Collaborator

Choose a reason for hiding this comment

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

Related: ISD-1070

db_client.erase()
synapse.execute_migrate_config(container=container, charm_state=charm_state)
except (psycopg2.Error, synapse.WorkloadError) as exc:
raise ResetInstanceError(str(exc)) from exc
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Since from exc is used, the message from that exception is already preserved. Perhaps for these, and any similar other re-raises, it would be better to include a message here saying "something went wrong during the reset" or something similar based on the context of the function which will add a little more information to the stack trace to help resolve the issue

Copy link
Collaborator

Choose a reason for hiding this comment

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

Related: ISD-1070

Comment on lines +51 to +65
require_nginx_route(
charm=self,
service_hostname=self.app.name,
service_name=self.app.name,
service_port=SYNAPSE_NGINX_PORT,
)
self._ingress = IngressPerAppRequirer(
self,
port=SYNAPSE_NGINX_PORT,
# We're forced to use the app's service endpoint
# as the ingress per app interface currently always routes to the leader.
# https://github.com/canonical/traefik-k8s-operator/issues/159
host=f"{self.app.name}-endpoints.{self.model.name}.svc.cluster.local",
strip_prefix=True,
)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Looks like we're supporting both nginx_route and ingress?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Yes, both are supported.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Related: #49



class DatabaseClient:
"""A class representing the Synapse application."""
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Is this docstring accurate? Based on the name it seems to represent a database rather than synapse?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Related: #52

"""A class representing the Synapse application."""

def __init__(
self, datasource: typing.Optional[DatasourcePostgreSQL], alternative_database: str = ""
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Do you think a None default would be better than an empty string? That way the type is a bit clearer and we can differentiate between the None case and someone accidentally passing an empty string.

Generally speaking empty strings as defaults should be avoided. Either None is good or even a sentinel value can help. Here is an example of a sentinel value: https://github.com/canonical/repo-policy-compliance/blob/fcdc9fb819b50ad3e874e8015d3b5e7134ebd60a/repo_policy_compliance/__init__.py#L15

Copy link
Collaborator

Choose a reason for hiding this comment

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

Related: #52

def __init__(
self, datasource: typing.Optional[DatasourcePostgreSQL], alternative_database: str = ""
):
"""Initialize a new instance of the Synapse class.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This also seems to refer to Synapse

Copy link
Collaborator

Choose a reason for hiding this comment

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

Related; #52

Comment on lines +87 to +89
except psycopg2.Error as exc:
logger.exception("Failed to prepare database: %r", exc)
raise
Copy link
Contributor Author

Choose a reason for hiding this comment

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

For these public methods, should the exception be remapped? That way the caller of the database doesn't need to know the library being used to interact with the database reducing the coupling

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Similar comment applies for the other public methods

Copy link
Collaborator

Choose a reason for hiding this comment

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

Based on this discussion, it could be even removed. It was left only for logging reason:
#13 (comment)

I agree regarding the library but Synapse only supports sqlite3 (for SQLite, local file) or psycopg2 (for PostgreSQL).

Copy link
Collaborator

Choose a reason for hiding this comment

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

Related: #52

Comment on lines +52 to +59
@property
def _pebble_service(self) -> typing.Any:
"""Return instance of pebble service.

Returns:
instance of pebble service or none.
"""
return getattr(self._charm, "pebble_service", None)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This doesn't quite feel right yet, it would be better not to need this. I believe this comes from that pebble service requires the charm state, charm state requires information from the database and the database observer requires the pebble service.

From memory, one of the options was to instantiate the DatabaseRequires in charm.py and pass that to CharmState for it to retrieve the necessary data from it if the relation is defined and also pass DatabaseRequires as an argument to the initialiser of this class. That way CharmState doesn't depend on the database observer anymore and it is safe to pass CharmState as an argument to the database observer which then means that the pebble service doesn't need to keep track of charm state and can be passed as an argument to the database observer as well

Copy link
Collaborator

Choose a reason for hiding this comment

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

Actually, this is here because after getting information from the relation with Database, the configuration must be updated and the container replaned.
This way avoids a circular dependency.
The idea was gently offered by Yanks at the time :-) : https://github.com/canonical/jenkins-agent-k8s-operator/blob/d094425a33a30b0bd08d36849d949c555e2f1511/src/agent.py#L20

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm thinking of proposing a Protocol based Charm class that can be passed on so that such circular dependencies can be mitigated.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Related: #54

@amandahla
Copy link
Collaborator

FYI there are existing stories for addressing:

  • Exceptions refactoring: ISD-1070
  • Mjolnir architecture (observer/service): ISD-1095
  • Unit tests (in review): ISD-997

Copy link
Contributor

@yanksyoon yanksyoon left a comment

Choose a reason for hiding this comment

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

Reviewed until tests.

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm wondering if it would be better to have a charm specific .gitignore file, things like *.so seems unnecessary.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Related: #49

Comment on lines +6 to +8
Set a new server_name before running this action.
Once a server_name is configured, you must start a new instance if you wish a different one.
This actions will erase all data and create a instance with the new server_name.
Copy link
Contributor

Choose a reason for hiding this comment

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

Out of curiosity, is there a reason for server_name? I'm wondering why a variable type name is being used instead of a regular server name.
Edit: I got it now, it's referring to the configuration option server_name, perhaps clarifying that might be a tiny bit more helpful :D

- cargo
- rustc
charm-binary-python-packages:
- psycopg2-binary==2.9.7
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm wondering if this specific version pinning is intended

Copy link
Collaborator

Choose a reason for hiding this comment

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

Related: #49

Copy link
Contributor

Choose a reason for hiding this comment

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

Out of curiosity, if we turn this into a snap do we maintain that too? I'm asking to understand how much overhead that would increase :D

parts:
add-user:
plugin: nil
overlay-script: |
Copy link
Contributor

Choose a reason for hiding this comment

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

daemon with the next available UID on that range, 584792.

From the rockcraft spec RK011 might be helpful as a reference here!

Raises:
Error: something went wrong while connecting to the database.
"""
if self._conn is None or self._conn.closed != 0:
Copy link
Contributor

Choose a reason for hiding this comment

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

Perhaps returning in the not case might help reduce indentation here as well :D

Suggested change
if self._conn is None or self._conn.closed != 0:
if self._conn is not None and self._conn.closed == 0:
return

Copy link
Collaborator

Choose a reason for hiding this comment

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

Related: #52

Comment on lines +52 to +59
@property
def _pebble_service(self) -> typing.Any:
"""Return instance of pebble service.

Returns:
instance of pebble service or none.
"""
return getattr(self._charm, "pebble_service", None)
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm thinking of proposing a Protocol based Charm class that can be passed on so that such circular dependencies can be mitigated.

Comment on lines +101 to +102
# The username is random because if the user exists, register_user will try to get the
# access_token.
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm wondering if checking if the username admin already exists and then returning that user might be an enhancement in UX which matches the behavior with other charms. It might be difficult to do if someone does register with admin username though..

Copy link
Collaborator

Choose a reason for hiding this comment

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

Related: ISD-1095

Copy link
Contributor

Choose a reason for hiding this comment

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

Loki would be a good addition here :D!

Copy link
Collaborator

Choose a reason for hiding this comment

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

To be addressed in future story :)

random password.
"""
choices = string.ascii_letters + string.digits
password = "".join([secrets.choice(choices) for i in range(16)])
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
password = "".join([secrets.choice(choices) for i in range(16)])
password = "".join(secrets.choice(choices) for _ in range(16))

The list wrapper can be removed since join takes an iterable :D

Copy link
Collaborator

Choose a reason for hiding this comment

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

Related: #52

Copy link
Contributor Author

@jdkandersson jdkandersson left a comment

Choose a reason for hiding this comment

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

Up to tests

Comment on lines +81 to +89
relation_data = {}
relations = list(self._charm.model.relations[self._RELATION_NAME])
relation_id = relations[0].id
for relation in relations:
relation_data[relation.id] = (
{key: value for key, value in relation.data[relation.app].items() if key != "data"}
if relation.app
else {}
)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

It looks like this can be refactored to a dict comprehension which is easier to read than a for loop and has a better underlying implementation

Also, it looks like relation_id = relations[0].id could raise an exception if the relations list is empty

Also, it doesn't look like a list is needed - a tuple would work better here which is generally preferred if possible as it doesn't have the same overheads as a list

Copy link
Collaborator

Choose a reason for hiding this comment

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

Related: #52

registration_shared_secret: str,
user: User,
server: typing.Optional[str] = None,
admin_access_token: typing.Optional[str] = None, # nosec
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Is this nosec still needed since it seems that it is being defaulted to None now?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Related: #52

Returns:
Access token to be used by the user.
"""
# get nonce
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Is this comment needed? The method get_nonce seems to be quite descriptive and is potentially enough to explain what is going on without a comment?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

similar comment for get_mac

Copy link
Collaborator

Choose a reason for hiding this comment

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

Related: #52

)
except (requests.exceptions.JSONDecodeError, TypeError, KeyError) as exc:
logger.exception("Failed to decode access_token: %r. Received: %s", exc, res.text)
raise RegisterUserError(str(exc)) from exc
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Similar comment as before, because from exc is used here, the error message in that exception will already be shown in the stack trace so the RegisterUserError could be passed a message which has a bit more context about what this module is trying to do

Copy link
Collaborator

Choose a reason for hiding this comment

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

Related: ISD-1070

raise RegisterUserError(str(exc)) from exc


def _generate_mac(
Copy link
Contributor Author

Choose a reason for hiding this comment

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

The general guidance is to list functions that are used by others before the function that is using them to make the code easier to read (i.e., the reader should encounter the definition of a function in a module before it is used for the first time)

Copy link
Collaborator

Choose a reason for hiding this comment

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

Related: #52

Comment on lines +274 to +276
user: user to be used for requesting access token.
admin_access_token: server admin access token to be used.
charm_state: Instance of CharmState.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Is this description right? It looks like this function does something other than granting access tokens

Copy link
Collaborator

Choose a reason for hiding this comment

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

Related: #52

Returns:
Mjolnir configuration
"""
with open("templates/mjolnir_production.yaml", encoding="utf-8") as mjolnir_config_file:
Copy link
Contributor Author

Choose a reason for hiding this comment

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

What about using pathlib.Path.read_text? Pathlib is a more modern interface compared to open and you can get what is needed without a context manager

Copy link
Collaborator

Choose a reason for hiding this comment

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

Related: #52

Comment on lines +205 to +208
config["homeserverUrl"] = SYNAPSE_URL
config["rawHomeserverUrl"] = SYNAPSE_URL
config["accessToken"] = access_token
config["managementRoom"] = room_id
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Reading the method _get_mjolnir_config i wouldn't expect it to add to the configuration - just to retrieve and return it in its current form. This seems to be modifying the configuration by adding more elements to it?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Agree, the method name should be different.
Related: #52

CreateMjolnirConfigError: something went wrong creating mjolnir config.
"""
try:
config = _get_mjolnir_config(access_token, room_id)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Perhaps add the additional configuration in this function? Or just in-line _get_mjolnir_config since it seems to be pretty simple?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Related: #52

Comment on lines +305 to +308
current_yaml["listeners"] = updated_listeners
current_yaml["saml2_enabled"] = True
current_yaml["saml2_config"] = {}
current_yaml["saml2_config"]["sp_config"] = _create_pysaml2_config(charm_state)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

It is somewhat confusing the read current_yaml being modified - at that point it isn't really current anymore, right? Perhaps consider renaming it to something else?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Related: #52

Copy link
Contributor

Choose a reason for hiding this comment

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

The term relation is still used in this file. I think it should be replaced by integration.

I have seen the term used in several places in the source code. I think it should be replaced there as well.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Related: #50


import ops

# pydantic is causing this no-name-in-module problem
Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Collaborator

Choose a reason for hiding this comment

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

Related: #49


"""Helper module used to manage interactions with Synapse API."""

# pylint: disable=too-few-public-methods, too-many-arguments
Copy link
Contributor

Choose a reason for hiding this comment

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

It seems that too-few-public-methods is no longer needed. too-many-arguments only applies to _generate_mac, I would suggest moving it there.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Related: #52

Comment on lines +200 to +204
try:
nonce = res.json()["nonce"]
except (requests.exceptions.JSONDecodeError, TypeError, KeyError) as exc:
logger.exception("Failed to decode nonce: %r. Received: %s", exc, res.text)
raise GetNonceError(str(exc)) from exc
Copy link
Contributor

Choose a reason for hiding this comment

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

It seems the pattern

try:
   x = res.json()["x"]    
except (requests.exceptions.JSONDecodeError, TypeError, KeyError) as exc:
   logger.exception("Failed to decode x: %r. Received: %s", exc, res.text)

is repeated multiple times in this module. Maybe introduce a private function _get_from_response(response, key, err_type) in order to avoid code duplication?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Related: #52

exec_process = container.exec(command, environment=environment, working_dir=SYNAPSE_CONFIG_DIR)
try:
stdout, stderr = exec_process.wait_output()
return ExecResult(0, typing.cast(str, stdout), typing.cast(str, stderr))
Copy link
Contributor

Choose a reason for hiding this comment

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

  • I think the cast is not necessary for stdout .
  • Can we always assume that stderr will be not None ?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Related: #52

Comment on lines +6 to +7
# ignoring duplicate-code with container connect check in the database observer.
# pylint: disable=R0801
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this should be moved to _enable_saml, as disabling should be done as specifically as possible (https://github.com/canonical/is-charms-contributing-guide/blob/main/CONTRIBUTING.md#static-code-analysis).

Copy link
Collaborator

Choose a reason for hiding this comment

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

Related: #52

- 'LICENSE'
- 'trivy.yaml'
- 'zap_rules.tsv'
- 'lib/**'
Copy link
Contributor

Choose a reason for hiding this comment

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

Perhaps we should generally agree on how to handle licences in libs, as @arturo-seijas has pointed out here https://chat.canonical.com/canonical/pl/6sr9h8uod3nimeddpc8dquxzao . In some charms we don't exclude and update the copyright header.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Related: #49

Run the following command:

```bash
echo -e "tox -e src-docs\ngit add src-docs\n" > .git/hooks/pre-commit
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
echo -e "tox -e src-docs\ngit add src-docs\n" > .git/hooks/pre-commit
echo -e "tox -e src-docs\ngit add src-docs\n" >> .git/hooks/pre-commit

I generally prefer not to override existing hooks.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Related: #50

Comment on lines +250 to +251
harness = harness_with_postgresql
harness = harness_with_postgresql
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
harness = harness_with_postgresql
harness = harness_with_postgresql
harness = harness_with_postgresql

Copy link
Collaborator

Choose a reason for hiding this comment

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

Related: #52

username = "any-user"
user = User(username=username, admin=True)
# Prepare mock to get the access token
mock_response = mock.MagicMock()
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
mock_response = mock.MagicMock()

Copy link
Collaborator

Choose a reason for hiding this comment

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

Whats the change here please?

Copy link
Contributor

Choose a reason for hiding this comment

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

mock_response is redefined in line 171, so this line is not needed.

@amandahla
Copy link
Collaborator

The charm has changed a lot since this was opened. Closing as it’s no longer relevant.

@amandahla amandahla closed this Nov 14, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants