21
21
if typing .TYPE_CHECKING :
22
22
import relations .database_requires
23
23
24
+ ROLE_DML = "charmed_dml"
25
+ ROLE_READ = "charmed_read"
26
+
24
27
logger = logging .getLogger (__name__ )
25
28
26
29
@@ -125,17 +128,30 @@ def _get_attributes(self, additional_attributes: dict = None) -> str:
125
128
attributes .update (additional_attributes )
126
129
return json .dumps (attributes )
127
130
128
- def create_application_database_and_user (self , * , username : str , database : str ) -> str :
129
- """Create database and user for related database_provides application."""
131
+ def create_application_database (self , * , database : str ) -> str :
132
+ """Create database for related database_provides application."""
133
+ mysql_roles = self .get_mysql_roles ("charmed_%" )
134
+ statements = [f"CREATE DATABASE IF NOT EXISTS `{ database } `" ]
135
+ if ROLE_READ in mysql_roles :
136
+ statements .append (f"GRANT SELECT ON `{ database } `.* TO { ROLE_READ } " )
137
+ if ROLE_DML in mysql_roles :
138
+ statements .append (f"GRANT SELECT, INSERT, DELETE, UPDATE ON `{ database } `.* TO { ROLE_DML } " )
139
+
140
+ logger .debug (f"Creating { database = } " )
141
+ self ._run_sql (statements )
142
+ logger .debug (f"Created { database = } " )
143
+ return database
144
+
145
+ def create_application_user (self , * , database : str , username : str ) -> str :
146
+ """Create database user for related database_provides application."""
130
147
attributes = self ._get_attributes ()
131
- logger .debug (f"Creating { database = } and { username = } with { attributes = } " )
132
148
password = utils .generate_password ()
149
+ logger .debug (f"Creating { username = } with { attributes = } " )
133
150
self ._run_sql ([
134
- f"CREATE DATABASE IF NOT EXISTS `{ database } `" ,
135
151
f"CREATE USER `{ username } ` IDENTIFIED BY '{ password } ' ATTRIBUTE '{ attributes } '" ,
136
152
f"GRANT ALL PRIVILEGES ON `{ database } `.* TO `{ username } `" ,
137
153
])
138
- logger .debug (f"Created { database = } and { username = } with { attributes = } " )
154
+ logger .debug (f"Created { username = } with { attributes = } " )
139
155
return password
140
156
141
157
def add_attributes_to_mysql_router_user (
@@ -150,6 +166,23 @@ def add_attributes_to_mysql_router_user(
150
166
self ._run_sql ([f"ALTER USER `{ username } ` ATTRIBUTE '{ attributes } '" ])
151
167
logger .debug (f"Added { attributes = } to { username = } " )
152
168
169
+ # TODO python3.10 min version: Use `set` instead of `typing.Set`
170
+ def get_mysql_roles (self , name_pattern : str ) -> typing .Set [str ]:
171
+ """Returns a set with the MySQL roles."""
172
+ logger .debug (f"Getting MySQL roles with { name_pattern = } " )
173
+ output_file = self ._container .path ("/tmp/mysqlsh_output.json" )
174
+ self ._run_code (
175
+ _jinja_env .get_template ("get_mysql_roles_with_pattern.py.jinja" ).render (
176
+ name_pattern = name_pattern ,
177
+ output_filepath = output_file .relative_to_container ,
178
+ )
179
+ )
180
+ with output_file .open ("r" ) as file :
181
+ rows = json .load (file )
182
+ output_file .unlink ()
183
+ logger .debug (f"MySQL roles found for { name_pattern = } : { len (rows )} " )
184
+ return set (rows )
185
+
153
186
def get_mysql_router_user_for_unit (
154
187
self , unit_name : str
155
188
) -> typing .Optional [RouterUserInformation ]:
0 commit comments