Merge branch 'downstream' into devel

This commit is contained in:
Ryan Petrello
2020-04-28 12:18:13 -04:00
34 changed files with 291 additions and 194 deletions
+5 -6
View File
@@ -44,8 +44,8 @@ class FixedSlidingWindow():
def cleanup(self, now_bucket=None):
now_bucket = now_bucket or now_seconds()
if self.start_time + 60 <= now_bucket:
self.start_time = now_bucket + 60 + 1
if self.start_time + 60 < now_bucket:
self.start_time = now_bucket - 60
# Delete old entries
for k in list(self.buckets.keys()):
@@ -53,16 +53,15 @@ class FixedSlidingWindow():
del self.buckets[k]
def record(self, ts=None):
ts = ts or datetime.datetime.now()
now_bucket = int((ts - datetime.datetime(1970,1,1)).total_seconds())
now_bucket = ts or dt_to_seconds(datetime.datetime.now())
val = self.buckets.get(now_bucket, 0)
self.buckets[now_bucket] = val + 1
self.cleanup(now_bucket)
def render(self):
self.cleanup()
def render(self, ts=None):
self.cleanup(now_bucket=ts)
return sum(self.buckets.values()) or 0
+11
View File
@@ -121,6 +121,17 @@ class InstanceManager(models.Manager):
if not hostname:
hostname = settings.CLUSTER_HOST_ID
with advisory_lock('instance_registration_%s' % hostname):
if settings.AWX_AUTO_DEPROVISION_INSTANCES:
# detect any instances with the same IP address.
# if one exists, set it to None
inst_conflicting_ip = self.filter(ip_address=ip_address).exclude(hostname=hostname)
if inst_conflicting_ip.exists():
for other_inst in inst_conflicting_ip:
other_hostname = other_inst.hostname
other_inst.ip_address = None
other_inst.save(update_fields=['ip_address'])
logger.warning("IP address {0} conflict detected, ip address unset for host {1}.".format(ip_address, other_hostname))
instance = self.filter(hostname=hostname)
if instance.exists():
instance = instance.get()
+9
View File
@@ -2577,6 +2577,12 @@ class satellite6(PluginFileInjector):
def inventory_as_dict(self, inventory_update, private_data_dir):
ret = super(satellite6, self).inventory_as_dict(inventory_update, private_data_dir)
want_ansible_ssh_host = False
foreman_opts = inventory_update.source_vars_dict.copy()
for k, v in foreman_opts.items():
if k == 'satellite6_want_ansible_ssh_host' and isinstance(v, bool):
want_ansible_ssh_host = v
# Compatibility content
group_by_hostvar = {
"environment": {"prefix": "foreman_environment_",
@@ -2603,6 +2609,9 @@ class satellite6(PluginFileInjector):
ret['want_facts'] = True
ret['want_params'] = True
if want_ansible_ssh_host:
ret['compose'] = {'ansible_ssh_host': "foreman['ip6'] | default(foreman['ip'], true)"}
return ret
+15 -10
View File
@@ -2074,29 +2074,34 @@ class RunProjectUpdate(BaseTask):
if settings.GALAXY_IGNORE_CERTS:
env['ANSIBLE_GALAXY_IGNORE'] = True
# Set up the public Galaxy server, if enabled
galaxy_configured = False
if settings.PUBLIC_GALAXY_ENABLED:
galaxy_servers = [settings.PUBLIC_GALAXY_SERVER]
galaxy_servers = [settings.PUBLIC_GALAXY_SERVER] # static setting
else:
galaxy_configured = True
galaxy_servers = []
# Set up fallback Galaxy servers, if configured
if settings.FALLBACK_GALAXY_SERVERS:
galaxy_configured = True
galaxy_servers = settings.FALLBACK_GALAXY_SERVERS + galaxy_servers
# Set up the primary Galaxy server, if configured
if settings.PRIMARY_GALAXY_URL:
galaxy_configured = True
galaxy_servers = [{'id': 'primary_galaxy'}] + galaxy_servers
for key in GALAXY_SERVER_FIELDS:
value = getattr(settings, 'PRIMARY_GALAXY_{}'.format(key.upper()))
if value:
galaxy_servers[0][key] = value
for server in galaxy_servers:
for key in GALAXY_SERVER_FIELDS:
if not server.get(key):
continue
env_key = ('ANSIBLE_GALAXY_SERVER_{}_{}'.format(server.get('id', 'unnamed'), key)).upper()
env[env_key] = server[key]
if galaxy_servers:
# now set the precedence of galaxy servers
env['ANSIBLE_GALAXY_SERVER_LIST'] = ','.join([server.get('id', 'unnamed') for server in galaxy_servers])
if galaxy_configured:
for server in galaxy_servers:
for key in GALAXY_SERVER_FIELDS:
if not server.get(key):
continue
env_key = ('ANSIBLE_GALAXY_SERVER_{}_{}'.format(server.get('id', 'unnamed'), key)).upper()
env[env_key] = server[key]
if galaxy_servers:
# now set the precedence of galaxy servers
env['ANSIBLE_GALAXY_SERVER_LIST'] = ','.join([server.get('id', 'unnamed') for server in galaxy_servers])
return env
def _build_scm_url_extra_vars(self, project_update):
@@ -1,3 +1,5 @@
compose:
ansible_ssh_host: foreman['ip6'] | default(foreman['ip'], true)
keyed_groups:
- key: foreman['environment_name'] | lower | regex_replace(' ', '') | regex_replace('[^A-Za-z0-9\_]', '_') | regex_replace('none', '')
prefix: foreman_environment_
@@ -0,0 +1,69 @@
import datetime
from awx.main.analytics.broadcast_websocket import FixedSlidingWindow
from awx.main.analytics.broadcast_websocket import dt_to_seconds
class TestFixedSlidingWindow():
def ts(self, **kwargs):
e = {
'year': 1985,
'month': 1,
'day': 1,
'hour': 1,
}
return dt_to_seconds(datetime.datetime(**kwargs, **e))
def test_record_same_minute(self):
"""
Legend:
- = record()
^ = render()
|---| = 1 minute, 60 seconds
....................
|------------------------------------------------------------|
^^^^^^^^^^^^^^^^^^^^
"""
fsw = FixedSlidingWindow(self.ts(minute=0, second=0, microsecond=0))
for i in range(20):
fsw.record(self.ts(minute=0, second=i, microsecond=0))
assert (i + 1) == fsw.render(self.ts(minute=0, second=i, microsecond=0))
def test_record_same_minute_render_diff_minute(self):
"""
Legend:
- = record()
^ = render()
|---| = 1 minute, 60 seconds
....................
|------------------------------------------------------------|
^^ ^
AB C
|------------------------------------------------------------|
^^^^^^^^^^^^^^^^^^^^^
DEEEEEEEEEEEEEEEEEEEF
"""
fsw = FixedSlidingWindow(self.ts(minute=0, second=0, microsecond=0))
for i in range(20):
fsw.record(self.ts(minute=0, second=i, microsecond=0))
assert 20 == fsw.render(self.ts(minute=0, second=19, microsecond=0)), \
"A. The second of the last record() call"
assert 20 == fsw.render(self.ts(minute=0, second=20, microsecond=0)), \
"B. The second after the last record() call"
assert 20 == fsw.render(self.ts(minute=0, second=59, microsecond=0)), \
"C. Last second in the same minute that all record() called in"
assert 20 == fsw.render(self.ts(minute=1, second=0, microsecond=0)), \
"D. First second of the minute following the minute that all record() calls in"
for i in range(20):
assert 20 - i == fsw.render(self.ts(minute=1, second=i, microsecond=0)), \
"E. Sliding window where 1 record() should drop from the results each time"
assert 0 == fsw.render(self.ts(minute=1, second=20, microsecond=0)), \
"F. First second one minute after all record() calls"
+7 -7
View File
@@ -44,7 +44,7 @@ data_loggly = {
'https',
'\n'.join([
'template(name="awx" type="string" string="%rawmsg-after-pri%")\nmodule(load="omhttp")',
'action(type="omhttp" server="logs-01.loggly.com" serverport="80" usehttps="off" skipverifyhost="off" action.resumeRetryCount="-1" template="awx" errorfile="/var/log/tower/rsyslog.err" action.resumeInterval="5" restpath="inputs/1fd38090-2af1-4e1e-8d80-492899da0f71/tag/http/")', # noqa
'action(type="omhttp" server="logs-01.loggly.com" serverport="80" usehttps="off" allowunsignedcerts="off" skipverifyhost="off" action.resumeRetryCount="-1" template="awx" errorfile="/var/log/tower/rsyslog.err" action.resumeInterval="5" restpath="inputs/1fd38090-2af1-4e1e-8d80-492899da0f71/tag/http/")', # noqa
])
),
(
@@ -77,7 +77,7 @@ data_loggly = {
None,
'\n'.join([
'template(name="awx" type="string" string="%rawmsg-after-pri%")\nmodule(load="omhttp")',
'action(type="omhttp" server="yoursplunk" serverport="443" usehttps="on" skipverifyhost="off" action.resumeRetryCount="-1" template="awx" errorfile="/var/log/tower/rsyslog.err" action.resumeInterval="5" restpath="services/collector/event")', # noqa
'action(type="omhttp" server="yoursplunk" serverport="443" usehttps="on" allowunsignedcerts="off" skipverifyhost="off" action.resumeRetryCount="-1" template="awx" errorfile="/var/log/tower/rsyslog.err" action.resumeInterval="5" restpath="services/collector/event")', # noqa
])
),
(
@@ -88,7 +88,7 @@ data_loggly = {
None,
'\n'.join([
'template(name="awx" type="string" string="%rawmsg-after-pri%")\nmodule(load="omhttp")',
'action(type="omhttp" server="yoursplunk" serverport="80" usehttps="off" skipverifyhost="off" action.resumeRetryCount="-1" template="awx" errorfile="/var/log/tower/rsyslog.err" action.resumeInterval="5" restpath="services/collector/event")', # noqa
'action(type="omhttp" server="yoursplunk" serverport="80" usehttps="off" allowunsignedcerts="off" skipverifyhost="off" action.resumeRetryCount="-1" template="awx" errorfile="/var/log/tower/rsyslog.err" action.resumeInterval="5" restpath="services/collector/event")', # noqa
])
),
(
@@ -99,7 +99,7 @@ data_loggly = {
None,
'\n'.join([
'template(name="awx" type="string" string="%rawmsg-after-pri%")\nmodule(load="omhttp")',
'action(type="omhttp" server="yoursplunk" serverport="8088" usehttps="on" skipverifyhost="off" action.resumeRetryCount="-1" template="awx" errorfile="/var/log/tower/rsyslog.err" action.resumeInterval="5" restpath="services/collector/event")', # noqa
'action(type="omhttp" server="yoursplunk" serverport="8088" usehttps="on" allowunsignedcerts="off" skipverifyhost="off" action.resumeRetryCount="-1" template="awx" errorfile="/var/log/tower/rsyslog.err" action.resumeInterval="5" restpath="services/collector/event")', # noqa
])
),
(
@@ -110,7 +110,7 @@ data_loggly = {
None,
'\n'.join([
'template(name="awx" type="string" string="%rawmsg-after-pri%")\nmodule(load="omhttp")',
'action(type="omhttp" server="yoursplunk" serverport="8088" usehttps="on" skipverifyhost="off" action.resumeRetryCount="-1" template="awx" errorfile="/var/log/tower/rsyslog.err" action.resumeInterval="5" restpath="services/collector/event")', # noqa
'action(type="omhttp" server="yoursplunk" serverport="8088" usehttps="on" allowunsignedcerts="off" skipverifyhost="off" action.resumeRetryCount="-1" template="awx" errorfile="/var/log/tower/rsyslog.err" action.resumeInterval="5" restpath="services/collector/event")', # noqa
])
),
(
@@ -121,7 +121,7 @@ data_loggly = {
'https',
'\n'.join([
'template(name="awx" type="string" string="%rawmsg-after-pri%")\nmodule(load="omhttp")',
'action(type="omhttp" server="yoursplunk.org" serverport="8088" usehttps="on" skipverifyhost="off" action.resumeRetryCount="-1" template="awx" errorfile="/var/log/tower/rsyslog.err" action.resumeInterval="5" restpath="services/collector/event")', # noqa
'action(type="omhttp" server="yoursplunk.org" serverport="8088" usehttps="on" allowunsignedcerts="off" skipverifyhost="off" action.resumeRetryCount="-1" template="awx" errorfile="/var/log/tower/rsyslog.err" action.resumeInterval="5" restpath="services/collector/event")', # noqa
])
),
(
@@ -132,7 +132,7 @@ data_loggly = {
None,
'\n'.join([
'template(name="awx" type="string" string="%rawmsg-after-pri%")\nmodule(load="omhttp")',
'action(type="omhttp" server="yoursplunk.org" serverport="8088" usehttps="off" skipverifyhost="off" action.resumeRetryCount="-1" template="awx" errorfile="/var/log/tower/rsyslog.err" action.resumeInterval="5" restpath="services/collector/event")', # noqa
'action(type="omhttp" server="yoursplunk.org" serverport="8088" usehttps="off" allowunsignedcerts="off" skipverifyhost="off" action.resumeRetryCount="-1" template="awx" errorfile="/var/log/tower/rsyslog.err" action.resumeInterval="5" restpath="services/collector/event")', # noqa
])
),
]
+2
View File
@@ -60,6 +60,7 @@ def construct_rsyslog_conf_template(settings=settings):
# https://github.com/rsyslog/rsyslog-doc/blob/master/source/configuration/modules/omhttp.rst
ssl = 'on' if parsed.scheme == 'https' else 'off'
skip_verify = 'off' if settings.LOG_AGGREGATOR_VERIFY_CERT else 'on'
allow_unsigned = 'off' if settings.LOG_AGGREGATOR_VERIFY_CERT else 'on'
if not port:
port = 443 if parsed.scheme == 'https' else 80
@@ -68,6 +69,7 @@ def construct_rsyslog_conf_template(settings=settings):
f'server="{host}"',
f'serverport="{port}"',
f'usehttps="{ssl}"',
f'allowunsignedcerts="{allow_unsigned}"',
f'skipverifyhost="{skip_verify}"',
'action.resumeRetryCount="-1"',
'template="awx"',
+4 -4
View File
@@ -136,9 +136,9 @@
register: doesRequirementsExist
- name: fetch galaxy roles from requirements.yml
command: ansible-galaxy install -r requirements.yml -p {{roles_destination|quote}}{{ ' -' + 'v' * ansible_verbosity if ansible_verbosity else '' }}
command: ansible-galaxy install -r roles/requirements.yml -p {{roles_destination|quote}}{{ ' -' + 'v' * ansible_verbosity if ansible_verbosity else '' }}
args:
chdir: "{{project_path|quote}}/roles"
chdir: "{{project_path|quote}}"
register: galaxy_result
when: doesRequirementsExist.stat.exists
changed_when: "'was installed successfully' in galaxy_result.stdout"
@@ -157,9 +157,9 @@
register: doesCollectionRequirementsExist
- name: fetch galaxy collections from collections/requirements.yml
command: ansible-galaxy collection install -r requirements.yml -p {{collections_destination|quote}}{{ ' -' + 'v' * ansible_verbosity if ansible_verbosity else '' }}
command: ansible-galaxy collection install -r collections/requirements.yml -p {{collections_destination|quote}}{{ ' -' + 'v' * ansible_verbosity if ansible_verbosity else '' }}
args:
chdir: "{{project_path|quote}}/collections"
chdir: "{{project_path|quote}}"
register: galaxy_collection_result
when: doesCollectionRequirementsExist.stat.exists
changed_when: "'Installing ' in galaxy_collection_result.stdout"
@@ -80,7 +80,7 @@
collection="vm.approvals"
dataset="vm.dataset"
iterator="template"
base-path="unified_job_templates"
base-path="workflow_approvals"
query-set="vm.queryset"
hide-view-per-page="true">
</paginate>
@@ -116,7 +116,7 @@
</div>
</div>
</div>
<div class="License-file--middle License-helperText" translate>
<div class="License-file--middle License-helperText">
<div class="License-separator"></div>
<div translate>OR</div>
<div class="License-separator"></div>
-9
View File
@@ -60,15 +60,6 @@ msgstr "<b>我同意最终用户许可证协议</b>"
msgid "<b>User analytics</b>: This data is used to enhance future releases of the Tower Software and help streamline customer experience and success."
msgstr "<b>用户分析</b>:这些数据用于增强未来的 Tower 软件发行版本,并帮助简化客户体验和成功。"
#: client/src/license/license.partial.html:119
msgid ""
"<div class=\"License-separator\"></div>\n"
"\t\t\t\t\t\t<div translate=\"\">OR</div>\n"
"\t\t\t\t\t\t<div class=\"License-separator\"></div>"
msgstr "<div class=\"License-separator\"></div>\n"
"\\t\\t\\t\\t\\t\\t<div translate=\"\">或</div>\n"
"\\t\\t\\t\\t\\t\\t<div class=\"License-separator\"></div>"
#: client/src/login/loginModal/loginModal.partial.html:26
msgid ""
"<i class=\"LoginModal-alertIcon fa fa-exclamation-triangle\"></i>\n"