mirror of
https://github.com/ZwareBear/awx.git
synced 2026-05-16 15:58:39 -05:00
Merge branch 'downstream' into devel
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
@@ -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"
|
||||
@@ -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
|
||||
])
|
||||
),
|
||||
]
|
||||
|
||||
@@ -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"',
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user