Initial commit
[ta/infra-ansible.git] / roles / access-management / templates / dbfiller.py.j2
1 import ConfigParser
2
3 import logging
4 import os
5 import sys
6 import M2Crypto
7 import time
8
9 from keystoneauth1.identity import v3
10 from keystoneauth1 import session
11 from keystoneauth1.exceptions.http import Conflict
12 from keystoneclient import utils
13 from keystoneclient.v3 import client
14
15 sys.path.append('{{ lib_source_folder }}')
16 from access_management.db.amdb import AMDatabase
17 from access_management.cryptohelper.decryptaaafiles import DecryptAAAFile
18
19
20 def get_config():
21     config = ConfigParser.ConfigParser()
22     config.read("/{{ am_plugin_config_path }}")
23     config_dict = {s: dict(config.items(s)) for s in config.sections()}
24     return config_dict
25
26
27 def set_logger():
28     logger = logging.getLogger("DBfiller")
29     shandler = logging.StreamHandler(sys.stdout)
30     shandler.setLevel(logging.DEBUG)
31     formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
32     shandler.setFormatter(formatter)
33     logger.addHandler(shandler)
34     logger.info("logger set")
35     return logger
36
37
38 def close_logger_handlers(logger):
39     for handler in logger.handlers:
40         logger.removeHandler(handler)
41
42
43 def read_files():
44     users = []
45     roles = []
46     permissions = []
47     user_roles = []
48     role_permissions = []
49     dir = "{{ am_server_values_dir }}"
50     for encrypted_file in os.listdir(dir):
51         if os.stat(os.path.join(dir, encrypted_file)).st_uid is not 0:
52             print "--- File: ", encrypted_file, "is not of root, skipping"
53             continue
54         try:
55             crypter = DecryptAAAFile("{{ am_server_temp_dir }}/am_pri_key.pem")
56             jsoned_content = crypter.decrypt_file(os.path.join(dir, encrypted_file))
57             for user in jsoned_content["users"]:
58                 users.append(user)
59             for role in jsoned_content["roles"]:
60                 roles.append(role)
61             for permission in jsoned_content["permissions"]:
62                 permissions.append(permission)
63             for user_role in jsoned_content["user_roles"]:
64                 user_roles.append(user_role)
65             for role_permission in jsoned_content["role_permissions"]:
66                 role_permissions.append(role_permission)
67         except M2Crypto.RSA.RSAError as ex:
68             print "Failed to decrypt file: {}, {}".format(encrypted_file, str(ex))
69         except Exception as ex:
70             print "File {} failed with error: {}".format(encrypted_file, str(ex))
71     users = map(list, set(map(tuple, users)))
72     roles = map(list, set(map(tuple, roles)))
73     permissions = map(list, set(map(tuple, permissions)))
74     user_roles = map(list, set(map(tuple, user_roles)))
75     role_permissions = map(list, set(map(tuple, role_permissions)))
76     return {"users": users, "roles": roles, "permissions": permissions, "user_roles": user_roles, "role_permissions": role_permissions}
77
78
79 def get_db_content(db):
80     db.create_tables()
81     users = db.get_user_table()
82     roles = db.get_role_table()
83     permissions = db.get_resource_table()
84     user_roles = db.get_user_role_table()
85     role_permissions = db.get_role_resource_table()
86     return {"users": users, "roles": roles, "permissions": permissions, "user_roles": user_roles, "role_permissions": role_permissions}
87
88
89 def compare_contents(db_content, files_content):
90     update_needed = {"roles":[], "permissions":[]}
91     adding_needed = {"users":[], "roles":[], "permissions":[], "user_roles":[], "role_permissions":[]}
92     for file_user in files_content["users"]:
93         if check_user_value(file_user, db_content["users"]):
94             print "User " + file_user[0] + " is ok"
95         else:
96             print "User " + file_user[0] + " needs to be added"
97             adding_needed["users"].append(file_user)
98
99     for file_role in files_content["roles"]:
100         result = check_role_value(file_role, db_content["roles"])
101         if result == "update":
102             if file_role[2] == "True":
103                 file_role[2] = 1
104             if file_role[2] == "False":
105                 file_role[2] = 0
106             update_needed["roles"].append(file_role)
107         elif result == "add":
108             print "Role " + file_role[0] + " needs to be added"
109             if file_role[2] == "True":
110                 file_role[2] = 1
111             if file_role[2] == "False":
112                 file_role[2] = 0
113             adding_needed["roles"].append(file_role)
114             if file_role[2] == 1:
115                 adding_needed["role_permissions"].append([file_role[0],"am/users/keys","POST"])
116                 adding_needed["role_permissions"].append([file_role[0],"am/users/keys","DELETE"])
117                 print "am/users/keys permissions also needs to be added for role " + file_role[0]
118         else:
119             print "Role " + file_role[0] + " is ok"
120
121     for file_permission in files_content["permissions"]:
122         result = check_permission_value(file_permission,db_content["permissions"])
123         if result == "update":
124             print "Permission " + file_permission[0] + ":" + file_permission[1] + " needs update due to changed description"
125             update_needed["permissions"].append(file_permission)
126         elif result == "add":
127             print "Permission " + file_permission[0] + ":" + file_permission[1] + " needs to be added"
128             adding_needed["permissions"].append(file_permission)
129         else:
130             print "Permission " + file_permission[0] + ":" + file_permission[1] + " is ok"
131
132     for file_user_role in files_content["user_roles"]:
133         if not check_user_role_value(file_user_role, db_content["user_roles"]):
134             adding_needed["user_roles"].append(file_user_role)
135
136     for file_role_permission in files_content["role_permissions"]:
137         if not check_role_permission_value(file_role_permission, db_content["role_permissions"]):
138             adding_needed["role_permissions"].append(file_role_permission)
139
140     return (update_needed, adding_needed)
141
142
143 def check_user_value(file_content, db_content):
144     for db_user in db_content:
145         if file_content[0] == db_user["name"]:
146             return True
147     return False
148
149
150 def check_permission_value(file_content, db_content):
151     for db_permission in db_content:
152         if file_content[0] == db_permission["path"] and file_content[1] == db_permission["op"]:
153             if file_content[2] == db_permission["desc"]:
154                 return "ok"
155             else:
156                 return "update"
157     return "add"
158
159
160 def check_role_permission_value(file_content, db_content):
161     for db_role_permission in db_content:
162         if file_content[0] == db_role_permission["name"] and file_content[1] == db_role_permission["path"] and file_content[2] == db_role_permission["op"]:
163             print "Role_permission " + file_content[0] + ":" + file_content[1] + ":" + file_content[2] + " is ok"
164             return True
165     print "Role_permission " + file_content[0] + ":" + file_content[1] + ":" + file_content[2] + " needs to be added"
166     return False
167
168
169 def check_user_role_value(file_content, db_content):
170     for db_user_role in db_content:
171         if file_content[0] == db_user_role["user_name"] and file_content[1] == db_user_role["role_name"]:
172             print "User_role " + file_content[0] + ":" + file_content[1] + " is ok"
173             return True
174     print "User_role " + file_content[0] + ":" + file_content[1] + " needs to be added"
175     return False
176
177
178 def check_role_value(file_content, db_content):
179     for db_role in db_content:
180         if file_content[0] == db_role["name"]:
181             if file_content[1] != db_role["desc"]:
182                 print "Role " + file_content[0] + " needs update due to changed description"
183                 return "update"
184             if file_content[2] != str(db_role["is_chroot"]):
185                 print "Role " + file_content[0] + " needs update due to changed is_chroot"
186                 return "update"
187             return "ok"
188     return "add"
189
190
191 def update_tables(db, update_needed):
192     try:
193         for row in update_needed["roles"]:
194             db.set_role_param(row[0],row[1],row[2])
195             print "Role {} updated".format(row[0])
196         for row in update_needed["permissions"]:
197             db.update_resource(row[0],row[1],row[2])
198             print "Permission {0}:{1} updated".format(row[0], row[1])
199     except Exception as ex:
200         print ex
201         return False
202     return True
203
204
205 def add_into_tables(db, adding_needed, config):
206     try:
207         keystone = make_keystone_auth(config)
208         for row in adding_needed["users"]:
209             uuid = get_resource_id(keystone, "users", row[0])
210             create_db_user(db, uuid, row[0])
211         for row in adding_needed["roles"]:
212             try:
213                 role_id = keystone.roles.create(row[0])
214                 print "Role {} created in Keystone".format(row[0])
215             except Conflict as ex:
216                 print "Role {} already in Keystone".format(row[0])
217             db.create_role(row[0],row[1],row[2])
218             print "Role {} created in DB".format(row[0])
219         for row in adding_needed["permissions"]:
220             db.create_resource(row[0],row[1],row[2])
221             print "Permission {} created in DB".format(row[0])
222         for row in adding_needed["user_roles"]:
223             try:
224                 project_id = get_resource_id(keystone, "projects", "{{ am_project_name }}")
225                 role_id = get_resource_id(keystone, "roles", row[1])
226                 uuid = db.get_user_uuid(row[0])
227                 if row[1] == "infrastructure_admin":
228                     admin_project_id = get_resource_id(keystone, "projects", "admin")
229                     admin_role_id = get_resource_id(keystone, "roles", "admin")
230                     heat_role_id = get_resource_id(keystone, "roles", "heat_stack_owner")
231                     keystone.roles.grant(admin_role_id, user=uuid, project=admin_project_id)
232                     keystone.roles.grant(heat_role_id, user=uuid, project=admin_project_id)
233                 keystone.roles.grant(role_id, user=uuid, project=project_id)
234                 print "Role {} added to user {} in Keystone".format(row[1], row[0])
235             except Conflict as ex:
236                 print "Role {} already at user {} in Keystone".format(row[1], row[0])
237             db.add_user_role(uuid, row[1])
238             print "Role {0} added to user {1} in DB".format(row[1], row[0])
239         for row in adding_needed["role_permissions"]:
240             db.add_resource_to_role(row[0], row[1], row[2])
241             print "Permission {0}:{1} added to role {2} in DB".format(row[1], row[2], row[0])
242     except Exception as ex:
243         print ex
244         print type(ex)
245         return False
246     return True
247
248
249 def create_db_user(db, uuid, name):
250     if name == "{{ infrastructure_admin_user_name }}" or name == "admin":
251         db.create_user(uuid, name)
252     else:
253         db.create_user(uuid, name, service=True)
254     print "User {} created in DB".format(name)
255
256
257 def get_resource_id(keystone, resource_type, resource_name):
258     res_type = getattr(keystone,resource_type)
259     resource = utils.find_resource(res_type, resource_name)
260     return resource.id
261
262
263 def make_keystone_auth(config):
264     auth = v3.Password(
265                        auth_url="{{ keystone_service_internalurl }}",
266                        username="{{ keystone_admin_user_name }}",
267                        password="{{ keystone_auth_admin_password }}",
268                        project_name="{{ keystone_admin_tenant_name }}",
269                        project_domain_id="{{ am_project_domain }}",
270                        user_domain_id="{{ am_project_domain }}")
271     sess = session.Session(auth=auth)
272     keystone = client.Client(session=sess)
273     print "+++ Keystone authentication OK"
274     return keystone
275
276
277 def main():
278     config = get_config()
279     logger = set_logger()
280     logger.info("logger set")
281     db = AMDatabase(db_name=config["DB"]["name"], db_addr=config["DB"]["addr"],
282                      db_port=int(config["DB"]["port"]), db_user=config["DB"]["user"],
283                      db_pwd=config["DB"]["pwd"], logger=logger, management_mode=True)
284     db.connect()
285     thime = time.strftime("%Y/%m/%d %H:%M:%S", time.localtime())
286     print "*** Start time " + thime + " ***"
287     print "+++ Connection to database successful"
288     db_content = get_db_content(db)
289     print "+++ DB dump acquired"
290     files_content = read_files()
291     print "+++ Value files read"
292     update_needed, adding_needed = compare_contents(db_content, files_content)
293     print "+++ Comparation done"
294     result = update_tables(db, update_needed)
295     if result:
296         print "+++ Updating tables completed"
297     else:
298         print "--- Problem during updating tables"
299     result = add_into_tables(db, adding_needed, config)
300     if result:
301         print "+++ Adding to tables completed"
302     else:
303         print "--- Problem during table additions"
304     db.close()
305     print "+++ Aaand done"
306     thime = time.strftime("%Y/%m/%d %H:%M:%S", time.localtime())
307     print "*** End time " + thime + " ***"
308     close_logger_handlers(logger)
309
310
311 if __name__ == '__main__':
312     main()