##// END OF EJS Templates
automation: updated update task to update repositories and groups....
dan -
r4160:7447e8d1 default
parent child Browse files
Show More
@@ -1,349 +1,365 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2012-2019 RhodeCode GmbH
3 # Copyright (C) 2012-2019 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 """
21 """
22 RhodeCode task modules, containing all task that suppose to be run
22 RhodeCode task modules, containing all task that suppose to be run
23 by celery daemon
23 by celery daemon
24 """
24 """
25
25
26 import os
26 import os
27 import time
27 import time
28
28
29 from pyramid import compat
29 from pyramid import compat
30 from pyramid_mailer.mailer import Mailer
30 from pyramid_mailer.mailer import Mailer
31 from pyramid_mailer.message import Message
31 from pyramid_mailer.message import Message
32
32
33 import rhodecode
33 import rhodecode
34 from rhodecode.lib import audit_logger
34 from rhodecode.lib import audit_logger
35 from rhodecode.lib.celerylib import get_logger, async_task, RequestContextTask
35 from rhodecode.lib.celerylib import get_logger, async_task, RequestContextTask
36 from rhodecode.lib.hooks_base import log_create_repository
36 from rhodecode.lib.hooks_base import log_create_repository
37 from rhodecode.lib.utils2 import safe_int, str2bool
37 from rhodecode.lib.utils2 import safe_int, str2bool
38 from rhodecode.model.db import Session, IntegrityError, Repository, User, true
38 from rhodecode.model.db import (
39 Session, IntegrityError, true, Repository, RepoGroup, User)
39
40
40
41
41 @async_task(ignore_result=True, base=RequestContextTask)
42 @async_task(ignore_result=True, base=RequestContextTask)
42 def send_email(recipients, subject, body='', html_body='', email_config=None):
43 def send_email(recipients, subject, body='', html_body='', email_config=None):
43 """
44 """
44 Sends an email with defined parameters from the .ini files.
45 Sends an email with defined parameters from the .ini files.
45
46
46 :param recipients: list of recipients, it this is empty the defined email
47 :param recipients: list of recipients, it this is empty the defined email
47 address from field 'email_to' is used instead
48 address from field 'email_to' is used instead
48 :param subject: subject of the mail
49 :param subject: subject of the mail
49 :param body: body of the mail
50 :param body: body of the mail
50 :param html_body: html version of body
51 :param html_body: html version of body
51 """
52 """
52 log = get_logger(send_email)
53 log = get_logger(send_email)
53
54
54 email_config = email_config or rhodecode.CONFIG
55 email_config = email_config or rhodecode.CONFIG
55
56
56 mail_server = email_config.get('smtp_server') or None
57 mail_server = email_config.get('smtp_server') or None
57 if mail_server is None:
58 if mail_server is None:
58 log.error("SMTP server information missing. Sending email failed. "
59 log.error("SMTP server information missing. Sending email failed. "
59 "Make sure that `smtp_server` variable is configured "
60 "Make sure that `smtp_server` variable is configured "
60 "inside the .ini file")
61 "inside the .ini file")
61 return False
62 return False
62
63
63 subject = "%s %s" % (email_config.get('email_prefix', ''), subject)
64 subject = "%s %s" % (email_config.get('email_prefix', ''), subject)
64
65
65 if recipients:
66 if recipients:
66 if isinstance(recipients, compat.string_types):
67 if isinstance(recipients, compat.string_types):
67 recipients = recipients.split(',')
68 recipients = recipients.split(',')
68 else:
69 else:
69 # if recipients are not defined we send to email_config + all admins
70 # if recipients are not defined we send to email_config + all admins
70 admins = []
71 admins = []
71 for u in User.query().filter(User.admin == true()).all():
72 for u in User.query().filter(User.admin == true()).all():
72 if u.email:
73 if u.email:
73 admins.append(u.email)
74 admins.append(u.email)
74 recipients = []
75 recipients = []
75 config_email = email_config.get('email_to')
76 config_email = email_config.get('email_to')
76 if config_email:
77 if config_email:
77 recipients += [config_email]
78 recipients += [config_email]
78 recipients += admins
79 recipients += admins
79
80
80 # translate our LEGACY config into the one that pyramid_mailer supports
81 # translate our LEGACY config into the one that pyramid_mailer supports
81 email_conf = dict(
82 email_conf = dict(
82 host=mail_server,
83 host=mail_server,
83 port=email_config.get('smtp_port', 25),
84 port=email_config.get('smtp_port', 25),
84 username=email_config.get('smtp_username'),
85 username=email_config.get('smtp_username'),
85 password=email_config.get('smtp_password'),
86 password=email_config.get('smtp_password'),
86
87
87 tls=str2bool(email_config.get('smtp_use_tls')),
88 tls=str2bool(email_config.get('smtp_use_tls')),
88 ssl=str2bool(email_config.get('smtp_use_ssl')),
89 ssl=str2bool(email_config.get('smtp_use_ssl')),
89
90
90 # SSL key file
91 # SSL key file
91 # keyfile='',
92 # keyfile='',
92
93
93 # SSL certificate file
94 # SSL certificate file
94 # certfile='',
95 # certfile='',
95
96
96 # Location of maildir
97 # Location of maildir
97 # queue_path='',
98 # queue_path='',
98
99
99 default_sender=email_config.get('app_email_from', 'RhodeCode'),
100 default_sender=email_config.get('app_email_from', 'RhodeCode'),
100
101
101 debug=str2bool(email_config.get('smtp_debug')),
102 debug=str2bool(email_config.get('smtp_debug')),
102 # /usr/sbin/sendmail Sendmail executable
103 # /usr/sbin/sendmail Sendmail executable
103 # sendmail_app='',
104 # sendmail_app='',
104
105
105 # {sendmail_app} -t -i -f {sender} Template for sendmail execution
106 # {sendmail_app} -t -i -f {sender} Template for sendmail execution
106 # sendmail_template='',
107 # sendmail_template='',
107 )
108 )
108
109
109 try:
110 try:
110 mailer = Mailer(**email_conf)
111 mailer = Mailer(**email_conf)
111
112
112 message = Message(subject=subject,
113 message = Message(subject=subject,
113 sender=email_conf['default_sender'],
114 sender=email_conf['default_sender'],
114 recipients=recipients,
115 recipients=recipients,
115 body=body, html=html_body)
116 body=body, html=html_body)
116 mailer.send_immediately(message)
117 mailer.send_immediately(message)
117
118
118 except Exception:
119 except Exception:
119 log.exception('Mail sending failed')
120 log.exception('Mail sending failed')
120 return False
121 return False
121 return True
122 return True
122
123
123
124
124 @async_task(ignore_result=True, base=RequestContextTask)
125 @async_task(ignore_result=True, base=RequestContextTask)
125 def create_repo(form_data, cur_user):
126 def create_repo(form_data, cur_user):
126 from rhodecode.model.repo import RepoModel
127 from rhodecode.model.repo import RepoModel
127 from rhodecode.model.user import UserModel
128 from rhodecode.model.user import UserModel
128 from rhodecode.model.scm import ScmModel
129 from rhodecode.model.scm import ScmModel
129 from rhodecode.model.settings import SettingsModel
130 from rhodecode.model.settings import SettingsModel
130
131
131 log = get_logger(create_repo)
132 log = get_logger(create_repo)
132
133
133 cur_user = UserModel()._get_user(cur_user)
134 cur_user = UserModel()._get_user(cur_user)
134 owner = cur_user
135 owner = cur_user
135
136
136 repo_name = form_data['repo_name']
137 repo_name = form_data['repo_name']
137 repo_name_full = form_data['repo_name_full']
138 repo_name_full = form_data['repo_name_full']
138 repo_type = form_data['repo_type']
139 repo_type = form_data['repo_type']
139 description = form_data['repo_description']
140 description = form_data['repo_description']
140 private = form_data['repo_private']
141 private = form_data['repo_private']
141 clone_uri = form_data.get('clone_uri')
142 clone_uri = form_data.get('clone_uri')
142 repo_group = safe_int(form_data['repo_group'])
143 repo_group = safe_int(form_data['repo_group'])
143 copy_fork_permissions = form_data.get('copy_permissions')
144 copy_fork_permissions = form_data.get('copy_permissions')
144 copy_group_permissions = form_data.get('repo_copy_permissions')
145 copy_group_permissions = form_data.get('repo_copy_permissions')
145 fork_of = form_data.get('fork_parent_id')
146 fork_of = form_data.get('fork_parent_id')
146 state = form_data.get('repo_state', Repository.STATE_PENDING)
147 state = form_data.get('repo_state', Repository.STATE_PENDING)
147
148
148 # repo creation defaults, private and repo_type are filled in form
149 # repo creation defaults, private and repo_type are filled in form
149 defs = SettingsModel().get_default_repo_settings(strip_prefix=True)
150 defs = SettingsModel().get_default_repo_settings(strip_prefix=True)
150 enable_statistics = form_data.get(
151 enable_statistics = form_data.get(
151 'enable_statistics', defs.get('repo_enable_statistics'))
152 'enable_statistics', defs.get('repo_enable_statistics'))
152 enable_locking = form_data.get(
153 enable_locking = form_data.get(
153 'enable_locking', defs.get('repo_enable_locking'))
154 'enable_locking', defs.get('repo_enable_locking'))
154 enable_downloads = form_data.get(
155 enable_downloads = form_data.get(
155 'enable_downloads', defs.get('repo_enable_downloads'))
156 'enable_downloads', defs.get('repo_enable_downloads'))
156
157
157 # set landing rev based on default branches for SCM
158 # set landing rev based on default branches for SCM
158 landing_ref, _label = ScmModel.backend_landing_ref(repo_type)
159 landing_ref, _label = ScmModel.backend_landing_ref(repo_type)
159
160
160 try:
161 try:
161 RepoModel()._create_repo(
162 RepoModel()._create_repo(
162 repo_name=repo_name_full,
163 repo_name=repo_name_full,
163 repo_type=repo_type,
164 repo_type=repo_type,
164 description=description,
165 description=description,
165 owner=owner,
166 owner=owner,
166 private=private,
167 private=private,
167 clone_uri=clone_uri,
168 clone_uri=clone_uri,
168 repo_group=repo_group,
169 repo_group=repo_group,
169 landing_rev=landing_ref,
170 landing_rev=landing_ref,
170 fork_of=fork_of,
171 fork_of=fork_of,
171 copy_fork_permissions=copy_fork_permissions,
172 copy_fork_permissions=copy_fork_permissions,
172 copy_group_permissions=copy_group_permissions,
173 copy_group_permissions=copy_group_permissions,
173 enable_statistics=enable_statistics,
174 enable_statistics=enable_statistics,
174 enable_locking=enable_locking,
175 enable_locking=enable_locking,
175 enable_downloads=enable_downloads,
176 enable_downloads=enable_downloads,
176 state=state
177 state=state
177 )
178 )
178 Session().commit()
179 Session().commit()
179
180
180 # now create this repo on Filesystem
181 # now create this repo on Filesystem
181 RepoModel()._create_filesystem_repo(
182 RepoModel()._create_filesystem_repo(
182 repo_name=repo_name,
183 repo_name=repo_name,
183 repo_type=repo_type,
184 repo_type=repo_type,
184 repo_group=RepoModel()._get_repo_group(repo_group),
185 repo_group=RepoModel()._get_repo_group(repo_group),
185 clone_uri=clone_uri,
186 clone_uri=clone_uri,
186 )
187 )
187 repo = Repository.get_by_repo_name(repo_name_full)
188 repo = Repository.get_by_repo_name(repo_name_full)
188 log_create_repository(created_by=owner.username, **repo.get_dict())
189 log_create_repository(created_by=owner.username, **repo.get_dict())
189
190
190 # update repo commit caches initially
191 # update repo commit caches initially
191 repo.update_commit_cache()
192 repo.update_commit_cache()
192
193
193 # set new created state
194 # set new created state
194 repo.set_state(Repository.STATE_CREATED)
195 repo.set_state(Repository.STATE_CREATED)
195 repo_id = repo.repo_id
196 repo_id = repo.repo_id
196 repo_data = repo.get_api_data()
197 repo_data = repo.get_api_data()
197
198
198 audit_logger.store(
199 audit_logger.store(
199 'repo.create', action_data={'data': repo_data},
200 'repo.create', action_data={'data': repo_data},
200 user=cur_user,
201 user=cur_user,
201 repo=audit_logger.RepoWrap(repo_name=repo_name, repo_id=repo_id))
202 repo=audit_logger.RepoWrap(repo_name=repo_name, repo_id=repo_id))
202
203
203 Session().commit()
204 Session().commit()
204 except Exception as e:
205 except Exception as e:
205 log.warning('Exception occurred when creating repository, '
206 log.warning('Exception occurred when creating repository, '
206 'doing cleanup...', exc_info=True)
207 'doing cleanup...', exc_info=True)
207 if isinstance(e, IntegrityError):
208 if isinstance(e, IntegrityError):
208 Session().rollback()
209 Session().rollback()
209
210
210 # rollback things manually !
211 # rollback things manually !
211 repo = Repository.get_by_repo_name(repo_name_full)
212 repo = Repository.get_by_repo_name(repo_name_full)
212 if repo:
213 if repo:
213 Repository.delete(repo.repo_id)
214 Repository.delete(repo.repo_id)
214 Session().commit()
215 Session().commit()
215 RepoModel()._delete_filesystem_repo(repo)
216 RepoModel()._delete_filesystem_repo(repo)
216 log.info('Cleanup of repo %s finished', repo_name_full)
217 log.info('Cleanup of repo %s finished', repo_name_full)
217 raise
218 raise
218
219
219 return True
220 return True
220
221
221
222
222 @async_task(ignore_result=True, base=RequestContextTask)
223 @async_task(ignore_result=True, base=RequestContextTask)
223 def create_repo_fork(form_data, cur_user):
224 def create_repo_fork(form_data, cur_user):
224 """
225 """
225 Creates a fork of repository using internal VCS methods
226 Creates a fork of repository using internal VCS methods
226 """
227 """
227 from rhodecode.model.repo import RepoModel
228 from rhodecode.model.repo import RepoModel
228 from rhodecode.model.user import UserModel
229 from rhodecode.model.user import UserModel
229
230
230 log = get_logger(create_repo_fork)
231 log = get_logger(create_repo_fork)
231
232
232 cur_user = UserModel()._get_user(cur_user)
233 cur_user = UserModel()._get_user(cur_user)
233 owner = cur_user
234 owner = cur_user
234
235
235 repo_name = form_data['repo_name'] # fork in this case
236 repo_name = form_data['repo_name'] # fork in this case
236 repo_name_full = form_data['repo_name_full']
237 repo_name_full = form_data['repo_name_full']
237 repo_type = form_data['repo_type']
238 repo_type = form_data['repo_type']
238 description = form_data['description']
239 description = form_data['description']
239 private = form_data['private']
240 private = form_data['private']
240 clone_uri = form_data.get('clone_uri')
241 clone_uri = form_data.get('clone_uri')
241 repo_group = safe_int(form_data['repo_group'])
242 repo_group = safe_int(form_data['repo_group'])
242 landing_ref = form_data['landing_rev']
243 landing_ref = form_data['landing_rev']
243 copy_fork_permissions = form_data.get('copy_permissions')
244 copy_fork_permissions = form_data.get('copy_permissions')
244 fork_id = safe_int(form_data.get('fork_parent_id'))
245 fork_id = safe_int(form_data.get('fork_parent_id'))
245
246
246 try:
247 try:
247 fork_of = RepoModel()._get_repo(fork_id)
248 fork_of = RepoModel()._get_repo(fork_id)
248 RepoModel()._create_repo(
249 RepoModel()._create_repo(
249 repo_name=repo_name_full,
250 repo_name=repo_name_full,
250 repo_type=repo_type,
251 repo_type=repo_type,
251 description=description,
252 description=description,
252 owner=owner,
253 owner=owner,
253 private=private,
254 private=private,
254 clone_uri=clone_uri,
255 clone_uri=clone_uri,
255 repo_group=repo_group,
256 repo_group=repo_group,
256 landing_rev=landing_ref,
257 landing_rev=landing_ref,
257 fork_of=fork_of,
258 fork_of=fork_of,
258 copy_fork_permissions=copy_fork_permissions
259 copy_fork_permissions=copy_fork_permissions
259 )
260 )
260
261
261 Session().commit()
262 Session().commit()
262
263
263 base_path = Repository.base_path()
264 base_path = Repository.base_path()
264 source_repo_path = os.path.join(base_path, fork_of.repo_name)
265 source_repo_path = os.path.join(base_path, fork_of.repo_name)
265
266
266 # now create this repo on Filesystem
267 # now create this repo on Filesystem
267 RepoModel()._create_filesystem_repo(
268 RepoModel()._create_filesystem_repo(
268 repo_name=repo_name,
269 repo_name=repo_name,
269 repo_type=repo_type,
270 repo_type=repo_type,
270 repo_group=RepoModel()._get_repo_group(repo_group),
271 repo_group=RepoModel()._get_repo_group(repo_group),
271 clone_uri=source_repo_path,
272 clone_uri=source_repo_path,
272 )
273 )
273 repo = Repository.get_by_repo_name(repo_name_full)
274 repo = Repository.get_by_repo_name(repo_name_full)
274 log_create_repository(created_by=owner.username, **repo.get_dict())
275 log_create_repository(created_by=owner.username, **repo.get_dict())
275
276
276 # update repo commit caches initially
277 # update repo commit caches initially
277 config = repo._config
278 config = repo._config
278 config.set('extensions', 'largefiles', '')
279 config.set('extensions', 'largefiles', '')
279 repo.update_commit_cache(config=config)
280 repo.update_commit_cache(config=config)
280
281
281 # set new created state
282 # set new created state
282 repo.set_state(Repository.STATE_CREATED)
283 repo.set_state(Repository.STATE_CREATED)
283
284
284 repo_id = repo.repo_id
285 repo_id = repo.repo_id
285 repo_data = repo.get_api_data()
286 repo_data = repo.get_api_data()
286 audit_logger.store(
287 audit_logger.store(
287 'repo.fork', action_data={'data': repo_data},
288 'repo.fork', action_data={'data': repo_data},
288 user=cur_user,
289 user=cur_user,
289 repo=audit_logger.RepoWrap(repo_name=repo_name, repo_id=repo_id))
290 repo=audit_logger.RepoWrap(repo_name=repo_name, repo_id=repo_id))
290
291
291 Session().commit()
292 Session().commit()
292 except Exception as e:
293 except Exception as e:
293 log.warning('Exception occurred when forking repository, '
294 log.warning('Exception occurred when forking repository, '
294 'doing cleanup...', exc_info=True)
295 'doing cleanup...', exc_info=True)
295 if isinstance(e, IntegrityError):
296 if isinstance(e, IntegrityError):
296 Session().rollback()
297 Session().rollback()
297
298
298 # rollback things manually !
299 # rollback things manually !
299 repo = Repository.get_by_repo_name(repo_name_full)
300 repo = Repository.get_by_repo_name(repo_name_full)
300 if repo:
301 if repo:
301 Repository.delete(repo.repo_id)
302 Repository.delete(repo.repo_id)
302 Session().commit()
303 Session().commit()
303 RepoModel()._delete_filesystem_repo(repo)
304 RepoModel()._delete_filesystem_repo(repo)
304 log.info('Cleanup of repo %s finished', repo_name_full)
305 log.info('Cleanup of repo %s finished', repo_name_full)
305 raise
306 raise
306
307
307 return True
308 return True
308
309
309
310
310 @async_task(ignore_result=True)
311 @async_task(ignore_result=True)
311 def repo_maintenance(repoid):
312 def repo_maintenance(repoid):
312 from rhodecode.lib import repo_maintenance as repo_maintenance_lib
313 from rhodecode.lib import repo_maintenance as repo_maintenance_lib
313 log = get_logger(repo_maintenance)
314 log = get_logger(repo_maintenance)
314 repo = Repository.get_by_id_or_repo_name(repoid)
315 repo = Repository.get_by_id_or_repo_name(repoid)
315 if repo:
316 if repo:
316 maintenance = repo_maintenance_lib.RepoMaintenance()
317 maintenance = repo_maintenance_lib.RepoMaintenance()
317 tasks = maintenance.get_tasks_for_repo(repo)
318 tasks = maintenance.get_tasks_for_repo(repo)
318 log.debug('Executing %s tasks on repo `%s`', tasks, repoid)
319 log.debug('Executing %s tasks on repo `%s`', tasks, repoid)
319 executed_types = maintenance.execute(repo)
320 executed_types = maintenance.execute(repo)
320 log.debug('Got execution results %s', executed_types)
321 log.debug('Got execution results %s', executed_types)
321 else:
322 else:
322 log.debug('Repo `%s` not found or without a clone_url', repoid)
323 log.debug('Repo `%s` not found or without a clone_url', repoid)
323
324
324
325
325 @async_task(ignore_result=True)
326 @async_task(ignore_result=True)
326 def check_for_update():
327 def check_for_update():
327 from rhodecode.model.update import UpdateModel
328 from rhodecode.model.update import UpdateModel
328 update_url = UpdateModel().get_update_url()
329 update_url = UpdateModel().get_update_url()
329 cur_ver = rhodecode.__version__
330 cur_ver = rhodecode.__version__
330
331
331 try:
332 try:
332 data = UpdateModel().get_update_data(update_url)
333 data = UpdateModel().get_update_data(update_url)
333 latest = data['versions'][0]
334 latest = data['versions'][0]
334 UpdateModel().store_version(latest['version'])
335 UpdateModel().store_version(latest['version'])
335 except Exception:
336 except Exception:
336 pass
337 pass
337
338
338
339
339 @async_task(ignore_result=False)
340 @async_task(ignore_result=False)
340 def beat_check(*args, **kwargs):
341 def beat_check(*args, **kwargs):
341 log = get_logger(beat_check)
342 log = get_logger(beat_check)
342 log.info('Got args: %r and kwargs %r', args, kwargs)
343 log.info('Got args: %r and kwargs %r', args, kwargs)
343 return time.time()
344 return time.time()
344
345
345
346
346 @async_task(ignore_result=True)
347 @async_task(ignore_result=True)
347 def sync_repo_groups_last_update(*args, **kwargs):
348 def sync_last_update(*args, **kwargs):
348 from rhodecode.model.repo_group import RepoGroupModel
349
349 return RepoGroupModel().update_commit_cache()
350 skip_repos = kwargs.get('skip_repos')
351 if not skip_repos:
352 repos = Repository.query() \
353 .order_by(Repository.group_id.asc())
354
355 for repo in repos:
356 repo.update_commit_cache()
357
358 skip_groups = kwargs.get('skip_groups')
359 if not skip_groups:
360 repo_groups = RepoGroup.query() \
361 .filter(RepoGroup.group_parent_id == None)
362
363 for root_gr in repo_groups:
364 for repo_gr in reversed(root_gr.recursive_groups()):
365 repo_gr.update_commit_cache()
General Comments 0
You need to be logged in to leave comments. Login now