##// END OF EJS Templates
release: merged default into stable
marcink -
r3012:22b5bff9 merge stable
parent child Browse files
Show More
@@ -0,0 +1,43 b''
1 |RCE| 4.13.1 |RNS|
2 ------------------
3
4 Release Date
5 ^^^^^^^^^^^^
6
7 - 2018-08-06
8
9
10 New Features
11 ^^^^^^^^^^^^
12
13
14
15 General
16 ^^^^^^^
17
18 - core: added option to prefix cache keys for usage in cluster.
19 - exception-tracker: store event sending exception for easier event fail debugging.
20 - maintenance: add repack and fsck for git maintenance execution list.
21
22
23 Security
24 ^^^^^^^^
25
26
27
28 Performance
29 ^^^^^^^^^^^
30
31
32
33 Fixes
34 ^^^^^
35
36 - caches: use single default cache dir for all backends.
37 - caches: don't use lower in cache settings to support uppercase PATHS
38
39
40 Upgrade notes
41 ^^^^^^^^^^^^^
42
43 - Unscheduled release addressing reported problems, and improving stability.
@@ -9,6 +9,7 b' Release Notes'
9 9 .. toctree::
10 10 :maxdepth: 1
11 11
12 release-notes-4.13.1.rst
12 13 release-notes-4.13.0.rst
13 14 release-notes-4.12.4.rst
14 15 release-notes-4.12.3.rst
@@ -1653,6 +1653,8 b' self: super: {'
1653 1653 self."setuptools-scm"
1654 1654 self."amqp"
1655 1655 self."authomatic"
1656 self."atomicwrites"
1657 self."attrs"
1656 1658 self."babel"
1657 1659 self."beaker"
1658 1660 self."celery"
@@ -4,6 +4,8 b' setuptools-scm==2.1.0'
4 4 amqp==2.3.1
5 5 # not released authomatic that has updated some oauth providers
6 6 https://code.rhodecode.com/upstream/authomatic/archive/90a9ce60cc405ae8a2bf5c3713acd5d78579a04e.tar.gz?md5=3c68720a1322b25254009518d1ff6801#egg=authomatic==0.1.0.post1
7 atomicwrites==1.1.5
8 attrs==18.1.0
7 9 babel==1.3
8 10 beaker==1.9.1
9 11 celery==4.1.1
@@ -32,8 +32,6 b' log = logging.getLogger(__name__)'
32 32 class RepoMaintenanceView(RepoAppView):
33 33 def load_default_context(self):
34 34 c = self._get_local_tmpl_context()
35
36
37 35 return c
38 36
39 37 @LoginRequired()
@@ -436,13 +436,23 b' def _sanitize_vcs_settings(settings):'
436 436
437 437
438 438 def _sanitize_cache_settings(settings):
439 _string_setting(settings, 'cache_dir',
440 os.path.join(tempfile.gettempdir(), 'rc_cache'))
439 default_cache_dir = os.path.join(tempfile.gettempdir(), 'rc_cache')
440
441 # save default, cache dir, and use it for all backends later.
442 default_cache_dir = _string_setting(
443 settings,
444 'cache_dir',
445 default_cache_dir, lower=False, default_when_empty=True)
446
447 # ensure we have our dir created
448 if not os.path.isdir(default_cache_dir):
449 os.makedirs(default_cache_dir, mode=0755)
450
441 451 # cache_perms
442 452 _string_setting(
443 453 settings,
444 454 'rc_cache.cache_perms.backend',
445 'dogpile.cache.rc.file_namespace')
455 'dogpile.cache.rc.file_namespace', lower=False)
446 456 _int_setting(
447 457 settings,
448 458 'rc_cache.cache_perms.expiration_time',
@@ -450,13 +460,13 b' def _sanitize_cache_settings(settings):'
450 460 _string_setting(
451 461 settings,
452 462 'rc_cache.cache_perms.arguments.filename',
453 os.path.join(tempfile.gettempdir(), 'rc_cache_1'))
463 os.path.join(default_cache_dir, 'rc_cache_1'), lower=False)
454 464
455 465 # cache_repo
456 466 _string_setting(
457 467 settings,
458 468 'rc_cache.cache_repo.backend',
459 'dogpile.cache.rc.file_namespace')
469 'dogpile.cache.rc.file_namespace', lower=False)
460 470 _int_setting(
461 471 settings,
462 472 'rc_cache.cache_repo.expiration_time',
@@ -464,13 +474,13 b' def _sanitize_cache_settings(settings):'
464 474 _string_setting(
465 475 settings,
466 476 'rc_cache.cache_repo.arguments.filename',
467 os.path.join(tempfile.gettempdir(), 'rc_cache_2'))
477 os.path.join(default_cache_dir, 'rc_cache_2'), lower=False)
468 478
469 479 # cache_license
470 480 _string_setting(
471 481 settings,
472 482 'rc_cache.cache_license.backend',
473 'dogpile.cache.rc.file_namespace')
483 'dogpile.cache.rc.file_namespace', lower=False)
474 484 _int_setting(
475 485 settings,
476 486 'rc_cache.cache_license.expiration_time',
@@ -478,13 +488,13 b' def _sanitize_cache_settings(settings):'
478 488 _string_setting(
479 489 settings,
480 490 'rc_cache.cache_license.arguments.filename',
481 os.path.join(tempfile.gettempdir(), 'rc_cache_3'))
491 os.path.join(default_cache_dir, 'rc_cache_3'), lower=False)
482 492
483 493 # cache_repo_longterm memory, 96H
484 494 _string_setting(
485 495 settings,
486 496 'rc_cache.cache_repo_longterm.backend',
487 'dogpile.cache.rc.memory_lru')
497 'dogpile.cache.rc.memory_lru', lower=False)
488 498 _int_setting(
489 499 settings,
490 500 'rc_cache.cache_repo_longterm.expiration_time',
@@ -498,7 +508,7 b' def _sanitize_cache_settings(settings):'
498 508 _string_setting(
499 509 settings,
500 510 'rc_cache.sql_cache_short.backend',
501 'dogpile.cache.rc.memory_lru')
511 'dogpile.cache.rc.memory_lru', lower=False)
502 512 _int_setting(
503 513 settings,
504 514 'rc_cache.sql_cache_short.expiration_time',
@@ -511,6 +521,7 b' def _sanitize_cache_settings(settings):'
511 521
512 522 def _int_setting(settings, name, default):
513 523 settings[name] = int(settings.get(name, default))
524 return settings[name]
514 525
515 526
516 527 def _bool_setting(settings, name, default):
@@ -518,6 +529,7 b' def _bool_setting(settings, name, defaul'
518 529 if isinstance(input_val, unicode):
519 530 input_val = input_val.encode('utf8')
520 531 settings[name] = asbool(input_val)
532 return settings[name]
521 533
522 534
523 535 def _list_setting(settings, name, default):
@@ -530,13 +542,20 b' def _list_setting(settings, name, defaul'
530 542 else:
531 543 # Otherwise we assume it uses pyramids space/newline separation.
532 544 settings[name] = aslist(raw_value)
545 return settings[name]
533 546
534 547
535 def _string_setting(settings, name, default, lower=True):
548 def _string_setting(settings, name, default, lower=True, default_when_empty=False):
536 549 value = settings.get(name, default)
550
551 if default_when_empty and not value:
552 # use default value when value is empty
553 value = default
554
537 555 if lower:
538 556 value = value.lower()
539 557 settings[name] = value
558 return settings[name]
540 559
541 560
542 561 def _substitute_values(mapping, substitutions):
@@ -81,9 +81,14 b' def get_vcs_server_protocol(config):'
81 81
82 82
83 83 def set_instance_id(config):
84 """ Sets a dynamic generated config['instance_id'] if missing or '*' """
84 """
85 Sets a dynamic generated config['instance_id'] if missing or '*'
86 E.g instance_id = *cluster-1 or instance_id = *
87 """
85 88
86 89 config['instance_id'] = config.get('instance_id') or ''
87 if config['instance_id'] == '*' or not config['instance_id']:
90 instance_id = config['instance_id']
91 if instance_id.startswith('*') or not instance_id:
92 prefix = instance_id.lstrip('*')
88 93 _platform_id = platform.uname()[1] or 'instance'
89 config['instance_id'] = '%s-%s' % (_platform_id, os.getpid())
94 config['instance_id'] = '%s%s-%s' % (prefix, _platform_id, os.getpid())
@@ -17,11 +17,13 b''
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20 import sys
21 21 import logging
22 22
23 23 from rhodecode.integrations.registry import IntegrationTypeRegistry
24 24 from rhodecode.integrations.types import webhook, slack, hipchat, email, base
25 from rhodecode.lib.exc_tracking import store_exception
26
25 27 log = logging.getLogger(__name__)
26 28
27 29
@@ -61,6 +63,8 b' def integrations_event_handler(event):'
61 63 try:
62 64 integration_model.send_event(integration, event)
63 65 except Exception:
66 exc_info = sys.exc_info()
67 store_exception(id(exc_info), exc_info)
64 68 log.exception(
65 69 'failure occurred when sending event %s to integration %s' % (
66 70 event, integration))
@@ -87,6 +87,13 b' def _store_exception(exc_id, exc_info, p'
87 87
88 88
89 89 def store_exception(exc_id, exc_info, prefix=global_prefix):
90 """
91 Example usage::
92
93 exc_info = sys.exc_info()
94 store_exception(id(exc_info), exc_info)
95 """
96
90 97 try:
91 98 _store_exception(exc_id=exc_id, exc_info=exc_info, prefix=prefix)
92 99 except Exception:
@@ -51,25 +51,81 b' class GitGC(MaintenanceTask):'
51 51 output = []
52 52 instance = self.db_repo.scm_instance()
53 53
54 objects = self._count_objects(instance)
55 output.append(objects)
56 log.debug('GIT objects:%s', objects)
57
58 stdout, stderr = instance.run_git_command(
59 ['gc', '--aggressive'], fail_on_stderr=False)
54 objects_before = self._count_objects(instance)
60 55
61 out = 'executed git gc --aggressive'
62 if stderr:
63 out = ''.join(stderr.splitlines())
56 log.debug('GIT objects:%s', objects_before)
57 cmd = ['gc', '--aggressive']
58 stdout, stderr = instance.run_git_command(cmd, fail_on_stderr=False)
64 59
65 elif stdout:
66 out = ''.join(stdout.splitlines())
67
60 out = 'executed {}'.format(' '.join(cmd))
68 61 output.append(out)
69 62
70 objects = self._count_objects(instance)
71 log.debug('GIT objects:%s', objects)
72 output.append(objects)
63 out = ''
64 if stderr:
65 out += ''.join(stderr.splitlines())
66
67 if stdout:
68 out += ''.join(stdout.splitlines())
69
70 if out:
71 output.append(out)
72
73 objects_after = self._count_objects(instance)
74 log.debug('GIT objects:%s', objects_after)
75 output.append('objects before :' + objects_before)
76 output.append('objects after :' + objects_after)
77
78 return '\n'.join(output)
79
80
81 class GitFSCK(MaintenanceTask):
82 human_name = 'GIT FSCK'
83
84 def run(self):
85 output = []
86 instance = self.db_repo.scm_instance()
87
88 cmd = ['fsck', '--full']
89 stdout, stderr = instance.run_git_command(cmd, fail_on_stderr=False)
90
91 out = 'executed {}'.format(' '.join(cmd))
92 output.append(out)
93
94 out = ''
95 if stderr:
96 out += ''.join(stderr.splitlines())
97
98 if stdout:
99 out += ''.join(stdout.splitlines())
100
101 if out:
102 output.append(out)
103
104 return '\n'.join(output)
105
106
107 class GitRepack(MaintenanceTask):
108 human_name = 'GIT Repack'
109
110 def run(self):
111 output = []
112 instance = self.db_repo.scm_instance()
113 cmd = ['repack', '-a', '-d',
114 '--window-memory', '10m', '--max-pack-size', '100m']
115 stdout, stderr = instance.run_git_command(cmd, fail_on_stderr=False)
116
117 out = 'executed {}'.format(' '.join(cmd))
118 output.append(out)
119 out = ''
120
121 if stderr:
122 out += ''.join(stderr.splitlines())
123
124 if stdout:
125 out += ''.join(stdout.splitlines())
126
127 if out:
128 output.append(out)
73 129
74 130 return '\n'.join(output)
75 131
@@ -98,7 +154,7 b' class RepoMaintenance(object):'
98 154 """
99 155 tasks = {
100 156 'hg': [HGVerify],
101 'git': [GitGC],
157 'git': [GitFSCK, GitGC, GitRepack],
102 158 'svn': [SVNVerify],
103 159 }
104 160
@@ -114,5 +170,6 b' class RepoMaintenance(object):'
114 170 def execute(self, db_repo):
115 171 executed_tasks = []
116 172 for task in self.tasks[db_repo.repo_type]:
117 executed_tasks.append(task(db_repo).run())
173 output = task.human_name + ':\n' + task(db_repo).run() + '\n--\n'
174 executed_tasks.append(output)
118 175 return executed_tasks
General Comments 0
You need to be logged in to leave comments. Login now